1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[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:
Sanjay Patel 2016-07-21 00:24:18 +00:00
parent 2a94ac8820
commit 8755396e8d
9 changed files with 58 additions and 82 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -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]]
;

View File

@ -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

View File

@ -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]]
;

View File

@ -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

View File

@ -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>