]> granicus.if.org Git - llvm/commitdiff
[InstCombine] Fold ((C1-zext(X)) & C2) -> zext((C1-X) & C2)
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 17 Jan 2017 00:45:57 +0000 (00:45 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 17 Jan 2017 00:45:57 +0000 (00:45 +0000)
This is valid if C2 fits within the bitwidth of X thanks to two's
complement modulo arithmetic.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292179 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
test/Transforms/InstCombine/and.ll

index da5384a86aac629fbb5e4adbf428e2d4ece8664a..4a0edf378c4bcfa81b3c75592d7396f76a45cc25 100644 (file)
@@ -1331,6 +1331,21 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
         if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I))
           return BinaryOperator::CreateAnd(V, AndRHS);
 
+        // ((C1-zext(X)) & C2) -> zext((C1-X) & C2) if C2 fits in the bitwidth
+        // of X.
+        if (auto *ZI = dyn_cast<ZExtInst>(Op0RHS)) {
+          auto *X = ZI->getOperand(0);
+          ConstantInt *C1;
+          if (match(Op0LHS, m_ConstantInt(C1)) &&
+              AndRHSMask.isIntN(X->getType()->getScalarSizeInBits())) {
+            auto *TruncC1 = ConstantExpr::getTrunc(C1, X->getType());
+            auto *Sub = Builder->CreateSub(TruncC1, X);
+            auto *TruncC2 = ConstantExpr::getTrunc(AndRHS, X->getType());
+            auto *And = Builder->CreateAnd(Sub, TruncC2);
+            return new ZExtInst(And, I.getType());
+          }
+        }
+
         // -x & 1 -> x & 1
         if (AndRHSMask == 1 && match(Op0LHS, m_Zero()))
           return BinaryOperator::CreateAnd(Op0RHS, AndRHS);
index e45012878ed5ddb3ce08083b6fff9696f0d81b78..ee1dfbbe12e3b90ffb8eee380c8ed856ac5a13d1 100644 (file)
@@ -425,3 +425,14 @@ define <2 x i32> @PR24942(<2 x i32> %x) {
   ret <2 x i32> %and
 }
 
+define i64 @test35(i32 %X) {
+; CHECK-LABEL: @test35(
+; CHECK-NEXT:  %[[sub:.*]] = sub i32 0, %X
+; CHECK-NEXT:  %[[and:.*]] = and i32 %[[sub]], 240
+; CHECK-NEXT:  %[[cst:.*]] = zext i32 %[[and]] to i64
+; CHECK-NEXT:  ret i64 %[[cst]]
+  %zext = zext i32 %X to i64
+  %zsub = sub i64 0, %zext
+  %res = and i64 %zsub, 240
+  ret i64 %res
+}