Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1170,26 +1170,6 @@ 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; } @@ -2733,5 +2713,13 @@ if (Instruction *CastedXor = foldCastedBitwiseLogic(I)) return CastedXor; + // xor(zext A), 1 --> zext(not A), if A is a boolean type. + // A 'not' operation is easier to pattern-match for other transforms. + if (match(Op0, m_OneUse(m_ZExt(m_Value(A)))) && match(Op1, m_One()) && + A->getType()->getScalarType()->isIntegerTy(1)) { + Value *NotA = Builder->CreateNot(A); + return CastInst::Create(Instruction::ZExt, NotA, I.getType()); + } + return Changed ? &I : nullptr; } Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -952,14 +952,6 @@ 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; } Index: test/Transforms/InstCombine/apint-select.ll =================================================================== --- test/Transforms/InstCombine/apint-select.ll +++ test/Transforms/InstCombine/apint-select.ll @@ -23,8 +23,8 @@ 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 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> Index: test/Transforms/InstCombine/demorgan-zext.ll =================================================================== --- test/Transforms/InstCombine/demorgan-zext.ll +++ test/Transforms/InstCombine/demorgan-zext.ll @@ -6,9 +6,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: ret i32 [[OR]] +; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[OR_DEMORGAN]], true +; CHECK-NEXT: [[Z:%.*]] = zext i1 [[NOT]] to i32 +; CHECK-NEXT: ret i32 [[Z]] ; %zextX = zext i1 %X to i32 %zextY = zext i1 %Y to i32 @@ -21,9 +21,9 @@ 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: ret i32 [[AND]] +; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[AND_DEMORGAN]], true +; CHECK-NEXT: [[Z:%.*]] = zext i1 [[NOT]] to i32 +; CHECK-NEXT: ret i32 [[Z]] ; %zextX = zext i1 %X to i32 %zextY = zext i1 %Y to i32 @@ -33,16 +33,12 @@ 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: ret <2 x i32> [[OR]] +; CHECK-NEXT: [[OR_DEMORGAN:%.*]] = and <2 x i1> %X, %Y +; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[OR_DEMORGAN]], +; CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[NOT]] to <2 x i32> +; CHECK-NEXT: ret <2 x i32> [[Z]] ; %zextX = zext <2 x i1> %X to <2 x i32> %zextY = zext <2 x i1> %Y to <2 x i32> @@ -54,12 +50,10 @@ 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: ret <2 x i32> [[AND]] +; CHECK-NEXT: [[AND_DEMORGAN:%.*]] = or <2 x i1> %X, %Y +; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[AND_DEMORGAN]], +; CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[NOT]] to <2 x i32> +; CHECK-NEXT: ret <2 x i32> [[Z]] ; %zextX = zext <2 x i1> %X to <2 x i32> %zextY = zext <2 x i1> %Y to <2 x i32> @@ -69,15 +63,12 @@ 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 Index: test/Transforms/InstCombine/select.ll =================================================================== --- test/Transforms/InstCombine/select.ll +++ test/Transforms/InstCombine/select.ll @@ -240,15 +240,16 @@ ; CHECK: ret i32 %c } -define i32 @test12b(i1 %cond, i32 %a) { - %b = ashr i32 %a, 1 - %c = select i1 %cond, i32 %a, i32 %b - ret i32 %c +define i32 @test12b(i1 %c, i32 %a) { ; CHECK-LABEL: @test12b( -; CHECK: zext i1 %cond to i32 -; CHECK: %b = xor i32 -; CHECK: %c = ashr i32 %a, %b -; CHECK: ret i32 %c +; CHECK-NEXT: [[NOT_C:%.*]] = xor i1 %c, true +; CHECK-NEXT: [[B:%.*]] = zext i1 [[NOT_C]] to i32 +; CHECK-NEXT: [[SEL:%.*]] = ashr i32 %a, [[B]] +; CHECK-NEXT: ret i32 [[SEL]] +; + %b = ashr i32 %a, 1 + %sel = select i1 %c, i32 %a, i32 %b + ret i32 %sel } define i32 @test13(i32 %a, i32 %b) { Index: test/Transforms/InstCombine/zext.ll =================================================================== --- test/Transforms/InstCombine/zext.ll +++ test/Transforms/InstCombine/zext.ll @@ -13,8 +13,8 @@ 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,