Skip to content

Commit 2a572a8

Browse files
Fold Select with a Const Operand to BinOp
1 parent 4fe3c73 commit 2a572a8

File tree

4 files changed

+99
-48
lines changed

4 files changed

+99
-48
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,69 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
18981898
return nullptr;
18991899
}
19001900

1901+
// Turn select (Cmp X C1) (BOp X C2) C3
1902+
// -> BOp (min/max X C1) C2
1903+
// iff C3 == BOp C1 C2
1904+
// This allows for better canonicalization.
1905+
static Value *canonicalizeConstToBOp(ICmpInst *Cmp, Value *TrueVal,
1906+
Value *FalseVal,
1907+
InstCombiner::BuilderTy &Builder) {
1908+
BinaryOperator *BOp;
1909+
Constant *C1, *C2, *C3;
1910+
Value *X;
1911+
ICmpInst::Predicate Predicate;
1912+
1913+
if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1))))
1914+
return nullptr;
1915+
1916+
if (!((match(TrueVal, m_BinOp(BOp)) && match(FalseVal, m_Constant(C3))) ||
1917+
(match(FalseVal, m_BinOp(BOp)) && match(TrueVal, m_Constant(C3)))))
1918+
return nullptr;
1919+
1920+
if (!match(BOp, m_OneUse(m_c_BinOp(m_Specific(X), m_Constant(C2)))))
1921+
return nullptr;
1922+
1923+
// `select (Cmp X C1) (sub C2 X) (sub C1 C2)` cannot be transformed
1924+
// into something like `sub (select (Cmp X C1) X C1) C2`
1925+
if (!BOp->isCommutative() && BOp->getOperand(0) != X)
1926+
return nullptr;
1927+
1928+
if (!(ICmpInst::isRelational(Predicate) &&
1929+
C3 == ConstantFoldBinaryOpOperands(BOp->getOpcode(), C1, C2,
1930+
BOp->getDataLayout())))
1931+
return nullptr;
1932+
1933+
Value *NewTrueVal = isa<Constant>(TrueVal) ? C1 : X;
1934+
Value *NewFalseVal = isa<Constant>(FalseVal) ? C1 : X;
1935+
Value *LHS, *RHS;
1936+
SelectPatternFlavor SPF =
1937+
matchDecomposedSelectPattern(Cmp, NewTrueVal, NewFalseVal, LHS, RHS)
1938+
.Flavor;
1939+
1940+
Intrinsic::ID IntrinsicID;
1941+
switch (SPF) {
1942+
case SelectPatternFlavor::SPF_UMIN:
1943+
IntrinsicID = Intrinsic::umin;
1944+
break;
1945+
case SelectPatternFlavor::SPF_UMAX:
1946+
IntrinsicID = Intrinsic::umax;
1947+
break;
1948+
case SelectPatternFlavor::SPF_SMIN:
1949+
IntrinsicID = Intrinsic::smin;
1950+
break;
1951+
case SelectPatternFlavor::SPF_SMAX:
1952+
IntrinsicID = Intrinsic::smax;
1953+
break;
1954+
default:
1955+
llvm_unreachable("Unexpected SPF");
1956+
}
1957+
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS);
1958+
BinaryOperator *NewBO = cast<BinaryOperator>(
1959+
Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2));
1960+
NewBO->copyIRFlags(BOp);
1961+
return NewBO;
1962+
}
1963+
19011964
/// Visit a SelectInst that has an ICmpInst as its first operand.
19021965
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19031966
ICmpInst *ICI) {
@@ -1987,6 +2050,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19872050
if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
19882051
return replaceInstUsesWith(SI, V);
19892052

2053+
if (Value *V = canonicalizeConstToBOp(ICI, TrueVal, FalseVal, Builder))
2054+
return replaceInstUsesWith(SI, V);
2055+
19902056
return Changed ? &SI : nullptr;
19912057
}
19922058

llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
define i8 @add_and_sgt(i8 %x) {
55
; CHECK-LABEL: define i8 @add_and_sgt(
66
; CHECK-SAME: i8 [[X:%.*]]) {
7-
; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 16
8-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8
9-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
7+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
8+
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
109
; CHECK-NEXT: ret i8 [[S]]
1110
;
1211
%add = add nsw i8 %x, 16
@@ -18,9 +17,8 @@ define i8 @add_and_sgt(i8 %x) {
1817
define i8 @add_sgt_nuw(i8 %x) {
1918
; CHECK-LABEL: define i8 @add_sgt_nuw(
2019
; CHECK-SAME: i8 [[X:%.*]]) {
21-
; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[X]], 16
22-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8
23-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
20+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
21+
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16
2422
; CHECK-NEXT: ret i8 [[S]]
2523
;
2624
%add = add nuw i8 %x, 16
@@ -32,9 +30,8 @@ define i8 @add_sgt_nuw(i8 %x) {
3230
define i8 @sub_and_ugt(i8 %x) {
3331
; CHECK-LABEL: define i8 @sub_and_ugt(
3432
; CHECK-SAME: i8 [[X:%.*]]) {
35-
; CHECK-NEXT: [[SUB:%.*]] = add nsw i8 [[X]], -50
36-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 100
37-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
33+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100)
34+
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -50
3835
; CHECK-NEXT: ret i8 [[S]]
3936
;
4037
%sub = sub nsw i8 %x, 50
@@ -46,9 +43,8 @@ define i8 @sub_and_ugt(i8 %x) {
4643
define i8 @sub_ugt_nuw_nsw(i8 %x) {
4744
; CHECK-LABEL: define i8 @sub_ugt_nuw_nsw(
4845
; CHECK-SAME: i8 [[X:%.*]]) {
49-
; CHECK-NEXT: [[SUB:%.*]] = add nsw i8 [[X]], -50
50-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 100
51-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
46+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100)
47+
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -50
5248
; CHECK-NEXT: ret i8 [[S]]
5349
;
5450
%sub = sub nuw nsw i8 %x, 50
@@ -60,9 +56,8 @@ define i8 @sub_ugt_nuw_nsw(i8 %x) {
6056
define i8 @mul_and_ult(i8 %x) {
6157
; CHECK-LABEL: define i8 @mul_and_ult(
6258
; CHECK-SAME: i8 [[X:%.*]]) {
63-
; CHECK-NEXT: [[ADD:%.*]] = mul nsw i8 [[X]], 10
64-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 10
65-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
59+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10)
60+
; CHECK-NEXT: [[S:%.*]] = mul nuw nsw i8 [[TMP1]], 10
6661
; CHECK-NEXT: ret i8 [[S]]
6762
;
6863
%add = mul nsw i8 %x, 10
@@ -74,9 +69,8 @@ define i8 @mul_and_ult(i8 %x) {
7469
define i8 @mul_ult_noflags(i8 %x) {
7570
; CHECK-LABEL: define i8 @mul_ult_noflags(
7671
; CHECK-SAME: i8 [[X:%.*]]) {
77-
; CHECK-NEXT: [[ADD:%.*]] = mul i8 [[X]], 10
78-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 10
79-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
72+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10)
73+
; CHECK-NEXT: [[S:%.*]] = mul nuw i8 [[TMP1]], 10
8074
; CHECK-NEXT: ret i8 [[S]]
8175
;
8276
%add = mul i8 %x, 10
@@ -88,9 +82,8 @@ define i8 @mul_ult_noflags(i8 %x) {
8882
define i8 @udiv_and_slt(i8 %x) {
8983
; CHECK-LABEL: define i8 @udiv_and_slt(
9084
; CHECK-SAME: i8 [[X:%.*]]) {
91-
; CHECK-NEXT: [[SUB:%.*]] = udiv i8 [[X]], 10
92-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 100
93-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
85+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 100)
86+
; CHECK-NEXT: [[S:%.*]] = udiv i8 [[TMP1]], 10
9487
; CHECK-NEXT: ret i8 [[S]]
9588
;
9689
%sub = udiv i8 %x, 10
@@ -102,9 +95,8 @@ define i8 @udiv_and_slt(i8 %x) {
10295
define i8 @udiv_slt_exact(i8 %x) {
10396
; CHECK-LABEL: define i8 @udiv_slt_exact(
10497
; CHECK-SAME: i8 [[X:%.*]]) {
105-
; CHECK-NEXT: [[SUB:%.*]] = udiv exact i8 [[X]], 10
106-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 100
107-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
98+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 100)
99+
; CHECK-NEXT: [[S:%.*]] = udiv exact i8 [[TMP1]], 10
108100
; CHECK-NEXT: ret i8 [[S]]
109101
;
110102
%sub = udiv exact i8 %x, 10
@@ -116,9 +108,8 @@ define i8 @udiv_slt_exact(i8 %x) {
116108
define i8 @canonicalize_icmp_operands(i8 %x) {
117109
; CHECK-LABEL: define i8 @canonicalize_icmp_operands(
118110
; CHECK-SAME: i8 [[X:%.*]]) {
119-
; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 8
120-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 119
121-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
111+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 119)
112+
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], 8
122113
; CHECK-NEXT: ret i8 [[S]]
123114
;
124115
%add = add nsw i8 %x, 8
@@ -133,10 +124,10 @@ declare void @use_byte(i8)
133124
define i8 @multi_use_cond_and_sel(i8 %x) {
134125
; CHECK-LABEL: define i8 @multi_use_cond_and_sel(
135126
; CHECK-SAME: i8 [[X:%.*]]) {
136-
; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 16
137127
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8
138128
; CHECK-NEXT: call void @use(i1 [[CMP]])
139-
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
129+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
130+
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
140131
; CHECK-NEXT: call void @use_byte(i8 [[S]])
141132
; CHECK-NEXT: ret i8 [[S]]
142133
;
@@ -155,11 +146,9 @@ define void @rust_noop_loop() {
155146
; CHECK: [[BB2_I]]:
156147
; CHECK-NEXT: [[ITER_SROA_0_07:%.*]] = phi i32 [ 0, %[[START]] ], [ [[SPEC_SELECT5:%.*]], %[[BB2_I]] ]
157148
; CHECK-NEXT: [[_0_I3_I:%.*]] = icmp sgt i32 [[ITER_SROA_0_07]], 99
158-
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[ITER_SROA_0_07]], 1
159-
; CHECK-NEXT: [[SPEC_SELECT5]] = select i1 [[_0_I3_I]], i32 100, i32 [[TMP0]]
160-
; CHECK-NEXT: [[_0_I_NOT_I:%.*]] = icmp sgt i32 [[SPEC_SELECT5]], 100
161-
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[_0_I3_I]], i1 true, i1 [[_0_I_NOT_I]]
162-
; CHECK-NEXT: br i1 [[OR_COND]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]]
149+
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.smin.i32(i32 [[ITER_SROA_0_07]], i32 99)
150+
; CHECK-NEXT: [[SPEC_SELECT5]] = add nsw i32 [[TMP0]], 1
151+
; CHECK-NEXT: br i1 [[_0_I3_I]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]]
163152
; CHECK: [[BASICBLOCK4]]:
164153
; CHECK-NEXT: ret void
165154
;
@@ -182,9 +171,8 @@ basicblock4:
182171
define <2 x i8> @add_non_splat_vector(<2 x i8> %x) {
183172
; CHECK-LABEL: define <2 x i8> @add_non_splat_vector(
184173
; CHECK-SAME: <2 x i8> [[X:%.*]]) {
185-
; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], <i8 1, i8 0>
186-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], <i8 0, i8 1>
187-
; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> splat (i8 1)
174+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> <i8 0, i8 1>)
175+
; CHECK-NEXT: [[S:%.*]] = add nuw <2 x i8> [[TMP1]], <i8 1, i8 0>
188176
; CHECK-NEXT: ret <2 x i8> [[S]]
189177
;
190178
%add = add <2 x i8> %x, <i8 1, i8 0>
@@ -196,9 +184,8 @@ define <2 x i8> @add_non_splat_vector(<2 x i8> %x) {
196184
define <2 x i8> @or_splat_vector(<2 x i8> %x) {
197185
; CHECK-LABEL: define <2 x i8> @or_splat_vector(
198186
; CHECK-SAME: <2 x i8> [[X:%.*]]) {
199-
; CHECK-NEXT: [[ADD:%.*]] = or <2 x i8> [[X]], splat (i8 1)
200-
; CHECK-NEXT: [[CMP_INV:%.*]] = icmp slt <2 x i8> [[X]], splat (i8 1)
201-
; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[CMP_INV]], <2 x i8> splat (i8 1), <2 x i8> [[ADD]]
187+
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> splat (i8 1))
188+
; CHECK-NEXT: [[S:%.*]] = or <2 x i8> [[TMP1]], splat (i8 1)
202189
; CHECK-NEXT: ret <2 x i8> [[S]]
203190
;
204191
%add = or <2 x i8> %x, <i8 1, i8 1>

llvm/test/Transforms/InstCombine/saturating-add-sub.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,10 +1793,9 @@ define i32 @not_uadd_sat(i32 %x, i32 %y) {
17931793

17941794
define i32 @not_uadd_sat2(i32 %x, i32 %y) {
17951795
; CHECK-LABEL: @not_uadd_sat2(
1796-
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2
1797-
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[X]], 1
1798-
; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1
1799-
; CHECK-NEXT: ret i32 [[R]]
1796+
; CHECK-NEXT: [[X:%.*]] = call i32 @llvm.umax.i32(i32 [[X1:%.*]], i32 1)
1797+
; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], -2
1798+
; CHECK-NEXT: ret i32 [[A]]
18001799
;
18011800
%a = add i32 %x, -2
18021801
%c = icmp ugt i32 %x, 1

llvm/test/Transforms/InstCombine/select.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2989,10 +2989,9 @@ define i8 @select_replacement_loop3(i32 noundef %x) {
29892989

29902990
define i16 @select_replacement_loop4(i16 noundef %p_12) {
29912991
; CHECK-LABEL: @select_replacement_loop4(
2992-
; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12:%.*]], 1
2993-
; CHECK-NEXT: [[CMP21:%.*]] = icmp ult i16 [[P_12]], 2
2994-
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[CMP21]], i16 [[AND1]], i16 0
2995-
; CHECK-NEXT: ret i16 [[AND3]]
2992+
; CHECK-NEXT: [[P_12:%.*]] = call i16 @llvm.umin.i16(i16 [[P_13:%.*]], i16 2)
2993+
; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12]], 1
2994+
; CHECK-NEXT: ret i16 [[AND1]]
29962995
;
29972996
%cmp1 = icmp ult i16 %p_12, 2
29982997
%and1 = and i16 %p_12, 1

0 commit comments

Comments
 (0)