From: Sanjay Patel Date: Thu, 21 Jul 2016 00:24:18 +0000 (+0000) Subject: [InstCombine] LogicOpc (zext X), C --> zext (LogicOpc X, C) (PR28476) X-Git-Tag: llvmorg-4.0.0-rc1~14693 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0753c06d9cfd7cbb6af1ed13af073cc274522862;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 4314b2b..3871b8a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -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(Op1); if (!Cast1) return nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 8f3b8ba..0d79733 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -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(X))) { - Value *New = Builder->CreateZExt(X, CI.getType()); - return BinaryOperator::CreateXor(New, ConstantInt::get(CI.getType(), 1)); - } - return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/apint-select.ll b/llvm/test/Transforms/InstCombine/apint-select.ll index 2aae232..72deeba 100644 --- a/llvm/test/Transforms/InstCombine/apint-select.ll +++ b/llvm/test/Transforms/InstCombine/apint-select.ll @@ -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]], +; CHECK-NEXT: [[NOT_C:%.*]] = xor <2 x i1> %C, +; 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> , <2 x i999> diff --git a/llvm/test/Transforms/InstCombine/assoc-cast-assoc.ll b/llvm/test/Transforms/InstCombine/assoc-cast-assoc.ll index e410fde..c6bec13 100644 --- a/llvm/test/Transforms/InstCombine/assoc-cast-assoc.ll +++ b/llvm/test/Transforms/InstCombine/assoc-cast-assoc.ll @@ -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]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> %a, +; 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, diff --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll index 3bc79ce..715956f 100644 --- a/llvm/test/Transforms/InstCombine/cast.ll +++ b/llvm/test/Transforms/InstCombine/cast.ll @@ -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]] ; diff --git a/llvm/test/Transforms/InstCombine/demorgan-zext.ll b/llvm/test/Transforms/InstCombine/demorgan-zext.ll index 045c15c..d537730 100644 --- a/llvm/test/Transforms/InstCombine/demorgan-zext.ll +++ b/llvm/test/Transforms/InstCombine/demorgan-zext.ll @@ -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]], -; CHECK-NEXT: [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], -; 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]], +; 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]], -; CHECK-NEXT: [[NOTY:%.*]] = xor <2 x i32> [[ZEXTY]], -; 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]], +; 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 diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll index 4b9f690..5429ffd 100644 --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -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]] ; diff --git a/llvm/test/Transforms/InstCombine/zeroext-and-reduce.ll b/llvm/test/Transforms/InstCombine/zeroext-and-reduce.ll index 48dd0fa..74bb731 100644 --- a/llvm/test/Transforms/InstCombine/zeroext-and-reduce.ll +++ b/llvm/test/Transforms/InstCombine/zeroext-and-reduce.ll @@ -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 diff --git a/llvm/test/Transforms/InstCombine/zext.ll b/llvm/test/Transforms/InstCombine/zext.ll index 2420393..1fb15a5 100644 --- a/llvm/test/Transforms/InstCombine/zext.ll +++ b/llvm/test/Transforms/InstCombine/zext.ll @@ -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]], +; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i1> %A, +; 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, @@ -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]], -; CHECK-NEXT: ret <2 x i64> [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> %a, +; 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,