The idea behind this canonicalization is that it allows us to handle less patterns, because we know that some will be canonicalized away. This is indeed very useful to e.g. know that constants are always on the right. However, this is only useful if the canonicalization is actually reliable. This is the case for constants, but not for arguments: Moving these to the right makes it look like the "more complex" expression is guaranteed to be on the left, but this is not actually the case in practice. It fails as soon as you replace the argument with another instruction. The end result is that it looks like things correctly work in tests, while they actually don't. We use the "thwart complexity-based canonicalization" trick to handle this in tests, but it's often a challenge for new contributors to get this right, and based on the regressions this PR originally exposed, we clearly don't get this right in many cases. For this reason, I think that it's better to remove this complexity canonicalization. It will make it much easier to write tests for commuted cases and make sure that they are handled.
1524 lines
59 KiB
LLVM
1524 lines
59 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
declare i1 @gen()
|
|
|
|
declare void @use(i8)
|
|
declare void @use1(i1)
|
|
declare void @use2(<2 x i1>)
|
|
|
|
define i32 @foo(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @foo(
|
|
; CHECK-NEXT: [[E_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[J:%.*]] = select i1 [[E_NOT]], i32 [[C:%.*]], i32 [[D:%.*]]
|
|
; CHECK-NEXT: ret i32 [[J]]
|
|
;
|
|
%e = icmp slt i32 %a, %b
|
|
%f = sext i1 %e to i32
|
|
%g = and i32 %c, %f
|
|
%h = xor i32 %f, -1
|
|
%i = and i32 %d, %h
|
|
%j = or i32 %g, %i
|
|
ret i32 %j
|
|
}
|
|
|
|
define i32 @bar(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @bar(
|
|
; CHECK-NEXT: [[E_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[J:%.*]] = select i1 [[E_NOT]], i32 [[C:%.*]], i32 [[D:%.*]]
|
|
; CHECK-NEXT: ret i32 [[J]]
|
|
;
|
|
%e = icmp slt i32 %a, %b
|
|
%f = sext i1 %e to i32
|
|
%g = and i32 %c, %f
|
|
%h = xor i32 %f, -1
|
|
%i = and i32 %d, %h
|
|
%j = or i32 %i, %g
|
|
ret i32 %j
|
|
}
|
|
|
|
define i32 @goo(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @goo(
|
|
; CHECK-NEXT: [[T0_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[T3:%.*]] = select i1 [[T0_NOT]], i32 [[C:%.*]], i32 [[D:%.*]]
|
|
; CHECK-NEXT: ret i32 [[T3]]
|
|
;
|
|
%t0 = icmp slt i32 %a, %b
|
|
%iftmp.0.0 = select i1 %t0, i32 -1, i32 0
|
|
%t1 = and i32 %iftmp.0.0, %c
|
|
%not = xor i32 %iftmp.0.0, -1
|
|
%t2 = and i32 %not, %d
|
|
%t3 = or i32 %t1, %t2
|
|
ret i32 %t3
|
|
}
|
|
|
|
define i32 @poo(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @poo(
|
|
; CHECK-NEXT: [[T0_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[T3:%.*]] = select i1 [[T0_NOT]], i32 [[C:%.*]], i32 [[D:%.*]]
|
|
; CHECK-NEXT: ret i32 [[T3]]
|
|
;
|
|
%t0 = icmp slt i32 %a, %b
|
|
%iftmp.0.0 = select i1 %t0, i32 -1, i32 0
|
|
%t1 = and i32 %iftmp.0.0, %c
|
|
%iftmp = select i1 %t0, i32 0, i32 -1
|
|
%t2 = and i32 %iftmp, %d
|
|
%t3 = or i32 %t1, %t2
|
|
ret i32 %t3
|
|
}
|
|
|
|
; PR32791 - https://bugs.llvm.org//show_bug.cgi?id=32791
|
|
; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
|
|
|
|
define i32 @fold_inverted_icmp_preds(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @fold_inverted_icmp_preds(
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[C:%.*]], i32 0
|
|
; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp slt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2_NOT]], i32 0, i32 [[D:%.*]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%cmp1 = icmp slt i32 %a, %b
|
|
%sel1 = select i1 %cmp1, i32 %c, i32 0
|
|
%cmp2 = icmp sge i32 %a, %b
|
|
%sel2 = select i1 %cmp2, i32 %d, i32 0
|
|
%or = or i32 %sel1, %sel2
|
|
ret i32 %or
|
|
}
|
|
|
|
; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
|
|
|
|
define i32 @fold_inverted_icmp_preds_reverse(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @fold_inverted_icmp_preds_reverse(
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 0, i32 [[C:%.*]]
|
|
; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp slt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2_NOT]], i32 [[D:%.*]], i32 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%cmp1 = icmp slt i32 %a, %b
|
|
%sel1 = select i1 %cmp1, i32 0, i32 %c
|
|
%cmp2 = icmp sge i32 %a, %b
|
|
%sel2 = select i1 %cmp2, i32 0, i32 %d
|
|
%or = or i32 %sel1, %sel2
|
|
ret i32 %or
|
|
}
|
|
|
|
; TODO: Should fcmp have the same sort of predicate canonicalization as icmp?
|
|
|
|
define i32 @fold_inverted_fcmp_preds(float %a, float %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @fold_inverted_fcmp_preds(
|
|
; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[C:%.*]], i32 0
|
|
; CHECK-NEXT: [[CMP2:%.*]] = fcmp uge float [[A]], [[B]]
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 [[D:%.*]], i32 0
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SEL1]], [[SEL2]]
|
|
; CHECK-NEXT: ret i32 [[OR]]
|
|
;
|
|
%cmp1 = fcmp olt float %a, %b
|
|
%sel1 = select i1 %cmp1, i32 %c, i32 0
|
|
%cmp2 = fcmp uge float %a, %b
|
|
%sel2 = select i1 %cmp2, i32 %d, i32 0
|
|
%or = or i32 %sel1, %sel2
|
|
ret i32 %or
|
|
}
|
|
|
|
; The 2nd compare/select are canonicalized, so CSE and another round of instcombine or some other pass will fold this.
|
|
|
|
define <2 x i32> @fold_inverted_icmp_vector_preds(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c, <2 x i32> %d) {
|
|
; CHECK-LABEL: @fold_inverted_icmp_vector_preds(
|
|
; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp eq <2 x i32> [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL1:%.*]] = select <2 x i1> [[CMP1_NOT]], <2 x i32> zeroinitializer, <2 x i32> [[C:%.*]]
|
|
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq <2 x i32> [[A]], [[B]]
|
|
; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[CMP2]], <2 x i32> [[D:%.*]], <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[SEL1]], [[SEL2]]
|
|
; CHECK-NEXT: ret <2 x i32> [[OR]]
|
|
;
|
|
%cmp1 = icmp ne <2 x i32> %a, %b
|
|
%sel1 = select <2 x i1> %cmp1, <2 x i32> %c, <2 x i32> <i32 0, i32 0>
|
|
%cmp2 = icmp eq <2 x i32> %a, %b
|
|
%sel2 = select <2 x i1> %cmp2, <2 x i32> %d, <2 x i32> <i32 0, i32 0>
|
|
%or = or <2 x i32> %sel1, %sel2
|
|
ret <2 x i32> %or
|
|
}
|
|
|
|
define i32 @par(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @par(
|
|
; CHECK-NEXT: [[T0_NOT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[T3:%.*]] = select i1 [[T0_NOT]], i32 [[C:%.*]], i32 [[D:%.*]]
|
|
; CHECK-NEXT: ret i32 [[T3]]
|
|
;
|
|
%t0 = icmp slt i32 %a, %b
|
|
%iftmp.1.0 = select i1 %t0, i32 -1, i32 0
|
|
%t1 = and i32 %iftmp.1.0, %c
|
|
%not = xor i32 %iftmp.1.0, -1
|
|
%t2 = and i32 %not, %d
|
|
%t3 = or i32 %t1, %t2
|
|
ret i32 %t3
|
|
}
|
|
|
|
; In the following tests (8 commutation variants), verify that a bitcast doesn't get
|
|
; in the way of a select transform. These bitcasts are common in SSE/AVX and possibly
|
|
; other vector code because of canonicalization to i64 elements for vectors.
|
|
|
|
; The fptosi instructions are included to avoid commutation canonicalization based on
|
|
; operator weight. Using another cast operator ensures that both operands of all logic
|
|
; ops are equally weighted, and this ensures that we're testing all commutation
|
|
; possibilities.
|
|
|
|
define <2 x i64> @bitcast_select_swap0(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap0(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %bc1, %sia
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %bc2, %sib
|
|
%or = or <2 x i64> %and1, %and2
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap1(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap1(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %bc1, %sia
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %bc2, %sib
|
|
%or = or <2 x i64> %and2, %and1
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap2(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap2(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %bc1, %sia
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %sib, %bc2
|
|
%or = or <2 x i64> %and1, %and2
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap3(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap3(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %bc1, %sia
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %sib, %bc2
|
|
%or = or <2 x i64> %and2, %and1
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap4(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap4(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %sia, %bc1
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %bc2, %sib
|
|
%or = or <2 x i64> %and1, %and2
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap5(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap5(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %sia, %bc1
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %bc2, %sib
|
|
%or = or <2 x i64> %and2, %and1
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap6(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap6(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %sia, %bc1
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %sib, %bc2
|
|
%or = or <2 x i64> %and1, %and2
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_swap7(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @bitcast_select_swap7(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[SIA]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[SIB]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[CMP:%.*]], <4 x i32> [[TMP1]], <4 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %sia, %bc1
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %sib, %bc2
|
|
%or = or <2 x i64> %and2, %and1
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <2 x i64> @bitcast_select_multi_uses(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) {
|
|
; CHECK-LABEL: @bitcast_select_multi_uses(
|
|
; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP:%.*]] to <4 x i32>
|
|
; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64>
|
|
; CHECK-NEXT: [[AND1:%.*]] = and <2 x i64> [[A:%.*]], [[BC1]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64>
|
|
; CHECK-NEXT: [[BC2:%.*]] = xor <2 x i64> [[TMP1]], <i64 -1, i64 -1>
|
|
; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[B:%.*]], [[BC2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND2]], [[AND1]]
|
|
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i64> [[AND2]], [[BC2]]
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i64> [[OR]], [[ADD]]
|
|
; CHECK-NEXT: ret <2 x i64> [[SUB]]
|
|
;
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%bc1 = bitcast <4 x i32> %sext to <2 x i64>
|
|
%and1 = and <2 x i64> %a, %bc1
|
|
%neg = xor <4 x i32> %sext, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%bc2 = bitcast <4 x i32> %neg to <2 x i64>
|
|
%and2 = and <2 x i64> %b, %bc2
|
|
%or = or <2 x i64> %and2, %and1
|
|
%add = add <2 x i64> %and2, %bc2
|
|
%sub = sub <2 x i64> %or, %add
|
|
ret <2 x i64> %sub
|
|
}
|
|
|
|
define i1 @bools(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools(
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = and i1 %not, %a
|
|
%and2 = and i1 %c, %b
|
|
%or = or i1 %and1, %and2
|
|
ret i1 %or
|
|
}
|
|
|
|
define i1 @bools_logical(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools_logical(
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = select i1 %not, i1 %a, i1 false
|
|
%and2 = select i1 %c, i1 %b, i1 false
|
|
%or = select i1 %and1, i1 true, i1 %and2
|
|
ret i1 %or
|
|
}
|
|
|
|
; Form a select if we know we can replace 2 simple logic ops.
|
|
|
|
define i1 @bools_multi_uses1(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools_multi_uses1(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[A:%.*]], [[NOT]]
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 [[A]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OR]], [[AND1]]
|
|
; CHECK-NEXT: ret i1 [[XOR]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = and i1 %not, %a
|
|
%and2 = and i1 %c, %b
|
|
%or = or i1 %and1, %and2
|
|
%xor = xor i1 %or, %and1
|
|
ret i1 %xor
|
|
}
|
|
|
|
define i1 @bools_multi_uses1_logical(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools_multi_uses1_logical(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[NOT]], i1 [[A:%.*]], i1 false
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 [[A]]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OR]], [[AND1]]
|
|
; CHECK-NEXT: ret i1 [[XOR]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = select i1 %not, i1 %a, i1 false
|
|
%and2 = select i1 %c, i1 %b, i1 false
|
|
%or = select i1 %and1, i1 true, i1 %and2
|
|
%xor = xor i1 %or, %and1
|
|
ret i1 %xor
|
|
}
|
|
|
|
; Don't replace a cheap logic op with a potentially expensive select
|
|
; unless we can also eliminate one of the other original ops.
|
|
|
|
define i1 @bools_multi_uses2(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools_multi_uses2(
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 [[A:%.*]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = and i1 %not, %a
|
|
%and2 = and i1 %c, %b
|
|
%or = or i1 %and1, %and2
|
|
%add = add i1 %and1, %and2
|
|
%and3 = and i1 %or, %add
|
|
ret i1 %and3
|
|
}
|
|
|
|
define i1 @bools_multi_uses2_logical(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @bools_multi_uses2_logical(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[NOT]], i1 [[A:%.*]], i1 false
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 false
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[C]], i1 [[B]], i1 [[A]]
|
|
; CHECK-NEXT: [[ADD:%.*]] = xor i1 [[AND1]], [[AND2]]
|
|
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[OR]], i1 [[ADD]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND3]]
|
|
;
|
|
%not = xor i1 %c, -1
|
|
%and1 = select i1 %not, i1 %a, i1 false
|
|
%and2 = select i1 %c, i1 %b, i1 false
|
|
%or = select i1 %and1, i1 true, i1 %and2
|
|
%add = add i1 %and1, %and2
|
|
%and3 = select i1 %or, i1 %add, i1 false
|
|
ret i1 %and3
|
|
}
|
|
|
|
define <4 x i1> @vec_of_bools(<4 x i1> %a, <4 x i1> %b, <4 x i1> %c) {
|
|
; CHECK-LABEL: @vec_of_bools(
|
|
; CHECK-NEXT: [[OR:%.*]] = select <4 x i1> [[C:%.*]], <4 x i1> [[B:%.*]], <4 x i1> [[A:%.*]]
|
|
; CHECK-NEXT: ret <4 x i1> [[OR]]
|
|
;
|
|
%not = xor <4 x i1> %c, <i1 true, i1 true, i1 true, i1 true>
|
|
%and1 = and <4 x i1> %not, %a
|
|
%and2 = and <4 x i1> %b, %c
|
|
%or = or <4 x i1> %and2, %and1
|
|
ret <4 x i1> %or
|
|
}
|
|
|
|
define <vscale x 1 x i1> @vec_of_bools_scalable(<vscale x 1 x i1> %a, <vscale x 1 x i1> %c, <vscale x 1 x i1> %d) {
|
|
; CHECK-LABEL: @vec_of_bools_scalable(
|
|
; CHECK-NEXT: [[R:%.*]] = select <vscale x 1 x i1> [[A:%.*]], <vscale x 1 x i1> [[C:%.*]], <vscale x 1 x i1> [[D:%.*]]
|
|
; CHECK-NEXT: ret <vscale x 1 x i1> [[R]]
|
|
;
|
|
%b = xor <vscale x 1 x i1> %a, splat (i1 true)
|
|
%t11 = and <vscale x 1 x i1> %a, %c
|
|
%t12 = and <vscale x 1 x i1> %b, %d
|
|
%r = or <vscale x 1 x i1> %t11, %t12
|
|
ret <vscale x 1 x i1> %r
|
|
}
|
|
|
|
define i4 @vec_of_casted_bools(i4 %a, i4 %b, <4 x i1> %c) {
|
|
; CHECK-LABEL: @vec_of_casted_bools(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i4 [[B:%.*]] to <4 x i1>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i4 [[A:%.*]] to <4 x i1>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[C:%.*]], <4 x i1> [[TMP1]], <4 x i1> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i1> [[TMP3]] to i4
|
|
; CHECK-NEXT: ret i4 [[OR]]
|
|
;
|
|
%not = xor <4 x i1> %c, <i1 true, i1 true, i1 true, i1 true>
|
|
%bc1 = bitcast <4 x i1> %not to i4
|
|
%bc2 = bitcast <4 x i1> %c to i4
|
|
%and1 = and i4 %a, %bc1
|
|
%and2 = and i4 %bc2, %b
|
|
%or = or i4 %and1, %and2
|
|
ret i4 %or
|
|
}
|
|
|
|
define <vscale x 1 x i64> @vec_of_casted_bools_scalable(<vscale x 1 x i64> %a, <vscale x 1 x i64> %b, <vscale x 8 x i1> %cond) {
|
|
; CHECK-LABEL: @vec_of_casted_bools_scalable(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <vscale x 1 x i64> [[A:%.*]] to <vscale x 8 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <vscale x 1 x i64> [[B:%.*]] to <vscale x 8 x i8>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <vscale x 8 x i1> [[COND:%.*]], <vscale x 8 x i8> [[TMP1]], <vscale x 8 x i8> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <vscale x 8 x i8> [[TMP3]] to <vscale x 1 x i64>
|
|
; CHECK-NEXT: ret <vscale x 1 x i64> [[OR]]
|
|
;
|
|
%scond = sext <vscale x 8 x i1> %cond to <vscale x 8 x i8>
|
|
%notcond = xor <vscale x 8 x i1> %cond, splat (i1 true)
|
|
%snotcond = sext <vscale x 8 x i1> %notcond to <vscale x 8 x i8>
|
|
%bc1 = bitcast <vscale x 8 x i8> %scond to <vscale x 1 x i64>
|
|
%bc2 = bitcast <vscale x 8 x i8> %snotcond to <vscale x 1 x i64>
|
|
%and1 = and <vscale x 1 x i64> %a, %bc1
|
|
%and2 = and <vscale x 1 x i64> %bc2, %b
|
|
%or = or <vscale x 1 x i64> %and1, %and2
|
|
ret <vscale x 1 x i64> %or
|
|
}
|
|
|
|
; Inverted 'and' constants mean this is a select which is canonicalized to a shuffle.
|
|
|
|
define <4 x i32> @vec_sel_consts(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @vec_sel_consts(
|
|
; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
|
|
; CHECK-NEXT: ret <4 x i32> [[OR]]
|
|
;
|
|
%and1 = and <4 x i32> %a, <i32 -1, i32 0, i32 0, i32 -1>
|
|
%and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 -1, i32 0>
|
|
%or = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %or
|
|
}
|
|
|
|
define <3 x i129> @vec_sel_consts_weird(<3 x i129> %a, <3 x i129> %b) {
|
|
; CHECK-LABEL: @vec_sel_consts_weird(
|
|
; CHECK-NEXT: [[OR:%.*]] = shufflevector <3 x i129> [[A:%.*]], <3 x i129> [[B:%.*]], <3 x i32> <i32 0, i32 4, i32 2>
|
|
; CHECK-NEXT: ret <3 x i129> [[OR]]
|
|
;
|
|
%and1 = and <3 x i129> %a, <i129 -1, i129 0, i129 -1>
|
|
%and2 = and <3 x i129> %b, <i129 0, i129 -1, i129 0>
|
|
%or = or <3 x i129> %and2, %and1
|
|
ret <3 x i129> %or
|
|
}
|
|
|
|
; The mask elements must be inverted for this to be a select.
|
|
|
|
define <4 x i32> @vec_not_sel_consts(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @vec_not_sel_consts(
|
|
; CHECK-NEXT: [[AND1:%.*]] = and <4 x i32> [[A:%.*]], <i32 -1, i32 0, i32 0, i32 0>
|
|
; CHECK-NEXT: [[AND2:%.*]] = and <4 x i32> [[B:%.*]], <i32 0, i32 -1, i32 0, i32 -1>
|
|
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[AND1]], [[AND2]]
|
|
; CHECK-NEXT: ret <4 x i32> [[OR]]
|
|
;
|
|
%and1 = and <4 x i32> %a, <i32 -1, i32 0, i32 0, i32 0>
|
|
%and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 0, i32 -1>
|
|
%or = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %or
|
|
}
|
|
|
|
define <4 x i32> @vec_not_sel_consts_undef_elts(<4 x i32> %a, <4 x i32> %b) {
|
|
; CHECK-LABEL: @vec_not_sel_consts_undef_elts(
|
|
; CHECK-NEXT: [[AND1:%.*]] = and <4 x i32> [[A:%.*]], <i32 -1, i32 undef, i32 0, i32 0>
|
|
; CHECK-NEXT: [[AND2:%.*]] = and <4 x i32> [[B:%.*]], <i32 0, i32 -1, i32 0, i32 undef>
|
|
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[AND1]], [[AND2]]
|
|
; CHECK-NEXT: ret <4 x i32> [[OR]]
|
|
;
|
|
%and1 = and <4 x i32> %a, <i32 -1, i32 undef, i32 0, i32 0>
|
|
%and2 = and <4 x i32> %b, <i32 0, i32 -1, i32 0, i32 undef>
|
|
%or = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %or
|
|
}
|
|
|
|
; The inverted constants may be operands of xor instructions.
|
|
|
|
define <4 x i32> @vec_sel_xor(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
|
|
; CHECK-LABEL: @vec_sel_xor(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[C:%.*]], <i1 false, i1 true, i1 true, i1 true>
|
|
; CHECK-NEXT: [[OR:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[OR]]
|
|
;
|
|
%mask = sext <4 x i1> %c to <4 x i32>
|
|
%mask_flip1 = xor <4 x i32> %mask, <i32 -1, i32 0, i32 0, i32 0>
|
|
%not_mask_flip1 = xor <4 x i32> %mask, <i32 0, i32 -1, i32 -1, i32 -1>
|
|
%and1 = and <4 x i32> %not_mask_flip1, %a
|
|
%and2 = and <4 x i32> %mask_flip1, %b
|
|
%or = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %or
|
|
}
|
|
|
|
; Allow the transform even if the mask values have multiple uses because
|
|
; there's still a net reduction of instructions from removing the and/and/or.
|
|
|
|
define <4 x i32> @vec_sel_xor_multi_use(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
|
|
; CHECK-LABEL: @vec_sel_xor_multi_use(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[C:%.*]], <i1 true, i1 false, i1 false, i1 false>
|
|
; CHECK-NEXT: [[MASK_FLIP1:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = xor <4 x i1> [[C]], <i1 false, i1 true, i1 true, i1 true>
|
|
; CHECK-NEXT: [[OR:%.*]] = select <4 x i1> [[TMP2]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
|
|
; CHECK-NEXT: [[ADD:%.*]] = add <4 x i32> [[OR]], [[MASK_FLIP1]]
|
|
; CHECK-NEXT: ret <4 x i32> [[ADD]]
|
|
;
|
|
%mask = sext <4 x i1> %c to <4 x i32>
|
|
%mask_flip1 = xor <4 x i32> %mask, <i32 -1, i32 0, i32 0, i32 0>
|
|
%not_mask_flip1 = xor <4 x i32> %mask, <i32 0, i32 -1, i32 -1, i32 -1>
|
|
%and1 = and <4 x i32> %not_mask_flip1, %a
|
|
%and2 = and <4 x i32> %mask_flip1, %b
|
|
%or = or <4 x i32> %and1, %and2
|
|
%add = add <4 x i32> %or, %mask_flip1
|
|
ret <4 x i32> %add
|
|
}
|
|
|
|
; The 'ashr' guarantees that we have a bitmask, so this is select with truncated condition.
|
|
|
|
define i32 @allSignBits(i32 %cond, i32 %tval, i32 %fval) {
|
|
; CHECK-LABEL: @allSignBits(
|
|
; CHECK-NEXT: [[ISNEG1:%.*]] = icmp slt i32 [[COND:%.*]], 0
|
|
; CHECK-NEXT: [[A1:%.*]] = select i1 [[ISNEG1]], i32 [[TVAL:%.*]], i32 0
|
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[COND]], 0
|
|
; CHECK-NEXT: [[A2:%.*]] = select i1 [[ISNEG]], i32 0, i32 [[FVAL:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = or i32 [[A1]], [[A2]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%bitmask = ashr i32 %cond, 31
|
|
%not_bitmask = xor i32 %bitmask, -1
|
|
%a1 = and i32 %tval, %bitmask
|
|
%a2 = and i32 %not_bitmask, %fval
|
|
%sel = or i32 %a1, %a2
|
|
ret i32 %sel
|
|
}
|
|
|
|
define <4 x i8> @allSignBits_vec(<4 x i8> %cond, <4 x i8> %tval, <4 x i8> %fval) {
|
|
; CHECK-LABEL: @allSignBits_vec(
|
|
; CHECK-NEXT: [[ISNEG1:%.*]] = icmp slt <4 x i8> [[COND:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[A1:%.*]] = select <4 x i1> [[ISNEG1]], <4 x i8> [[TVAL:%.*]], <4 x i8> zeroinitializer
|
|
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <4 x i8> [[COND]], zeroinitializer
|
|
; CHECK-NEXT: [[A2:%.*]] = select <4 x i1> [[ISNEG]], <4 x i8> zeroinitializer, <4 x i8> [[FVAL:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = or <4 x i8> [[A2]], [[A1]]
|
|
; CHECK-NEXT: ret <4 x i8> [[SEL]]
|
|
;
|
|
%bitmask = ashr <4 x i8> %cond, <i8 7, i8 7, i8 7, i8 7>
|
|
%not_bitmask = xor <4 x i8> %bitmask, <i8 -1, i8 -1, i8 -1, i8 -1>
|
|
%a1 = and <4 x i8> %tval, %bitmask
|
|
%a2 = and <4 x i8> %fval, %not_bitmask
|
|
%sel = or <4 x i8> %a2, %a1
|
|
ret <4 x i8> %sel
|
|
}
|
|
|
|
; Negative test - make sure that bitcasts from FP do not cause a crash.
|
|
|
|
define <2 x i64> @fp_bitcast(<4 x i1> %cmp, <2 x double> %a, <2 x double> %b) {
|
|
; CHECK-LABEL: @fp_bitcast(
|
|
; CHECK-NEXT: [[SIA:%.*]] = fptosi <2 x double> [[A:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[SIB:%.*]] = fptosi <2 x double> [[B:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[BC1:%.*]] = bitcast <2 x double> [[A]] to <2 x i64>
|
|
; CHECK-NEXT: [[AND1:%.*]] = and <2 x i64> [[SIA]], [[BC1]]
|
|
; CHECK-NEXT: [[BC2:%.*]] = bitcast <2 x double> [[B]] to <2 x i64>
|
|
; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[SIB]], [[BC2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND2]], [[AND1]]
|
|
; CHECK-NEXT: ret <2 x i64> [[OR]]
|
|
;
|
|
%sia = fptosi <2 x double> %a to <2 x i64>
|
|
%sib = fptosi <2 x double> %b to <2 x i64>
|
|
%bc1 = bitcast <2 x double> %a to <2 x i64>
|
|
%and1 = and <2 x i64> %sia, %bc1
|
|
%bc2 = bitcast <2 x double> %b to <2 x i64>
|
|
%and2 = and <2 x i64> %sib, %bc2
|
|
%or = or <2 x i64> %and2, %and1
|
|
ret <2 x i64> %or
|
|
}
|
|
|
|
define <4 x i32> @computesignbits_through_shuffles(<4 x float> %x, <4 x float> %y, <4 x float> %z) {
|
|
; CHECK-LABEL: @computesignbits_through_shuffles(
|
|
; CHECK-NEXT: [[CMP:%.*]] = fcmp ole <4 x float> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
|
|
; CHECK-NEXT: [[S1:%.*]] = shufflevector <4 x i32> [[SEXT]], <4 x i32> poison, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
|
|
; CHECK-NEXT: [[S2:%.*]] = shufflevector <4 x i32> [[SEXT]], <4 x i32> poison, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
|
|
; CHECK-NEXT: [[SHUF_OR1:%.*]] = or <4 x i32> [[S1]], [[S2]]
|
|
; CHECK-NEXT: [[S3:%.*]] = shufflevector <4 x i32> [[SHUF_OR1]], <4 x i32> poison, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
|
|
; CHECK-NEXT: [[S4:%.*]] = shufflevector <4 x i32> [[SHUF_OR1]], <4 x i32> poison, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
|
|
; CHECK-NEXT: [[SHUF_OR2:%.*]] = or <4 x i32> [[S3]], [[S4]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw <4 x i32> [[SHUF_OR2]] to <4 x i1>
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select <4 x i1> [[TMP1]], <4 x float> [[Z:%.*]], <4 x float> [[X]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = bitcast <4 x float> [[SEL_V]] to <4 x i32>
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%cmp = fcmp ole <4 x float> %x, %y
|
|
%sext = sext <4 x i1> %cmp to <4 x i32>
|
|
%s1 = shufflevector <4 x i32> %sext, <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
|
|
%s2 = shufflevector <4 x i32> %sext, <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
|
|
%shuf_or1 = or <4 x i32> %s1, %s2
|
|
%s3 = shufflevector <4 x i32> %shuf_or1, <4 x i32> undef, <4 x i32> <i32 0, i32 0, i32 1, i32 1>
|
|
%s4 = shufflevector <4 x i32> %shuf_or1, <4 x i32> undef, <4 x i32> <i32 2, i32 2, i32 3, i32 3>
|
|
%shuf_or2 = or <4 x i32> %s3, %s4
|
|
%not_or2 = xor <4 x i32> %shuf_or2, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%xbc = bitcast <4 x float> %x to <4 x i32>
|
|
%zbc = bitcast <4 x float> %z to <4 x i32>
|
|
%and1 = and <4 x i32> %not_or2, %xbc
|
|
%and2 = and <4 x i32> %shuf_or2, %zbc
|
|
%sel = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
define <4 x i32> @computesignbits_through_two_input_shuffle(<4 x i32> %x, <4 x i32> %y, <4 x i1> %cond1, <4 x i1> %cond2) {
|
|
; CHECK-LABEL: @computesignbits_through_two_input_shuffle(
|
|
; CHECK-NEXT: [[COND:%.*]] = shufflevector <4 x i1> [[COND1:%.*]], <4 x i1> [[COND2:%.*]], <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
|
; CHECK-NEXT: [[SEL:%.*]] = select <4 x i1> [[COND]], <4 x i32> [[Y:%.*]], <4 x i32> [[X:%.*]]
|
|
; CHECK-NEXT: ret <4 x i32> [[SEL]]
|
|
;
|
|
%sext1 = sext <4 x i1> %cond1 to <4 x i32>
|
|
%sext2 = sext <4 x i1> %cond2 to <4 x i32>
|
|
%cond = shufflevector <4 x i32> %sext1, <4 x i32> %sext2, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
|
%notcond = xor <4 x i32> %cond, <i32 -1, i32 -1, i32 -1, i32 -1>
|
|
%and1 = and <4 x i32> %notcond, %x
|
|
%and2 = and <4 x i32> %cond, %y
|
|
%sel = or <4 x i32> %and1, %and2
|
|
ret <4 x i32> %sel
|
|
}
|
|
|
|
; Bitcast of condition from narrow source element type can be converted to select.
|
|
|
|
define <2 x i64> @bitcast_vec_cond(<16 x i1> %cond, <2 x i64> %c, <2 x i64> %d) {
|
|
; CHECK-LABEL: @bitcast_vec_cond(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[D:%.*]] to <16 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[C:%.*]] to <16 x i8>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <16 x i1> [[COND:%.*]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]
|
|
; CHECK-NEXT: [[R:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
|
|
; CHECK-NEXT: ret <2 x i64> [[R]]
|
|
;
|
|
%s = sext <16 x i1> %cond to <16 x i8>
|
|
%t9 = bitcast <16 x i8> %s to <2 x i64>
|
|
%nott9 = xor <2 x i64> %t9, <i64 -1, i64 -1>
|
|
%t11 = and <2 x i64> %nott9, %c
|
|
%t12 = and <2 x i64> %t9, %d
|
|
%r = or <2 x i64> %t11, %t12
|
|
ret <2 x i64> %r
|
|
}
|
|
|
|
define <vscale x 2 x i64> @bitcast_vec_cond_scalable(<vscale x 16 x i1> %cond, <vscale x 2 x i64> %c, <vscale x 2 x i64> %d) {
|
|
; CHECK-LABEL: @bitcast_vec_cond_scalable(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <vscale x 2 x i64> [[D:%.*]] to <vscale x 16 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <vscale x 2 x i64> [[C:%.*]] to <vscale x 16 x i8>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <vscale x 16 x i1> [[COND:%.*]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]]
|
|
; CHECK-NEXT: [[R:%.*]] = bitcast <vscale x 16 x i8> [[TMP3]] to <vscale x 2 x i64>
|
|
; CHECK-NEXT: ret <vscale x 2 x i64> [[R]]
|
|
;
|
|
%s = sext <vscale x 16 x i1> %cond to <vscale x 16 x i8>
|
|
%t9 = bitcast <vscale x 16 x i8> %s to <vscale x 2 x i64>
|
|
%nott9 = xor <vscale x 2 x i64> %t9, splat (i64 -1)
|
|
%t11 = and <vscale x 2 x i64> %nott9, %c
|
|
%t12 = and <vscale x 2 x i64> %t9, %d
|
|
%r = or <vscale x 2 x i64> %t11, %t12
|
|
ret <vscale x 2 x i64> %r
|
|
}
|
|
|
|
; Negative test - bitcast of condition from wide source element type cannot be converted to select.
|
|
|
|
define <8 x i3> @bitcast_vec_cond_commute1(<3 x i1> noundef %cond, <8 x i3> %pc, <8 x i3> %d) {
|
|
; CHECK-LABEL: @bitcast_vec_cond_commute1(
|
|
; CHECK-NEXT: [[C:%.*]] = mul <8 x i3> [[PC:%.*]], [[PC]]
|
|
; CHECK-NEXT: [[S:%.*]] = sext <3 x i1> [[COND:%.*]] to <3 x i8>
|
|
; CHECK-NEXT: [[T9:%.*]] = bitcast <3 x i8> [[S]] to <8 x i3>
|
|
; CHECK-NEXT: [[NOTT9:%.*]] = xor <8 x i3> [[T9]], <i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1>
|
|
; CHECK-NEXT: [[T11:%.*]] = and <8 x i3> [[C]], [[NOTT9]]
|
|
; CHECK-NEXT: [[T12:%.*]] = and <8 x i3> [[D:%.*]], [[T9]]
|
|
; CHECK-NEXT: [[R:%.*]] = or disjoint <8 x i3> [[T11]], [[T12]]
|
|
; CHECK-NEXT: ret <8 x i3> [[R]]
|
|
;
|
|
%c = mul <8 x i3> %pc, %pc ; thwart complexity-based canonicalization
|
|
%s = sext <3 x i1> %cond to <3 x i8>
|
|
%t9 = bitcast <3 x i8> %s to <8 x i3>
|
|
%nott9 = xor <8 x i3> %t9, <i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1, i3 -1>
|
|
%t11 = and <8 x i3> %c, %nott9
|
|
%t12 = and <8 x i3> %t9, %d
|
|
%r = or <8 x i3> %t11, %t12
|
|
ret <8 x i3> %r
|
|
}
|
|
|
|
define <2 x i16> @bitcast_vec_cond_commute2(<4 x i1> %cond, <2 x i16> %pc, <2 x i16> %pd) {
|
|
; CHECK-LABEL: @bitcast_vec_cond_commute2(
|
|
; CHECK-NEXT: [[C:%.*]] = mul <2 x i16> [[PC:%.*]], [[PC]]
|
|
; CHECK-NEXT: [[D:%.*]] = mul <2 x i16> [[PD:%.*]], [[PD]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i16> [[D]] to <4 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i16> [[C]] to <4 x i8>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[COND:%.*]], <4 x i8> [[TMP1]], <4 x i8> [[TMP2]]
|
|
; CHECK-NEXT: [[R:%.*]] = bitcast <4 x i8> [[TMP3]] to <2 x i16>
|
|
; CHECK-NEXT: ret <2 x i16> [[R]]
|
|
;
|
|
%c = mul <2 x i16> %pc, %pc ; thwart complexity-based canonicalization
|
|
%d = mul <2 x i16> %pd, %pd ; thwart complexity-based canonicalization
|
|
%s = sext <4 x i1> %cond to <4 x i8>
|
|
%t9 = bitcast <4 x i8> %s to <2 x i16>
|
|
%nott9 = xor <2 x i16> %t9, <i16 -1, i16 -1>
|
|
%t11 = and <2 x i16> %c, %nott9
|
|
%t12 = and <2 x i16> %d, %t9
|
|
%r = or <2 x i16> %t11, %t12
|
|
ret <2 x i16> %r
|
|
}
|
|
|
|
; Condition doesn't have to be a bool vec - just all signbits.
|
|
|
|
define <2 x i16> @bitcast_vec_cond_commute3(<4 x i8> %cond, <2 x i16> %pc, <2 x i16> %pd) {
|
|
; CHECK-LABEL: @bitcast_vec_cond_commute3(
|
|
; CHECK-NEXT: [[C:%.*]] = mul <2 x i16> [[PC:%.*]], [[PC]]
|
|
; CHECK-NEXT: [[D:%.*]] = mul <2 x i16> [[PD:%.*]], [[PD]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i16> [[D]] to <4 x i8>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i16> [[C]] to <4 x i8>
|
|
; CHECK-NEXT: [[DOTNOT2:%.*]] = icmp slt <4 x i8> [[COND:%.*]], zeroinitializer
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[DOTNOT2]], <4 x i8> [[TMP1]], <4 x i8> [[TMP2]]
|
|
; CHECK-NEXT: [[R:%.*]] = bitcast <4 x i8> [[TMP3]] to <2 x i16>
|
|
; CHECK-NEXT: ret <2 x i16> [[R]]
|
|
;
|
|
%c = mul <2 x i16> %pc, %pc ; thwart complexity-based canonicalization
|
|
%d = mul <2 x i16> %pd, %pd ; thwart complexity-based canonicalization
|
|
%s = ashr <4 x i8> %cond, <i8 7, i8 7, i8 7, i8 7>
|
|
%t9 = bitcast <4 x i8> %s to <2 x i16>
|
|
%nott9 = xor <2 x i16> %t9, <i16 -1, i16 -1>
|
|
%t11 = and <2 x i16> %c, %nott9
|
|
%t12 = and <2 x i16> %d, %t9
|
|
%r = or <2 x i16> %t11, %t12
|
|
ret <2 x i16> %r
|
|
}
|
|
|
|
; Don't crash on invalid type for compute signbits.
|
|
|
|
define <2 x i64> @bitcast_fp_vec_cond(<2 x double> noundef %s, <2 x i64> %c, <2 x i64> %d) {
|
|
; CHECK-LABEL: @bitcast_fp_vec_cond(
|
|
; CHECK-NEXT: [[T9:%.*]] = bitcast <2 x double> [[S:%.*]] to <2 x i64>
|
|
; CHECK-NEXT: [[NOTT9:%.*]] = xor <2 x i64> [[T9]], <i64 -1, i64 -1>
|
|
; CHECK-NEXT: [[T11:%.*]] = and <2 x i64> [[C:%.*]], [[NOTT9]]
|
|
; CHECK-NEXT: [[T12:%.*]] = and <2 x i64> [[D:%.*]], [[T9]]
|
|
; CHECK-NEXT: [[R:%.*]] = or disjoint <2 x i64> [[T11]], [[T12]]
|
|
; CHECK-NEXT: ret <2 x i64> [[R]]
|
|
;
|
|
%t9 = bitcast <2 x double> %s to <2 x i64>
|
|
%nott9 = xor <2 x i64> %t9, <i64 -1, i64 -1>
|
|
%t11 = and <2 x i64> %nott9, %c
|
|
%t12 = and <2 x i64> %t9, %d
|
|
%r = or <2 x i64> %t11, %t12
|
|
ret <2 x i64> %r
|
|
}
|
|
|
|
; Wider source type would be ok except poison could leak across elements.
|
|
|
|
define <2 x i64> @bitcast_int_vec_cond(i1 noundef %b, <2 x i64> %c, <2 x i64> %d) {
|
|
; CHECK-LABEL: @bitcast_int_vec_cond(
|
|
; CHECK-NEXT: [[S:%.*]] = sext i1 [[B:%.*]] to i128
|
|
; CHECK-NEXT: [[T9:%.*]] = bitcast i128 [[S]] to <2 x i64>
|
|
; CHECK-NEXT: [[NOTT9:%.*]] = xor <2 x i64> [[T9]], <i64 -1, i64 -1>
|
|
; CHECK-NEXT: [[T11:%.*]] = and <2 x i64> [[C:%.*]], [[NOTT9]]
|
|
; CHECK-NEXT: [[T12:%.*]] = and <2 x i64> [[D:%.*]], [[T9]]
|
|
; CHECK-NEXT: [[R:%.*]] = or disjoint <2 x i64> [[T11]], [[T12]]
|
|
; CHECK-NEXT: ret <2 x i64> [[R]]
|
|
;
|
|
%s = sext i1 %b to i128
|
|
%t9 = bitcast i128 %s to <2 x i64>
|
|
%nott9 = xor <2 x i64> %t9, <i64 -1, i64 -1>
|
|
%t11 = and <2 x i64> %nott9, %c
|
|
%t12 = and <2 x i64> %t9, %d
|
|
%r = or <2 x i64> %t11, %t12
|
|
ret <2 x i64> %r
|
|
}
|
|
|
|
; Converting integer logic ops to vector select is allowed.
|
|
|
|
define i64 @bitcast_int_scalar_cond(<2 x i1> %b, i64 %c, i64 %d) {
|
|
; CHECK-LABEL: @bitcast_int_scalar_cond(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[D:%.*]] to <2 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64 [[C:%.*]] to <2 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <2 x i1> [[B:%.*]], <2 x i32> [[TMP1]], <2 x i32> [[TMP2]]
|
|
; CHECK-NEXT: [[R:%.*]] = bitcast <2 x i32> [[TMP3]] to i64
|
|
; CHECK-NEXT: ret i64 [[R]]
|
|
;
|
|
%s = sext <2 x i1> %b to <2 x i32>
|
|
%t9 = bitcast <2 x i32> %s to i64
|
|
%nott9 = xor i64 %t9, -1
|
|
%t11 = and i64 %nott9, %c
|
|
%t12 = and i64 %t9, %d
|
|
%r = or i64 %t11, %t12
|
|
ret i64 %r
|
|
}
|
|
|
|
; Peek through bitcasts and sexts to find negated bool condition.
|
|
|
|
define <1 x i6> @bitcast_sext_cond(<2 x i1> %cmp, <1 x i6> %a, <1 x i6> %b) {
|
|
; CHECK-LABEL: @bitcast_sext_cond(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <1 x i6> [[A:%.*]] to <2 x i3>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <1 x i6> [[B:%.*]] to <2 x i3>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = select <2 x i1> [[CMP:%.*]], <2 x i3> [[TMP1]], <2 x i3> [[TMP2]]
|
|
; CHECK-NEXT: [[OR:%.*]] = bitcast <2 x i3> [[TMP3]] to <1 x i6>
|
|
; CHECK-NEXT: ret <1 x i6> [[OR]]
|
|
;
|
|
%sext = sext <2 x i1> %cmp to <2 x i3>
|
|
%bc1 = bitcast <2 x i3> %sext to <1 x i6>
|
|
%neg = xor <2 x i1> %cmp, <i1 -1, i1 -1>
|
|
%sext2 = sext <2 x i1> %neg to <2 x i3>
|
|
%bc2 = bitcast <2 x i3> %sext2 to <1 x i6>
|
|
%and1 = and <1 x i6> %bc1, %a
|
|
%and2 = and <1 x i6> %bc2, %b
|
|
%or = or <1 x i6> %and1, %and2
|
|
ret <1 x i6> %or
|
|
}
|
|
|
|
; Extra uses may prevent other transforms from creating the canonical patterns.
|
|
|
|
define i8 @sext_cond_extra_uses(i1 %cmp, i8 %a, i8 %b) {
|
|
; CHECK-LABEL: @sext_cond_extra_uses(
|
|
; CHECK-NEXT: [[NEG:%.*]] = xor i1 [[CMP:%.*]], true
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i1 [[CMP]] to i8
|
|
; CHECK-NEXT: call void @use(i8 [[SEXT1]])
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i1 [[NEG]] to i8
|
|
; CHECK-NEXT: call void @use(i8 [[SEXT2]])
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP]], i8 [[A:%.*]], i8 [[B:%.*]]
|
|
; CHECK-NEXT: ret i8 [[OR]]
|
|
;
|
|
%neg = xor i1 %cmp, -1
|
|
%sext1 = sext i1 %cmp to i8
|
|
call void @use(i8 %sext1)
|
|
%sext2 = sext i1 %neg to i8
|
|
call void @use(i8 %sext2)
|
|
%and1 = and i8 %sext1, %a
|
|
%and2 = and i8 %sext2, %b
|
|
%or = or i8 %and1, %and2
|
|
ret i8 %or
|
|
}
|
|
|
|
define i1 @xor_commute0(i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @xor_commute0(
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
%and = select i1 %x, i1 %y, i1 false
|
|
%or = select i1 %x, i1 true, i1 %y
|
|
%nand = xor i1 %and, true
|
|
%and2 = select i1 %nand, i1 %or, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @xor_commute1(i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @xor_commute1(
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
|
|
; CHECK-NEXT: [[NAND:%.*]] = xor i1 [[AND]], true
|
|
; CHECK-NEXT: call void @use1(i1 [[NAND]])
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X]], [[Y]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
%and = select i1 %x, i1 %y, i1 false
|
|
%or = select i1 %y, i1 true, i1 %x
|
|
%nand = xor i1 %and, true
|
|
call void @use1(i1 %nand)
|
|
%and2 = select i1 %nand, i1 %or, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @xor_commute2(i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @xor_commute2(
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
|
|
; CHECK-NEXT: call void @use1(i1 [[AND]])
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[X]], i1 true, i1 [[Y]]
|
|
; CHECK-NEXT: call void @use1(i1 [[OR]])
|
|
; CHECK-NEXT: [[NAND:%.*]] = xor i1 [[AND]], true
|
|
; CHECK-NEXT: call void @use1(i1 [[NAND]])
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X]], [[Y]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
%and = select i1 %x, i1 %y, i1 false
|
|
call void @use1(i1 %and)
|
|
%or = select i1 %x, i1 true, i1 %y
|
|
call void @use1(i1 %or)
|
|
%nand = xor i1 %and, true
|
|
call void @use1(i1 %nand)
|
|
%and2 = select i1 %or, i1 %nand, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define <2 x i1> @xor_commute3(<2 x i1> %x, <2 x i1> %y) {
|
|
; CHECK-LABEL: @xor_commute3(
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor <2 x i1> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[AND2]]
|
|
;
|
|
%and = select <2 x i1> %x, <2 x i1> %y, <2 x i1> <i1 false, i1 false>
|
|
%or = select <2 x i1> %y, <2 x i1> <i1 true, i1 true>, <2 x i1> %x
|
|
%nand = xor <2 x i1> %and, <i1 true, i1 true>
|
|
%and2 = select <2 x i1> %or, <2 x i1> %nand, <2 x i1> <i1 false, i1 false>
|
|
ret <2 x i1> %and2
|
|
}
|
|
|
|
define i1 @not_d_bools_commute00(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_commute00(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %c, %y
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %c, %x
|
|
%r = or i1 %and1, %and2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @not_d_bools_commute01(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_commute01(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %y, %c
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %c, %x
|
|
%r = or i1 %and1, %and2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @not_d_bools_commute10(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_commute10(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %c, %y
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %x, %c
|
|
%r = or i1 %and1, %and2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @not_d_bools_commute11(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_commute11(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y:%.*]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 [[TMP1]]
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %y, %c
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %x, %c
|
|
%r = or i1 %and1, %and2
|
|
ret i1 %r
|
|
}
|
|
|
|
define <2 x i1> @not_d_bools_vector(<2 x i1> %c, <2 x i1> %x, <2 x i1> %y) {
|
|
; CHECK-LABEL: @not_d_bools_vector(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> [[Y:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[X:%.*]], <2 x i1> [[TMP1]]
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%y_c = or <2 x i1> %y, %c
|
|
%and2 = xor <2 x i1> %y_c, <i1 true, i1 true>
|
|
%and1 = and <2 x i1> %x, %c
|
|
%r = or <2 x i1> %and1, %and2
|
|
ret <2 x i1> %r
|
|
}
|
|
|
|
define <2 x i1> @not_d_bools_vector_poison(<2 x i1> %c, <2 x i1> %x, <2 x i1> %y) {
|
|
; CHECK-LABEL: @not_d_bools_vector_poison(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i1> [[Y:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[X:%.*]], <2 x i1> [[TMP1]]
|
|
; CHECK-NEXT: ret <2 x i1> [[R]]
|
|
;
|
|
%y_c = or <2 x i1> %y, %c
|
|
%and2 = xor <2 x i1> %y_c, <i1 poison, i1 true>
|
|
%and1 = and <2 x i1> %x, %c
|
|
%r = or <2 x i1> %and1, %and2
|
|
ret <2 x i1> %r
|
|
}
|
|
|
|
define i32 @not_d_allSignBits(i32 %cond, i32 %tval, i32 %fval) {
|
|
; CHECK-LABEL: @not_d_allSignBits(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[FVAL:%.*]], -1
|
|
; CHECK-NEXT: [[DOTNOT2:%.*]] = icmp slt i32 [[COND:%.*]], 0
|
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[DOTNOT2]], i32 [[TVAL:%.*]], i32 [[TMP1]]
|
|
; CHECK-NEXT: ret i32 [[SEL]]
|
|
;
|
|
%bitmask = ashr i32 %cond, 31
|
|
%a1 = and i32 %tval, %bitmask
|
|
%or = or i32 %bitmask, %fval
|
|
%a2 = xor i32 %or, -1
|
|
%sel = or i32 %a1, %a2
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i1 @not_d_bools_use2(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_use2(
|
|
; CHECK-NEXT: [[Y_C:%.*]] = or i1 [[C:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[C]], [[X:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y]], true
|
|
; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i1 [[X]], i1 [[TMP1]]
|
|
; CHECK-NEXT: call void @use1(i1 [[AND1]])
|
|
; CHECK-NEXT: call void @use1(i1 [[Y_C]])
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %c, %y
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %c, %x
|
|
%r = or i1 %and1, %and2
|
|
call void @use1(i1 %and1)
|
|
call void @use1(i1 %y_c)
|
|
ret i1 %r
|
|
}
|
|
|
|
; negative test: both op is not one-use
|
|
|
|
define i1 @not_d_bools_negative_use2(i1 %c, i1 %x, i1 %y) {
|
|
; CHECK-LABEL: @not_d_bools_negative_use2(
|
|
; CHECK-NEXT: [[Y_C:%.*]] = or i1 [[C:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[Y_C]], true
|
|
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[C]], [[X:%.*]]
|
|
; CHECK-NEXT: [[R:%.*]] = or i1 [[AND1]], [[AND2]]
|
|
; CHECK-NEXT: call void @use1(i1 [[AND2]])
|
|
; CHECK-NEXT: call void @use1(i1 [[AND1]])
|
|
; CHECK-NEXT: ret i1 [[R]]
|
|
;
|
|
%y_c = or i1 %c, %y
|
|
%and2 = xor i1 %y_c, true
|
|
%and1 = and i1 %c, %x
|
|
%r = or i1 %and1, %and2
|
|
call void @use1(i1 %and2)
|
|
call void @use1(i1 %and1)
|
|
ret i1 %r
|
|
}
|
|
|
|
; A & (~C | B)
|
|
define i1 @logical_and_or_with_not_op(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @logical_and_or_with_not_op(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[OR:%.*]] = or i1 [[B:%.*]], [[NOT]]
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[OR]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND]]
|
|
;
|
|
%not = xor i1 %c, true
|
|
%or = or i1 %not, %b
|
|
%and = select i1 %a, i1 %or, i1 zeroinitializer
|
|
ret i1 %and
|
|
}
|
|
|
|
; As logical_and_or_with_not_op but with C=A
|
|
; A & (~A | B) --> A & B
|
|
define i1 @logical_and_or_with_common_not_op_variant1(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @logical_and_or_with_common_not_op_variant1(
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND]]
|
|
;
|
|
%not = xor i1 %a, true
|
|
%or = or i1 %not, %b
|
|
%and = select i1 %a, i1 %or, i1 zeroinitializer
|
|
ret i1 %and
|
|
}
|
|
|
|
; As logical_and_or_with_common_not_op_variant1 but operating on vectors
|
|
; A & (~A | B) --> A & B
|
|
define <2 x i1> @logical_and_or_with_common_not_op_variant2(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @logical_and_or_with_common_not_op_variant2(
|
|
; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[AND]]
|
|
;
|
|
%not = xor <2 x i1> %a, <i1 true, i1 true>
|
|
%or = or <2 x i1> %not, %b
|
|
%and = select <2 x i1> %a, <2 x i1> %or, <2 x i1> zeroinitializer
|
|
ret <2 x i1> %and
|
|
}
|
|
|
|
; As logical_and_or_with_common_not_op_variant1 but with "or" implemented as
|
|
; "select X, true, Y"
|
|
; A & (~A | B) --> A & B
|
|
define i1 @logical_and_or_with_common_not_op_variant3(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @logical_and_or_with_common_not_op_variant3(
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND]]
|
|
;
|
|
%not = xor i1 %a, true
|
|
%or = select i1 %not, i1 true, i1 %b
|
|
%and = select i1 %a, i1 %or, i1 zeroinitializer
|
|
ret i1 %and
|
|
}
|
|
|
|
; As logical_and_or_with_common_not_op_variant3 but operating on vectors where
|
|
; each operand has other uses
|
|
; A & (~A | B) --> A & B
|
|
define <2 x i1> @logical_and_or_with_common_not_op_variant4(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @logical_and_or_with_common_not_op_variant4(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[NOT]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
|
|
; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[A]], <2 x i1> [[B]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[A]])
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[B]])
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[OR]])
|
|
; CHECK-NEXT: ret <2 x i1> [[AND]]
|
|
;
|
|
%not = xor <2 x i1> %a, <i1 true, i1 true>
|
|
%or = select <2 x i1> %not, <2 x i1> <i1 true, i1 true>, <2 x i1> %b
|
|
%and = select <2 x i1> %a, <2 x i1> %or, <2 x i1> zeroinitializer
|
|
call void @use2(<2 x i1> %a)
|
|
call void @use2(<2 x i1> %b)
|
|
call void @use2(<2 x i1> %or)
|
|
ret <2 x i1> %and
|
|
}
|
|
|
|
; As logical_and_or_with_common_not_op_variant1 but with |'s operands swapped
|
|
; A & (B | ~A) --> A & B
|
|
define i1 @logical_and_or_with_common_not_op_variant5(i1 %a) {
|
|
; CHECK-LABEL: @logical_and_or_with_common_not_op_variant5(
|
|
; CHECK-NEXT: [[B:%.*]] = call i1 @gen()
|
|
; CHECK-NEXT: [[AND:%.*]] = select i1 [[A:%.*]], i1 [[B]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND]]
|
|
;
|
|
%b = call i1 @gen()
|
|
%not = xor i1 %a, true
|
|
%or = or i1 %b, %not
|
|
%and = select i1 %a, i1 %or, i1 zeroinitializer
|
|
ret i1 %and
|
|
}
|
|
|
|
; A | (~C & B)
|
|
define i1 @logical_or_and_with_not_op(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @logical_or_and_with_not_op(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[AND:%.*]] = and i1 [[B:%.*]], [[NOT]]
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[AND]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %c, true
|
|
%and = and i1 %not, %b
|
|
%or = select i1 %a, i1 true, i1 %and
|
|
ret i1 %or
|
|
}
|
|
|
|
; As logical_or_and_with_not_op but with C=A
|
|
; A | (~A & B) --> A | B
|
|
define i1 @logical_or_and_with_common_not_op_variant1(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @logical_or_and_with_common_not_op_variant1(
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %a, true
|
|
%and = and i1 %not, %b
|
|
%or = select i1 %a, i1 true, i1 %and
|
|
ret i1 %or
|
|
}
|
|
|
|
; As logical_or_and_with_common_not_op_variant1 but operating on vectors
|
|
; A | (~A & B) --> A | B
|
|
define <2 x i1> @logical_or_and_with_common_not_op_variant2(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @logical_or_and_with_common_not_op_variant2(
|
|
; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
|
|
; CHECK-NEXT: ret <2 x i1> [[OR]]
|
|
;
|
|
%not = xor <2 x i1> %a, <i1 true, i1 true>
|
|
%and = and <2 x i1> %not, %b
|
|
%or = select <2 x i1> %a, <2 x i1> <i1 true, i1 true>, <2 x i1> %and
|
|
ret <2 x i1> %or
|
|
}
|
|
|
|
; As logical_or_and_with_common_not_op_variant1 but with "and" implemented as
|
|
; "select X, Y, false"
|
|
; A | (~A & B) --> A | B
|
|
define i1 @logical_or_and_with_common_not_op_variant3(i1 %a, i1 %b) {
|
|
; CHECK-LABEL: @logical_or_and_with_common_not_op_variant3(
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%not = xor i1 %a, true
|
|
%and = select i1 %not, i1 %b, i1 false
|
|
%or = select i1 %a, i1 true, i1 %and
|
|
ret i1 %or
|
|
}
|
|
|
|
; As logical_or_and_with_common_not_op_variant3 but operating on vectors where
|
|
; each operand has other uses
|
|
; A | (~A & B) --> A | B
|
|
define <2 x i1> @logical_or_and_with_common_not_op_variant4(<2 x i1> %a, <2 x i1> %b) {
|
|
; CHECK-LABEL: @logical_or_and_with_common_not_op_variant4(
|
|
; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
|
|
; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[NOT]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
|
|
; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[A]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B]]
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[A]])
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[B]])
|
|
; CHECK-NEXT: call void @use2(<2 x i1> [[AND]])
|
|
; CHECK-NEXT: ret <2 x i1> [[OR]]
|
|
;
|
|
%not = xor <2 x i1> %a, <i1 true, i1 true>
|
|
%and = select <2 x i1> %not, <2 x i1> %b, <2 x i1> zeroinitializer
|
|
%or = select <2 x i1> %a, <2 x i1> <i1 true, i1 true>, <2 x i1> %and
|
|
call void @use2(<2 x i1> %a)
|
|
call void @use2(<2 x i1> %b)
|
|
call void @use2(<2 x i1> %and)
|
|
ret <2 x i1> %or
|
|
}
|
|
|
|
; As logical_or_and_with_common_not_op_variant1 but with &'s operands swapped
|
|
; A | (B & ~A) --> A | B
|
|
define i1 @logical_or_and_with_common_not_op_variant5(i1 %a) {
|
|
; CHECK-LABEL: @logical_or_and_with_common_not_op_variant5(
|
|
; CHECK-NEXT: [[B:%.*]] = call i1 @gen()
|
|
; CHECK-NEXT: [[OR:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B]]
|
|
; CHECK-NEXT: ret i1 [[OR]]
|
|
;
|
|
%b = call i1 @gen()
|
|
%not = xor i1 %a, true
|
|
%and = and i1 %b, %not
|
|
%or = select i1 %a, i1 true, i1 %and
|
|
ret i1 %or
|
|
}
|
|
|
|
define i1 @reduce_logical_and1(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_and1(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP1]], [[CMP]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 %cmp1, i1 false
|
|
%and2 = select i1 %and1, i1 %cmp, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_and2(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @reduce_logical_and2(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
|
|
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[B:%.*]], [[TMP0]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%or = xor i1 %c, %b
|
|
%and1 = select i1 %a, i1 %or, i1 false
|
|
%and2 = select i1 %and1, i1 %b, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_and3(i1 %a, i32 %b, i32 noundef %c) {
|
|
; CHECK-LABEL: @reduce_logical_and3(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP]], [[CMP1]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 %cmp, i1 false
|
|
%and2 = select i1 %and1, i1 %cmp1, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_or1(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_or1(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP1]], [[CMP]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 true, i1 %cmp1
|
|
%and2 = select i1 %and1, i1 true, i1 %cmp
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_or2(i1 %a, i1 %b, i1 %c) {
|
|
; CHECK-LABEL: @reduce_logical_or2(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[C:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%or = xor i1 %c, %b
|
|
%and1 = select i1 %a, i1 true, i1 %or
|
|
%and2 = select i1 %and1, i1 true, i1 %b
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_or3(i1 %a, i32 %b, i32 noundef %c) {
|
|
; CHECK-LABEL: @reduce_logical_or3(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP]], [[CMP1]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 true, i1 %cmp
|
|
%and2 = select i1 %and1, i1 true, i1 %cmp1
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_and_fail1(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_and_fail1(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 %cmp, i1 false
|
|
%and2 = select i1 %and1, i1 %cmp1, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_and_fail2(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_and_fail2(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, 7
|
|
%and1 = select i1 %a, i1 %cmp, i1 false
|
|
%and2 = select i1 %and1, i1 %cmp1, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_or_fail1(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_or_fail1(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 true, i1 %cmp
|
|
%and2 = select i1 %and1, i1 true, i1 %cmp1
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_or_fail2(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_or_fail2(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, 7
|
|
%and1 = select i1 %a, i1 true, i1 %cmp
|
|
%and2 = select i1 %and1, i1 true, i1 %cmp1
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_logical_and_multiuse(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_logical_and_multiuse(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
|
|
; CHECK-NEXT: call void @use1(i1 [[AND1]])
|
|
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP]], i1 false
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 %cmp1, i1 false
|
|
call void @use1(i1 %and1)
|
|
%and2 = select i1 %and1, i1 %cmp, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_bitwise_and1(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_bitwise_and1(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = or i1 [[A:%.*]], [[CMP1]]
|
|
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[CMP]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = or i1 %a, %cmp1
|
|
%and2 = select i1 %and1, i1 %cmp, i1 false
|
|
ret i1 %and2
|
|
}
|
|
|
|
define i1 @reduce_bitwise_and2(i1 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @reduce_bitwise_and2(
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
|
|
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
|
|
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
|
|
; CHECK-NEXT: [[AND2:%.*]] = or i1 [[AND1]], [[CMP]]
|
|
; CHECK-NEXT: ret i1 [[AND2]]
|
|
;
|
|
bb:
|
|
%cmp = icmp slt i32 %b, 6
|
|
%cmp1 = icmp sgt i32 %c, %b
|
|
%and1 = select i1 %a, i1 %cmp1, i1 false
|
|
%and2 = or i1 %and1, %cmp
|
|
ret i1 %and2
|
|
}
|