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; } @@ -1253,6 +1233,22 @@ 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; Index: lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCasts.cpp +++ lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -920,14 +920,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/assoc-cast-assoc.ll =================================================================== --- test/Transforms/InstCombine/assoc-cast-assoc.ll +++ test/Transforms/InstCombine/assoc-cast-assoc.ll @@ -53,8 +53,8 @@ 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 <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, Index: test/Transforms/InstCombine/cast.ll =================================================================== --- test/Transforms/InstCombine/cast.ll +++ test/Transforms/InstCombine/cast.ll @@ -637,9 +637,9 @@ 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 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]] ; Index: test/Transforms/InstCombine/demorgan-zext.ll =================================================================== --- test/Transforms/InstCombine/demorgan-zext.ll +++ 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_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 @@ -37,11 +37,9 @@ 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 +52,9 @@ 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> @@ -73,11 +69,10 @@ 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 @@ -242,8 +242,8 @@ 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_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]] ; Index: test/Transforms/InstCombine/zeroext-and-reduce.ll =================================================================== --- test/Transforms/InstCombine/zeroext-and-reduce.ll +++ 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 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, @@ -50,9 +50,8 @@ 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 +62,9 @@ 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,