Skip to content

Commit 8e63645

Browse files
committed
[AggressiveInstCombine] Inline strcmp/strncmp
* improve tests
1 parent 4ca7ba9 commit 8e63645

File tree

3 files changed

+60
-78
lines changed

3 files changed

+60
-78
lines changed

llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ static cl::opt<unsigned> MaxInstrsToScan(
4949
"aggressive-instcombine-max-scan-instrs", cl::init(64), cl::Hidden,
5050
cl::desc("Max number of instructions to scan for aggressive instcombine."));
5151

52+
static cl::opt<unsigned> StrNCmpInlineThreshold(
53+
"strncmp-inline-threshold", cl::init(3), cl::Hidden,
54+
cl::desc("The maximum length of a constant string for a builtin string cmp "
55+
"call eligible for inlining. The default value is 3."));
56+
5257
/// Match a pattern for a bitwise funnel/rotate operation that partially guards
5358
/// against undefined behavior by branching around the funnel-shift/rotation
5459
/// when the shift amount is 0.
@@ -914,11 +919,6 @@ static bool foldPatternedLoads(Instruction &I, const DataLayout &DL) {
914919
return true;
915920
}
916921

917-
static cl::opt<unsigned> StrNCmpInlineThreshold(
918-
"strncmp-inline-threshold", cl::init(3), cl::Hidden,
919-
cl::desc("The maximum length of a constant string for a builtin string cmp "
920-
"call eligible for inlining. The default value is 3."));
921-
922922
namespace {
923923
class StrNCmpInliner {
924924
public:
@@ -929,7 +929,7 @@ class StrNCmpInliner {
929929
bool optimizeStrNCmp();
930930

931931
private:
932-
bool inlineCompare(Value *LHS, StringRef RHS, uint64_t N, bool Swapped);
932+
void inlineCompare(Value *LHS, StringRef RHS, uint64_t N, bool Swapped);
933933

934934
CallInst *CI;
935935
LibFunc Func;
@@ -981,18 +981,19 @@ bool StrNCmpInliner::optimizeStrNCmp() {
981981
return false;
982982

983983
StringRef Str1, Str2;
984-
bool HasStr1 = getConstantStringInfo(Str1P, Str1, false);
985-
bool HasStr2 = getConstantStringInfo(Str2P, Str2, false);
984+
bool HasStr1 = getConstantStringInfo(Str1P, Str1, /*TrimAtNul=*/false);
985+
bool HasStr2 = getConstantStringInfo(Str2P, Str2, /*TrimAtNul=*/false);
986986
if (HasStr1 == HasStr2)
987987
return false;
988988

989989
// Note that '\0' and characters after it are not trimmed.
990990
StringRef Str = HasStr1 ? Str1 : Str2;
991+
Value *StrP = HasStr1 ? Str2P : Str1P;
991992

992993
size_t Idx = Str.find('\0');
993994
uint64_t N = Idx == StringRef::npos ? UINT64_MAX : Idx + 1;
994995
if (Func == LibFunc_strncmp) {
995-
if (auto ConstInt = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
996+
if (auto *ConstInt = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
996997
N = std::min(N, ConstInt->getZExtValue());
997998
else
998999
return false;
@@ -1001,15 +1002,13 @@ bool StrNCmpInliner::optimizeStrNCmp() {
10011002
if (N > Str.size() || N < 2 || N > StrNCmpInlineThreshold)
10021003
return false;
10031004

1004-
Value *StrP = HasStr1 ? Str2P : Str1P;
1005-
10061005
// Cases where StrP has two or more dereferenceable bytes might be better
10071006
// optimized elsewhere.
10081007
bool CanBeNull = false, CanBeFreed = false;
10091008
if (StrP->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed) > 1)
10101009
return false;
1011-
1012-
return inlineCompare(StrP, Str, N, HasStr1);
1010+
inlineCompare(StrP, Str, N, HasStr1);
1011+
return true;
10131012
}
10141013

10151014
/// Convert
@@ -1046,7 +1045,7 @@ bool StrNCmpInliner::optimizeStrNCmp() {
10461045
/// ... |
10471046
/// BBSubs[N-1] (sub) ---------+
10481047
///
1049-
bool StrNCmpInliner::inlineCompare(Value *LHS, StringRef RHS, uint64_t N,
1048+
void StrNCmpInliner::inlineCompare(Value *LHS, StringRef RHS, uint64_t N,
10501049
bool Swapped) {
10511050
auto &Ctx = CI->getContext();
10521051
IRBuilder<> B(Ctx);
@@ -1056,9 +1055,9 @@ bool StrNCmpInliner::inlineCompare(Value *LHS, StringRef RHS, uint64_t N,
10561055
SplitBlock(BBCI, CI, DTU, nullptr, nullptr, BBCI->getName() + ".tail");
10571056

10581057
SmallVector<BasicBlock *> BBSubs;
1059-
for (uint64_t i = 0; i < N; ++i)
1060-
BBSubs.push_back(BasicBlock::Create(Ctx, "sub_" + std::to_string(i),
1061-
BBCI->getParent(), BBTail));
1058+
for (uint64_t I = 0; I < N; ++I)
1059+
BBSubs.push_back(
1060+
BasicBlock::Create(Ctx, "sub_" + Twine(I), BBCI->getParent(), BBTail));
10621061
BasicBlock *BBNE = BasicBlock::Create(Ctx, "ne", BBCI->getParent(), BBTail);
10631062

10641063
cast<BranchInst>(BBCI->getTerminator())->setSuccessor(0, BBSubs[0]);
@@ -1100,11 +1099,10 @@ bool StrNCmpInliner::inlineCompare(Value *LHS, StringRef RHS, uint64_t N,
11001099
Updates.push_back({DominatorTree::Delete, BBCI, BBTail});
11011100
DTU->applyUpdates(Updates);
11021101
}
1103-
return true;
11041102
}
11051103

11061104
static bool foldLibCalls(Instruction &I, TargetTransformInfo &TTI,
1107-
TargetLibraryInfo &TLI, llvm::AssumptionCache &AC,
1105+
TargetLibraryInfo &TLI, AssumptionCache &AC,
11081106
DominatorTree &DT, const DataLayout &DL,
11091107
bool &MadeCFGChange) {
11101108

llvm/test/Transforms/AggressiveInstCombine/strncmp-1.ll

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2-
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=3 < %s | FileCheck %s
2+
; RUN: opt -S -passes=aggressive-instcombine < %s | FileCheck %s
33

44
; check whether we generate the right IR
55

@@ -9,9 +9,9 @@ declare i32 @strcmp(ptr nocapture, ptr nocapture)
99
@s2 = constant [2 x i8] c"a\00"
1010
@s3 = constant [3 x i8] c"ab\00"
1111

12-
define i1 @test_strncmp_1(ptr nocapture readonly %s) {
12+
define i1 @test_strncmp_1(ptr %s) {
1313
; CHECK-LABEL: define i1 @test_strncmp_1(
14-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
14+
; CHECK-SAME: ptr [[S:%.*]]) {
1515
; CHECK-NEXT: entry:
1616
; CHECK-NEXT: br label [[SUB:%.*]]
1717
; CHECK: sub_0:
@@ -39,9 +39,9 @@ entry:
3939
ret i1 %cmp
4040
}
4141

42-
define i1 @test_strncmp_2(ptr nocapture readonly %s) {
42+
define i1 @test_strncmp_2(ptr %s) {
4343
; CHECK-LABEL: define i1 @test_strncmp_2(
44-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
44+
; CHECK-SAME: ptr [[S:%.*]]) {
4545
; CHECK-NEXT: entry:
4646
; CHECK-NEXT: br label [[SUB:%.*]]
4747
; CHECK: sub_0:
@@ -76,9 +76,9 @@ entry:
7676
ret i1 %cmp
7777
}
7878

79-
define i1 @test_strncmp_3(ptr nocapture readonly %s) {
79+
define i1 @test_strncmp_3(ptr %s) {
8080
; CHECK-LABEL: define i1 @test_strncmp_3(
81-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
81+
; CHECK-SAME: ptr [[S:%.*]]) {
8282
; CHECK-NEXT: entry:
8383
; CHECK-NEXT: br label [[SUB:%.*]]
8484
; CHECK: sub_0:
@@ -113,9 +113,9 @@ entry:
113113
ret i1 %cmp
114114
}
115115

116-
define i1 @test_strcmp_1(ptr nocapture readonly %s) {
116+
define i1 @test_strcmp_1(ptr %s) {
117117
; CHECK-LABEL: define i1 @test_strcmp_1(
118-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
118+
; CHECK-SAME: ptr [[S:%.*]]) {
119119
; CHECK-NEXT: entry:
120120
; CHECK-NEXT: br label [[SUB:%.*]]
121121
; CHECK: sub_0:
@@ -142,9 +142,9 @@ entry:
142142
ret i1 %cmp
143143
}
144144

145-
define i1 @test_strcmp_2(ptr nocapture readonly %s) {
145+
define i1 @test_strcmp_2(ptr %s) {
146146
; CHECK-LABEL: define i1 @test_strcmp_2(
147-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
147+
; CHECK-SAME: ptr [[S:%.*]]) {
148148
; CHECK-NEXT: entry:
149149
; CHECK-NEXT: br label [[SUB:%.*]]
150150
; CHECK: sub_0:
@@ -178,9 +178,9 @@ entry:
178178
ret i1 %cmp
179179
}
180180

181-
define i1 @test_strcmp_3(ptr nocapture readonly %s) {
181+
define i1 @test_strcmp_3(ptr %s) {
182182
; CHECK-LABEL: define i1 @test_strcmp_3(
183-
; CHECK-SAME: ptr nocapture readonly [[S:%.*]]) {
183+
; CHECK-SAME: ptr [[S:%.*]]) {
184184
; CHECK-NEXT: entry:
185185
; CHECK-NEXT: br label [[SUB:%.*]]
186186
; CHECK: sub_0:
Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=3 < %s | FileCheck %s
2-
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=2 < %s | FileCheck --check-prefix TH-2 %s
3-
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=1 < %s | FileCheck --check-prefix TH-1 %s
4-
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=0 < %s | FileCheck --check-prefix TH-0 %s
1+
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=3 < %s | FileCheck --check-prefixes=CHECK,TH-3 %s
2+
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=2 < %s | FileCheck --check-prefixes=CHECK,TH-2 %s
3+
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=1 < %s | FileCheck --check-prefixes=CHECK,TH-1 %s
4+
; RUN: opt -S -passes=aggressive-instcombine -strncmp-inline-threshold=0 < %s | FileCheck --check-prefixes=CHECK,TH-0 %s
55

66
declare i32 @strcmp(ptr nocapture, ptr nocapture)
77
declare i32 @strncmp(ptr nocapture, ptr nocapture, i64)
@@ -12,152 +12,136 @@ declare i32 @strncmp(ptr nocapture, ptr nocapture, i64)
1212
@s4 = constant [4 x i8] c"aab\00", align 1
1313

1414
; strncmp(s, "aa", 1)
15-
define i1 @test_strncmp_0(i8* nocapture readonly %s) {
15+
define i1 @test_strncmp_0(i8* %s) {
1616
entry:
1717
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3, i64 1)
1818
%cmp = icmp eq i32 %call, 0
1919
ret i1 %cmp
2020
}
2121
; CHECK-LABEL: @test_strncmp_0(
22-
; CHECK: @strncmp
22+
; TH-3: @strncmp
2323

2424
; strncmp(s, "aa", 2)
25-
define i1 @test_strncmp_1(i8* nocapture readonly %s) {
25+
define i1 @test_strncmp_1(i8* %s) {
2626
entry:
2727
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3, i64 2)
2828
%cmp = icmp eq i32 %call, 0
2929
ret i1 %cmp
3030
}
3131
; CHECK-LABEL: @test_strncmp_1(
32-
; CHECK-NOT: @strncmp
33-
34-
; TH-2-LABEL: @test_strncmp_1(
32+
; TH-3-NOT: @strncmp
3533
; TH-2-NOT: @strncmp
36-
; TH-1-LABEL: @test_strncmp_1(
3734
; TH-1: @strncmp
38-
; TH-0-LABEL: @test_strncmp_1(
3935
; TH-0: @strncmp
4036

41-
define i1 @test_strncmp_1_dereferenceable(i8* nocapture readonly dereferenceable(2) %s) {
37+
define i1 @test_strncmp_1_dereferenceable(i8* dereferenceable(2) %s) {
4238
entry:
4339
%call = tail call i32 @strncmp(ptr nonnull %s, ptr nonnull dereferenceable(3) @s3, i64 2)
4440
%cmp = icmp eq i32 %call, 0
4541
ret i1 %cmp
4642
}
4743
; CHECK-LABEL: @test_strncmp_1_dereferenceable(
48-
; CHECK: @strncmp
49-
50-
; TH-2-LABEL: @test_strncmp_1_dereferenceable(
51-
; TH-1-LABEL: @test_strncmp_1_dereferenceable(
52-
; TH-0-LABEL: @test_strncmp_1_dereferenceable(
44+
; TH-3: @strncmp
5345

54-
define i32 @test_strncmp_1_not_comparision(i8* nocapture readonly %s) {
46+
define i32 @test_strncmp_1_not_comparision(i8* %s) {
5547
entry:
5648
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3, i64 2)
5749
ret i32 %call
5850
}
5951
; CHECK-LABEL: @test_strncmp_1_not_comparision(
60-
; CHECK: @strncmp
52+
; TH-3: @strncmp
6153

6254
; strncmp(s, "aa", 3)
63-
define i1 @test_strncmp_2(i8* nocapture readonly %s) {
55+
define i1 @test_strncmp_2(i8* %s) {
6456
entry:
6557
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3, i64 3)
6658
%cmp = icmp eq i32 %call, 0
6759
ret i1 %cmp
6860
}
6961
; CHECK-LABEL: @test_strncmp_2(
70-
; CHECK-NOT: @strncmp
71-
72-
; TH-2-LABEL: @test_strncmp_2(
62+
; TH-3-NOT: @strncmp
7363
; TH-2: @strncmp
74-
; TH-1-LABEL: @test_strncmp_2(
7564
; TH-1: @strncmp
76-
; TH-0-LABEL: @test_strncmp_2(
7765
; TH-0: @strncmp
7866

7967
; strncmp(s, "aab", 3)
80-
define i1 @test_strncmp_3(i8* nocapture readonly %s) {
68+
define i1 @test_strncmp_3(i8* %s) {
8169
entry:
8270
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(4) @s4, i64 3)
8371
%cmp = icmp eq i32 %call, 0
8472
ret i1 %cmp
8573
}
8674
; CHECK-LABEL: @test_strncmp_3(
87-
; CHECK-NOT: @strncmp
88-
89-
; TH-2-LABEL: @test_strncmp_3(
90-
; TH-1-LABEL: @test_strncmp_3(
91-
; TH-0-LABEL: @test_strncmp_3(
75+
; TH-3-NOT: @strncmp
9276

9377
; strncmp(s, "aab", 4)
94-
define i1 @test_strncmp_4(i8* nocapture readonly %s) {
78+
define i1 @test_strncmp_4(i8* %s) {
9579
entry:
9680
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(4) @s4, i64 4)
9781
%cmp = icmp eq i32 %call, 0
9882
ret i1 %cmp
9983
}
10084
; CHECK-LABEL: @test_strncmp_4(
101-
; CHECK: @strncmp
85+
; TH-3: @strncmp
10286

10387
; strncmp(s, "aa", 2)
104-
define i1 @test_strncmp_5(i8* nocapture readonly %s) {
88+
define i1 @test_strncmp_5(i8* %s) {
10589
entry:
10690
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3, i64 2)
10791
%cmp = icmp eq i32 %call, 0
10892
ret i1 %cmp
10993
}
11094
; CHECK-LABEL: @test_strncmp_5(
111-
; CHECK-NOT: @strncmp
95+
; TH-3-NOT: @strncmp
11296

11397
; char s2[] = {'a', 'a'}
11498
; strncmp(s1, s2, 2)
115-
define i1 @test_strncmp_6(i8* nocapture readonly %s1) {
99+
define i1 @test_strncmp_6(i8* %s1) {
116100
entry:
117101
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s1, ptr nonnull dereferenceable(3) @s2n, i64 2)
118102
%cmp = icmp eq i32 %call, 0
119103
ret i1 %cmp
120104
}
121105
; CHECK-LABEL: @test_strncmp_6(
122-
; CHECK-NOT: @strncmp
106+
; TH-3-NOT: @strncmp
123107

124108
; char s2[] = {'a', 'a'}
125109
; strncmp(s1, s2, 3)
126-
define i1 @test_strncmp_7(i8* nocapture readonly %s1) {
110+
define i1 @test_strncmp_7(i8* %s1) {
127111
entry:
128112
%call = tail call i32 @strncmp(ptr nonnull dereferenceable(1) %s1, ptr nonnull dereferenceable(3) @s2n, i64 3)
129113
%cmp = icmp eq i32 %call, 0
130114
ret i1 %cmp
131115
}
132116
; CHECK-LABEL: @test_strncmp_7(
133-
; CHECK: @strncmp
117+
; TH-3: @strncmp
134118

135119
; strcmp(s, "")
136-
define i1 @test_strcmp_0(i8* nocapture readonly %s) {
120+
define i1 @test_strcmp_0(i8* %s) {
137121
entry:
138122
%call = tail call i32 @strcmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(1) @s1)
139123
%cmp = icmp eq i32 %call, 0
140124
ret i1 %cmp
141125
}
142126
; CHECK-LABEL: @test_strcmp_0(
143-
; CHECK: @strcmp
127+
; TH-3: @strcmp
144128

145129
; strcmp(s, "aa")
146-
define i1 @test_strcmp_1(i8* nocapture readonly %s) {
130+
define i1 @test_strcmp_1(i8* %s) {
147131
entry:
148132
%call = tail call i32 @strcmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(3) @s3)
149133
%cmp = icmp eq i32 %call, 0
150134
ret i1 %cmp
151135
}
152136
; CHECK-LABEL: @test_strcmp_1(
153-
; CHECK-NOT: @strcmp
137+
; TH-3-NOT: @strcmp
154138

155139
; strcmp(s, "aab")
156-
define i1 @test_strcmp_2(i8* nocapture readonly %s) {
140+
define i1 @test_strcmp_2(i8* %s) {
157141
entry:
158142
%call = tail call i32 @strcmp(ptr nonnull dereferenceable(1) %s, ptr nonnull dereferenceable(4) @s4)
159143
%cmp = icmp eq i32 %call, 0
160144
ret i1 %cmp
161145
}
162146
; CHECK-LABEL: @test_strcmp_2(
163-
; CHECK: @strcmp
147+
; TH-3: @strcmp

0 commit comments

Comments
 (0)