Skip to content

Commit 6186971

Browse files
committedNov 14, 2017
[PGO] Detect more structural changes with the stable hash
Lifting from Bob Wilson's notes: The hash value that we compute and store in PGO profile data to detect out-of-date profiles does not include enough information. This means that many significant changes to the source will not cause compiler warnings about the profile being out of date, and worse, we may continue to use the outdated profile data to make bad optimization decisions. There is some tension here because some source changes won't affect PGO and we don't want to invalidate the profile unnecessarily. This patch adds a new hashing scheme which is more sensitive to loop nesting, conditions, and out-of-order control flow. Here are examples which show snippets which get the same hash under the current scheme, and different hashes under the new scheme: Loop Nesting Example -------------------- // Snippet 1 while (foo()) { while (bar()) {} } // Snippet 2 while (foo()) {} while (bar()) {} Condition Example ----------------- // Snippet 1 if (foo()) bar(); baz(); // Snippet 2 if (foo()) bar(); else baz(); Out-of-order Control Flow Example --------------------------------- // Snippet 1 while (foo()) { if (bar()) {} baz(); } // Snippet 2 while (foo()) { if (bar()) continue; baz(); } In each of these cases, it's useful to differentiate between the snippets because swapping their profiles gives bad optimization hints. The new hashing scheme considers some logical operators in an effort to detect more changes in conditions. This isn't a perfect scheme. E.g, it does not produce the same hash for these equivalent snippets: // Snippet 1 bool c = !a || b; if (d && e) {} // Snippet 2 bool f = d && e; bool c = !a || b; if (f) {} This would require an expensive data flow analysis. Short of that, the new hashing scheme looks reasonably complete, based on a scan over the statements we place counters on. Profiles which use the old version of the PGO hash remain valid and can be used without issue (there are tests in tree which check this). rdar://17068282 Differential Revision: https://reviews.llvm.org/D39446 llvm-svn: 318229
1 parent 865046f commit 6186971

19 files changed

+649
-64
lines changed
 

Diff for: ‎clang/lib/CodeGen/CodeGenPGO.cpp

+153-13
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ void CodeGenPGO::setFuncName(llvm::Function *Fn) {
4747
llvm::createPGOFuncNameMetadata(*Fn, FuncName);
4848
}
4949

50+
/// The version of the PGO hash algorithm.
51+
enum PGOHashVersion : unsigned {
52+
PGO_HASH_V1,
53+
PGO_HASH_V2,
54+
55+
// Keep this set to the latest hash version.
56+
PGO_HASH_LATEST = PGO_HASH_V2
57+
};
58+
5059
namespace {
5160
/// \brief Stable hasher for PGO region counters.
5261
///
@@ -61,6 +70,7 @@ namespace {
6170
class PGOHash {
6271
uint64_t Working;
6372
unsigned Count;
73+
PGOHashVersion HashVersion;
6474
llvm::MD5 MD5;
6575

6676
static const int NumBitsPerType = 6;
@@ -93,33 +103,63 @@ class PGOHash {
93103
BinaryOperatorLAnd,
94104
BinaryOperatorLOr,
95105
BinaryConditionalOperator,
106+
// The preceding values are available with PGO_HASH_V1.
107+
108+
EndOfScope,
109+
IfThenBranch,
110+
IfElseBranch,
111+
GotoStmt,
112+
IndirectGotoStmt,
113+
BreakStmt,
114+
ContinueStmt,
115+
ReturnStmt,
116+
ThrowExpr,
117+
UnaryOperatorLNot,
118+
BinaryOperatorLT,
119+
BinaryOperatorGT,
120+
BinaryOperatorLE,
121+
BinaryOperatorGE,
122+
BinaryOperatorEQ,
123+
BinaryOperatorNE,
124+
// The preceding values are available with PGO_HASH_V2.
96125

97126
// Keep this last. It's for the static assert that follows.
98127
LastHashType
99128
};
100129
static_assert(LastHashType <= TooBig, "Too many types in HashType");
101130

102-
// TODO: When this format changes, take in a version number here, and use the
103-
// old hash calculation for file formats that used the old hash.
104-
PGOHash() : Working(0), Count(0) {}
131+
PGOHash(PGOHashVersion HashVersion)
132+
: Working(0), Count(0), HashVersion(HashVersion), MD5() {}
105133
void combine(HashType Type);
106134
uint64_t finalize();
135+
PGOHashVersion getHashVersion() const { return HashVersion; }
107136
};
108137
const int PGOHash::NumBitsPerType;
109138
const unsigned PGOHash::NumTypesPerWord;
110139
const unsigned PGOHash::TooBig;
111140

141+
/// Get the PGO hash version used in the given indexed profile.
142+
static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader,
143+
CodeGenModule &CGM) {
144+
if (PGOReader->getVersion() <= 4)
145+
return PGO_HASH_V1;
146+
return PGO_HASH_V2;
147+
}
148+
112149
/// A RecursiveASTVisitor that fills a map of statements to PGO counters.
113150
struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
151+
using Base = RecursiveASTVisitor<MapRegionCounters>;
152+
114153
/// The next counter value to assign.
115154
unsigned NextCounter;
116155
/// The function hash.
117156
PGOHash Hash;
118157
/// The map of statements to counters.
119158
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
120159

121-
MapRegionCounters(llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
122-
: NextCounter(0), CounterMap(CounterMap) {}
160+
MapRegionCounters(PGOHashVersion HashVersion,
161+
llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
162+
: NextCounter(0), Hash(HashVersion), CounterMap(CounterMap) {}
123163

124164
// Blocks and lambdas are handled as separate functions, so we need not
125165
// traverse them in the parent context.
@@ -145,16 +185,66 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
145185
return true;
146186
}
147187

148-
bool VisitStmt(const Stmt *S) {
149-
auto Type = getHashType(S);
150-
if (Type == PGOHash::None)
151-
return true;
188+
/// If \p S gets a fresh counter, update the counter mappings. Return the
189+
/// V1 hash of \p S.
190+
PGOHash::HashType updateCounterMappings(Stmt *S) {
191+
auto Type = getHashType(PGO_HASH_V1, S);
192+
if (Type != PGOHash::None)
193+
CounterMap[S] = NextCounter++;
194+
return Type;
195+
}
152196

153-
CounterMap[S] = NextCounter++;
154-
Hash.combine(Type);
197+
/// Include \p S in the function hash.
198+
bool VisitStmt(Stmt *S) {
199+
auto Type = updateCounterMappings(S);
200+
if (Hash.getHashVersion() != PGO_HASH_V1)
201+
Type = getHashType(Hash.getHashVersion(), S);
202+
if (Type != PGOHash::None)
203+
Hash.combine(Type);
155204
return true;
156205
}
157-
PGOHash::HashType getHashType(const Stmt *S) {
206+
207+
bool TraverseIfStmt(IfStmt *If) {
208+
// If we used the V1 hash, use the default traversal.
209+
if (Hash.getHashVersion() == PGO_HASH_V1)
210+
return Base::TraverseIfStmt(If);
211+
212+
// Otherwise, keep track of which branch we're in while traversing.
213+
VisitStmt(If);
214+
for (Stmt *CS : If->children()) {
215+
if (!CS)
216+
continue;
217+
if (CS == If->getThen())
218+
Hash.combine(PGOHash::IfThenBranch);
219+
else if (CS == If->getElse())
220+
Hash.combine(PGOHash::IfElseBranch);
221+
TraverseStmt(CS);
222+
}
223+
Hash.combine(PGOHash::EndOfScope);
224+
return true;
225+
}
226+
227+
// If the statement type \p N is nestable, and its nesting impacts profile
228+
// stability, define a custom traversal which tracks the end of the statement
229+
// in the hash (provided we're not using the V1 hash).
230+
#define DEFINE_NESTABLE_TRAVERSAL(N) \
231+
bool Traverse##N(N *S) { \
232+
Base::Traverse##N(S); \
233+
if (Hash.getHashVersion() != PGO_HASH_V1) \
234+
Hash.combine(PGOHash::EndOfScope); \
235+
return true; \
236+
}
237+
238+
DEFINE_NESTABLE_TRAVERSAL(WhileStmt)
239+
DEFINE_NESTABLE_TRAVERSAL(DoStmt)
240+
DEFINE_NESTABLE_TRAVERSAL(ForStmt)
241+
DEFINE_NESTABLE_TRAVERSAL(CXXForRangeStmt)
242+
DEFINE_NESTABLE_TRAVERSAL(ObjCForCollectionStmt)
243+
DEFINE_NESTABLE_TRAVERSAL(CXXTryStmt)
244+
DEFINE_NESTABLE_TRAVERSAL(CXXCatchStmt)
245+
246+
/// Get version \p HashVersion of the PGO hash for \p S.
247+
PGOHash::HashType getHashType(PGOHashVersion HashVersion, const Stmt *S) {
158248
switch (S->getStmtClass()) {
159249
default:
160250
break;
@@ -192,9 +282,53 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
192282
return PGOHash::BinaryOperatorLAnd;
193283
if (BO->getOpcode() == BO_LOr)
194284
return PGOHash::BinaryOperatorLOr;
285+
if (HashVersion == PGO_HASH_V2) {
286+
switch (BO->getOpcode()) {
287+
default:
288+
break;
289+
case BO_LT:
290+
return PGOHash::BinaryOperatorLT;
291+
case BO_GT:
292+
return PGOHash::BinaryOperatorGT;
293+
case BO_LE:
294+
return PGOHash::BinaryOperatorLE;
295+
case BO_GE:
296+
return PGOHash::BinaryOperatorGE;
297+
case BO_EQ:
298+
return PGOHash::BinaryOperatorEQ;
299+
case BO_NE:
300+
return PGOHash::BinaryOperatorNE;
301+
}
302+
}
195303
break;
196304
}
197305
}
306+
307+
if (HashVersion == PGO_HASH_V2) {
308+
switch (S->getStmtClass()) {
309+
default:
310+
break;
311+
case Stmt::GotoStmtClass:
312+
return PGOHash::GotoStmt;
313+
case Stmt::IndirectGotoStmtClass:
314+
return PGOHash::IndirectGotoStmt;
315+
case Stmt::BreakStmtClass:
316+
return PGOHash::BreakStmt;
317+
case Stmt::ContinueStmtClass:
318+
return PGOHash::ContinueStmt;
319+
case Stmt::ReturnStmtClass:
320+
return PGOHash::ReturnStmt;
321+
case Stmt::CXXThrowExprClass:
322+
return PGOHash::ThrowExpr;
323+
case Stmt::UnaryOperatorClass: {
324+
const UnaryOperator *UO = cast<UnaryOperator>(S);
325+
if (UO->getOpcode() == UO_LNot)
326+
return PGOHash::UnaryOperatorLNot;
327+
break;
328+
}
329+
}
330+
}
331+
198332
return PGOHash::None;
199333
}
200334
};
@@ -653,8 +787,14 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
653787
}
654788

655789
void CodeGenPGO::mapRegionCounters(const Decl *D) {
790+
// Use the latest hash version when inserting instrumentation, but use the
791+
// version in the indexed profile if we're reading PGO data.
792+
PGOHashVersion HashVersion = PGO_HASH_LATEST;
793+
if (auto *PGOReader = CGM.getPGOReader())
794+
HashVersion = getPGOHashVersion(PGOReader, CGM);
795+
656796
RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
657-
MapRegionCounters Walker(*RegionCounterMap);
797+
MapRegionCounters Walker(HashVersion, *RegionCounterMap);
658798
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
659799
Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
660800
else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))

Diff for: ‎clang/test/Frontend/Inputs/optimization-remark-with-hotness.proftext

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
foo
22
# Func Hash:
3-
0
3+
24
44
# Num Counters:
55
1
66
# Counter Values:
@@ -16,7 +16,7 @@ bar
1616

1717
main
1818
# Func Hash:
19-
4
19+
1160280
2020
# Num Counters:
2121
2
2222
# Counter Values:

Diff for: ‎clang/test/Profile/Inputs/c-captured.proftext

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
c-captured.c:__captured_stmt
2-
10
2+
42129
33
2
44
1
55
1
66

77
c-captured.c:__captured_stmt.1
8-
266
8+
4752450705
99
3
1010
1
1111
10
1212
1
1313

1414
main
15-
0
15+
24
1616
1
1717
1
1818

1919
debug_captured
20-
650
20+
11043906705
2121
3
2222
1
2323
1

Diff for: ‎clang/test/Profile/Inputs/c-counter-overflows.proftext

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
main
2-
285734896137
2+
10111551811706059223
33
8
44
1
55
68719476720

Diff for: ‎clang/test/Profile/Inputs/c-general.proftext

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
simple_loops
2-
16515
2+
1245818015463121
33
4
44
1
55
100
66
100
77
75
88

99
conditionals
10-
74917022372782735
10+
4190663230902537370
1111
11
1212
1
1313
100
@@ -22,7 +22,7 @@ conditionals
2222
100
2323

2424
early_exits
25-
44128811889290
25+
8265526549255474475
2626
9
2727
1
2828
0
@@ -35,7 +35,7 @@ early_exits
3535
0
3636

3737
jumps
38-
2016037664281362839
38+
15872630527555456493
3939
22
4040
1
4141
1
@@ -61,7 +61,7 @@ jumps
6161
9
6262

6363
switches
64-
2745195701975551402
64+
11892326508727782373
6565
19
6666
1
6767
1
@@ -84,7 +84,7 @@ switches
8484
0
8585

8686
big_switch
87-
10218718452081869619
87+
16933280399284440835
8888
17
8989
1
9090
32
@@ -105,7 +105,7 @@ big_switch
105105
2
106106

107107
boolean_operators
108-
291222909838
108+
1245693242827665
109109
8
110110
1
111111
100
@@ -117,7 +117,7 @@ boolean_operators
117117
50
118118

119119
boolop_loops
120-
9760565944591
120+
11270260636676715317
121121
9
122122
1
123123
50
@@ -130,27 +130,27 @@ boolop_loops
130130
26
131131

132132
conditional_operator
133-
848
133+
54992
134134
3
135135
1
136136
0
137137
1
138138

139139
do_fallthrough
140-
16586
140+
6898770640283947069
141141
4
142142
1
143143
10
144144
2
145145
8
146146

147147
main
148-
0
148+
24
149149
1
150150
1
151151

152152
c-general.c:static_func
153-
4
153+
18129
154154
2
155155
1
156156
10

Diff for: ‎clang/test/Profile/Inputs/c-unprofiled-blocks.proftext

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
never_called
2-
44257542701577
2+
5644096560937528444
33
9
44
0
55
0
@@ -12,12 +12,12 @@ never_called
1212
0
1313

1414
main
15-
1
15+
24
1616
1
1717
1
1818

1919
dead_code
20-
2859007309808137
20+
9636018207904213947
2121
10
2222
1
2323
0

Diff for: ‎clang/test/Profile/Inputs/cxx-class.proftext

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
11
_Z14simple_wrapperv
2-
4
2+
18129
33
2
44
1
55
100
66

77
main
8-
0
8+
24
99
1
1010
1
1111

1212
_ZN6SimpleD1Ev
13-
10
13+
42129
1414
2
1515
0
1616
0
1717

1818
_ZN6SimpleD2Ev
19-
10
19+
42129
2020
2
2121
100
2222
99
2323

2424
_ZN6Simple6methodEv
25-
10
25+
42129
2626
2
2727
100
2828
99
2929

3030
_ZN6SimpleC1Ei
31-
10
31+
42129
3232
2
3333
0
3434
0
3535

3636
_ZN6SimpleC2Ei
37-
10
37+
42129
3838
2
3939
100
4040
99
4141

4242
_ZN7DerivedC1Ev
43-
10
43+
42129
4444
2
4545
100
4646
99
4747

4848
_ZN7DerivedD2Ev
49-
10
49+
42129
5050
2
5151
100
5252
99

Diff for: ‎clang/test/Profile/Inputs/cxx-hash-v2.profdata.v5

3.2 KB
Binary file not shown.

Diff for: ‎clang/test/Profile/Inputs/cxx-hash-v2.proftext

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
_Z11loop_returnv
2+
# Func Hash:
3+
1160721
4+
# Num Counters:
5+
2
6+
# Counter Values:
7+
0
8+
0
9+
10+
_Z10loop_breakv
11+
# Func Hash:
12+
1160593
13+
# Num Counters:
14+
2
15+
# Counter Values:
16+
0
17+
0
18+
19+
_Z8no_gotosv
20+
# Func Hash:
21+
1
22+
# Num Counters:
23+
2
24+
# Counter Values:
25+
0
26+
0
27+
28+
_Z13loop_continuev
29+
# Func Hash:
30+
1160657
31+
# Num Counters:
32+
2
33+
# Counter Values:
34+
0
35+
0
36+
37+
_Z18loop_after_if_elsev
38+
# Func Hash:
39+
11044458641
40+
# Num Counters:
41+
3
42+
# Counter Values:
43+
0
44+
0
45+
0
46+
47+
_Z21consecutive_try_catchv
48+
# Func Hash:
49+
49221687100497
50+
# Num Counters:
51+
5
52+
# Counter Values:
53+
0
54+
0
55+
0
56+
0
57+
0
58+
59+
_Z16nested_try_catchv
60+
# Func Hash:
61+
49147600487505
62+
# Num Counters:
63+
5
64+
# Counter Values:
65+
0
66+
0
67+
0
68+
0
69+
0
70+
71+
_Z13indirect_gotov
72+
# Func Hash:
73+
1345
74+
# Num Counters:
75+
2
76+
# Counter Values:
77+
0
78+
0
79+
80+
_Z17nested_for_rangesv
81+
# Func Hash:
82+
1332305
83+
# Num Counters:
84+
3
85+
# Counter Values:
86+
0
87+
0
88+
0
89+
90+
_Z18loop_in_then_blockv
91+
# Func Hash:
92+
11040003281
93+
# Num Counters:
94+
3
95+
# Counter Values:
96+
0
97+
0
98+
0
99+
100+
_Z22consecutive_for_rangesv
101+
# Func Hash:
102+
1380689
103+
# Num Counters:
104+
3
105+
# Counter Values:
106+
0
107+
0
108+
0
109+
110+
_Z15consecutive_dosv
111+
# Func Hash:
112+
856273
113+
# Num Counters:
114+
3
115+
# Counter Values:
116+
0
117+
0
118+
0
119+
120+
_Z11direct_gotov
121+
# Func Hash:
122+
1281
123+
# Num Counters:
124+
2
125+
# Counter Values:
126+
0
127+
0
128+
129+
main
130+
# Func Hash:
131+
24
132+
# Num Counters:
133+
1
134+
# Counter Values:
135+
1
136+
137+
_Z11double_lnotv
138+
# Func Hash:
139+
174695569
140+
# Num Counters:
141+
2
142+
# Counter Values:
143+
0
144+
0
145+
146+
_Z18if_inside_of_whilev
147+
# Func Hash:
148+
36250705
149+
# Num Counters:
150+
3
151+
# Counter Values:
152+
0
153+
0
154+
0
155+
156+
_Z11single_lnotv
157+
# Func Hash:
158+
2729105
159+
# Num Counters:
160+
2
161+
# Counter Values:
162+
0
163+
0
164+
165+
_Z19if_outside_of_whilev
166+
# Func Hash:
167+
38053009
168+
# Num Counters:
169+
3
170+
# Counter Values:
171+
0
172+
0
173+
0
174+
175+
_Z8no_throwv
176+
# Func Hash:
177+
0
178+
# Num Counters:
179+
1
180+
# Counter Values:
181+
0
182+
183+
_Z9has_throwv
184+
# Func Hash:
185+
25
186+
# Num Counters:
187+
1
188+
# Counter Values:
189+
0
190+
191+
_Z10nested_dosv
192+
# Func Hash:
193+
799825
194+
# Num Counters:
195+
3
196+
# Counter Values:
197+
0
198+
0
199+
0
200+
201+
_Z16if_inside_of_forv
202+
# Func Hash:
203+
4750648401
204+
# Num Counters:
205+
3
206+
# Counter Values:
207+
0
208+
0
209+
0
210+
211+
_Z18loop_in_else_blockv
212+
# Func Hash:
213+
11044398161
214+
# Num Counters:
215+
3
216+
# Counter Values:
217+
0
218+
0
219+
0
220+
221+
_Z17if_outside_of_forv
222+
# Func Hash:
223+
4752450705
224+
# Num Counters:
225+
3
226+
# Counter Values:
227+
0
228+
0
229+
0
230+
231+
_Z10loop_emptyv
232+
# Func Hash:
233+
18129
234+
# Num Counters:
235+
2
236+
# Counter Values:
237+
0
238+
0
239+

Diff for: ‎clang/test/Profile/Inputs/cxx-lambda.proftext

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
cxx-lambda.cpp:_ZZ7lambdasvENK3$_0clEi
2-
654
2+
11211970062
33
3
44
10
55
9
66
9
77

88
main
9-
0
9+
24
1010
1
1111
1
1212

1313
_Z7lambdasv
14-
41226
14+
2895087587861649
1515
4
1616
1
1717
1

Diff for: ‎clang/test/Profile/Inputs/cxx-rangefor.proftext

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
_Z9range_forv
2-
0x000000000014a28a
2+
6169071350249721981
33
5
44
1
55
4
@@ -8,6 +8,6 @@ _Z9range_forv
88
1
99

1010
main
11-
0
11+
24
1212
1
1313
1

Diff for: ‎clang/test/Profile/Inputs/cxx-templates.proftext

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
main
2-
0
2+
24
33
1
44
1
55

66
_Z4loopILj0EEvv
7-
4
7+
18129
88
2
99
1
1010
0
1111

1212
_Z4loopILj100EEvv
13-
4
13+
18129
1414
2
1515
1
1616
100

Diff for: ‎clang/test/Profile/Inputs/cxx-throws.proftext

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
_Z6throwsv
2-
18359008150154
2+
340120998528097520
33
9
44
1
55
100
@@ -12,14 +12,14 @@ _Z6throwsv
1212
100
1313

1414
_Z11unreachablei
15-
0x28a
15+
706946049169
1616
3
1717
1
1818
1
1919
0
2020

2121
main
22-
0x2cc
22+
187765848
2323
3
2424
1
2525
1

Diff for: ‎clang/test/Profile/Inputs/func-entry.proftext

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
foo
2-
0
2+
24
33
1
44
1000
55

66
main
7-
4
7+
1160280
88
2
99
1
1010
10000
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
main
2-
4
2+
1160280
33
2
44
1
55
100

Diff for: ‎clang/test/Profile/Inputs/objc-general.proftext

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
objc-general.m:__13+[A foreach:]_block_invoke
2-
10
2+
42129
33
2
44
2
55
1
66

77
objc-general.m:+[A foreach:]
8-
6
8+
401
99
2
1010
1
1111
2
1212

1313
main
14-
0
14+
24
1515
1
1616
1
1717

18+
consecutive_objc_for_ranges
19+
1642897
20+
3
21+
0
22+
0
23+
0
24+
25+
nested_objc_for_ranges
26+
1598545
27+
3
28+
0
29+
0
30+
0

Diff for: ‎clang/test/Profile/c-outdated-data.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING
88
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING
99

10-
// NO_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored
10+
// NO_MISSING: warning: profile data may be out of date: of 3 functions, 2 have mismatched data that will be ignored
1111
// NO_MISSING-NOT: 1 has no data
1212

13-
// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored
13+
// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 2 have mismatched data that will be ignored
1414
// WITH_MISSING: warning: profile data may be incomplete: of 3 functions, 1 has no data
1515

1616
void no_usable_data() {

Diff for: ‎clang/test/Profile/cxx-hash-v2.cpp

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// REQUIRES: shell
2+
3+
// Check that all of the hashes in this file are unique (i.e, that none of the
4+
// profiles for these functions are mutually interchangeable).
5+
//
6+
// RUN: llvm-profdata show -all-functions %S/Inputs/cxx-hash-v2.profdata.v5 | grep "Hash: 0x" | sort > %t.hashes
7+
// RUN: uniq %t.hashes > %t.hashes.unique
8+
// RUN: diff %t.hashes %t.hashes.unique
9+
10+
// RUN: llvm-profdata merge %S/Inputs/cxx-hash-v2.proftext -o %t.profdata
11+
// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -allow-empty
12+
// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%S/Inputs/cxx-hash-v2.profdata.v5 2>&1 | FileCheck %s -allow-empty
13+
14+
// CHECK-NOT: warning: profile data may be out of date
15+
16+
int x;
17+
int arr[1] = {0};
18+
19+
void loop_after_if_else() {
20+
if (1)
21+
x = 1;
22+
else
23+
x = 2;
24+
while (0)
25+
++x;
26+
}
27+
28+
void loop_in_then_block() {
29+
if (1) {
30+
while (0)
31+
++x;
32+
} else {
33+
x = 2;
34+
}
35+
}
36+
37+
void loop_in_else_block() {
38+
if (1) {
39+
x = 1;
40+
} else {
41+
while (0)
42+
++x;
43+
}
44+
}
45+
46+
void if_inside_of_for() {
47+
for (x = 0; x < 0; ++x) {
48+
x = 1;
49+
if (1)
50+
x = 2;
51+
}
52+
}
53+
54+
void if_outside_of_for() {
55+
for (x = 0; x < 0; ++x)
56+
x = 1;
57+
if (1)
58+
x = 2;
59+
}
60+
61+
void if_inside_of_while() {
62+
while (0) {
63+
x = 1;
64+
if (1)
65+
x = 2;
66+
}
67+
}
68+
69+
void if_outside_of_while() {
70+
while (0)
71+
x = 1;
72+
if (1)
73+
x = 2;
74+
}
75+
76+
void nested_dos() {
77+
do {
78+
do {
79+
++x;
80+
} while (0);
81+
} while (0);
82+
}
83+
84+
void consecutive_dos() {
85+
do {
86+
} while (0);
87+
do {
88+
++x;
89+
} while (0);
90+
}
91+
92+
void loop_empty() {
93+
for (x = 0; x < 5; ++x) {}
94+
}
95+
96+
void loop_return() {
97+
for (x = 0; x < 5; ++x)
98+
return;
99+
}
100+
101+
void loop_continue() {
102+
for (x = 0; x < 5; ++x)
103+
continue;
104+
}
105+
106+
void loop_break() {
107+
for (x = 0; x < 5; ++x)
108+
break;
109+
}
110+
111+
void no_gotos() {
112+
static void *dispatch[] = {&&done};
113+
x = 0;
114+
done:
115+
++x;
116+
}
117+
118+
void direct_goto() {
119+
static void *dispatch[] = {&&done};
120+
x = 0;
121+
goto done;
122+
done:
123+
++x;
124+
}
125+
126+
void indirect_goto() {
127+
static void *dispatch[] = {&&done};
128+
x = 0;
129+
goto *dispatch[x];
130+
done:
131+
++x;
132+
}
133+
134+
void nested_for_ranges() {
135+
for (int a : arr)
136+
for (int b : arr)
137+
++x;
138+
}
139+
140+
void consecutive_for_ranges() {
141+
for (int a : arr) {}
142+
for (int b : arr)
143+
++x;
144+
}
145+
146+
void nested_try_catch() {
147+
try {
148+
try {
149+
++x;
150+
} catch (...) {}
151+
} catch (...) {}
152+
}
153+
154+
void consecutive_try_catch() {
155+
try {} catch (...) {}
156+
try {
157+
++x;
158+
} catch (...) {}
159+
}
160+
161+
void no_throw() {}
162+
163+
void has_throw() {
164+
throw 0;
165+
}
166+
167+
void single_lnot() {
168+
if (!x) {}
169+
}
170+
171+
void double_lnot() {
172+
if (!!x) {}
173+
}
174+
175+
int main() {
176+
return 0;
177+
}

Diff for: ‎clang/test/Profile/objc-general.m

+17-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument=clang | FileCheck -check-prefix=PGOGEN %s
44

55
// RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata
6-
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata | FileCheck -check-prefix=PGOUSE %s
6+
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s
7+
8+
// PGOUSE-NOT: warning: profile data may be out of date
79

810
#ifdef HAVE_FOUNDATION
911

@@ -63,6 +65,20 @@ + (void)foreach: (NSArray *)array
6365
}
6466
@end
6567

68+
void nested_objc_for_ranges(NSArray *arr) {
69+
int x = 0;
70+
for (id a in arr)
71+
for (id b in arr)
72+
++x;
73+
}
74+
75+
void consecutive_objc_for_ranges(NSArray *arr) {
76+
int x = 0;
77+
for (id a in arr) {}
78+
for (id b in arr)
79+
++x;
80+
}
81+
6682
// PGOUSE-DAG: ![[FR1]] = !{!"branch_weights", i32 2, i32 3}
6783
// PGOUSE-DAG: ![[FR2]] = !{!"branch_weights", i32 3, i32 2}
6884
// PGOUSE-DAG: ![[BL1]] = !{!"branch_weights", i32 2, i32 2}

0 commit comments

Comments
 (0)
Please sign in to comment.