[PATCH] D46760: [InstCombine] Enhance narrowUDivURem.

Sanjay Patel via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 6 08:50:54 PDT 2018


spatel added a comment.

In https://reviews.llvm.org/D46760#1123181, @bixia wrote:

> What Sanjoy suggested doesn't (completely) solve the problem we have , where UDIV and UREM are used to calculate the dimensional indices from a linear index, and the dimensionally indices are then used to access tensors of different shapes (for example, two tensors being accessed both require broadcasting but along different dimensions). 
>  With the current state of https://reviews.llvm.org/D47113,  would it be acceptable if I revise my change here to only narrow i64 udiv/urem to i32 using the added patterns?


We're missing the fundamental motivation. This isn't about div/rem based on the IR example posted on May 12. That code is canonicalized to use shifts. So we must account for the fact that the source code could have been written using shifts in the first place. Otherwise, we're chasing an incomplete solution.

So let's look at that example after -instcombine:

  define void @narrow_long_chain_with_udiv_urem(i64* %result) {
    %num1 = call i32 @get_number(), !range !0
    %num2 = call i32 @get_number(), !range !0
    %1 = shl nuw nsw i32 %num1, 6
    %addconv = add nuw nsw i32 %1, %num2
    %2 = urem i32 %addconv, 384
    %tmp2 = zext i32 %2 to i64
    %lane_id = and i64 %tmp2, 31
    %3 = lshr i64 %tmp2, 2             <---
    %tmp4 = shl nuw nsw i64 %3, 5      <---
    %tmp5 = or i64 %tmp4, 224
    %tmp6 = or i64 %lane_id, %tmp5
    store i64 %tmp6, i64* %result, align 4
    ret void
  }

I've pointed out what I think is the critical sequence: shift right followed by shift left. Why is that a better canonicalization than:

  %and = and i64 %x, -4
  %left = shl i64 %and, 3

https://rise4fun.com/Alive/Gmc

If we had that transform, then everything would be shrunken to i32 already as we want/expect:

  define void @narrow_long_chain_with_shifts(i64* %result) {
    %num1 = call i32 @get_number(), !range !0
    %num2 = call i32 @get_number(), !range !0
    %1 = shl nuw nsw i32 %num1, 6
    %addconv = add nuw nsw i32 %1, %num2
    %2 = urem i32 %addconv, 384
    %3 = and i32 %2, 31
    %4 = shl nuw nsw i32 %2, 3
    %5 = and i32 %4, 3840
    %6 = or i32 %5, 224
    %tmp61 = or i32 %3, %6
    %tmp6 = zext i32 %tmp61 to i64
    store i64 %tmp6, i64* %result, align 4
    ret void
  }

I suspect there's some codegen concern about having a large 'and' constant mask, so if that's a problem, we can add a reverse canonicalization to the DAG to transform back to shift from 'and'. The 'and' seems better for analysis and enabling other transforms (as seen here), so I think we should have this canonicalization in IR.


Repository:
  rL LLVM

https://reviews.llvm.org/D46760





More information about the llvm-commits mailing list