3
3
4
4
int getNum (void ); // Get an opaque number.
5
5
6
- void clang_analyzer_numTimesReached (void );
7
6
void clang_analyzer_dump (int arg );
8
7
9
8
//-----------------------------------------------------------------------------
10
- // Simple case: inlined function never reaches `analyzer-max-loop`.
9
+ // Simple case: inlined function never reaches `analyzer-max-loop`, so it is
10
+ // always inlined.
11
11
12
- int inner_simple (void ) {
13
- clang_analyzer_numTimesReached (); // expected-warning {{2}}
12
+ int inner_simple (int callIdx ) {
13
+ clang_analyzer_dump (callIdx ); // expected-warning {{1 S32}}
14
+ // expected-warning@-1 {{2 S32}}
14
15
return 42 ;
15
16
}
16
17
17
18
int outer_simple (void ) {
18
- int x = inner_simple ();
19
- int y = inner_simple ();
19
+ int x = inner_simple (1 );
20
+ int y = inner_simple (2 );
20
21
return 53 / (x - y ); // expected-warning {{Division by zero}}
21
22
}
22
23
23
24
//-----------------------------------------------------------------------------
24
- // Inlined function always reaches `analyzer-max-loop`.
25
+ // Inlined function always reaches `analyzer-max-loop`, which stops the
26
+ // analysis on that path and puts the function on the "do not inline" list.
25
27
26
- int inner_fixed_loop_1 (void ) {
28
+ int inner_fixed_loop_1 (int callIdx ) {
27
29
int i ;
28
- clang_analyzer_numTimesReached ( ); // expected-warning {{1}}
30
+ clang_analyzer_dump ( callIdx ); // expected-warning {{1 S32 }}
29
31
for (i = 0 ; i < 10 ; i ++ );
30
- clang_analyzer_numTimesReached ( ); // no-warning
32
+ clang_analyzer_dump ( callIdx ); // no-warning
31
33
return 42 ;
32
34
}
33
35
34
36
int outer_fixed_loop_1 (void ) {
35
- int x = inner_fixed_loop_1 ();
36
- int y = inner_fixed_loop_1 ();
37
+ int x = inner_fixed_loop_1 (1 );
38
+ int y = inner_fixed_loop_1 (2 );
37
39
return 53 / (x - y ); // no-warning
38
40
}
39
41
40
42
//-----------------------------------------------------------------------------
41
43
// Inlined function always reaches `analyzer-max-loop`; inlining is prevented
42
44
// even for different entry points.
43
- // This test uses `clang_analyzer_dump` and distinct `arg` values because
44
- // `clang_analyzer_numTimesReached` only counts the paths reaching that node
45
- // during the analysis of one particular entry point, so it cannot distinguish
46
- // "two entry points reached this, both with one path" (where the two reports
47
- // are unified as duplicates by the generic report postprocessing) and "one
48
- // entry point reached this with one path" (where naturally nothing shows that
49
- // the second entry point _tried_ to reach it).
50
-
51
- int inner_fixed_loop_2 (int arg ) {
45
+ // NOTE: the analyzer happens to analyze the entry points in a reversed order,
46
+ // so `outer_2_fixed_loop_2` is analyzed first and it will be the one which is
47
+ // able to inline the inner function.
48
+
49
+ int inner_fixed_loop_2 (int callIdx ) {
52
50
// Identical copy of inner_fixed_loop_1
53
51
int i ;
54
- clang_analyzer_dump (arg ); // expected-warning {{2}}
52
+ clang_analyzer_dump (callIdx ); // expected-warning {{2 S32 }}
55
53
for (i = 0 ; i < 10 ; i ++ );
56
- clang_analyzer_dump (arg ); // no-warning
54
+ clang_analyzer_dump (callIdx ); // no-warning
57
55
return 42 ;
58
56
}
59
57
@@ -72,9 +70,10 @@ int outer_2_fixed_loop_2(void) {
72
70
73
71
int inner_parametrized_loop_1 (int count ) {
74
72
int i ;
75
- clang_analyzer_numTimesReached (); // expected-warning {{2}}
73
+ clang_analyzer_dump (count ); // expected-warning {{2 S32}}
74
+ // expected-warning@-1 {{10 S32}}
76
75
for (i = 0 ; i < count ; i ++ );
77
- clang_analyzer_numTimesReached ( ); // expected-warning {{1 }}
76
+ clang_analyzer_dump ( count ); // expected-warning {{2 S32 }}
78
77
return 42 ;
79
78
}
80
79
@@ -90,9 +89,9 @@ int outer_parametrized_loop_1(void) {
90
89
91
90
int inner_parametrized_loop_2 (int count ) {
92
91
int i ;
93
- clang_analyzer_numTimesReached ( ); // expected-warning {{1 }}
92
+ clang_analyzer_dump ( count ); // expected-warning {{10 S32 }}
94
93
for (i = 0 ; i < count ; i ++ );
95
- clang_analyzer_numTimesReached ( ); // no-warning
94
+ clang_analyzer_dump ( count ); // no-warning
96
95
return 42 ;
97
96
}
98
97
@@ -108,23 +107,28 @@ int outer_parametrized_loop_2(void) {
108
107
// cases: the function is placed on the "don't inline" list when any execution
109
108
// path reaches `analyzer-max-loop` (even if other execution paths reach the
110
109
// end of the function).
110
+ // NOTE: This is tested with two separate entry points to ensure that one
111
+ // inlined call is fully evaluated before we try to inline the other call.
112
+ // NOTE: the analyzer happens to analyze the entry points in a reversed order,
113
+ // so `outer_2_conditional_loop` is analyzed first and it will be the one which
114
+ // is able to inline the inner function.
111
115
112
- int inner_conditional_loop (void ) {
116
+ int inner_conditional_loop (int callIdx ) {
113
117
int i ;
114
- clang_analyzer_numTimesReached ( ); // expected-warning {{1 }}
118
+ clang_analyzer_dump ( callIdx ); // expected-warning {{2 S32 }}
115
119
if (getNum () == 777 ) {
116
120
for (i = 0 ; i < 10 ; i ++ );
117
121
}
118
- clang_analyzer_numTimesReached ( ); // expected-warning {{1 }}
122
+ clang_analyzer_dump ( callIdx ); // expected-warning {{2 S32 }}
119
123
return 42 ;
120
124
}
121
125
122
126
int outer_1_conditional_loop (void ) {
123
- return inner_conditional_loop ();
127
+ return inner_conditional_loop (1 );
124
128
}
125
129
126
130
int outer_2_conditional_loop (void ) {
127
- return inner_conditional_loop ();
131
+ return inner_conditional_loop (2 );
128
132
}
129
133
130
134
//-----------------------------------------------------------------------------
@@ -142,57 +146,24 @@ int outer_2_conditional_loop(void) {
142
146
// option `legacy-inlining-prevention` was introduced and enabled by default to
143
147
// suppress the inlining in situations where the "don't assume third iteration"
144
148
// logic activates.
145
- // This testcase demonstrate that the inlining is prevented with the default
146
- // `legacy-inlining-prevention=true` config, but is not prevented when this
147
- // option is disabled (set to false).
148
-
149
- int inner_opaque_loop_1 (void ) {
150
- int i ;
151
- clang_analyzer_numTimesReached (); // default-warning {{1}} disabled-warning {{2}}
152
- for (i = 0 ; i < getNum (); i ++ );
153
- return i ;
154
- }
149
+ // NOTE: This is tested with two separate entry points to ensure that one
150
+ // inlined call is fully evaluated before we try to inline the other call.
151
+ // NOTE: the analyzer happens to analyze the entry points in a reversed order,
152
+ // so `outer_2_opaque_loop` is analyzed first and it will be the one which is
153
+ // able to inline the inner function.
155
154
156
- int outer_opaque_loop_1 (void ) {
157
- int iterCount = inner_opaque_loop_1 ();
158
-
159
- // The first call to `inner_opaque_loop_1()` splits three execution paths that
160
- // differ in the number of performed iterations (0, 1 or 2). The function
161
- // `inner_opaque_loop_1` is added to the "do not inline this" list when the
162
- // path that performed two iterations tries to enter the third iteration (and
163
- // the "don't assume third iteration" logic prevents this) -- but the other
164
- // two paths (which performed 0 and 1 iterations) would reach and inline the
165
- // second `inner_opaque_loop_1()` before this would happen (because the
166
- // default traversal is a complex heuristic that happens to prefer this). The
167
- // following `if` will discard these "early exit" paths to highlight the
168
- // difference between the default and disabled state:
169
- if (iterCount < 2 )
170
- return 0 ;
171
-
172
- return inner_opaque_loop_1 ();
173
- }
174
-
175
- //-----------------------------------------------------------------------------
176
- // Another less contrived testcase that demonstrates the difference between the
177
- // enabled (default) and disabled state of `legacy-inlining-prevention`.
178
- // Here the two calls to `inner_opaque_loop_2()` are in different entry points
179
- // so the first call is fully analyzed (and can put the function on the "do
180
- // not inline" list) before reaching the second call.
181
- // This test uses `clang_analyzer_dump` because (as explained in an earlier
182
- // comment block) `clang_analyzer_numTimesReached` is not suitable for counting
183
- // visits from separate entry points.
184
-
185
- int inner_opaque_loop_2 (int arg ) {
155
+ int inner_opaque_loop (int callIdx ) {
186
156
int i ;
187
- clang_analyzer_dump (arg ); // default-warning {{2}}
188
- // disabled-warning@-1 {{1}} disabled-warning@-1 {{2}}
157
+ clang_analyzer_dump (callIdx ); // default-warning {{2 S32}}
158
+ // disabled-warning@-1 {{1 S32}}
159
+ // disabled-warning@-2 {{2 S32}}
189
160
for (i = 0 ; i < getNum (); i ++ );
190
161
return i ;
191
162
}
192
163
193
- int outer_1_opaque_loop_2 (void ) {
194
- return inner_opaque_loop_2 (1 );
164
+ int outer_1_opaque_loop (void ) {
165
+ return inner_opaque_loop (1 );
195
166
}
196
167
int outer_2_opaque_loop (void ) {
197
- return inner_opaque_loop_2 (2 );
168
+ return inner_opaque_loop (2 );
198
169
}
0 commit comments