Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1727,64 +1727,110 @@
       (Opcode == Instruction::And) ? Instruction::Or : Instruction::And;
 
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
-  Value *A, *B, *C, *X, *Y, *Dummy;
+  Value *A, *B, *C, *X, *Y, *NotA, *NotB, *Dummy;
 
   // Match following expressions:
   // (~(A | B) & C)
   // (~(A & B) | C)
-  // Captures X = ~(A | B) or ~(A & B)
+  // The LHS is not demorganed if any subexpressions are used multiple times,
+  // thus match it in this form too:
+  // (~A & ~B & C)
+  // (~A | ~B | C)
+  // Captures X = ~(A | B) or ~(A & B) for demorganed form.
+  // Captures NotA = ~A and NotB = ~B otherwise.
   const auto matchNotOrAnd =
       [Opcode, FlippedOpcode](Value *Op, auto m_A, auto m_B, auto m_C,
-                              Value *&X, bool CountUses = false) -> bool {
+                              Value *&X, Value *&NotA, Value *&NotB,
+                              bool CountUses = false) -> bool {
     if (CountUses && !Op->hasOneUse())
       return false;
 
+    NotA = nullptr;
+    NotB = nullptr;
     if (match(Op, m_c_BinOp(FlippedOpcode,
                             m_CombineAnd(m_Value(X),
                                          m_Not(m_c_BinOp(Opcode, m_A, m_B))),
                             m_C)))
       return !CountUses || X->hasOneUse();
 
+    X = nullptr;
+    Value *Y;
+    if (match(Op, m_c_BinOp(FlippedOpcode,
+                            m_CombineAnd(m_Value(Y),
+                                         m_c_BinOp(FlippedOpcode, m_C,
+                                                   m_CombineAnd(m_Value(NotB),
+                                                                m_Not(m_B)))),
+                            m_CombineAnd(m_Value(NotA), m_Not(m_A)))) ||
+        match(Op,
+              m_c_BinOp(FlippedOpcode,
+                        m_CombineAnd(
+                            m_Value(Y),
+                            m_c_BinOp(FlippedOpcode,
+                                      m_CombineAnd(m_Value(NotA), m_Not(m_A)),
+                                      m_CombineAnd(m_Value(NotB), m_Not(m_B)))),
+                        m_C)))
+      return !CountUses || Y->hasOneUse();
+
     return false;
   };
 
   // (~(A | B) & C) | ... --> ...
   // (~(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 (matchNotOrAnd(Op0, m_Value(A), m_Value(B), m_Value(C), X)) {
+  if (matchNotOrAnd(Op0, m_Value(A), m_Value(B), m_Value(C), X, NotA, NotB)) {
     // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
     // (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A)
+    // (~A & ~B & C) | (~(A | C) & B) --> (B ^ C) & ~A
+    // (~A | ~B | C) & (~(A & C) | B) --> ~((B ^ C) & A)
+
+    // (~(A | B) & C) | (~A & ~C & B) --> (B ^ C) & ~A
+    // (~(A & B) | C) & (~A | ~C | B) --> ~((B ^ C) & A)
+    // (~A & ~B & C) | (~A & ~C & B) --> (B ^ C) & ~A
+    // (~A | ~B | C) & (~A | ~C | B) --> ~((B ^ C) & A)
     if (matchNotOrAnd(Op1, m_Specific(A), m_Specific(C), m_Specific(B), Dummy,
-                      true)) {
+                      Y, Dummy, true)) {
+      NotA = NotA ? NotA : Y;
       Value *Xor = Builder.CreateXor(B, C);
       return (Opcode == Instruction::Or)
-                 ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A))
+                 ? BinaryOperator::CreateAnd(Xor,
+                                             NotA ? NotA : 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)
+    // (~A & ~B & C) | (~(B | C) & A) --> (A ^ C) & ~B
+    // (~A | ~B | C) & (~(B & C) | A) --> ~((A ^ C) & B)
+
+    // (~(A | B) & C) | (~B & ~C & A) --> (A ^ C) & ~B
+    // (~(A & B) | C) & (~B | ~C | A) --> ~((A ^ C) & B)
+    // (~A & ~B & C) | (~B & ~C & A) --> (A ^ C) & ~B
+    // (~A | ~B | C) & (~B | ~C | A) --> ~((A ^ C) & B)
     if (matchNotOrAnd(Op1, m_Specific(B), m_Specific(C), m_Specific(A), Dummy,
-                      true)) {
+                      Y, Dummy, true)) {
+      NotB = NotB ? NotB : Y;
       Value *Xor = Builder.CreateXor(A, C);
       return (Opcode == Instruction::Or)
-                 ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B))
+                 ? BinaryOperator::CreateAnd(Xor,
+                                             NotB ? NotB : 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)))))))
+    if (X && 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)))))))
+    if (X && 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));
 
@@ -1792,7 +1838,7 @@
     // Note, the pattern with swapped and/or is not handled because the
     // result is more undefined than a source:
     // (~(A & B) | C) & ~(C & (A ^ B)) --> (A ^ B ^ C) | ~(A | C) is invalid.
-    if (Opcode == Instruction::Or && Op0->hasOneUse() &&
+    if (X && Opcode == Instruction::Or && Op0->hasOneUse() &&
         match(Op1, m_OneUse(m_Not(m_CombineAnd(
                        m_Value(Y),
                        m_c_BinOp(Opcode, m_Specific(C),
Index: llvm/test/Transforms/InstCombine/and-xor-or.ll
===================================================================
--- llvm/test/Transforms/InstCombine/and-xor-or.ll
+++ llvm/test/Transforms/InstCombine/and-xor-or.ll
@@ -1425,6 +1425,1190 @@
   ret i32 %and3
 }
 
+; (~a & ~b & c) | (b & ~(a | c)) --> ~a & (b ^ c)
+
+define i32 @not_and_not_and_and_or(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute1(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and3, %and2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute2(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %notb, %nota
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute3(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %c
+  %and2 = and i32 %and1, %notb
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute4(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %c, %a
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute5(i32 %a, i32 %b0, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute5(
+; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %b, %not1
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+; (~a & ~b & c) | (a & ~(b | c)) --> ~b & (a ^ c)
+
+define i32 @not_and_not_and_and_or_commute6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute6(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %b, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %a
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute7(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute7(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[A]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %b, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %a
+  %or3 = or i32 %and3, %and2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute8(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute8(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %notb, %nota
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %b, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %a
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute9(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute9(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %notb, %c
+  %and2 = and i32 %and1, %nota
+  %or1 = or i32 %b, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %a
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute10(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute10(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %c, %b
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %a
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute11(i32 %a0, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute11(
+; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %b, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %a, %not1
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %or3
+}
+
+; (~a & ~b & c) | (b & ~a & ~c) --> ~a & (b ^ c)
+
+define i32 @not_and_not_and_and_or_commute12(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute12(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %nota, %notc
+  %and4 = and i32 %and3, %b
+  %or3 = or i32 %and2, %and4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute13(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute13(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTB]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %notb, %notc
+  %and4 = and i32 %and3, %a
+  %or3 = or i32 %and2, %and4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_commute14(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_commute14(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %notc, %nota
+  %and4 = and i32 %and3, %b
+  %or3 = or i32 %and4, %and2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use1(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[AND1]])
+; CHECK-NEXT:    call void @use(i32 [[AND2]])
+; CHECK-NEXT:    call void @use(i32 [[AND3]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %and1)
+  call void @use(i32 %and2)
+  call void @use(i32 %and3)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use2(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[NOTA]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[AND1]])
+; CHECK-NEXT:    call void @use(i32 [[AND2]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %and1)
+  call void @use(i32 %and2)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use3(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[AND1]])
+; CHECK-NEXT:    call void @use(i32 [[AND3]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %and1)
+  call void @use(i32 %and3)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use4(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[AND2]])
+; CHECK-NEXT:    call void @use(i32 [[AND3]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %or1 = or i32 %a, %c
+  %not1 = xor i32 %or1, -1
+  %and3 = and i32 %not1, %b
+  %or3 = or i32 %and2, %and3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %and2)
+  call void @use(i32 %and3)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use5(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use5(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[AND4:%.*]] = and i32 [[AND3]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[AND3]])
+; CHECK-NEXT:    call void @use(i32 [[AND4]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %nota, %notc
+  %and4 = and i32 %and3, %b
+  %or3 = or i32 %and2, %and4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %and3)
+  call void @use(i32 %and4)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use6(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[AND4:%.*]] = and i32 [[AND3]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[AND3]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %nota, %notc
+  %and4 = and i32 %and3, %b
+  %or3 = or i32 %and2, %and4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %and3)
+  ret i32 %or3
+}
+
+define i32 @not_and_not_and_and_or_use7(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_and_not_and_and_or_use7(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[AND4:%.*]] = and i32 [[AND3]], [[B]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[AND4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[AND4]])
+; CHECK-NEXT:    ret i32 [[OR3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %and1 = and i32 %nota, %notb
+  %and2 = and i32 %and1, %c
+  %and3 = and i32 %nota, %notc
+  %and4 = and i32 %and3, %b
+  %or3 = or i32 %and2, %and4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %and4)
+  ret i32 %or3
+}
+
+; (~a | ~b | c) & (b | ~(a & c)) --> ~((b ^ c) & a)
+
+define i32 @not_or_not_or_or_and(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute1(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or3, %or2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute2(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %notb, %nota
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute3(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %c
+  %or2 = or i32 %or1, %notb
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute4(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %c, %a
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute5(i32 %a, i32 %b0, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute5(
+; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %b, %not1
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+; (~a | ~b | c) & (a | ~(b & c)) --> ~((a ^ c) & b)
+
+define i32 @not_or_not_or_or_and_commute6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute6(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %b, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %a
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute7(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute7(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[A]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %b, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %a
+  %and3 = and i32 %or3, %or2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute8(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute8(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %notb, %nota
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %b, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %a
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute9(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute9(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %notb, %c
+  %or2 = or i32 %or1, %nota
+  %and1 = and i32 %b, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %a
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute10(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute10(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %c, %b
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %a
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute11(i32 %a0, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute11(
+; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %b, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %a, %not1
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  ret i32 %and3
+}
+
+; (~a | ~b | c) & (b | ~a | ~c) --> ~((b ^ c) & a)
+
+define i32 @not_or_not_or_or_and_commute12(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute12(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; 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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %nota, %notc
+  %or4 = or i32 %or3, %b
+  %and3 = and i32 %or2, %or4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute13(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute13(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %notb, %notc
+  %or4 = or i32 %or3, %a
+  %and3 = and i32 %or2, %or4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_commute14(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_commute14(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %notc, %nota
+  %or4 = or i32 %or3, %b
+  %and3 = and i32 %or4, %or2
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use1(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[OR1]])
+; CHECK-NEXT:    call void @use(i32 [[OR2]])
+; CHECK-NEXT:    call void @use(i32 [[OR3]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %or1)
+  call void @use(i32 %or2)
+  call void @use(i32 %or3)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use2(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[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 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[OR1]])
+; CHECK-NEXT:    call void @use(i32 [[OR2]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %or1)
+  call void @use(i32 %or2)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use3(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[OR1]])
+; CHECK-NEXT:    call void @use(i32 [[OR3]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %or1)
+  call void @use(i32 %or3)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use4(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[C]]
+; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOT1]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR3]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[OR2]])
+; CHECK-NEXT:    call void @use(i32 [[OR3]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %and1 = and i32 %a, %c
+  %not1 = xor i32 %and1, -1
+  %or3 = or i32 %not1, %b
+  %and3 = and i32 %or2, %or3
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %or2)
+  call void @use(i32 %or3)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use5(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use5(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[OR4:%.*]] = or i32 [[OR3]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[OR3]])
+; CHECK-NEXT:    call void @use(i32 [[OR4]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %nota, %notc
+  %or4 = or i32 %or3, %b
+  %and3 = and i32 %or2, %or4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %or3)
+  call void @use(i32 %or4)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use6(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[OR4:%.*]] = or i32 [[OR3]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[OR3]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %nota, %notc
+  %or4 = or i32 %or3, %b
+  %and3 = and i32 %or2, %or4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %or3)
+  ret i32 %and3
+}
+
+define i32 @not_or_not_or_or_and_use7(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @not_or_not_or_or_and_use7(
+; CHECK-NEXT:    [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[NOTB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]]
+; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C]]
+; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[NOTA]], [[NOTC]]
+; CHECK-NEXT:    [[OR4:%.*]] = or i32 [[OR3]], [[B]]
+; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR4]]
+; CHECK-NEXT:    call void @use(i32 [[NOTA]])
+; CHECK-NEXT:    call void @use(i32 [[NOTB]])
+; CHECK-NEXT:    call void @use(i32 [[NOTC]])
+; CHECK-NEXT:    call void @use(i32 [[OR4]])
+; CHECK-NEXT:    ret i32 [[AND3]]
+;
+  %nota = xor i32 %a, -1
+  %notb = xor i32 %b, -1
+  %notc = xor i32 %c, -1
+  %or1 = or i32 %nota, %notb
+  %or2 = or i32 %or1, %c
+  %or3 = or i32 %nota, %notc
+  %or4 = or i32 %or3, %b
+  %and3 = and i32 %or2, %or4
+  call void @use(i32 %nota)
+  call void @use(i32 %notb)
+  call void @use(i32 %notc)
+  call void @use(i32 %or4)
+  ret i32 %and3
+}
+
 ; (b & ~(a | c)) | ~(a | b) --> ~((b & c) | a)
 
 define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {