if (Instruction *NewXor = sinkNotIntoXor(I, Builder))
return NewXor;
+ // Otherwise, if all else failed, try to hoist the xor-by-constant:
+ // (X ^ C) ^ Y --> (X ^ Y) ^ C
+ // FIXME: does this need hardening against ConstantExpr's
+ // to prevent infinite combine loops?
+ if (match(&I,
+ m_c_Xor(m_OneUse(m_Xor(m_Value(X), m_Constant(C1))), m_Value(Y))))
+ return BinaryOperator::CreateXor(Builder.CreateXor(X, Y), C1);
+
return nullptr;
}
define i8 @t0_scalar(i8 %x, i8 %y) {
; CHECK-LABEL: @t0_scalar(
-; CHECK-NEXT: [[I0:%.*]] = xor i8 [[X:%.*]], 42
-; CHECK-NEXT: [[R:%.*]] = xor i8 [[I0]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP1]], 42
; CHECK-NEXT: ret i8 [[R]]
;
%i0 = xor i8 %x, 42
define <2 x i8> @t1_splatvec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @t1_splatvec(
-; CHECK-NEXT: [[I0:%.*]] = xor <2 x i8> [[X:%.*]], <i8 42, i8 42>
-; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[I0]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[TMP1]], <i8 42, i8 42>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%i0 = xor <2 x i8> %x, <i8 42, i8 42>
}
define <2 x i8> @t2_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @t2_vec(
-; CHECK-NEXT: [[I0:%.*]] = xor <2 x i8> [[X:%.*]], <i8 42, i8 24>
-; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[I0]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[TMP1]], <i8 42, i8 24>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%i0 = xor <2 x i8> %x, <i8 42, i8 24>
}
define <2 x i8> @t3_vec_undef(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @t3_vec_undef(
-; CHECK-NEXT: [[I0:%.*]] = xor <2 x i8> [[X:%.*]], <i8 42, i8 undef>
-; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[I0]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <2 x i8> [[TMP1]], <i8 42, i8 undef>
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%i0 = xor <2 x i8> %x, <i8 42, i8 undef>
define i8 @t5_commutativity(i8 %x) {
; CHECK-LABEL: @t5_commutativity(
-; CHECK-NEXT: [[I0:%.*]] = xor i8 [[X:%.*]], 42
; CHECK-NEXT: [[Y:%.*]] = call i8 @gen8()
-; CHECK-NEXT: [[R:%.*]] = xor i8 [[Y]], [[I0]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP1]], 42
; CHECK-NEXT: ret i8 [[R]]
;
%i0 = xor i8 %x, 42
define i4 @in_constant_mone_vary_invmask(i4 %y, i4 %mask) {
; CHECK-LABEL: @in_constant_mone_vary_invmask(
-; CHECK-NEXT: [[N1_DEMORGAN:%.*]] = or i4 [[Y:%.*]], [[MASK:%.*]]
-; CHECK-NEXT: [[N1:%.*]] = xor i4 [[N1_DEMORGAN]], -1
-; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
+; CHECK-NEXT: [[MASK_NOT:%.*]] = xor i4 [[MASK:%.*]], -1
+; CHECK-NEXT: [[R:%.*]] = or i4 [[MASK_NOT]], [[Y:%.*]]
; CHECK-NEXT: ret i4 [[R]]
;
%notmask = xor i4 %mask, -1
define <2 x i4> @in_constant_mone_vary_invmask(<2 x i4> %y, <2 x i4> %mask) {
; CHECK-LABEL: @in_constant_mone_vary_invmask(
-; CHECK-NEXT: [[N1_DEMORGAN:%.*]] = or <2 x i4> [[Y:%.*]], [[MASK:%.*]]
-; CHECK-NEXT: [[N1:%.*]] = xor <2 x i4> [[N1_DEMORGAN]], <i4 -1, i4 -1>
-; CHECK-NEXT: [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
+; CHECK-NEXT: [[MASK_NOT:%.*]] = xor <2 x i4> [[MASK:%.*]], <i4 -1, i4 -1>
+; CHECK-NEXT: [[R:%.*]] = or <2 x i4> [[MASK_NOT]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i4> [[R]]
;
%notmask = xor <2 x i4> %mask, <i4 -1, i4 -1>
ret i32 %z
}
+; (A ^ B) | (~A ^ B) --> -1
+
define i32 @test10(i32 %A, i32 %B) {
; CHECK-LABEL: @test10(
-; CHECK-NEXT: ret i32 -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%xor1 = xor i32 %B, %A
%not = xor i32 %A, -1
define i32 @test10_commuted(i32 %A, i32 %B) {
; CHECK-LABEL: @test10_commuted(
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %xor1 = xor i32 %B, %A
+ %not = xor i32 %A, -1
+ %xor2 = xor i32 %not, %B
+ %or = or i32 %xor2, %xor1
+ ret i32 %or
+}
+
+define i32 @test10_extrause(i32 %A, i32 %B, i32* %dst) {
+; CHECK-LABEL: @test10_extrause(
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT: store i32 [[NOT]], i32* [[DST:%.*]], align 4
+; CHECK-NEXT: ret i32 -1
+;
+ %xor1 = xor i32 %B, %A
+ %not = xor i32 %A, -1
+ store i32 %not, i32* %dst
+ %xor2 = xor i32 %not, %B
+ %or = or i32 %xor1, %xor2
+ ret i32 %or
+}
+
+define i32 @test10_commuted_extrause(i32 %A, i32 %B, i32* %dst) {
+; CHECK-LABEL: @test10_commuted_extrause(
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT: store i32 [[NOT]], i32* [[DST:%.*]], align 4
; CHECK-NEXT: ret i32 -1
;
%xor1 = xor i32 %B, %A
%not = xor i32 %A, -1
+ store i32 %not, i32* %dst
%xor2 = xor i32 %not, %B
%or = or i32 %xor2, %xor1
ret i32 %or
}
+; (A ^ B) | ~(A ^ B) --> -1
+define i32 @test10_canonical(i32 %A, i32 %B) {
+; CHECK-LABEL: @test10_canonical(
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[XOR2]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[XOR1]], [[NOT]]
+; CHECK-NEXT: ret i32 [[OR]]
+;
+ %xor1 = xor i32 %B, %A
+ %xor2 = xor i32 %A, %B
+ %not = xor i32 %xor2, -1
+ %or = or i32 %xor1, %not
+ ret i32 %or
+}
+
; (x | y) & ((~x) ^ y) -> (x & y)
define i32 @test11(i32 %x, i32 %y) {
; CHECK-LABEL: @test11(
define i8 @test17(i8 %A, i8 %B) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33
-; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR1]], 33
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[TMP1]], 33
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR1]], [[XOR2]]
; CHECK-NEXT: [[RES:%.*]] = mul i8 [[OR]], [[XOR2]]
; CHECK-NEXT: ret i8 [[RES]]
;
define i8 @test18(i8 %A, i8 %B) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33
-; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR1]], 33
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[TMP1]], 33
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[XOR2]], [[XOR1]]
; CHECK-NEXT: [[RES:%.*]] = mul i8 [[OR]], [[XOR2]]
; CHECK-NEXT: ret i8 [[RES]]
;
define i4 @in_constant_mone_vary(i4 %y, i4 %mask) {
; CHECK-LABEL: @in_constant_mone_vary(
-; CHECK-NEXT: [[N0:%.*]] = and i4 [[Y:%.*]], 1
-; CHECK-NEXT: [[N1:%.*]] = xor i4 [[N0]], 1
-; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]
-; CHECK-NEXT: ret i4 [[R]]
+; CHECK-NEXT: [[R1:%.*]] = or i4 [[Y:%.*]], 1
+; CHECK-NEXT: ret i4 [[R1]]
;
%n0 = xor i4 %y, -1 ; %x
%n1 = and i4 %n0, 1
define <2 x i4> @in_constant_mone_vary(<2 x i4> %y, <2 x i4> %mask) {
; CHECK-LABEL: @in_constant_mone_vary(
-; CHECK-NEXT: [[N0:%.*]] = and <2 x i4> [[Y:%.*]], <i4 1, i4 1>
-; CHECK-NEXT: [[N1:%.*]] = xor <2 x i4> [[N0]], <i4 1, i4 1>
-; CHECK-NEXT: [[R:%.*]] = xor <2 x i4> [[N1]], [[Y]]
-; CHECK-NEXT: ret <2 x i4> [[R]]
+; CHECK-NEXT: [[R1:%.*]] = or <2 x i4> [[Y:%.*]], <i4 1, i4 1>
+; CHECK-NEXT: ret <2 x i4> [[R1]]
;
%n0 = xor <2 x i4> %y, <i4 -1, i4 -1> ; %x
%n1 = and <2 x i4> %n0, <i4 1, i4 1>
define <5 x i32> @splat_assoc_xor(<4 x i32> %x, <5 x i32> %y) {
; CHECK-LABEL: @splat_assoc_xor(
; CHECK-NEXT: [[SPLATX:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <5 x i32> zeroinitializer
-; CHECK-NEXT: [[A:%.*]] = xor <5 x i32> [[Y:%.*]], <i32 42, i32 42, i32 42, i32 42, i32 42>
-; CHECK-NEXT: [[R:%.*]] = xor <5 x i32> [[SPLATX]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor <5 x i32> [[SPLATX]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <5 x i32> [[TMP1]], <i32 42, i32 42, i32 42, i32 42, i32 42>
; CHECK-NEXT: ret <5 x i32> [[R]]
;
%splatx = shufflevector <4 x i32> %x, <4 x i32> undef, <5 x i32> zeroinitializer
define <5 x i32> @splat_assoc_xor(<4 x i32> %x, <5 x i32> %y) {
; CHECK-LABEL: @splat_assoc_xor(
; CHECK-NEXT: [[SPLATX:%.*]] = shufflevector <4 x i32> [[X:%.*]], <4 x i32> undef, <5 x i32> zeroinitializer
-; CHECK-NEXT: [[A:%.*]] = xor <5 x i32> [[Y:%.*]], <i32 42, i32 42, i32 42, i32 42, i32 42>
-; CHECK-NEXT: [[R:%.*]] = xor <5 x i32> [[SPLATX]], [[A]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor <5 x i32> [[SPLATX]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = xor <5 x i32> [[TMP1]], <i32 42, i32 42, i32 42, i32 42, i32 42>
; CHECK-NEXT: ret <5 x i32> [[R]]
;
%splatx = shufflevector <4 x i32> %x, <4 x i32> undef, <5 x i32> zeroinitializer
define i32 @test11(i32 %A, i32 %B) {
; CHECK-LABEL: @test11(
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%xor1 = xor i32 %B, %A
%not = xor i32 %A, -1
define i32 @test11b(i32 %A, i32 %B) {
; CHECK-LABEL: @test11b(
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%xor1 = xor i32 %B, %A
%not = xor i32 %A, -1
define i32 @test11c(i32 %A, i32 %B) {
; CHECK-LABEL: @test11c(
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[NOT]], [[B]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
; CHECK-NEXT: ret i32 [[AND]]
;
define i32 @test11d(i32 %A, i32 %B) {
; CHECK-LABEL: @test11d(
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[NOT]], [[B]]
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR2]], [[XOR1]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
; CHECK-NEXT: ret i32 [[AND]]
;
%xor1 = xor i32 %A, %B
; CHECK-LABEL: @test11e(
; CHECK-NEXT: [[FORCE:%.*]] = mul i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[FORCE]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[FORCE]], [[NOT]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[FORCE]], [[A]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
; CHECK-NEXT: ret i32 [[AND]]
;
; CHECK-LABEL: @test11f(
; CHECK-NEXT: [[FORCE:%.*]] = mul i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[FORCE]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[FORCE]], [[NOT]]
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR2]], [[XOR1]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[FORCE]], [[A]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[TMP1]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR1]], [[XOR2]]
; CHECK-NEXT: ret i32 [[AND]]
;
%force = mul i32 %B, %C
define i8 @test15(i8 %A, i8 %B) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33
-; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
-; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR1]], -34
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[TMP1]], 33
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR1]], [[XOR2]]
; CHECK-NEXT: [[RES:%.*]] = mul i8 [[AND]], [[XOR2]]
; CHECK-NEXT: ret i8 [[RES]]
;
define i8 @test16(i8 %A, i8 %B) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A]], 33
-; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[NOT]], [[B]]
-; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR1]], -34
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[A]], [[B]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[TMP1]], 33
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR2]], [[XOR1]]
; CHECK-NEXT: [[RES:%.*]] = mul i8 [[AND]], [[XOR2]]
; CHECK-NEXT: ret i8 [[RES]]
;