[InstCombine] Fold ((C1 OP zext(X)) & C2) -> zext((C1 OP X) & C2)
This further extends r292179 to support additional binary operators beyond subtraction. llvm-svn: 292238
This commit is contained in:
parent
e7d1f92344
commit
de55c606d1
|
@ -1331,21 +1331,6 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||||
if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I))
|
if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I))
|
||||||
return BinaryOperator::CreateAnd(V, AndRHS);
|
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
|
// -x & 1 -> x & 1
|
||||||
if (AndRHSMask == 1 && match(Op0LHS, m_Zero()))
|
if (AndRHSMask == 1 && match(Op0LHS, m_Zero()))
|
||||||
return BinaryOperator::CreateAnd(Op0RHS, AndRHS);
|
return BinaryOperator::CreateAnd(Op0RHS, AndRHS);
|
||||||
|
@ -1376,6 +1361,34 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||||
break;
|
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 (ConstantInt *Op0CI = dyn_cast<ConstantInt>(Op0I->getOperand(1)))
|
||||||
if (Instruction *Res = OptAndOp(Op0I, Op0CI, AndRHS, I))
|
if (Instruction *Res = OptAndOp(Op0I, Op0CI, AndRHS, I))
|
||||||
return Res;
|
return Res;
|
||||||
|
|
|
@ -436,3 +436,49 @@ define i64 @test35(i32 %X) {
|
||||||
%res = and i64 %zsub, 240
|
%res = and i64 %zsub, 240
|
||||||
ret i64 %res
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue