[llvm] 42f488b - [InstCombine] improve matching for sext-lshr-trunc patterns

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 08:55:37 PDT 2020


Author: Sanjay Patel
Date: 2020-06-08T11:55:30-04:00
New Revision: 42f488b63a04fdaa931315bdadecb6d23e20529a

URL: https://github.com/llvm/llvm-project/commit/42f488b63a04fdaa931315bdadecb6d23e20529a
DIFF: https://github.com/llvm/llvm-project/commit/42f488b63a04fdaa931315bdadecb6d23e20529a.diff

LOG: [InstCombine] improve matching for sext-lshr-trunc patterns

This is intended to preserve the logic of the existing transform,
but remove unnecessary restrictions on uses and types.

https://rise4fun.com/Alive/pYfR

  Pre: C1 <= width(C1) - 8
  %B = sext i8 %A
  %C = lshr %B, C1
  %r = trunc %C to i8
   =>
  %r = ashr i8 %A, trunc(umin(C1, 7))

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
    llvm/test/Transforms/InstCombine/cast.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index bfe1fb7817df..7256c88f5dc3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -784,7 +784,21 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) {
     return CastInst::CreateIntegerCast(Shift, DestTy, false);
   }
 
-  // FIXME: We should canonicalize to zext/trunc and remove this transform.
+  const APInt *C;
+  if (match(Src, m_LShr(m_SExt(m_Value(A)), m_APInt(C))) &&
+      A->getType() == DestTy) {
+    // If the shift is small enough, all zero bits created by the shift are
+    // removed by the trunc:
+    // trunc (lshr (sext A), C) --> ashr A, C
+    if (C->getZExtValue() <= SrcWidth - DestWidth) {
+      unsigned ShAmt = std::min((unsigned)C->getZExtValue(), DestWidth - 1);
+      return BinaryOperator::CreateAShr(A, ConstantInt::get(DestTy, ShAmt));
+    }
+    // TODO: Mask high bits with 'and'.
+  }
+
+  // More complicated: deal with mismatched sizes.
+  // FIXME: This is too restrictive for uses and doesn't work with vectors.
   // Transform trunc(lshr (sext A), Cst) to ashr A, Cst to eliminate type
   // conversion.
   // It works because bits coming from sign extension have the same value as
@@ -803,9 +817,6 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) {
     // FIXME: Instead of bailing when the shift is too large, use and to clear
     // the extra bits.
     if (ShiftAmt <= MaxAmt) {
-      if (DestWidth == ASize)
-        return BinaryOperator::CreateAShr(
-            A, ConstantInt::get(DestTy, std::min(ShiftAmt, ASize - 1)));
       if (SExt->hasOneUse()) {
         Value *Shift = Builder.CreateAShr(A, std::min(ShiftAmt, ASize - 1));
         Shift->takeName(Src);

diff  --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll
index 6215e6694cd6..ac6c814cd45a 100644
--- a/llvm/test/Transforms/InstCombine/cast.ll
+++ b/llvm/test/Transforms/InstCombine/cast.ll
@@ -1518,8 +1518,7 @@ define <2 x i8> @trunc_lshr_sext_uses1(<2 x i8> %A) {
 ; ALL-LABEL: @trunc_lshr_sext_uses1(
 ; ALL-NEXT:    [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
 ; ALL-NEXT:    call void @use_v2i32(<2 x i32> [[B]])
-; ALL-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 6>
-; ALL-NEXT:    [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT:    [[D:%.*]] = ashr <2 x i8> [[A]], <i8 6, i8 6>
 ; ALL-NEXT:    ret <2 x i8> [[D]]
 ;
   %B = sext <2 x i8> %A to <2 x i32>
@@ -1534,7 +1533,7 @@ define i8 @trunc_lshr_sext_uses2(i8 %A) {
 ; ALL-NEXT:    [[B:%.*]] = sext i8 [[A:%.*]] to i32
 ; ALL-NEXT:    [[C:%.*]] = lshr i32 [[B]], 6
 ; ALL-NEXT:    call void @use_i32(i32 [[C]])
-; ALL-NEXT:    [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT:    [[D:%.*]] = ashr i8 [[A]], 6
 ; ALL-NEXT:    ret i8 [[D]]
 ;
   %B = sext i8 %A to i32
@@ -1550,7 +1549,7 @@ define <2 x i8 >@trunc_lshr_sext_uses3(<2 x i8> %A) {
 ; ALL-NEXT:    call void @use_v2i32(<2 x i32> [[B]])
 ; ALL-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 6>
 ; ALL-NEXT:    call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT:    [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT:    [[D:%.*]] = ashr <2 x i8> [[A]], <i8 6, i8 6>
 ; ALL-NEXT:    ret <2 x i8> [[D]]
 ;
   %B = sext <2 x i8 >%A to <2 x i32>
@@ -1563,9 +1562,7 @@ define <2 x i8 >@trunc_lshr_sext_uses3(<2 x i8> %A) {
 
 define <2 x i8> @trunc_lshr_overshift_sext(<2 x i8> %A) {
 ; ALL-LABEL: @trunc_lshr_overshift_sext(
-; ALL-NEXT:    [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
-; ALL-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 8, i32 8>
-; ALL-NEXT:    [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT:    [[D:%.*]] = ashr <2 x i8> [[A:%.*]], <i8 7, i8 7>
 ; ALL-NEXT:    ret <2 x i8> [[D]]
 ;
   %B = sext <2 x i8> %A to <2 x i32>
@@ -1593,7 +1590,7 @@ define <2 x i8> @trunc_lshr_overshift_sext_uses2(<2 x i8> %A) {
 ; ALL-NEXT:    [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
 ; ALL-NEXT:    [[C:%.*]] = lshr <2 x i32> [[B]], <i32 8, i32 8>
 ; ALL-NEXT:    call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT:    [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT:    [[D:%.*]] = ashr <2 x i8> [[A]], <i8 7, i8 7>
 ; ALL-NEXT:    ret <2 x i8> [[D]]
 ;
   %B = sext <2 x i8> %A to <2 x i32>
@@ -1609,7 +1606,7 @@ define i8 @trunc_lshr_overshift_sext_uses3(i8 %A) {
 ; ALL-NEXT:    call void @use_i32(i32 [[B]])
 ; ALL-NEXT:    [[C:%.*]] = lshr i32 [[B]], 8
 ; ALL-NEXT:    call void @use_i32(i32 [[C]])
-; ALL-NEXT:    [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT:    [[D:%.*]] = ashr i8 [[A]], 7
 ; ALL-NEXT:    ret i8 [[D]]
 ;
   %B = sext i8 %A to i32


        


More information about the llvm-commits mailing list