| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| declare void @use(i32) |
| declare void @use_i8(i8) |
| |
| ; a & (a ^ b) --> a & ~b |
| |
| define i32 @and_xor_common_op(i32 %pa, i32 %pb) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_common_op |
| ; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) { |
| ; 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: define {{[^@]+}}@and_xor_common_op_commute1 |
| ; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) { |
| ; 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: define {{[^@]+}}@and_xor_common_op_commute2 |
| ; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) { |
| ; 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: define {{[^@]+}}@and_xor_common_op_commute3 |
| ; CHECK-SAME: (<2 x i32> [[PA:%.*]], <2 x i32> [[PB:%.*]]) { |
| ; 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: define {{[^@]+}}@and_xor_common_op_constant |
| ; CHECK-SAME: (<4 x i32> [[A:%.*]]) { |
| ; 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: define {{[^@]+}}@and_xor_not_common_op |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) { |
| ; 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, ptr %dst) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_not_common_op_extrause |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], ptr [[DST:%.*]]) { |
| ; CHECK-NEXT: [[B2:%.*]] = xor i32 [[B]], -1 |
| ; CHECK-NEXT: store i32 [[B2]], ptr [[DST]], align 4 |
| ; CHECK-NEXT: [[T4:%.*]] = and i32 [[A]], [[B]] |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %b2 = xor i32 %b, -1 |
| store i32 %b2, ptr %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: define {{[^@]+}}@and_not_xor_common_op |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_xor_common_op_commutative |
| ; CHECK-SAME: (i32 [[B:%.*]]) { |
| ; 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: define {{[^@]+}}@or |
| ; CHECK-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { |
| ; 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: define {{[^@]+}}@or2 |
| ; CHECK-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { |
| ; 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 |
| } |
| |
| ; ((x & y) ^ z) | y -> (z | y) |
| |
| define i64 @and_xor_or1(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or1 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Z]], [[Y]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %x, %y |
| %2 = xor i64 %1, %z |
| %3 = or i64 %2, %y |
| ret i64 %3 |
| } |
| |
| ; ((y & x) ^ z) | y -> (z | y) |
| |
| define i64 @and_xor_or2(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or2 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Z]], [[Y]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %y, %x |
| %2 = xor i64 %1, %z |
| %3 = or i64 %2, %y |
| ret i64 %3 |
| } |
| |
| ; (z ^ (x & y)) | y -> (z | y) |
| |
| define i64 @and_xor_or3(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or3 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Z]], [[Y]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %x, %y |
| %2 = xor i64 %z, %1 |
| %3 = or i64 %2, %y |
| ret i64 %3 |
| } |
| |
| ; (z ^ (y & x)) | y -> (z | y) |
| |
| define i64 @and_xor_or4(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or4 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Z]], [[Y]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %y, %x |
| %2 = xor i64 %z, %1 |
| %3 = or i64 %2, %y |
| ret i64 %3 |
| } |
| |
| ; y | ((x & y) ^ z) -> (y | z) |
| |
| define i64 @and_xor_or5(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or5 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Y]], [[Z]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %x, %y |
| %2 = xor i64 %1, %z |
| %3 = or i64 %y, %2 |
| ret i64 %3 |
| } |
| |
| ; y | ((y & x) ^ z) -> (y | z) |
| |
| define i64 @and_xor_or6(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or6 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Y]], [[Z]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %y, %x |
| %2 = xor i64 %1, %z |
| %3 = or i64 %y, %2 |
| ret i64 %3 |
| } |
| |
| ; y | (z ^ (x & y)) -> (y | z) |
| |
| define i64 @and_xor_or7(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or7 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Y]], [[Z]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %x, %y |
| %2 = xor i64 %z, %1 |
| %3 = or i64 %y, %2 |
| ret i64 %3 |
| } |
| |
| ; y | (z ^ (y & x)) -> (y | z) |
| |
| define i64 @and_xor_or8(i64 %px, i64 %py, i64 %pz) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or8 |
| ; CHECK-SAME: (i64 [[PX:%.*]], i64 [[PY:%.*]], i64 [[PZ:%.*]]) { |
| ; CHECK-NEXT: [[Y:%.*]] = udiv i64 42, [[PY]] |
| ; CHECK-NEXT: [[Z:%.*]] = udiv i64 42, [[PZ]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i64 [[Y]], [[Z]] |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| %x = udiv i64 42, %px ; thwart complexity-based canonicalization |
| %y = udiv i64 42, %py ; thwart complexity-based canonicalization |
| %z = udiv i64 42, %pz ; thwart complexity-based canonicalization |
| %1 = and i64 %y, %x |
| %2 = xor i64 %z, %1 |
| %3 = or i64 %y, %2 |
| ret i64 %3 |
| } |
| |
| ; w | (z ^ (y & x)) |
| |
| define i64 @and_xor_or_negative(i64 %x, i64 %y, i64 %z, i64 %w) { |
| ; CHECK-LABEL: define {{[^@]+}}@and_xor_or_negative |
| ; CHECK-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]], i64 [[Z:%.*]], i64 [[W:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[Y]], [[X]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], [[Z]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP2]], [[W]] |
| ; CHECK-NEXT: ret i64 [[TMP3]] |
| ; |
| %1 = and i64 %y, %x |
| %2 = xor i64 %z, %1 |
| %3 = or i64 %w, %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: define {{[^@]+}}@and_shl |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[Y]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], [[SHAMT]] |
| ; CHECK-NEXT: [[R:%.*]] = and i8 [[TMP2]], [[Z]] |
| ; 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: define {{[^@]+}}@or_shl |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X]], [[Y]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], [[SHAMT]] |
| ; CHECK-NEXT: [[R:%.*]] = or i8 [[TMP2]], [[Z]] |
| ; 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: define {{[^@]+}}@xor_shl |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[ZARG:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@and_lshr |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[ZARG:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@or_lshr |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X]], [[Y]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], [[SHAMT]] |
| ; CHECK-NEXT: [[R:%.*]] = or i8 [[TMP2]], [[Z]] |
| ; 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: define {{[^@]+}}@xor_lshr |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], [[SHAMT]] |
| ; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP2]], [[Z]] |
| ; 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: define {{[^@]+}}@and_ashr |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[ZARG:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@or_ashr |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[ZARG:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@xor_ashr |
| ; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]], <2 x i8> [[Z:%.*]], <2 x i8> [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_shl |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@or_lshr_shl |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@or_lshr_shamt2 |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; 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: define {{[^@]+}}@xor_lshr_multiuse |
| ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) { |
| ; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X]], [[SHAMT]] |
| ; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], [[SHAMT]] |
| ; CHECK-NEXT: [[R:%.*]] = xor i8 [[TMP2]], [[Z]] |
| ; 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: define {{[^@]+}}@sext_or_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@zext_or_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@sext_and_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@zext_and_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@sext_xor_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@zext_xor_chain |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@sext_or_chain_two_uses1 |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]], i64 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@sext_or_chain_two_uses2 |
| ; CHECK-SAME: (i64 [[A:%.*]], i16 [[B:%.*]], i16 [[C:%.*]], i64 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_not |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_not_4i64 |
| ; CHECK-SAME: (<4 x i64> [[A0:%.*]], <4 x i64> [[B:%.*]], <4 x i64> [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_not_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_not_commute2_extra_not_use |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_not_extra_and1_use |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_or_or_not |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_or_or_not_2i6 |
| ; CHECK-SAME: (<2 x i6> [[A0:%.*]], <2 x i6> [[B:%.*]], <2 x i6> [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_or_or_not_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_or_or_not_commute2_extra_not_use |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_or_or_not_extra_or1_use |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute5 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute7 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute8 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_commute9 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B0:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_extra_not_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_extra_not_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[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]], [[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: define {{[^@]+}}@or_not_and_extra_and_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_extra_and_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[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]], [[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: define {{[^@]+}}@or_not_and_extra_or_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_extra_or_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_wrong_c |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_wrong_b |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute5 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute7 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute8 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_commute9 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B0:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_extra_not_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_extra_not_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[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]], [[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: define {{[^@]+}}@and_not_or_extra_and_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_extra_and_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[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]], [[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: define {{[^@]+}}@and_not_or_extra_or_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_extra_or_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_wrong_c |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_wrong_b |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_commute7 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_extra_not_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_extra_not_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_extra_and_use |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_extra_or_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_extra_or_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_2_extra_uses |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_wrong_a |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@or_and_not_not_wrong_b |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_commute7 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_extra_not_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_extra_not_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_extra_and_use |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_extra_or_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_extra_or_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_2_extra_uses |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_wrong_a |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@and_or_not_not_wrong_b |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_commute2 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_commute4 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_commute5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@and_not_or_or_not_or_xor_use6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_commute2 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_commute4 |
| ; CHECK-SAME: (i32 [[A0:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_commute5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use5 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@or_not_and_and_not_and_xor_use6 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute1_or |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute2_or |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute1_and |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute2_and |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute3 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_commute4 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_use1 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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: define {{[^@]+}}@not_and_and_or_not_or_or_use2 |
| ; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) { |
| ; 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 |