; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instcombine -S | FileCheck %s

declare void @use(i32)

; a & (a ^ b) --> a & ~b

define i32 @and_xor_common_op(i32 %pa, i32 %pb) {
; CHECK-LABEL: @and_xor_common_op(
; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[PA:%.*]]
; CHECK-NEXT:    [[B:%.*]] = udiv i32 43, [[PB:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
; CHECK-NEXT:    ret i32 [[R]]
;
  %a = udiv i32 42, %pa ; thwart complexity-based canonicalization
  %b = udiv i32 43, %pb ; thwart complexity-based canonicalization
  %xor = xor i32 %a, %b
  %r = and i32 %a, %xor
  ret i32 %r
}

; a & (b ^ a) --> a & ~b

define i32 @and_xor_common_op_commute1(i32 %pa, i32 %pb) {
; CHECK-LABEL: @and_xor_common_op_commute1(
; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[PA:%.*]]
; CHECK-NEXT:    [[B:%.*]] = udiv i32 43, [[PB:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
; CHECK-NEXT:    ret i32 [[R]]
;
  %a = udiv i32 42, %pa ; thwart complexity-based canonicalization
  %b = udiv i32 43, %pb ; thwart complexity-based canonicalization
  %xor = xor i32 %b, %a
  %r = and i32 %a, %xor
  ret i32 %r
}

; (b ^ a) & a --> a & ~b

define i32 @and_xor_common_op_commute2(i32 %pa, i32 %pb) {
; CHECK-LABEL: @and_xor_common_op_commute2(
; CHECK-NEXT:    [[A:%.*]] = udiv i32 42, [[PA:%.*]]
; CHECK-NEXT:    [[B:%.*]] = udiv i32 43, [[PB:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[R:%.*]] = and i32 [[A]], [[TMP1]]
; CHECK-NEXT:    ret i32 [[R]]
;
  %a = udiv i32 42, %pa ; thwart complexity-based canonicalization
  %b = udiv i32 43, %pb ; thwart complexity-based canonicalization
  %xor = xor i32 %b, %a
  %r = and i32 %xor, %a
  ret i32 %r
}

; (a ^ b) & a --> a & ~b

define <2 x i32> @and_xor_common_op_commute3(<2 x i32> %pa, <2 x i32> %pb) {
; CHECK-LABEL: @and_xor_common_op_commute3(
; CHECK-NEXT:    [[A:%.*]] = udiv <2 x i32> <i32 42, i32 43>, [[PA:%.*]]
; CHECK-NEXT:    [[B:%.*]] = udiv <2 x i32> <i32 43, i32 42>, [[PB:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i32> [[B]], <i32 -1, i32 -1>
; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[A]], [[TMP1]]
; CHECK-NEXT:    ret <2 x i32> [[R]]
;
  %a = udiv <2 x i32> <i32 42, i32 43>, %pa ; thwart complexity-based canonicalization
  %b = udiv <2 x i32> <i32 43, i32 42>, %pb ; thwart complexity-based canonicalization
  %xor = xor <2 x i32> %a, %b
  %r = and <2 x i32> %xor, %a
  ret <2 x i32> %r
}

; It's ok to match a common constant.
; The xor should be a 'not' op (-1 constant).

define <4 x i32> @and_xor_common_op_constant(<4 x i32> %A) {
; CHECK-LABEL: @and_xor_common_op_constant(
; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i32> [[A:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
; CHECK-NEXT:    [[TMP2:%.*]] = and <4 x i32> [[TMP1]], <i32 1, i32 2, i32 3, i32 4>
; CHECK-NEXT:    ret <4 x i32> [[TMP2]]
;
  %1 = xor <4 x i32> %A, <i32 1, i32 2, i32 3, i32 4>
  %2 = and <4 x i32> <i32 1, i32 2, i32 3, i32 4>, %1
  ret <4 x i32> %2
}

; a & (a ^ ~b) --> a & b

define i32 @and_xor_not_common_op(i32 %a, i32 %b) {
; CHECK-LABEL: @and_xor_not_common_op(
; CHECK-NEXT:    [[T4:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    ret i32 [[T4]]
;
  %b2 = xor i32 %b, -1
  %t2 = xor i32 %a, %b2
  %t4 = and i32 %t2, %a
  ret i32 %t4
}

; a & (a ^ ~b) --> a & b

define i32 @and_xor_not_common_op_extrause(i32 %a, i32 %b, i32* %dst) {
; CHECK-LABEL: @and_xor_not_common_op_extrause(
; CHECK-NEXT:    [[B2:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    store i32 [[B2]], i32* [[DST:%.*]], align 4
; CHECK-NEXT:    [[T4:%.*]] = and i32 [[A:%.*]], [[B]]
; CHECK-NEXT:    ret i32 [[T4]]
;
  %b2 = xor i32 %b, -1
  store i32 %b2, i32* %dst
  %t2 = xor i32 %a, %b2
  %t4 = and i32 %t2, %a
  ret i32 %t4
}

; a & ~(a ^ b) --> a & b

define i32 @and_not_xor_common_op(i32 %a, i32 %b) {
; CHECK-LABEL: @and_not_xor_common_op(
; CHECK-NEXT:    [[T4:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    ret i32 [[T4]]
;
  %b2 = xor i32 %b, %a
  %t2 = xor i32 %b2, -1
  %t4 = and i32 %t2, %a
  ret i32 %t4
}

declare i32 @gen32()
define i32 @and_not_xor_common_op_commutative(i32 %b) {
; CHECK-LABEL: @and_not_xor_common_op_commutative(
; CHECK-NEXT:    [[A:%.*]] = call i32 @gen32()
; CHECK-NEXT:    [[T4:%.*]] = and i32 [[A]], [[B:%.*]]
; CHECK-NEXT:    ret i32 [[T4]]
;
  %a = call i32 @gen32()
  %b2 = xor i32 %a, %b ; swapped order
  %t2 = xor i32 %b2, -1
  %t4 = and i32 %a, %t2 ; swapped order
  ret i32 %t4
}

; rdar://10770603
; (x & y) | (x ^ y) -> x | y

define i64 @or(i64 %x, i64 %y) {
; CHECK-LABEL: @or(
; CHECK-NEXT:    [[TMP1:%.*]] = or i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT:    ret i64 [[TMP1]]
;
  %1 = and i64 %y, %x
  %2 = xor i64 %y, %x
  %3 = add i64 %1, %2
  ret i64 %3
}

; (x & y) + (x ^ y) -> x | y

define i64 @or2(i64 %x, i64 %y) {
; CHECK-LABEL: @or2(
; CHECK-NEXT:    [[TMP1:%.*]] = or i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT:    ret i64 [[TMP1]]
;
  %1 = and i64 %y, %x
  %2 = xor i64 %y, %x
  %3 = or i64 %1, %2
  ret i64 %3
}

; PR37098 - https://bugs.llvm.org/show_bug.cgi?id=37098
; Reassociate bitwise logic to eliminate a shift.
; There are 4 commuted * 3 shift ops * 3 logic ops = 36 potential variations of this fold.
; Mix the commutation options to provide coverage using less tests.

define i8 @and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @and_shl(
; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = and i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = shl i8 %x, %shamt
  %sy = shl i8 %y, %shamt
  %a = and i8 %sx, %z
  %r = and i8 %sy, %a
  ret i8 %r
}

define i8 @or_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @or_shl(
; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = shl i8 %x, %shamt
  %sy = shl i8 %y, %shamt
  %a = or i8 %sx, %z
  %r = or i8 %a, %sy
  ret i8 %r
}

define i8 @xor_shl(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
; CHECK-LABEL: @xor_shl(
; CHECK-NEXT:    [[Z:%.*]] = sdiv i8 42, [[ZARG:%.*]]
; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = xor i8 [[Z]], [[SX]]
; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %z = sdiv i8 42, %zarg ; thwart complexity-based canonicalization
  %sx = shl i8 %x, %shamt
  %sy = shl i8 %y, %shamt
  %a = xor i8 %z, %sx
  %r = xor i8 %a, %sy
  ret i8 %r
}

define i8 @and_lshr(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
; CHECK-LABEL: @and_lshr(
; CHECK-NEXT:    [[Z:%.*]] = sdiv i8 42, [[ZARG:%.*]]
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = and i8 [[Z]], [[SX]]
; CHECK-NEXT:    [[R:%.*]] = and i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %z = sdiv i8 42, %zarg ; thwart complexity-based canonicalization
  %sx = lshr i8 %x, %shamt
  %sy = lshr i8 %y, %shamt
  %a = and i8 %z, %sx
  %r = and i8 %sy, %a
  ret i8 %r
}

define i8 @or_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @or_lshr(
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = or i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = lshr i8 %x, %shamt
  %sy = lshr i8 %y, %shamt
  %a = or i8 %sx, %z
  %r = or i8 %sy, %a
  ret i8 %r
}

define i8 @xor_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @xor_lshr(
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = lshr i8 %x, %shamt
  %sy = lshr i8 %y, %shamt
  %a = xor i8 %sx, %z
  %r = xor i8 %a, %sy
  ret i8 %r
}

define i8 @and_ashr(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
; CHECK-LABEL: @and_ashr(
; CHECK-NEXT:    [[Z:%.*]] = sdiv i8 42, [[ZARG:%.*]]
; CHECK-NEXT:    [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = and i8 [[Z]], [[SX]]
; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[SY]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %z = sdiv i8 42, %zarg ; thwart complexity-based canonicalization
  %sx = ashr i8 %x, %shamt
  %sy = ashr i8 %y, %shamt
  %a = and i8 %z, %sx
  %r = and i8 %a, %sy
  ret i8 %r
}

define i8 @or_ashr(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
; CHECK-LABEL: @or_ashr(
; CHECK-NEXT:    [[Z:%.*]] = sdiv i8 42, [[ZARG:%.*]]
; CHECK-NEXT:    [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[Z]], [[SX]]
; CHECK-NEXT:    [[R:%.*]] = or i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %z = sdiv i8 42, %zarg ; thwart complexity-based canonicalization
  %sx = ashr i8 %x, %shamt
  %sy = ashr i8 %y, %shamt
  %a = or i8 %z, %sx
  %r = or i8 %sy, %a
  ret i8 %r
}

define <2 x i8> @xor_ashr(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z, <2 x i8> %shamt) {
; CHECK-LABEL: @xor_ashr(
; CHECK-NEXT:    [[SX:%.*]] = ashr <2 x i8> [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = ashr <2 x i8> [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = xor <2 x i8> [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = xor <2 x i8> [[A]], [[SY]]
; CHECK-NEXT:    ret <2 x i8> [[R]]
;
  %sx = ashr <2 x i8> %x, %shamt
  %sy = ashr <2 x i8> %y, %shamt
  %a = xor <2 x i8> %sx, %z
  %r = xor <2 x i8> %a, %sy
  ret <2 x i8> %r
}

; Negative test - different logic ops

define i8 @or_and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @or_and_shl(
; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = and i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = shl i8 %x, %shamt
  %sy = shl i8 %y, %shamt
  %a = or i8 %sx, %z
  %r = and i8 %sy, %a
  ret i8 %r
}

; Negative test - different shift ops

define i8 @or_lshr_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @or_lshr_shl(
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = lshr i8 %x, %shamt
  %sy = shl i8 %y, %shamt
  %a = or i8 %sx, %z
  %r = or i8 %a, %sy
  ret i8 %r
}

; Negative test - different shift amounts

define i8 @or_lshr_shamt2(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @or_lshr_shamt2(
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], 5
; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = or i8 [[SY]], [[A]]
; CHECK-NEXT:    ret i8 [[R]]
;
  %sx = lshr i8 %x, 5
  %sy = lshr i8 %y, %shamt
  %a = or i8 %sx, %z
  %r = or i8 %sy, %a
  ret i8 %r
}

; Negative test - multi-use

define i8 @xor_lshr_multiuse(i8 %x, i8 %y, i8 %z, i8 %shamt) {
; CHECK-LABEL: @xor_lshr_multiuse(
; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
; CHECK-NEXT:    [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[A]], [[R]]
; CHECK-NEXT:    ret i8 [[R2]]
;
  %sx = lshr i8 %x, %shamt
  %sy = lshr i8 %y, %shamt
  %a = xor i8 %sx, %z
  %r = xor i8 %a, %sy
  %r2 = sdiv i8 %a, %r
  ret i8 %r2
}

; Reassociate chains of extend(X) | (extend(Y) | Z).
; Check that logical op is performed on a smaller type and then extended.

define i64 @sext_or_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @sext_or_chain(
; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[OR]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[OR2]]
;
  %conv = sext i16 %b to i64
  %conv2 = sext i16 %c to i64
  %or = or i64 %a, %conv
  %or2 = or i64 %or, %conv2
  ret i64 %or2
}

define i64 @zext_or_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @zext_or_chain(
; CHECK-NEXT:    [[CONV:%.*]] = zext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[OR]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[OR2]]
;
  %conv = zext i16 %b to i64
  %conv2 = zext i16 %c to i64
  %or = or i64 %a, %conv
  %or2 = or i64 %or, %conv2
  ret i64 %or2
}

define i64 @sext_and_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @sext_and_chain(
; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[AND:%.*]] = and i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[AND]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[AND2]]
;
  %conv = sext i16 %b to i64
  %conv2 = sext i16 %c to i64
  %and = and i64 %a, %conv
  %and2 = and i64 %and, %conv2
  ret i64 %and2
}

define i64 @zext_and_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @zext_and_chain(
; CHECK-NEXT:    [[CONV:%.*]] = zext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[AND:%.*]] = and i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i64 [[AND]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[AND2]]
;
  %conv = zext i16 %b to i64
  %conv2 = zext i16 %c to i64
  %and = and i64 %a, %conv
  %and2 = and i64 %and, %conv2
  ret i64 %and2
}

define i64 @sext_xor_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @sext_xor_chain(
; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[XOR:%.*]] = xor i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[XOR2:%.*]] = xor i64 [[XOR]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[XOR2]]
;
  %conv = sext i16 %b to i64
  %conv2 = sext i16 %c to i64
  %xor = xor i64 %a, %conv
  %xor2 = xor i64 %xor, %conv2
  ret i64 %xor2
}

define i64 @zext_xor_chain(i64 %a, i16 %b, i16 %c) {
; CHECK-LABEL: @zext_xor_chain(
; CHECK-NEXT:    [[CONV:%.*]] = zext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = zext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[XOR:%.*]] = xor i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[XOR2:%.*]] = xor i64 [[XOR]], [[CONV2]]
; CHECK-NEXT:    ret i64 [[XOR2]]
;
  %conv = zext i16 %b to i64
  %conv2 = zext i16 %c to i64
  %xor = xor i64 %a, %conv
  %xor2 = xor i64 %xor, %conv2
  ret i64 %xor2
}

; Negative test with more uses.
define i64 @sext_or_chain_two_uses1(i64 %a, i16 %b, i16 %c, i64 %d) {
; CHECK-LABEL: @sext_or_chain_two_uses1(
; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[OR]], [[CONV2]]
; CHECK-NEXT:    [[USE:%.*]] = udiv i64 [[OR]], [[D:%.*]]
; CHECK-NEXT:    [[RETVAL:%.*]] = udiv i64 [[OR2]], [[USE]]
; CHECK-NEXT:    ret i64 [[RETVAL]]
;
  %conv = sext i16 %b to i64
  %conv2 = sext i16 %c to i64
  ; %or has two uses
  %or = or i64 %a, %conv
  %or2 = or i64 %or, %conv2
  %use = udiv i64 %or, %d
  %retval = udiv i64 %or2, %use
  ret i64 %retval
}
define i64 @sext_or_chain_two_uses2(i64 %a, i16 %b, i16 %c, i64 %d) {
; CHECK-LABEL: @sext_or_chain_two_uses2(
; CHECK-NEXT:    [[CONV:%.*]] = sext i16 [[B:%.*]] to i64
; CHECK-NEXT:    [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[CONV]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i64 [[OR]], [[CONV2]]
; CHECK-NEXT:    [[USE1:%.*]] = udiv i64 [[OR2]], [[D:%.*]]
; CHECK-NEXT:    [[USE2:%.*]] = udiv i64 [[OR2]], [[USE1]]
; CHECK-NEXT:    ret i64 [[USE2]]
;
  %conv = sext i16 %b to i64
  %conv2 = sext i16 %c to i64
  %or = or i64 %a, %conv
  ; %or2 has two uses
  %or2 = or i64 %or, %conv2
  %use1 = udiv i64 %or2, %d
  %use2 = udiv i64 %or2, %use1
  ret i64 %use2
}

; (a & ~b) & ~c --> a & ~(b | c)

define i32 @not_and_and_not(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_not(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %and1 = and i32 %a, %not1
  %and2 = and i32 %and1, %not2
  ret i32 %and2
}

define <4 x i64> @not_and_and_not_4i64(<4 x i64> %a0, <4 x i64> %b, <4 x i64> %c) {
; CHECK-LABEL: @not_and_and_not_4i64(
; CHECK-NEXT:    [[A:%.*]] = sdiv <4 x i64> <i64 42, i64 42, i64 42, i64 42>, [[A0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = or <4 x i64> [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i64> [[TMP1]], <i64 -1, i64 -1, i64 -1, i64 -1>
; CHECK-NEXT:    [[AND2:%.*]] = and <4 x i64> [[A]], [[TMP2]]
; CHECK-NEXT:    ret <4 x i64> [[AND2]]
;
  %a = sdiv <4 x i64> <i64 42, i64 42, i64 42, i64 42>, %a0 ; thwart complexity-based canonicalization
  %not1 = xor <4 x i64> %b, <i64 -1, i64 -1, i64 -1, i64 -1>
  %not2 = xor <4 x i64> %c, <i64 -1, i64 -1, i64 -1, i64 -1>
  %and1 = and <4 x i64> %a, %not1
  %and2 = and <4 x i64> %and1, %not2
  ret <4 x i64> %and2
}

; (~b & a) & ~c --> a & ~(b | c)

define i32 @not_and_and_not_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_not_commute1(
; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[TMP2]], [[A:%.*]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %and1 = and i32 %not1, %a
  %and2 = and i32 %and1, %not2
  ret i32 %and2
}

; ~c & (a & ~b) --> a & ~(b | c)

define i32 @not_and_and_not_commute2_extra_not_use(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_not_commute2_extra_not_use(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[C:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B:%.*]], [[C]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[TMP2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %and1 = and i32 %a, %not1
  %and2 = and i32 %not2, %and1
  call void @use(i32 %not2)
  ret i32 %and2
}

define i32 @not_and_and_not_extra_and1_use(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_not_extra_and1_use(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[C:%.*]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[NOT1]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %and1 = and i32 %a, %not1
  %and2 = and i32 %and1, %not2
  call void @use(i32 %and1)
  ret i32 %and2
}

; (a | ~b) | ~c --> a | ~(b & c)

define i32 @not_or_or_not(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_not(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %or1 = or i32 %a, %not1
  %or2 = or i32 %or1, %not2
  ret i32 %or2
}

define <2 x i6> @not_or_or_not_2i6(<2 x i6> %a0, <2 x i6> %b, <2 x i6> %c) {
; CHECK-LABEL: @not_or_or_not_2i6(
; CHECK-NEXT:    [[A:%.*]] = sdiv <2 x i6> <i6 3, i6 3>, [[A0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i6> [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor <2 x i6> [[TMP1]], <i6 -1, i6 -1>
; CHECK-NEXT:    [[OR2:%.*]] = or <2 x i6> [[A]], [[TMP2]]
; CHECK-NEXT:    ret <2 x i6> [[OR2]]
;
  %a = sdiv <2 x i6> <i6 3, i6 3>, %a0 ; thwart complexity-based canonicalization
  %not1 = xor <2 x i6> %b, <i6 -1, i6 -1>
  %not2 = xor <2 x i6> %c, <i6 -1, i6 undef>
  %or1 = or <2 x i6> %a, %not1
  %or2 = or <2 x i6> %or1, %not2
  ret <2 x i6> %or2
}

; (~b | a) | ~c --> a | ~(b & c)

define i32 @not_or_or_not_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_not_commute1(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[TMP2]], [[A:%.*]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %or1 = or i32 %not1, %a
  %or2 = or i32 %or1, %not2
  ret i32 %or2
}

; ~c | (a | ~b) --> a | ~(b & c)

define i32 @not_or_or_not_commute2_extra_not_use(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_not_commute2_extra_not_use(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[C:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[TMP2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %or1 = or i32 %a, %not1
  %or2 = or i32 %not2, %or1
  call void @use(i32 %not2)
  ret i32 %or2
}

define i32 @not_or_or_not_extra_or1_use(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_not_extra_or1_use(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[C:%.*]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[NOT1]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %not1 = xor i32 %b, -1
  %not2 = xor i32 %c, -1
  %or1 = or i32 %a, %not1
  %or2 = or i32 %or1, %not2
  call void @use(i32 %or1)
  ret i32 %or2
}

; (c & ~(a | b)) | (b & ~(a | c)) --> ~a & (b ^ c)

define i32 @or_not_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute1(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_not_and_commute1(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %b, %not2
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute2(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_not_and_commute2(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %b, %not2
  %or3 = or i32 %and2, %and1
  ret i32 %or3
}

define i32 @or_not_and_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_commute3(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute4(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @or_not_and_commute4(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %c, %not1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute5(i32 %a0, i32 %b, i32 %c0) {
; CHECK-LABEL: @or_not_and_commute5(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %c, %not1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_commute6(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_commute7(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute8(i32 %a0, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_not_and_commute8(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %b, %not2
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_commute9(i32 %a0, i32 %b0, i32 %c0) {
; CHECK-LABEL: @or_not_and_commute9(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[TMP2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %b, %not2
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_not_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -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 [[NOT1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %not1)
  ret i32 %or3
}

define i32 @or_not_and_extra_not_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_not_use2(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %not2)
  ret i32 %or3
}

define i32 @or_not_and_extra_and_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_and_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; 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 [[AND1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %and1)
  ret i32 %or3
}

define i32 @or_not_and_extra_and_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_and_use2(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT:    call void @use(i32 [[AND2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %and2)
  ret i32 %or3
}

define i32 @or_not_and_extra_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_or_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; 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 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %or1)
  ret i32 %or3
}

define i32 @or_not_and_extra_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_or_use2(
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; 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 [[OR2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  call void @use(i32 %or2)
  ret i32 %or3
}

define i32 @or_not_and_wrong_c(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @or_not_and_wrong_c(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[D:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %d
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %b
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

define i32 @or_not_and_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @or_not_and_wrong_b(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[NOT2]], [[D:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %c
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and2 = and i32 %not2, %d
  %or3 = or i32 %and1, %and2
  ret i32 %or3
}

; (c | ~(a & b)) & (b | ~(a & c)) --> ~(a & (b ^ c))

define i32 @and_not_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or(
; 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
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

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:    [[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
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %b, %not2
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

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:    [[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
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %b, %not2
  %and3 = and i32 %or2, %or1
  ret i32 %and3
}

define i32 @and_not_or_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute3(
; 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
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

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:    [[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
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %c, %not1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_commute5(i32 %a0, i32 %b, i32 %c0) {
; CHECK-LABEL: @and_not_or_commute5(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; 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
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %c, %not1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_commute6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute6(
; 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
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_commute7(
; 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
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_commute8(i32 %a0, i32 %b0, i32 %c) {
; CHECK-LABEL: @and_not_or_commute8(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; 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
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %b, %not2
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_commute9(i32 %a0, i32 %b0, i32 %c0) {
; CHECK-LABEL: @and_not_or_commute9(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; 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
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %b, %not2
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_not_use1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -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 [[NOT1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %not1)
  ret i32 %and3
}

define i32 @and_not_or_extra_not_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_not_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:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %not2)
  ret i32 %and3
}

define i32 @and_not_or_extra_and_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_and_use1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[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 [[OR1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %or1)
  ret i32 %and3
}

define i32 @and_not_or_extra_and_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_extra_and_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:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %or2)
  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:    [[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]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %and1)
  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:    [[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]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  call void @use(i32 %and2)
  ret i32 %and3
}

define i32 @and_not_or_wrong_c(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @and_not_or_wrong_c(
; 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]], [[D:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %d
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %b
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

define i32 @and_not_or_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @and_not_or_wrong_b(
; 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]], [[D:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %c
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or2 = or i32 %not2, %d
  %and3 = and i32 %or1, %or2
  ret i32 %and3
}

; (b & ~(a | c)) | ~(a | b) --> ~((b & c) | a)

define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute1(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %b, %not2
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute2(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute3(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute4(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute5(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %not1, %and
  ret i32 %or3
}

define i32 @or_and_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute6(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and = and i32 %b, %not2
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute7(
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %c, %a
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_not_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  call void @use(i32 %not1)
  ret i32 %or3
}

define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_not_use2(
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  call void @use(i32 %not2)
  ret i32 %or3
}

define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_and_use(
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C]], [[B]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[AND]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  call void @use(i32 %and)
  ret i32 %or3
}

define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_or_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  call void @use(i32 %or1)
  ret i32 %or3
}

define i32 @or_and_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_or_use2(
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  call void @use(i32 %or2)
  ret i32 %or3
}

; Check the use limit. It can be adjusted in the future in terms of
; LHS and RHS uses distribution to be more flexible.
define i32 @or_and_not_not_2_extra_uses(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_2_extra_uses(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    call void @use(i32 [[AND]])
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  call void @use(i32 %or1)
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  call void @use(i32 %and)
  %or3 = or i32 %not1, %and
  ret i32 %or3
}

define i32 @or_and_not_not_wrong_a(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @or_and_not_not_wrong_a(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[D:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %d
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

define i32 @or_and_not_not_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @or_and_not_not_wrong_b(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[D:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %d, %a
  %not1 = xor i32 %or1, -1
  %or2 = or i32 %a, %c
  %not2 = xor i32 %or2, -1
  %and = and i32 %not2, %b
  %or3 = or i32 %and, %not1
  ret i32 %or3
}

; (b | ~(a & c)) & ~(a & b) --> ~((b | c) & a)

define i32 @and_or_not_not(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

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:    [[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
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %b, %not2
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_commute2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute2(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute3(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_commute4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute4(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute5(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %not1, %or
  ret i32 %and3
}

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:    [[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
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or = or i32 %b, %not2
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_commute7(
; 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
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %c, %a
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_extra_not_use1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; 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:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  call void @use(i32 %not1)
  ret i32 %and3
}

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:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; 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]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  call void @use(i32 %not2)
  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:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; 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]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  call void @use(i32 %or)
  ret i32 %and3
}

define i32 @and_or_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_extra_or_use1(
; 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:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  call void @use(i32 %and1)
  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:    [[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]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  call void @use(i32 %and2)
  ret i32 %and3
}

define i32 @and_or_not_not_2_extra_uses(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_or_not_not_2_extra_uses(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    call void @use(i32 [[OR]])
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  call void @use(i32 %and1)
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  call void @use(i32 %or)
  %and3 = and i32 %not1, %or
  ret i32 %and3
}

define i32 @and_or_not_not_wrong_a(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @and_or_not_not_wrong_a(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[D:%.*]]
; 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:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %d
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

define i32 @and_or_not_not_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: @and_or_not_not_wrong_b(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[D:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR]], [[NOT1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %d, %a
  %not1 = xor i32 %and1, -1
  %and2 = and i32 %a, %c
  %not2 = xor i32 %and2, -1
  %or = or i32 %not2, %b
  %and3 = and i32 %or, %not1
  ret i32 %and3
}

; (a & ~(b | c)) | ~(a | (b ^ c)) --> (~a & b & c) | ~(b | c)

define i32 @and_not_or_or_not_or_xor(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_commute1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %c, %b
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_commute2(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_commute2(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %a, %not1
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_commute3(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[C]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %c, %b
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_commute4(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_commute4(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[A]], [[XOR1]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %a, %not1
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %a, %xor1
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_commute5(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %not2, %and1
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %or1)
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use2(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %not1)
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use3(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %and1)
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use4(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    call void @use(i32 [[XOR1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %xor1)
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use5(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[OR1]], [[OR2]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP1]], -1
; CHECK-NEXT:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %or2)
  ret i32 %or3
}

define i32 @and_not_or_or_not_or_xor_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @and_not_or_or_not_or_xor_use6(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %not1 = xor i32 %or1, -1
  %and1 = and i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %or2 = or i32 %xor1, %a
  %not2 = xor i32 %or2, -1
  %or3 = or i32 %and1, %not2
  call void @use(i32 %not2)
  ret i32 %or3
}

; (a | ~(b & c)) & ~(a & (b ^ c)) --> ~(a | b) | (a ^ b ^ c)
; This pattern is not handled because the result is more undefined than a source.
; It is invalid as is, but feezing %a and %b will make it valid.

define i32 @or_not_and_and_not_and_xor(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_commute1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %c, %b
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_commute2(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_commute2(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[NOT1]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %a, %not1
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_commute3(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[C]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %c, %b
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_commute4(i32 %a0, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_commute4(
; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[A]], [[NOT1]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[XOR1]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %a, %not1
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %a, %xor1
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_commute5(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %not2, %or1
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %and1)
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use2(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %not1)
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use3(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %or1)
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use4(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[XOR1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %xor1)
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use5(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[AND2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %and2)
  ret i32 %and3
}

define i32 @or_not_and_and_not_and_xor_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_and_not_and_xor_use6(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[A:%.*]]
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR1]], [[A]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR1]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %not1 = xor i32 %and1, -1
  %or1 = or i32 %not1, %a
  %xor1 = xor i32 %b, %c
  %and2 = and i32 %xor1, %a
  %not2 = xor i32 %and2, -1
  %and3 = and i32 %or1, %not2
  call void @use(i32 %not2)
  ret i32 %and3
}

; (~a & b & c) | ~(a | b | c) -> ~(a | (b ^ c))

define i32 @not_and_and_or_not_or_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute1_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute1_or(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %c, %a
  %or2 = or i32 %or1, %b
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute2_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute2_or(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %c
  %or2 = or i32 %or1, %a
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute1_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute1_and(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %c
  %and2 = and i32 %and1, %b
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute2_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute2_and(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %b, %c
  %and2 = and i32 %and1, %not2
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute1(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %a, %b
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute2(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute2(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %or2 = or i32 %c, %or1
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute3(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute3(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %b, %not2
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_commute4(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_and_and_or_not_or_or_commute4(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %c, %and1
  %or3 = or i32 %and2, %not1
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use1(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %or1)
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use2(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %or2)
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use3(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %not1)
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use4(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %not2)
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use5(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT:    [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %and1)
  ret i32 %or3
}

define i32 @not_and_and_or_not_or_or_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_not_or_or_use6(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C]]
; CHECK-NEXT:    [[OR3:%.*]] = or i32 [[AND2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[AND2]])
; CHECK-NEXT:    ret i32 [[OR3]]
;
  %or1 = or i32 %b, %a
  %or2 = or i32 %or1, %c
  %not1 = xor i32 %or2, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or3 = or i32 %and2, %not1
  call void @use(i32 %and2)
  ret i32 %or3
}

; (~a | b | c) & ~(a & b & c) -> ~a | (b ^ c)

define i32 @not_or_or_and_not_and_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute1_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute1_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %c, %a
  %and2 = and i32 %and1, %b
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute2_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute2_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %c
  %and2 = and i32 %and1, %a
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute1_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute1_or(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %c
  %or2 = or i32 %or1, %b
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute2_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute2_or(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %b, %c
  %or2 = or i32 %or1, %not2
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute1(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %a, %b
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute2(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute2(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %a
  %and2 = and i32 %c, %and1
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute3(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute3(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %b, %not2
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_commute4(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_or_or_and_not_and_and_commute4(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %c, %or1
  %and3 = and i32 %or2, %not1
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use1(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %and1)
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use2(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[AND2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %and2)
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use3(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND2]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR2]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %not1)
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use4(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %not2)
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use5(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C:%.*]], [[B]]
; CHECK-NEXT:    [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %or1)
  ret i32 %and3
}

define i32 @not_or_or_and_not_and_and_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_not_and_and_use6(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C]]
; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND2]], [[OR2]]
; CHECK-NEXT:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[AND3]]
;
  %and1 = and i32 %b, %a
  %and2 = and i32 %and1, %c
  %not1 = xor i32 %and2, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and3 = and i32 %or2, %not1
  call void @use(i32 %or2)
  ret i32 %and3
}

; (~a & b & c) | ~(a | b) -> (c | ~b) & ~a

define i32 @not_and_and_or_no_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_commute1_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_commute1_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %c, %b
  %and2 = and i32 %and1, %not2
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_commute2_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_commute2_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %c
  %and2 = and i32 %and1, %b
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_commute1(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %a, %b
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_commute2(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_commute2(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %b, %not2
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_commute3(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_and_and_or_no_or_commute3(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[C]], [[TMP1]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %c, %and1
  %or2 = or i32 %and2, %not1
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use1(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  call void @use(i32 %not2)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use2(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %b, %c
  %and2 = and i32 %and1, %not2
  %or2 = or i32 %and2, %not1
  call void @use(i32 %not2)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use3(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %c
  %and2 = and i32 %and1, %b
  %or2 = or i32 %and2, %not1
  call void @use(i32 %not2)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use4(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %c
  %and2 = and i32 %and1, %b
  %or2 = or i32 %and2, %not1
  call void @use(i32 %not2)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use5(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  call void @use(i32 %or1)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use6(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  call void @use(i32 %not1)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use7(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  call void @use(i32 %and1)
  ret i32 %or2
}

define i32 @not_and_and_or_no_or_use8(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_and_and_or_no_or_use8(
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[AND2]])
; CHECK-NEXT:    ret i32 [[OR2]]
;
  %or1 = or i32 %b, %a
  %not1 = xor i32 %or1, -1
  %not2 = xor i32 %a, -1
  %and1 = and i32 %not2, %b
  %and2 = and i32 %and1, %c
  %or2 = or i32 %and2, %not1
  call void @use(i32 %and2)
  ret i32 %or2
}

; (~a | b | c) & ~(a & b) -> (c & ~b) | ~a

define i32 @not_or_or_and_no_and(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_commute1_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_commute1_or(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %c, %b
  %or2 = or i32 %or1, %not2
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_commute2_or(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_commute2_or(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %c
  %or2 = or i32 %or1, %b
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_commute1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_commute1(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %a, %b
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_commute2(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_commute2(
; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %b, %not2
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_commute3(i32 %a, i32 %b, i32 %c0) {
; CHECK-LABEL: @not_or_or_and_no_and_commute3(
; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[C]], [[TMP1]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %c, %or1
  %and2 = and i32 %or2, %not1
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use1(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  call void @use(i32 %not2)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use2(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %b, %c
  %or2 = or i32 %or1, %not2
  %and2 = and i32 %or2, %not1
  call void @use(i32 %not2)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use3(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %c
  %or2 = or i32 %or1, %b
  %and2 = and i32 %or2, %not1
  call void @use(i32 %not2)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use4(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[NOT2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %c
  %or2 = or i32 %or1, %b
  %and2 = and i32 %or2, %not1
  call void @use(i32 %not2)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use5(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[OR2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[AND1]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  call void @use(i32 %and1)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use6(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use6(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[OR2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[NOT1]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  call void @use(i32 %not1)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use7(
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A:%.*]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], -1
; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
; CHECK-NEXT:    call void @use(i32 [[OR1]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  call void @use(i32 %or1)
  ret i32 %and2
}

define i32 @not_or_or_and_no_and_use8(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @not_or_or_and_no_and_use8(
; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[OR1]], [[C:%.*]]
; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[OR2]], [[NOT1]]
; CHECK-NEXT:    call void @use(i32 [[OR2]])
; CHECK-NEXT:    ret i32 [[AND2]]
;
  %and1 = and i32 %b, %a
  %not1 = xor i32 %and1, -1
  %not2 = xor i32 %a, -1
  %or1 = or i32 %not2, %b
  %or2 = or i32 %or1, %c
  %and2 = and i32 %or2, %not1
  call void @use(i32 %or2)
  ret i32 %and2
}
