Skip to content

Commit 46dbce2

Browse files
Fold Select with a Const Operand to BinOp
1 parent 4fe3c73 commit 46dbce2

File tree

7 files changed

+115
-91
lines changed

7 files changed

+115
-91
lines changed

clang/test/CodeGen/attr-counted-by.c

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,8 @@ void test1(struct annotated *p, int index, int val) {
119119
// SANITIZE-WITH-ATTR: cont3:
120120
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
121121
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]]
122-
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
123-
// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
124-
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]]
122+
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
123+
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP2]], 2
125124
// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
126125
// SANITIZE-WITH-ATTR-NEXT: ret void
127126
//
@@ -130,9 +129,8 @@ void test1(struct annotated *p, int index, int val) {
130129
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
131130
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
132131
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
133-
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
134-
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
135-
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]]
132+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
133+
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP0]], 2
136134
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
137135
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]]
138136
// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
@@ -539,10 +537,9 @@ size_t test5_bdos(struct anon_struct *p) {
539537
// SANITIZE-WITH-ATTR: cont3:
540538
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
541539
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
542-
// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
543-
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
544-
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2
545-
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]]
540+
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
541+
// SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc i64 [[TMP2]] to i32
542+
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2
546543
// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
547544
// SANITIZE-WITH-ATTR-NEXT: ret void
548545
//
@@ -551,10 +548,9 @@ size_t test5_bdos(struct anon_struct *p) {
551548
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
552549
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
553550
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
554-
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
555-
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
556-
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2
557-
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]]
551+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
552+
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32
553+
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2
558554
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
559555
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
560556
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
@@ -588,19 +584,17 @@ void test6(struct anon_struct *p, int index) {
588584
// SANITIZE-WITH-ATTR-NEXT: entry:
589585
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
590586
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
591-
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
592-
// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
593-
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]]
587+
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
588+
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2
594589
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
595590
//
596591
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
597592
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
598593
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
599594
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
600595
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
601-
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
602-
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
603-
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]]
596+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
597+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2
604598
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
605599
//
606600
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test6_bdos(
@@ -1740,9 +1734,8 @@ struct annotated_struct_array {
17401734
// SANITIZE-WITH-ATTR: cont20:
17411735
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
17421736
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX18:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM15]]
1743-
// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
1744-
// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
1745-
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP5]]
1737+
// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
1738+
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP5]], 2
17461739
// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA4]]
17471740
// SANITIZE-WITH-ATTR-NEXT: ret void
17481741
//
@@ -1754,9 +1747,8 @@ struct annotated_struct_array {
17541747
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
17551748
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
17561749
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
1757-
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
1758-
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
1759-
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP1]]
1750+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
1751+
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP1]], 2
17601752
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12
17611753
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM4:%.*]] = sext i32 [[IDX2]] to i64
17621754
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM4]]

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,10 @@ SelectPatternResult matchDecomposedSelectPattern(
11821182
/// minimum/maximum flavor.
11831183
CmpInst::Predicate getMinMaxPred(SelectPatternFlavor SPF, bool Ordered = false);
11841184

1185+
/// Convert given `SPF` to equivalent min/max intrinsic.
1186+
/// Caller must ensure `SPF` is an integer min or max pattern.
1187+
Intrinsic::ID getMinMaxIntrinsic(SelectPatternFlavor SPF);
1188+
11851189
/// Return the inverse minimum/maximum flavor of the specified flavor.
11861190
/// For example, signed minimum is the inverse of signed maximum.
11871191
SelectPatternFlavor getInverseMinMaxFlavor(SelectPatternFlavor SPF);

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8960,6 +8960,21 @@ CmpInst::Predicate llvm::getMinMaxPred(SelectPatternFlavor SPF, bool Ordered) {
89608960
llvm_unreachable("unhandled!");
89618961
}
89628962

8963+
Intrinsic::ID llvm::getMinMaxIntrinsic(SelectPatternFlavor SPF) {
8964+
switch (SPF) {
8965+
case SelectPatternFlavor::SPF_UMIN:
8966+
return Intrinsic::umin;
8967+
case SelectPatternFlavor::SPF_UMAX:
8968+
return Intrinsic::umax;
8969+
case SelectPatternFlavor::SPF_SMIN:
8970+
return Intrinsic::smin;
8971+
case SelectPatternFlavor::SPF_SMAX:
8972+
return Intrinsic::smax;
8973+
default:
8974+
llvm_unreachable("Unexpected SPF");
8975+
}
8976+
}
8977+
89638978
SelectPatternFlavor llvm::getInverseMinMaxFlavor(SelectPatternFlavor SPF) {
89648979
if (SPF == SPF_SMIN) return SPF_SMAX;
89658980
if (SPF == SPF_UMIN) return SPF_UMAX;

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,23 +1257,7 @@ static Value *canonicalizeSPF(ICmpInst &Cmp, Value *TrueVal, Value *FalseVal,
12571257
}
12581258

12591259
if (SelectPatternResult::isMinOrMax(SPF)) {
1260-
Intrinsic::ID IntrinsicID;
1261-
switch (SPF) {
1262-
case SelectPatternFlavor::SPF_UMIN:
1263-
IntrinsicID = Intrinsic::umin;
1264-
break;
1265-
case SelectPatternFlavor::SPF_UMAX:
1266-
IntrinsicID = Intrinsic::umax;
1267-
break;
1268-
case SelectPatternFlavor::SPF_SMIN:
1269-
IntrinsicID = Intrinsic::smin;
1270-
break;
1271-
case SelectPatternFlavor::SPF_SMAX:
1272-
IntrinsicID = Intrinsic::smax;
1273-
break;
1274-
default:
1275-
llvm_unreachable("Unexpected SPF");
1276-
}
1260+
Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
12771261
return IC.Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS);
12781262
}
12791263

@@ -1898,6 +1882,47 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
18981882
return nullptr;
18991883
}
19001884

1885+
/// Fold `X Pred C2 ? X BOp C1 : C2 BOp C1` to `min/max(X, C2) BOp C1`.
1886+
/// This allows for better canonicalization.
1887+
static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
1888+
Value *FalseVal,
1889+
IRBuilderBase &Builder) {
1890+
BinaryOperator *BOp;
1891+
Constant *C1, *C2, *C3;
1892+
Value *X, *NewTrue, *NewFalse;
1893+
ICmpInst::Predicate Predicate;
1894+
1895+
if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1))))
1896+
return nullptr;
1897+
1898+
if (match(TrueVal, m_Constant())) {
1899+
std::swap(FalseVal, TrueVal);
1900+
NewTrue = C1;
1901+
NewFalse = X;
1902+
} else {
1903+
NewTrue = X;
1904+
NewFalse = C1;
1905+
}
1906+
1907+
if (!match(TrueVal, m_BinOp(BOp)) || !match(FalseVal, m_Constant(C3)))
1908+
return nullptr;
1909+
1910+
if (!match(BOp, m_OneUse(m_BinOp(m_Specific(X), m_Constant(C2)))))
1911+
return nullptr;
1912+
1913+
if (!ICmpInst::isRelational(Predicate) ||
1914+
C3 != ConstantFoldBinaryOpOperands(BOp->getOpcode(), C1, C2,
1915+
BOp->getDataLayout()))
1916+
return nullptr;
1917+
1918+
Value *LHS, *RHS;
1919+
SelectPatternFlavor SPF =
1920+
matchDecomposedSelectPattern(Cmp, NewTrue, NewFalse, LHS, RHS).Flavor;
1921+
Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
1922+
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS);
1923+
return Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2);
1924+
}
1925+
19011926
/// Visit a SelectInst that has an ICmpInst as its first operand.
19021927
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19031928
ICmpInst *ICI) {
@@ -1987,6 +2012,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19872012
if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
19882013
return replaceInstUsesWith(SI, V);
19892014

2015+
if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal, Builder))
2016+
return replaceInstUsesWith(SI, V);
2017+
19902018
return Changed ? &SI : nullptr;
19912019
}
19922020

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 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 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 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 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>

0 commit comments

Comments
 (0)