[llvm] a91e967 - [InstCombine] Fold `and(shl(zext(x), width(SIGNMASK) - width(%x)), SIGNMASK)` to `and(sext(%x), SIGNMASK)`

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 19 13:32:22 PST 2020


Author: Roman Lebedev
Date: 2020-11-20T00:31:27+03:00
New Revision: a91e96702a3b8ef19afc5b7d2e51ce6b6a7fded9

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

LOG: [InstCombine] Fold `and(shl(zext(x), width(SIGNMASK) - width(%x)), SIGNMASK)` to `and(sext(%x), SIGNMASK)`

One less instruction and reducing use count of zext.
As alive2 confirms, we're fine with all the weird combinations of
undef elts in constants, but unless the shift amount was undef
for a lane, we must sanitize undef mask to zero, since sign bits
are no longer zeros.

https://rise4fun.com/Alive/d7r
```
----------------------------------------
Optimization: zz
Precondition: ((C1 == (width(%r) - width(%x))) && isSignBit(C2))
  %o0 = zext %x
  %o1 = shl %o0, C1
  %r = and %o1, C2
=>
  %n0 = sext %x
  %r = and %n0, C2

Done: 2016
Optimization is correct!
```

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/signmask-of-sext-vs-of-shl-of-zext.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index a12957979190..6b5fd571ecf5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1846,6 +1846,25 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
     }
   }
 
+  if (match(&I, m_And(m_OneUse(m_Shl(m_ZExt(m_Value(X)), m_Value(Y))),
+                      m_SignMask())) &&
+      match(Y, m_SpecificInt_ICMP(
+                   ICmpInst::Predicate::ICMP_EQ,
+                   APInt(Ty->getScalarSizeInBits(),
+                         Ty->getScalarSizeInBits() -
+                             X->getType()->getScalarSizeInBits())))) {
+    auto *SExt = Builder.CreateSExt(X, Ty, X->getName() + ".signext");
+    auto *SanitizedSignMask = cast<Constant>(Op1);
+    // We must be careful with the undef elements of the sign bit mask, however:
+    // the mask elt can be undef iff the shift amount for that lane was undef,
+    // otherwise we need to sanitize undef masks to zero.
+    SanitizedSignMask = Constant::replaceUndefsWith(
+        SanitizedSignMask, ConstantInt::getNullValue(Ty->getScalarType()));
+    SanitizedSignMask =
+        Constant::mergeUndefsWith(SanitizedSignMask, cast<Constant>(Y));
+    return BinaryOperator::CreateAnd(SExt, SanitizedSignMask);
+  }
+
   if (Instruction *Z = narrowMaskedBinOp(I))
     return Z;
 

diff  --git a/llvm/test/Transforms/InstCombine/signmask-of-sext-vs-of-shl-of-zext.ll b/llvm/test/Transforms/InstCombine/signmask-of-sext-vs-of-shl-of-zext.ll
index f529023e2a0d..cb7451cc7e37 100644
--- a/llvm/test/Transforms/InstCombine/signmask-of-sext-vs-of-shl-of-zext.ll
+++ b/llvm/test/Transforms/InstCombine/signmask-of-sext-vs-of-shl-of-zext.ll
@@ -12,9 +12,8 @@ declare void @use32(i32)
 
 define i32 @t0(i16 %x) {
 ; CHECK-LABEL: @t0(
-; CHECK-NEXT:    [[I0:%.*]] = zext i16 [[X:%.*]] to i32
-; CHECK-NEXT:    [[I1:%.*]] = shl nuw i32 [[I0]], 16
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[I1]], -2147483648
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext i16 [[X:%.*]] to i32
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %i0 = zext i16 %x to i32
@@ -24,9 +23,8 @@ define i32 @t0(i16 %x) {
 }
 define i32 @t1(i8 %x) {
 ; CHECK-LABEL: @t1(
-; CHECK-NEXT:    [[I0:%.*]] = zext i8 [[X:%.*]] to i32
-; CHECK-NEXT:    [[I1:%.*]] = shl nuw i32 [[I0]], 24
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[I1]], -2147483648
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext i8 [[X:%.*]] to i32
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %i0 = zext i8 %x to i32
@@ -77,8 +75,8 @@ define i32 @t5(i16 %x) {
 ; CHECK-LABEL: @t5(
 ; CHECK-NEXT:    [[I0:%.*]] = zext i16 [[X:%.*]] to i32
 ; CHECK-NEXT:    call void @use32(i32 [[I0]])
-; CHECK-NEXT:    [[I1:%.*]] = shl nuw i32 [[I0]], 16
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[I1]], -2147483648
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext i16 [[X]] to i32
+; CHECK-NEXT:    [[R:%.*]] = and i32 [[X_SIGNEXT]], -2147483648
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %i0 = zext i16 %x to i32
@@ -122,9 +120,8 @@ define i32 @n7(i16 %x) {
 
 define <2 x i32> @t8(<2 x i16> %x) {
 ; CHECK-LABEL: @t8(
-; CHECK-NEXT:    [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[I1:%.*]] = shl nuw <2 x i32> [[I0]], <i32 16, i32 16>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 -2147483648>
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %i0 = zext <2 x i16> %x to <2 x i32>
@@ -134,9 +131,8 @@ define <2 x i32> @t8(<2 x i16> %x) {
 }
 define <2 x i32> @t9(<2 x i16> %x) {
 ; CHECK-LABEL: @t9(
-; CHECK-NEXT:    [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[I1:%.*]] = shl <2 x i32> [[I0]], <i32 16, i32 undef>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 -2147483648>
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 undef>
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %i0 = zext <2 x i16> %x to <2 x i32>
@@ -147,9 +143,8 @@ define <2 x i32> @t9(<2 x i16> %x) {
 }
 define <2 x i32> @t10(<2 x i16> %x) {
 ; CHECK-LABEL: @t10(
-; CHECK-NEXT:    [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[I1:%.*]] = shl nuw <2 x i32> [[I0]], <i32 16, i32 16>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 undef>
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 0>
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %i0 = zext <2 x i16> %x to <2 x i32>
@@ -161,9 +156,8 @@ define <2 x i32> @t10(<2 x i16> %x) {
 }
 define <2 x i32> @t11(<2 x i16> %x) {
 ; CHECK-LABEL: @t11(
-; CHECK-NEXT:    [[I0:%.*]] = zext <2 x i16> [[X:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[I1:%.*]] = shl <2 x i32> [[I0]], <i32 16, i32 undef>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[I1]], <i32 -2147483648, i32 undef>
+; CHECK-NEXT:    [[X_SIGNEXT:%.*]] = sext <2 x i16> [[X:%.*]] to <2 x i32>
+; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[X_SIGNEXT]], <i32 -2147483648, i32 undef>
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %i0 = zext <2 x i16> %x to <2 x i32>


        


More information about the llvm-commits mailing list