[llvm] r292238 - [InstCombine] Fold ((C1 OP zext(X)) & C2) -> zext((C1 OP X) & C2)
David Majnemer via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 17 10:08:06 PST 2017
Author: majnemer
Date: Tue Jan 17 12:08:06 2017
New Revision: 292238
URL: http://llvm.org/viewvc/llvm-project?rev=292238&view=rev
Log:
[InstCombine] Fold ((C1 OP zext(X)) & C2) -> zext((C1 OP X) & C2)
This further extends r292179 to support additional binary operators
beyond subtraction.
Modified:
llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/trunk/test/Transforms/InstCombine/and.ll
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp?rev=292238&r1=292237&r2=292238&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Tue Jan 17 12:08:06 2017
@@ -1331,21 +1331,6 @@ Instruction *InstCombiner::visitAnd(Bina
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);
@@ -1376,6 +1361,34 @@ Instruction *InstCombiner::visitAnd(Bina
break;
}
+ // ((C1 OP zext(X)) & C2) -> zext((C1-X) & C2) if C2 fits in the bitwidth
+ // of X and OP behaves well when given trunc(C1) and X.
+ switch (Op0I->getOpcode()) {
+ default:
+ break;
+ case Instruction::Xor:
+ case Instruction::Or:
+ case Instruction::Mul:
+ case Instruction::Add:
+ case Instruction::Sub:
+ Value *X;
+ ConstantInt *C1;
+ if (match(Op0I, m_BinOp(m_ZExt(m_Value(X)), m_ConstantInt(C1))) ||
+ match(Op0I, m_BinOp(m_ConstantInt(C1), m_ZExt(m_Value(X))))) {
+ if (AndRHSMask.isIntN(X->getType()->getScalarSizeInBits())) {
+ auto *TruncC1 = ConstantExpr::getTrunc(C1, X->getType());
+ Value *BinOp;
+ if (isa<ZExtInst>(Op0LHS))
+ BinOp = Builder->CreateBinOp(Op0I->getOpcode(), X, TruncC1);
+ else
+ BinOp = Builder->CreateBinOp(Op0I->getOpcode(), TruncC1, X);
+ auto *TruncC2 = ConstantExpr::getTrunc(AndRHS, X->getType());
+ auto *And = Builder->CreateAnd(BinOp, TruncC2);
+ return new ZExtInst(And, I.getType());
+ }
+ }
+ }
+
if (ConstantInt *Op0CI = dyn_cast<ConstantInt>(Op0I->getOperand(1)))
if (Instruction *Res = OptAndOp(Op0I, Op0CI, AndRHS, I))
return Res;
Modified: llvm/trunk/test/Transforms/InstCombine/and.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/and.ll?rev=292238&r1=292237&r2=292238&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/and.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/and.ll Tue Jan 17 12:08:06 2017
@@ -436,3 +436,49 @@ define i64 @test35(i32 %X) {
%res = and i64 %zsub, 240
ret i64 %res
}
+
+define i64 @test36(i32 %X) {
+; CHECK-LABEL: @test36(
+; CHECK-NEXT: %[[sub:.*]] = add i32 %X, 7
+; 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 = add i64 %zext, 7
+ %res = and i64 %zsub, 240
+ ret i64 %res
+}
+
+define i64 @test37(i32 %X) {
+; CHECK-LABEL: @test37(
+; CHECK-NEXT: %[[sub:.*]] = mul i32 %X, 7
+; 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 = mul i64 %zext, 7
+ %res = and i64 %zsub, 240
+ ret i64 %res
+}
+
+define i64 @test38(i32 %X) {
+; CHECK-LABEL: @test38(
+; CHECK-NEXT: %[[and:.*]] = and i32 %X, 240
+; CHECK-NEXT: %[[cst:.*]] = zext i32 %[[and]] to i64
+; CHECK-NEXT: ret i64 %[[cst]]
+ %zext = zext i32 %X to i64
+ %zsub = xor i64 %zext, 7
+ %res = and i64 %zsub, 240
+ ret i64 %res
+}
+
+define i64 @test39(i32 %X) {
+; CHECK-LABEL: @test39(
+; CHECK-NEXT: %[[and:.*]] = and i32 %X, 240
+; CHECK-NEXT: %[[cst:.*]] = zext i32 %[[and]] to i64
+; CHECK-NEXT: ret i64 %[[cst]]
+ %zext = zext i32 %X to i64
+ %zsub = or i64 %zext, 7
+ %res = and i64 %zsub, 240
+ ret i64 %res
+}
More information about the llvm-commits
mailing list