forked from OSchip/llvm-project
[InstCombine] LogicOpc (zext X), C --> zext (LogicOpc X, C) (PR28476)
The benefits of this change include: 1. Remove DeMorgan-matching code that was added specifically to work-around the missing transform in http://reviews.llvm.org/rL248634. 2. Makes the DeMorgan transform work for vectors too. 3. Fix PR28476: https://llvm.org/bugs/show_bug.cgi?id=28476 Extending this transform to other casts and other associative operators may be useful too. See https://reviews.llvm.org/D22421 for a prerequisite for doing that though. Differential Revision: https://reviews.llvm.org/D22271 llvm-svn: 276221
This commit is contained in:
parent
99bd2de619
commit
0753c06d9c
|
@ -1123,26 +1123,6 @@ static Instruction *matchDeMorgansLaws(BinaryOperator &I,
|
|||
return BinaryOperator::CreateNot(LogicOp);
|
||||
}
|
||||
|
||||
// De Morgan's Law in disguise:
|
||||
// (zext(bool A) ^ 1) & (zext(bool B) ^ 1) -> zext(~(A | B))
|
||||
// (zext(bool A) ^ 1) | (zext(bool B) ^ 1) -> zext(~(A & B))
|
||||
Value *A = nullptr;
|
||||
Value *B = nullptr;
|
||||
ConstantInt *C1 = nullptr;
|
||||
if (match(Op0, m_OneUse(m_Xor(m_ZExt(m_Value(A)), m_ConstantInt(C1)))) &&
|
||||
match(Op1, m_OneUse(m_Xor(m_ZExt(m_Value(B)), m_Specific(C1))))) {
|
||||
// TODO: This check could be loosened to handle different type sizes.
|
||||
// Alternatively, we could fix the definition of m_Not to recognize a not
|
||||
// operation hidden by a zext?
|
||||
if (A->getType()->isIntegerTy(1) && B->getType()->isIntegerTy(1) &&
|
||||
C1->isOne()) {
|
||||
Value *LogicOp = Builder->CreateBinOp(Opcode, A, B,
|
||||
I.getName() + ".demorgan");
|
||||
Value *Not = Builder->CreateNot(LogicOp);
|
||||
return CastInst::CreateZExtOrBitCast(Not, I.getType());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1199,6 +1179,22 @@ Instruction *InstCombiner::foldCastedBitwiseLogic(BinaryOperator &I) {
|
|||
return CastInst::CreateBitOrPointerCast(NewOp, DestTy);
|
||||
}
|
||||
|
||||
// Similarly, if one operand is zexted and the other is a constant, move the
|
||||
// logic operation ahead of the zext if the constant is unchanged in the
|
||||
// smaller source type. Performing the logic in a smaller type may provide
|
||||
// more information to later folds, and the smaller logic instruction may be
|
||||
// cheaper (particularly in the case of vectors).
|
||||
Value *X;
|
||||
if (match(Op0, m_OneUse(m_ZExt(m_Value(X)))) && match(Op1, m_Constant(C))) {
|
||||
Constant *TruncC = ConstantExpr::getTrunc(C, SrcTy);
|
||||
Constant *ZextTruncC = ConstantExpr::getZExt(TruncC, DestTy);
|
||||
if (ZextTruncC == C) {
|
||||
// LogicOpc (zext X), C --> zext (LogicOpc X, C)
|
||||
Value *NewOp = Builder->CreateBinOp(LogicOpc, X, TruncC);
|
||||
return new ZExtInst(NewOp, DestTy);
|
||||
}
|
||||
}
|
||||
|
||||
CastInst *Cast1 = dyn_cast<CastInst>(Op1);
|
||||
if (!Cast1)
|
||||
return nullptr;
|
||||
|
|
|
@ -920,14 +920,6 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) {
|
|||
return BinaryOperator::CreateXor(Builder->CreateAnd(X, ZC), ZC);
|
||||
}
|
||||
|
||||
// zext (xor i1 X, true) to i32 --> xor (zext i1 X to i32), 1
|
||||
if (SrcI && SrcI->hasOneUse() &&
|
||||
SrcI->getType()->getScalarType()->isIntegerTy(1) &&
|
||||
match(SrcI, m_Not(m_Value(X))) && (!X->hasOneUse() || !isa<CmpInst>(X))) {
|
||||
Value *New = Builder->CreateZExt(X, CI.getType());
|
||||
return BinaryOperator::CreateXor(New, ConstantInt::get(CI.getType(), 1));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ define i41 @sext(i1 %C) {
|
|||
|
||||
define i999 @not_zext(i1 %C) {
|
||||
; CHECK-LABEL: @not_zext(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 %C to i999
|
||||
; CHECK-NEXT: [[V:%.*]] = xor i999 [[TMP1]], 1
|
||||
; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 %C, true
|
||||
; CHECK-NEXT: [[V:%.*]] = zext i1 [[NOT_C]] to i999
|
||||
; CHECK-NEXT: ret i999 [[V]]
|
||||
;
|
||||
%V = select i1 %C, i999 0, i999 1
|
||||
|
@ -63,8 +63,8 @@ define <2 x i32> @sext_vec(<2 x i1> %C) {
|
|||
|
||||
define <2 x i999> @not_zext_vec(<2 x i1> %C) {
|
||||
; CHECK-LABEL: @not_zext_vec(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i1> %C to <2 x i999>
|
||||
; CHECK-NEXT: [[V:%.*]] = xor <2 x i999> [[TMP1]], <i999 1, i999 1>
|
||||
; CHECK-NEXT: [[NOT_C:%.*]] = xor <2 x i1> %C, <i1 true, i1 true>
|
||||
; CHECK-NEXT: [[V:%.*]] = zext <2 x i1> [[NOT_C]] to <2 x i999>
|
||||
; CHECK-NEXT: ret <2 x i999> [[V]]
|
||||
;
|
||||
%V = select <2 x i1> %C, <2 x i999> <i999 0, i999 0>, <2 x i999> <i999 1, i999 1>
|
||||
|
|
|
@ -53,8 +53,8 @@ define <2 x i32> @OrZextOrVec(<2 x i2> %a) {
|
|||
|
||||
define i5 @AndZextAnd(i3 %a) {
|
||||
; CHECK-LABEL: @AndZextAnd(
|
||||
; CHECK-NEXT: [[CAST:%.*]] = zext i3 %a to i5
|
||||
; CHECK-NEXT: [[OP2:%.*]] = and i5 [[CAST]], 2
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i3 %a, 2
|
||||
; CHECK-NEXT: [[OP2:%.*]] = zext i3 [[TMP1]] to i5
|
||||
; CHECK-NEXT: ret i5 [[OP2]]
|
||||
;
|
||||
%op1 = and i3 %a, 3
|
||||
|
@ -65,8 +65,8 @@ define i5 @AndZextAnd(i3 %a) {
|
|||
|
||||
define <2 x i32> @AndZextAndVec(<2 x i8> %a) {
|
||||
; CHECK-LABEL: @AndZextAndVec(
|
||||
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i8> %a to <2 x i32>
|
||||
; CHECK-NEXT: [[OP2:%.*]] = and <2 x i32> [[CAST]], <i32 5, i32 0>
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> %a, <i8 5, i8 0>
|
||||
; CHECK-NEXT: [[OP2:%.*]] = zext <2 x i8> [[TMP1]] to <2 x i32>
|
||||
; CHECK-NEXT: ret <2 x i32> [[OP2]]
|
||||
;
|
||||
%op1 = and <2 x i8> %a, <i8 7, i8 0>
|
||||
|
|
|
@ -637,9 +637,9 @@ define i32 @test52(i64 %A) {
|
|||
|
||||
define i64 @test53(i32 %A) {
|
||||
; CHECK-LABEL: @test53(
|
||||
; CHECK-NEXT: [[B:%.*]] = zext i32 %A to i64
|
||||
; CHECK-NEXT: [[C:%.*]] = and i64 [[B]], 7224
|
||||
; CHECK-NEXT: [[D:%.*]] = or i64 [[C]], 32962
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i32 %A, 7224
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], 32962
|
||||
; CHECK-NEXT: [[D:%.*]] = zext i32 [[TMP2]] to i64
|
||||
; CHECK-NEXT: ret i64 [[D]]
|
||||
;
|
||||
%B = trunc i32 %A to i16
|
||||
|
@ -665,8 +665,8 @@ define i32 @test54(i64 %A) {
|
|||
|
||||
define i64 @test55(i32 %A) {
|
||||
; CHECK-LABEL: @test55(
|
||||
; CHECK-NEXT: [[B:%.*]] = zext i32 %A to i64
|
||||
; CHECK-NEXT: [[C:%.*]] = and i64 [[B]], 7224
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i32 %A, 7224
|
||||
; CHECK-NEXT: [[C:%.*]] = zext i32 [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[D:%.*]] = or i64 [[C]], -32574
|
||||
; CHECK-NEXT: ret i64 [[D]]
|
||||
;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
define i32 @demorgan_or(i1 %X, i1 %Y) {
|
||||
; CHECK-LABEL: @demorgan_or(
|
||||
; CHECK-NEXT: [[OR_DEMORGAN:%.*]] = and i1 %X, %Y
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[OR_DEMORGAN]] to i32
|
||||
; CHECK-NEXT: [[OR:%.*]] = xor i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and i1 %X, %Y
|
||||
; CHECK-NEXT: [[OR1:%.*]] = xor i1 [[OR1_DEMORGAN]], true
|
||||
; CHECK-NEXT: [[OR:%.*]] = zext i1 [[OR:%.*]]1 to i32
|
||||
; CHECK-NEXT: ret i32 [[OR]]
|
||||
;
|
||||
%zextX = zext i1 %X to i32
|
||||
|
@ -20,9 +20,9 @@ define i32 @demorgan_or(i1 %X, i1 %Y) {
|
|||
|
||||
define i32 @demorgan_and(i1 %X, i1 %Y) {
|
||||
; CHECK-LABEL: @demorgan_and(
|
||||
; CHECK-NEXT: [[AND_DEMORGAN:%.*]] = or i1 %X, %Y
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[AND_DEMORGAN]] to i32
|
||||
; CHECK-NEXT: [[AND:%.*]] = xor i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or i1 %X, %Y
|
||||
; CHECK-NEXT: [[AND1:%.*]] = xor i1 [[AND1_DEMORGAN]], true
|
||||
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[AND:%.*]]1 to i32
|
||||
; CHECK-NEXT: ret i32 [[AND]]
|
||||
;
|
||||
%zextX = zext i1 %X to i32
|
||||
|
@ -33,15 +33,11 @@ define i32 @demorgan_and(i1 %X, i1 %Y) {
|
|||
ret i32 %and
|
||||
}
|
||||
|
||||
; FIXME: Vectors should get the same transform.
|
||||
|
||||
define <2 x i32> @demorgan_or_vec(<2 x i1> %X, <2 x i1> %Y) {
|
||||
; CHECK-LABEL: @demorgan_or_vec(
|
||||
; CHECK-NEXT: [[ZEXTX:%.*]] = zext <2 x i1> %X to <2 x i32>
|
||||
; CHECK-NEXT: [[ZEXTY:%.*]] = zext <2 x i1> %Y to <2 x i32>
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor <2 x i32> [[ZEXTX]], <i32 1, i32 1>
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], <i32 1, i32 1>
|
||||
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[NOTX]], [[NOTY]]
|
||||
; CHECK-NEXT: [[OR1_DEMORGAN:%.*]] = and <2 x i1> %X, %Y
|
||||
; CHECK-NEXT: [[OR1:%.*]] = xor <2 x i1> [[OR1_DEMORGAN]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: [[OR:%.*]] = zext <2 x i1> [[OR:%.*]]1 to <2 x i32>
|
||||
; CHECK-NEXT: ret <2 x i32> [[OR]]
|
||||
;
|
||||
%zextX = zext <2 x i1> %X to <2 x i32>
|
||||
|
@ -54,11 +50,9 @@ define <2 x i32> @demorgan_or_vec(<2 x i1> %X, <2 x i1> %Y) {
|
|||
|
||||
define <2 x i32> @demorgan_and_vec(<2 x i1> %X, <2 x i1> %Y) {
|
||||
; CHECK-LABEL: @demorgan_and_vec(
|
||||
; CHECK-NEXT: [[ZEXTX:%.*]] = zext <2 x i1> %X to <2 x i32>
|
||||
; CHECK-NEXT: [[ZEXTY:%.*]] = zext <2 x i1> %Y to <2 x i32>
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor <2 x i32> [[ZEXTX]], <i32 1, i32 1>
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], <i32 1, i32 1>
|
||||
; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[NOTX]], [[NOTY]]
|
||||
; CHECK-NEXT: [[AND1_DEMORGAN:%.*]] = or <2 x i1> %X, %Y
|
||||
; CHECK-NEXT: [[AND1:%.*]] = xor <2 x i1> [[AND1_DEMORGAN]], <i1 true, i1 true>
|
||||
; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[AND:%.*]]1 to <2 x i32>
|
||||
; CHECK-NEXT: ret <2 x i32> [[AND]]
|
||||
;
|
||||
%zextX = zext <2 x i1> %X to <2 x i32>
|
||||
|
@ -69,15 +63,12 @@ define <2 x i32> @demorgan_and_vec(<2 x i1> %X, <2 x i1> %Y) {
|
|||
ret <2 x i32> %and
|
||||
}
|
||||
|
||||
; FIXME: If the xor was canonicalized to a 'not', then this would simplify.
|
||||
|
||||
define i32 @PR28476(i32 %x, i32 %y) {
|
||||
; CHECK-LABEL: @PR28476(
|
||||
; CHECK-NEXT: [[CMP0:%.*]] = icmp ne i32 %x, 0
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 %y, 0
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[AND]] to i32
|
||||
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[ZEXT]], 1
|
||||
; CHECK-NEXT: [[NOTLHS:%.*]] = icmp eq i32 %x, 0
|
||||
; CHECK-NEXT: [[NOTRHS:%.*]] = icmp eq i32 %y, 0
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[NOTRHS]], [[NOTLHS]]
|
||||
; CHECK-NEXT: [[COND:%.*]] = zext i1 [[TMP1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[COND]]
|
||||
;
|
||||
%cmp0 = icmp ne i32 %x, 0
|
||||
|
|
|
@ -242,8 +242,8 @@ define i32 @test12a(i1 %cond, i32 %a) {
|
|||
|
||||
define i32 @test12b(i1 %cond, i32 %a) {
|
||||
; CHECK-LABEL: @test12b(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 %cond to i32
|
||||
; CHECK-NEXT: [[B:%.*]] = xor i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: [[NOT_COND:%.*]] = xor i1 %cond, true
|
||||
; CHECK-NEXT: [[B:%.*]] = zext i1 [[NOT_COND]] to i32
|
||||
; CHECK-NEXT: [[D:%.*]] = ashr i32 %a, [[B]]
|
||||
; CHECK-NEXT: ret i32 [[D]]
|
||||
;
|
||||
|
@ -1193,8 +1193,8 @@ define i64 @select_icmp_x_and_8_ne_0_y_xor_8(i32 %x, i64 %y) {
|
|||
define i64 @select_icmp_x_and_8_ne_0_y_or_8(i32 %x, i64 %y) {
|
||||
; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y_or_8(
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 8
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[AND]] to i64
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], 8
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP2]], %y
|
||||
; CHECK-NEXT: ret i64 [[TMP3]]
|
||||
;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
define i32 @test1(i8 %X) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: [[Y:%.*]] = zext i8 %X to i32
|
||||
; CHECK-NEXT: [[Z:%.*]] = and i32 [[Y]], 8
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i8 %X, 8
|
||||
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[TMP1]] to i32
|
||||
; CHECK-NEXT: ret i32 [[Z]]
|
||||
;
|
||||
%Y = zext i8 %X to i32
|
||||
|
|
|
@ -13,8 +13,8 @@ define i64 @test_sext_zext(i16 %A) {
|
|||
|
||||
define <2 x i64> @test2(<2 x i1> %A) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i1> %A to <2 x i64>
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = xor <2 x i64> [[TMP1]], <i64 1, i64 1>
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i1> %A, <i1 true, i1 true>
|
||||
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i1> [[XOR]] to <2 x i64>
|
||||
; CHECK-NEXT: ret <2 x i64> [[ZEXT]]
|
||||
;
|
||||
%xor = xor <2 x i1> %A, <i1 true, i1 true>
|
||||
|
@ -46,13 +46,10 @@ define <2 x i64> @test4(<2 x i64> %A) {
|
|||
ret <2 x i64> %zext
|
||||
}
|
||||
|
||||
; FIXME: If the xor was done in the smaller type, the back-to-back zexts would get combined.
|
||||
|
||||
define i64 @fold_xor_zext_sandwich(i1 %a) {
|
||||
; CHECK-LABEL: @fold_xor_zext_sandwich(
|
||||
; CHECK-NEXT: [[ZEXT1:%.*]] = zext i1 %a to i32
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[ZEXT1]], 1
|
||||
; CHECK-NEXT: [[ZEXT2:%.*]] = zext i32 [[XOR]] to i64
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 %a, true
|
||||
; CHECK-NEXT: [[ZEXT2:%.*]] = zext i1 [[TMP1]] to i64
|
||||
; CHECK-NEXT: ret i64 [[ZEXT2]]
|
||||
;
|
||||
%zext1 = zext i1 %a to i32
|
||||
|
@ -63,9 +60,9 @@ define i64 @fold_xor_zext_sandwich(i1 %a) {
|
|||
|
||||
define <2 x i64> @fold_xor_zext_sandwich_vec(<2 x i1> %a) {
|
||||
; CHECK-LABEL: @fold_xor_zext_sandwich_vec(
|
||||
; CHECK-NEXT: [[ZEXT1:%.*]] = zext <2 x i1> %a to <2 x i64>
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i64> [[ZEXT1]], <i64 1, i64 1>
|
||||
; CHECK-NEXT: ret <2 x i64> [[XOR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> %a, <i1 true, i1 true>
|
||||
; CHECK-NEXT: [[ZEXT2:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i64>
|
||||
; CHECK-NEXT: ret <2 x i64> [[ZEXT2]]
|
||||
;
|
||||
%zext1 = zext <2 x i1> %a to <2 x i32>
|
||||
%xor = xor <2 x i32> %zext1, <i32 1, i32 1>
|
||||
|
|
Loading…
Reference in New Issue