return new ZExtInst(Builder.CreateAnd(NewBO, X), Ty);
}
+/// Try folding relatively complex patterns for both And and Or operations
+/// with all And and Or swapped.
+static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
+ InstCombiner::BuilderTy &Builder) {
+ const Instruction::BinaryOps Opcode = I.getOpcode();
+ assert(Opcode == Instruction::And || Opcode == Instruction::Or);
+
+ // Flip the logic operation.
+ const Instruction::BinaryOps FlippedOpcode =
+ (Opcode == Instruction::And) ? Instruction::Or : Instruction::And;
+
+ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+ Value *A, *B, *C;
+
+ // (~(A | B) & C) | ... --> ...
+ // (~(A & B) | C) & ... --> ...
+ // TODO: One use checks are conservative. We just need to check that a total
+ // number of multiple used values does not exceed reduction
+ // in operations.
+ if (match(Op0, m_c_BinOp(FlippedOpcode,
+ m_Not(m_BinOp(Opcode, m_Value(A), m_Value(B))),
+ m_Value(C)))) {
+ // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
+ // (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A)
+ if (match(Op1,
+ m_OneUse(m_c_BinOp(FlippedOpcode,
+ m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(A),
+ m_Specific(C)))),
+ m_Specific(B))))) {
+ Value *Xor = Builder.CreateXor(B, C);
+ return (Opcode == Instruction::Or)
+ ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A))
+ : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, A));
+ }
+
+ // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B
+ // (~(A & B) | C) & (~(B & C) | A) --> ~((A ^ C) & B)
+ if (match(Op1,
+ m_OneUse(m_c_BinOp(FlippedOpcode,
+ m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(B),
+ m_Specific(C)))),
+ m_Specific(A))))) {
+ Value *Xor = Builder.CreateXor(A, C);
+ return (Opcode == Instruction::Or)
+ ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B))
+ : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, B));
+ }
+
+ // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
+ // (~(A & B) | C) & ~(A & C) --> ~((B | C) & A)
+ if (match(Op1, m_OneUse(m_Not(m_OneUse(
+ m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))))
+ return BinaryOperator::CreateNot(Builder.CreateBinOp(
+ Opcode, Builder.CreateBinOp(FlippedOpcode, B, C), A));
+
+ // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
+ // (~(A & B) | C) & ~(B & C) --> ~((A | C) & B)
+ if (match(Op1, m_OneUse(m_Not(m_OneUse(
+ m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)))))))
+ return BinaryOperator::CreateNot(Builder.CreateBinOp(
+ Opcode, Builder.CreateBinOp(FlippedOpcode, A, C), B));
+ }
+
+ return nullptr;
+}
+
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
// here. We should standardize that construct where it is needed or choose some
// other way to ensure that commutated variants of patterns are not missed.
if (Instruction *Xor = foldAndToXor(I, Builder))
return Xor;
+ if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
+ return X;
+
// (A|B)&(A|C) -> A|(B&C) etc
if (Value *V = SimplifyUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
if (Instruction *Xor = foldOrToXor(I, Builder))
return Xor;
+ if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
+ return X;
+
// (A&B)|(A&C) -> A&(B|C) etc
if (Value *V = SimplifyUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A))))
return BinaryOperator::CreateOr(Op1, Builder.CreateAnd(A, C));
- // (~(A | B) & C) | ... --> ...
- // TODO: One use checks are conservative. We just need to check that a total
- // number of multiple used values does not exceed reduction
- // in operations.
- if (match(Op0, m_c_And(m_Not(m_Or(m_Value(A), m_Value(B))), m_Value(C)))) {
- // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
- if (match(Op1, m_OneUse(m_c_And(
- m_OneUse(m_Not(m_c_Or(m_Specific(A), m_Specific(C)))),
- m_Specific(B))))) {
- Value *Xor = Builder.CreateXor(B, C);
- return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A));
- }
-
- // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B
- if (match(Op1, m_OneUse(m_c_And(
- m_OneUse(m_Not(m_c_Or(m_Specific(B), m_Specific(C)))),
- m_Specific(A))))) {
- Value *Xor = Builder.CreateXor(A, C);
- return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B));
- }
-
- // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
- if (match(Op1,
- m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C)))))))
- return BinaryOperator::CreateNot(
- Builder.CreateOr(Builder.CreateAnd(B, C), A));
-
- // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
- if (match(Op1,
- m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(B), m_Specific(C)))))))
- return BinaryOperator::CreateNot(
- Builder.CreateOr(Builder.CreateAnd(A, C), B));
- }
-
if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder))
return DeMorgan;
define i32 @and_not_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %a, %b
define i32 @and_not_or_commute1(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @and_not_or_commute1(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
define i32 @and_not_or_commute2(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @and_not_or_commute2(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR2]], [[OR1]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
define i32 @and_not_or_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute3(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
define i32 @and_not_or_commute4(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @and_not_or_commute4(
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
; CHECK-LABEL: @and_not_or_commute5(
; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
define i32 @and_not_or_commute6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute6(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %a, %b
define i32 @and_not_or_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute7(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
; CHECK-LABEL: @and_not_or_commute8(
; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
; CHECK-LABEL: @and_not_or_extra_not_use1(
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[NOT1]])
; CHECK-NEXT: ret i32 [[AND3]]
;
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[OR1]])
; CHECK-NEXT: ret i32 [[AND3]]
;
define i32 @and_not_or_extra_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_or_use1(
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[AND1]])
; CHECK-NEXT: ret i32 [[AND3]]
;
define i32 @and_not_or_extra_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_or_use2(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[AND2]])
; CHECK-NEXT: ret i32 [[AND3]]
;
define i32 @and_or_not_not(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
define i32 @and_or_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute1(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
define i32 @and_or_not_not_commute2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute2(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
define i32 @and_or_not_not_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute3(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
define i32 @and_or_not_not_commute4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute4(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %a, %b
define i32 @and_or_not_not_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute5(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %b, %a
define i32 @and_or_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute6(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
define i32 @and_or_not_not_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute7(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[AND3]]
;
%and1 = and i32 %a, %b
define i32 @and_or_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_extra_not_use2(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
+; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[NOT2]])
; CHECK-NEXT: ret i32 [[AND3]]
;
define i32 @and_or_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_extra_and_use(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
+; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[OR]])
; CHECK-NEXT: ret i32 [[AND3]]
;
define i32 @and_or_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_extra_or_use2(
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[AND2]])
; CHECK-NEXT: ret i32 [[AND3]]
;