4596 lines
156 KiB
LLVM
4596 lines
156 KiB
LLVM
; 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: [[SX:%.*]] = shl i8 [[X]], [[SHAMT]]
|
|
; CHECK-NEXT: [[SY:%.*]] = shl i8 [[Y]], [[SHAMT]]
|
|
; CHECK-NEXT: [[A:%.*]] = and i8 [[SX]], [[Z]]
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[SY]], [[A]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sx = shl i8 %x, %shamt
|
|
%sy = shl i8 %y, %shamt
|
|
%a = and i8 %sx, %z
|
|
%r = and i8 %sy, %a
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @or_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
|
|
; CHECK-LABEL: define {{[^@]+}}@or_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:%.*]] = or i8 [[A]], [[SY]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sx = shl i8 %x, %shamt
|
|
%sy = shl i8 %y, %shamt
|
|
%a = or i8 %sx, %z
|
|
%r = or i8 %a, %sy
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @xor_shl(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
|
|
; CHECK-LABEL: 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: [[SX:%.*]] = lshr i8 [[X]], [[SHAMT]]
|
|
; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y]], [[SHAMT]]
|
|
; CHECK-NEXT: [[A:%.*]] = or i8 [[SX]], [[Z]]
|
|
; CHECK-NEXT: [[R:%.*]] = or i8 [[SY]], [[A]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sx = lshr i8 %x, %shamt
|
|
%sy = lshr i8 %y, %shamt
|
|
%a = or i8 %sx, %z
|
|
%r = or i8 %sy, %a
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @xor_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
|
|
; CHECK-LABEL: define {{[^@]+}}@xor_lshr
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]], i8 [[SHAMT:%.*]]) {
|
|
; CHECK-NEXT: [[SX:%.*]] = lshr i8 [[X]], [[SHAMT]]
|
|
; CHECK-NEXT: [[SY:%.*]] = lshr i8 [[Y]], [[SHAMT]]
|
|
; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z]]
|
|
; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[SY]]
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%sx = lshr i8 %x, %shamt
|
|
%sy = lshr i8 %y, %shamt
|
|
%a = xor i8 %sx, %z
|
|
%r = xor i8 %a, %sy
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @and_ashr(i8 %x, i8 %y, i8 %zarg, i8 %shamt) {
|
|
; CHECK-LABEL: 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: [[SY:%.*]] = lshr i8 [[Y]], [[SHAMT]]
|
|
; CHECK-NEXT: [[A:%.*]] = xor i8 [[SX]], [[Z]]
|
|
; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], [[SY]]
|
|
; CHECK-NEXT: [[R2:%.*]] = sdiv i8 [[A]], [[R]]
|
|
; CHECK-NEXT: ret i8 [[R2]]
|
|
;
|
|
%sx = lshr i8 %x, %shamt
|
|
%sy = lshr i8 %y, %shamt
|
|
%a = xor i8 %sx, %z
|
|
%r = xor i8 %a, %sy
|
|
%r2 = sdiv i8 %a, %r
|
|
ret i8 %r2
|
|
}
|
|
|
|
; Reassociate chains of extend(X) | (extend(Y) | Z).
|
|
; Check that logical op is performed on a smaller type and then extended.
|
|
|
|
define i64 @sext_or_chain(i64 %a, i16 %b, i16 %c) {
|
|
; CHECK-LABEL: 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, %a
|
|
%or2 = or i32 %or1, %c
|
|
%not1 = xor i32 %or2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or3 = or i32 %and2, %not1
|
|
call void @use(i32 %or2)
|
|
ret i32 %or3
|
|
}
|
|
|
|
define i32 @not_and_and_or_not_or_or_use3(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_not_or_or_use3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]]
|
|
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND2]], [[NOT1]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT1]])
|
|
; CHECK-NEXT: ret i32 [[OR3]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%or2 = or i32 %or1, %c
|
|
%not1 = xor i32 %or2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or3 = or i32 %and2, %not1
|
|
call void @use(i32 %not1)
|
|
ret i32 %or3
|
|
}
|
|
|
|
define i32 @not_and_and_or_not_or_or_use4(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_not_or_or_use4
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
|
|
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[OR3]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%or2 = or i32 %or1, %c
|
|
%not1 = xor i32 %or2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or3 = or i32 %and2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %or3
|
|
}
|
|
|
|
define i32 @not_and_and_or_not_or_or_use5(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_not_or_or_use5
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
|
|
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
|
|
; CHECK-NEXT: call void @use(i32 [[AND1]])
|
|
; CHECK-NEXT: ret i32 [[OR3]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%or2 = or i32 %or1, %c
|
|
%not1 = xor i32 %or2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or3 = or i32 %and2, %not1
|
|
call void @use(i32 %and1)
|
|
ret i32 %or3
|
|
}
|
|
|
|
define i32 @not_and_and_or_not_or_or_use6(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_not_or_or_use6
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]]
|
|
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND2]], [[NOT1]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND2]])
|
|
; CHECK-NEXT: ret i32 [[OR3]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%or2 = or i32 %or1, %c
|
|
%not1 = xor i32 %or2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or3 = or i32 %and2, %not1
|
|
call void @use(i32 %and2)
|
|
ret i32 %or3
|
|
}
|
|
|
|
; (~a | b | c) & ~(a & b & c) -> ~a | (b ^ c)
|
|
|
|
define i32 @not_or_or_and_not_and_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute1_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute1_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %c, %a
|
|
%and2 = and i32 %and1, %b
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute2_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute2_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %c
|
|
%and2 = and i32 %and1, %a
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute1_or(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute1_or
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %c
|
|
%or2 = or i32 %or1, %b
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute2_or(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute2_or
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %b, %c
|
|
%or2 = or i32 %or1, %not2
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %a, %b
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute2(i32 %a, i32 %b, i32 %c0) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) {
|
|
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %c, %and1
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute3(i32 %a, i32 %b0, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %b, %not2
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_commute4(i32 %a, i32 %b, i32 %c0) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_commute4
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) {
|
|
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %c, %or1
|
|
%and3 = and i32 %or2, %not1
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND1]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %and1)
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use2(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND2]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %and2)
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use3(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND2]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND2]], [[OR2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT1]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %not1)
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use4(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use4
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use5(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use5
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = or i32 [[TMP1]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR1]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %or1)
|
|
ret i32 %and3
|
|
}
|
|
|
|
define i32 @not_or_or_and_not_and_and_use6(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_not_and_and_use6
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND2]], [[OR2]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR2]])
|
|
; CHECK-NEXT: ret i32 [[AND3]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%and2 = and i32 %and1, %c
|
|
%not1 = xor i32 %and2, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and3 = and i32 %or2, %not1
|
|
call void @use(i32 %or2)
|
|
ret i32 %and3
|
|
}
|
|
|
|
; (~a & b & c) | ~(a | b) -> (c | ~b) & ~a
|
|
|
|
define i32 @not_and_and_or_no_or(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_commute1_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_commute1_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %c, %b
|
|
%and2 = and i32 %and1, %not2
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_commute2_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_commute2_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %c
|
|
%and2 = and i32 %and1, %b
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_commute1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_commute1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %a, %b
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_commute2(i32 %a, i32 %b0, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_commute2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %b, %not2
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_commute3(i32 %a, i32 %b, i32 %c0) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_commute3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) {
|
|
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[C]], [[TMP1]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %c, %and1
|
|
%or2 = or i32 %and2, %not1
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use2(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %b, %c
|
|
%and2 = and i32 %and1, %not2
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use3(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %c
|
|
%and2 = and i32 %and1, %b
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use4(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use4
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %c
|
|
%and2 = and i32 %and1, %b
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use5(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use5
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR1]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %or1)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use6(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use6
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT1]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %not1)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use7(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use7
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND1]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %and1)
|
|
ret i32 %or2
|
|
}
|
|
|
|
define i32 @not_and_and_or_no_or_use8(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_and_and_or_no_or_use8
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND2]])
|
|
; CHECK-NEXT: ret i32 [[OR2]]
|
|
;
|
|
%or1 = or i32 %b, %a
|
|
%not1 = xor i32 %or1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%and1 = and i32 %not2, %b
|
|
%and2 = and i32 %and1, %c
|
|
%or2 = or i32 %and2, %not1
|
|
call void @use(i32 %and2)
|
|
ret i32 %or2
|
|
}
|
|
|
|
; (~a | b | c) & ~(a & b) -> (c & ~b) | ~a
|
|
|
|
define i32 @not_or_or_and_no_and(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_commute1_or(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_commute1_or
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %c, %b
|
|
%or2 = or i32 %or1, %not2
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_commute2_or(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_commute2_or
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %c
|
|
%or2 = or i32 %or1, %b
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_commute1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_commute1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %a, %b
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_commute2(i32 %a, i32 %b0, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_commute2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B0:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %b, %not2
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_commute3(i32 %a, i32 %b, i32 %c0) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_commute3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C0:%.*]]) {
|
|
; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[C]], [[TMP1]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %c, %or1
|
|
%and2 = and i32 %or2, %not1
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use1(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use1
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use2(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %b, %c
|
|
%or2 = or i32 %or1, %not2
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use3(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %c
|
|
%or2 = or i32 %or1, %b
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use4(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use4
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT2]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %c
|
|
%or2 = or i32 %or1, %b
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %not2)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use5(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use5
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i32 [[AND1]], [[OR2]]
|
|
; CHECK-NEXT: call void @use(i32 [[AND1]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %and1)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use6(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use6
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i32 [[AND1]], [[OR2]]
|
|
; CHECK-NEXT: call void @use(i32 [[NOT1]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %not1)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use7(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use7
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT2]], [[B]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[C]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i32 [[TMP2]], [[NOT2]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR1]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %or1)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i32 @not_or_or_and_no_and_use8(i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@not_or_or_and_no_and_use8
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A]]
|
|
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[NOT2]], [[C]]
|
|
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i32 [[AND1]], [[OR2]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR2]])
|
|
; CHECK-NEXT: ret i32 [[AND2]]
|
|
;
|
|
%and1 = and i32 %b, %a
|
|
%not1 = xor i32 %and1, -1
|
|
%not2 = xor i32 %a, -1
|
|
%or1 = or i32 %not2, %b
|
|
%or2 = or i32 %or1, %c
|
|
%and2 = and i32 %or2, %not1
|
|
call void @use(i32 %or2)
|
|
ret i32 %and2
|
|
}
|
|
|
|
define i4 @and_orn_xor(i4 %a, i4 %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor
|
|
; CHECK-SAME: (i4 [[A:%.*]], i4 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i4 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: ret i4 [[R]]
|
|
;
|
|
%xor = xor i4 %a, %b
|
|
%nota = xor i4 %a, -1
|
|
%or = or i4 %nota, %b
|
|
%r = and i4 %or, %xor
|
|
ret i4 %r
|
|
}
|
|
|
|
define <2 x i4> @and_orn_xor_commute1(<2 x i4> %a, <2 x i4> %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute1
|
|
; CHECK-SAME: (<2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i4> [[A]], <i4 -1, i4 -1>
|
|
; CHECK-NEXT: [[R:%.*]] = and <2 x i4> [[TMP1]], [[B]]
|
|
; CHECK-NEXT: ret <2 x i4> [[R]]
|
|
;
|
|
%xor = xor <2 x i4> %a, %b
|
|
%nota = xor <2 x i4> %a, <i4 -1, i4 undef>
|
|
%or = or <2 x i4> %nota, %b
|
|
%r = and <2 x i4> %xor, %or
|
|
ret <2 x i4> %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute2
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B]], [[A]]
|
|
; CHECK-NEXT: call void @use(i32 [[XOR]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%xor = xor i32 %b, %a
|
|
call void @use(i32 %xor)
|
|
%nota = xor i32 %a, -1
|
|
%or = or i32 %nota, %b
|
|
%r = and i32 %or, %xor
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute3(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute3
|
|
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[TMP1]], [[B]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%xor = xor i32 %b, %a
|
|
%nota = xor i32 %a, -1
|
|
call void @use(i32 %nota)
|
|
%or = or i32 %nota, %b
|
|
%r = and i32 %xor, %or
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute5(i32 %pa, i32 %pb) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute5
|
|
; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA]], [[PA]]
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB]], [[PB]]
|
|
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = mul i32 %pa, %pa
|
|
%b = mul i32 %pb, %pb
|
|
%xor = xor i32 %a, %b
|
|
%nota = xor i32 %a, -1
|
|
%or = or i32 %b, %nota
|
|
call void @use(i32 %or)
|
|
%r = and i32 %or, %xor
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute6(i32 %pa, i32 %pb) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute6
|
|
; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA]], [[PA]]
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB]], [[PB]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
|
; CHECK-NEXT: call void @use(i32 [[XOR]])
|
|
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = mul i32 %pa, %pa
|
|
%b = mul i32 %pb, %pb
|
|
%xor = xor i32 %a, %b
|
|
call void @use(i32 %xor)
|
|
%nota = xor i32 %a, -1
|
|
call void @use(i32 %nota)
|
|
%or = or i32 %b, %nota
|
|
%r = and i32 %xor, %or
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute7(i32 %pa, i32 %pb) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute7
|
|
; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA]], [[PA]]
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB]], [[PB]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B]], [[A]]
|
|
; CHECK-NEXT: call void @use(i32 [[XOR]])
|
|
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
|
; CHECK-NEXT: call void @use(i32 [[OR]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = mul i32 %pa, %pa
|
|
%b = mul i32 %pb, %pb
|
|
%xor = xor i32 %b, %a
|
|
call void @use(i32 %xor)
|
|
%nota = xor i32 %a, -1
|
|
call void @use(i32 %nota)
|
|
%or = or i32 %b, %nota
|
|
call void @use(i32 %or)
|
|
%r = and i32 %or, %xor
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @and_orn_xor_commute8(i32 %pa, i32 %pb) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_orn_xor_commute8
|
|
; CHECK-SAME: (i32 [[PA:%.*]], i32 [[PB:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA]], [[PA]]
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB]], [[PB]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = mul i32 %pa, %pa
|
|
%b = mul i32 %pb, %pb
|
|
%xor = xor i32 %b, %a
|
|
%nota = xor i32 %a, -1
|
|
%or = or i32 %b, %nota
|
|
%r = and i32 %xor, %or
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @zext_zext_and_uses(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@zext_zext_and_uses
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[ZX]])
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[ZY]])
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%zx = zext i8 %x to i32
|
|
call void @use(i32 %zx)
|
|
%zy = zext i8 %y to i32
|
|
call void @use(i32 %zy)
|
|
%r = and i32 %zx, %zy
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @sext_sext_or_uses(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@sext_sext_or_uses
|
|
; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[SX]])
|
|
; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[SY]])
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[SX]], [[SY]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%sx = sext i8 %x to i32
|
|
call void @use(i32 %sx)
|
|
%sy = sext i8 %y to i32
|
|
call void @use(i32 %sy)
|
|
%r = or i32 %sx, %sy
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @trunc_trunc_xor_uses(i65 %x, i65 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@trunc_trunc_xor_uses
|
|
; CHECK-SAME: (i65 [[X:%.*]], i65 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SX:%.*]] = trunc i65 [[X]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[SX]])
|
|
; CHECK-NEXT: [[SY:%.*]] = trunc i65 [[Y]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[SY]])
|
|
; CHECK-NEXT: [[R:%.*]] = xor i32 [[SX]], [[SY]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%sx = trunc i65 %x to i32
|
|
call void @use(i32 %sx)
|
|
%sy = trunc i65 %y to i32
|
|
call void @use(i32 %sy)
|
|
%r = xor i32 %sx, %sy
|
|
ret i32 %r
|
|
}
|
|
|
|
define i16 @and_zext_zext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_zext_zext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y]] to i8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = zext i8 [[TMP2]] to i16
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%zx = zext i8 %x to i16
|
|
%zy = zext i4 %y to i16
|
|
%r = and i16 %zx, %zy
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @or_zext_zext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@or_zext_zext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y]] to i8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = zext i8 [[TMP2]] to i16
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%zx = zext i8 %x to i16
|
|
%zy = zext i4 %y to i16
|
|
%r = or i16 %zy, %zx
|
|
ret i16 %r
|
|
}
|
|
|
|
define <2 x i16> @xor_zext_zext(<2 x i8> %x, <2 x i4> %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@xor_zext_zext
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i4> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i4> [[Y]] to <2 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i8> [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = zext <2 x i8> [[TMP2]] to <2 x i16>
|
|
; CHECK-NEXT: ret <2 x i16> [[R]]
|
|
;
|
|
%zx = zext <2 x i8> %x to <2 x i16>
|
|
%zy = zext <2 x i4> %y to <2 x i16>
|
|
%r = xor <2 x i16> %zx, %zy
|
|
ret <2 x i16> %r
|
|
}
|
|
|
|
define i16 @and_sext_sext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_sext_sext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y]] to i8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = sext i8 [[TMP2]] to i16
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%sx = sext i8 %x to i16
|
|
%sy = sext i4 %y to i16
|
|
%r = and i16 %sy, %sx
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @or_sext_sext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@or_sext_sext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y]] to i8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = sext i8 [[TMP2]] to i16
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%sx = sext i8 %x to i16
|
|
%sy = sext i4 %y to i16
|
|
%r = or i16 %sx, %sy
|
|
ret i16 %r
|
|
}
|
|
|
|
define i16 @xor_sext_sext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@xor_sext_sext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y]] to i8
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[TMP1]], [[X]]
|
|
; CHECK-NEXT: [[R:%.*]] = sext i8 [[TMP2]] to i16
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%sx = sext i8 %x to i16
|
|
%sy = sext i4 %y to i16
|
|
%r = xor i16 %sx, %sy
|
|
ret i16 %r
|
|
}
|
|
|
|
; negative test - mismatched casts
|
|
|
|
define i16 @and_zext_sext(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_zext_sext
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i16
|
|
; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y]] to i16
|
|
; CHECK-NEXT: [[R:%.*]] = and i16 [[ZX]], [[SY]]
|
|
; CHECK-NEXT: ret i16 [[R]]
|
|
;
|
|
%zx = zext i8 %x to i16
|
|
%sy = sext i4 %y to i16
|
|
%r = and i16 %zx, %sy
|
|
ret i16 %r
|
|
}
|
|
|
|
; negative test - don't create an extra instruction
|
|
|
|
define i32 @and_zext_zext_use1(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@and_zext_zext_use1
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[ZX]])
|
|
; CHECK-NEXT: [[ZY:%.*]] = zext i4 [[Y]] to i32
|
|
; CHECK-NEXT: [[R:%.*]] = and i32 [[ZX]], [[ZY]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%zx = zext i8 %x to i32
|
|
call void @use(i32 %zx)
|
|
%zy = zext i4 %y to i32
|
|
%r = and i32 %zx, %zy
|
|
ret i32 %r
|
|
}
|
|
|
|
; negative test - don't create an extra instruction
|
|
|
|
define i32 @or_sext_sext_use1(i8 %x, i4 %y) {
|
|
; CHECK-LABEL: define {{[^@]+}}@or_sext_sext_use1
|
|
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i32
|
|
; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[SY]])
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[SX]], [[SY]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%sx = sext i8 %x to i32
|
|
%sy = sext i4 %y to i32
|
|
call void @use(i32 %sy)
|
|
%r = or i32 %sx, %sy
|
|
ret i32 %r
|
|
}
|
|
|
|
define i1 @PR56294(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@PR56294
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%t2 = icmp eq i8 %x, 2
|
|
%t3 = and i8 %x, 1
|
|
%t4 = zext i1 %t2 to i32
|
|
%t5 = zext i8 %t3 to i32
|
|
%t6 = and i32 %t4, %t5
|
|
%t7 = icmp ne i32 %t6, 0
|
|
ret i1 %t7
|
|
}
|
|
|
|
define i32 @canonicalize_logic_first_or0(i32 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or0
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X]], 15
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], 112
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, 112 ; 01110000
|
|
%r = or i32 %a, 15 ; 00001111
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i32> @canonicalize_logic_first_or_vector0(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_vector0
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X]], <i32 15, i32 15>
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], <i32 112, i32 112>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 112, i32 112>, %x ; <0x00000070, 0x00000070>
|
|
%r = or <2 x i32> <i32 15, i32 15>, %a ; <0x0000000F, 0x0000000F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; elementwise these constants should be ok to canonicalize logic op then math
|
|
define <2 x i32> @canonicalize_logic_first_or_vector1(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_vector1
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 -8388608, i32 2071986176>
|
|
; CHECK-NEXT: [[R:%.*]] = or <2 x i32> [[A]], <i32 32783, i32 2063>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 -8388608, i32 2071986176>, %x ; <0xFF800000, 0x7B800000>
|
|
%r = or <2 x i32> <i32 32783, i32 2063>, %a ; <0x0000800F, 0x0000080F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @canonicalize_logic_first_or_vector2(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_vector2
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 2147483632, i32 2147483640>
|
|
; CHECK-NEXT: [[R:%.*]] = or <2 x i32> [[A]], <i32 32783, i32 2063>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 2147483632, i32 2147483640>, %x ; <0x7FFFFFF0, 0x7FFFFFF8>
|
|
%r = or <2 x i32> <i32 32783, i32 2063>, %a ; <0x0000800F, 0x0000080F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define i32 @canonicalize_logic_first_or_mult_use1(i32 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_mult_use1
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], 112
|
|
; CHECK-NEXT: call void @use(i32 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[A]], 15
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, 112 ; 01110000
|
|
call void @use(i32 %a)
|
|
%r = or i32 %a, 15 ; 00001111
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @canonicalize_logic_first_or_bad_constraints2(i32 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_or_bad_constraints2
|
|
; CHECK-SAME: (i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], 112
|
|
; CHECK-NEXT: [[R:%.*]] = or i32 [[A]], 16
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
%a = add i32 %x, 112 ; 01110000
|
|
%r = or i32 %a, 16 ; 00010000
|
|
ret i32 %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_and0(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and0
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], -10
|
|
; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], 48
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%b = add i8 %x, 48 ; 00110000
|
|
%r = and i8 %b, -10 ; 11110110
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i8> @canonicalize_logic_first_and_vector0(<2 x i8> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_vector0
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], <i8 -10, i8 -10>
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[TMP1]], <i8 48, i8 48>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = add <2 x i8> <i8 48, i8 48>, %x
|
|
%r = and <2 x i8> <i8 -10, i8 -10>, %a
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; element-wise the constants match constraints
|
|
define <2 x i8> @canonicalize_logic_first_and_vector1(<2 x i8> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_vector1
|
|
; CHECK-SAME: (<2 x i8> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X]], <i8 48, i8 32>
|
|
; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[A]], <i8 -10, i8 -4>
|
|
; CHECK-NEXT: ret <2 x i8> [[R]]
|
|
;
|
|
%a = add <2 x i8> <i8 48, i8 32>, %x
|
|
%r = and <2 x i8> <i8 -10, i8 -4>, %a
|
|
ret <2 x i8> %r
|
|
}
|
|
|
|
; elementwise these constants do match constraints needed to canonicalize
|
|
; logic op first then math op
|
|
define <2 x i32> @canonicalize_logic_first_and_vector2(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_vector2
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 612368384, i32 612368384>
|
|
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[A]], <i32 -65536, i32 -32768>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 612368384, i32 612368384>, %x ; <0x24800000, 0x24800000>
|
|
%r = and <2 x i32> <i32 -65536, i32 -32768>, %a ; <0xFFFF0000, 0xFFFF8000>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @canonicalize_logic_first_and_vector3(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_vector3
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 32768, i32 16384>
|
|
; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[A]], <i32 -65536, i32 -32768>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 32768, i32 16384>, %x ; <0x00008000, 0x00004000>
|
|
%r = and <2 x i32> <i32 -65536, i32 -32768>, %a ; <0xFFFF0000, 0xFFFF8000>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_and_mult_use1(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_mult_use1
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[B:%.*]] = add i8 [[X]], 48
|
|
; CHECK-NEXT: call void @use_i8(i8 [[B]])
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[B]], -10
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%b = add i8 %x, 48 ; 00110000
|
|
call void @use_i8(i8 %b)
|
|
%r = and i8 %b, -10 ; 11110110
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_and_bad_constraints2(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_and_bad_constraints2
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[B:%.*]] = add i8 [[X]], 48
|
|
; CHECK-NEXT: [[R:%.*]] = and i8 [[B]], -26
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%b = add i8 %x, 48 ; 00110000
|
|
%r = and i8 %b, -26 ; 11100110
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_xor_0(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_0
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], 31
|
|
; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], 96
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, 96 ; 01100000
|
|
%r = xor i8 %a, 31 ; 00011111
|
|
ret i8 %r
|
|
}
|
|
|
|
define <2 x i32> @canonicalize_logic_first_xor_vector0(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_vector0
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X]], <i32 32783, i32 32783>
|
|
; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], <i32 -8388608, i32 -8388608>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 -8388608, i32 -8388608>, %x ; <0xFF800000, 0xFF800000>
|
|
%r = xor <2 x i32> <i32 32783, i32 32783>, %a ; <0x0000800F, 0x0000800F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
; elementwise these constants do obey constraints required to canonicalize
|
|
define <2 x i32> @canonicalize_logic_first_xor_vector1(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_vector1
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 -8388608, i32 2071986176>
|
|
; CHECK-NEXT: [[R:%.*]] = xor <2 x i32> [[A]], <i32 32783, i32 2063>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 -8388608, i32 2071986176>, %x ; <0xFF800000, 0x7B800000>
|
|
%r = xor <2 x i32> <i32 32783, i32 2063>, %a ; <0x0000800F, 0x0000080F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define <2 x i32> @canonicalize_logic_first_xor_vector2(<2 x i32> %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_vector2
|
|
; CHECK-SAME: (<2 x i32> [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add <2 x i32> [[X]], <i32 2147483632, i32 2147483640>
|
|
; CHECK-NEXT: [[R:%.*]] = xor <2 x i32> [[A]], <i32 32783, i32 2063>
|
|
; CHECK-NEXT: ret <2 x i32> [[R]]
|
|
;
|
|
%a = add <2 x i32> <i32 2147483632, i32 2147483640>, %x ; <0x7FFFFFF0, 0x7FFFFFF8>
|
|
%r = xor <2 x i32> <i32 32783, i32 2063>, %a ; <0x0000800F, 0x0000080F>
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_xor_mult_use1(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_mult_use1
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], 96
|
|
; CHECK-NEXT: call void @use_i8(i8 [[A]])
|
|
; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], 31
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, 96 ; 01100000
|
|
call void @use_i8(i8 %a)
|
|
%r = xor i8 %a, 31 ; 00011111
|
|
ret i8 %r
|
|
}
|
|
|
|
define i8 @canonicalize_logic_first_xor_bad_constants2(i8 %x) {
|
|
; CHECK-LABEL: define {{[^@]+}}@canonicalize_logic_first_xor_bad_constants2
|
|
; CHECK-SAME: (i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], 96
|
|
; CHECK-NEXT: [[R:%.*]] = xor i8 [[A]], 32
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%a = add i8 %x, 96 ; 01100000
|
|
%r = xor i8 %a, 32 ; 00100000
|
|
ret i8 %r
|
|
}
|