llvm.org GIT mirror llvm / 3470693
Allow inlining of functions with returns_twice calls, if they have the attribute themselve. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146851 91177308-0d34-0410-b5e6-96231b3b80d8 Joerg Sonnenberger 8 years ago
6 changed file(s) with 72 addition(s) and 24 deletion(s). Raw diff Collapse all Expand all
3030 /// caller.
3131 // bool NeverInline;
3232
33 // True if this function contains a call to setjmp or _setjmp
34 bool callsSetJmp;
33 // True if this function contains a call to setjmp or other functions
34 // with attribute "returns twice" without having the attribute by itself.
35 bool exposesReturnsTwice;
3536
3637 // True if this function calls itself
3738 bool isRecursive;
6566 /// NumRets - Keep track of how many Ret instructions the block contains.
6667 unsigned NumRets;
6768
68 CodeMetrics() : callsSetJmp(false), isRecursive(false),
69 CodeMetrics() : exposesReturnsTwice(false), isRecursive(false),
6970 containsIndirectBr(false), usesDynamicAlloca(false),
7071 NumInsts(0), NumBlocks(0), NumCalls(0),
7172 NumInlineCandidates(0), NumVectorInsts(0),
119119 /// Alignment - The alignment of the function.
120120 unsigned Alignment;
121121
122 /// CallsSetJmp - True if the function calls setjmp or sigsetjmp. This is used
123 /// to limit optimizations which cannot reason about the control flow of
124 /// setjmp.
125 bool CallsSetJmp;
122 /// ExposesReturnsTwice - True if the function calls setjmp or related
123 /// functions with attribute "returns twice", but doesn't have
124 /// the attribute itself.
125 /// This is used to limit optimizations which cannot reason
126 /// about the control flow of such functions.
127 bool ExposesReturnsTwice;
126128
127129 MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT
128130 void operator=(const MachineFunction&); // DO NOT IMPLEMENT
191193 if (Alignment < A) Alignment = A;
192194 }
193195
194 /// callsSetJmp - Returns true if the function calls setjmp or sigsetjmp.
195 bool callsSetJmp() const {
196 return CallsSetJmp;
197 }
198
199 /// setCallsSetJmp - Set a flag that indicates if there's a call to setjmp or
200 /// sigsetjmp.
201 void setCallsSetJmp(bool B) {
202 CallsSetJmp = B;
196 /// exposesReturnsTwice - Returns true if the function calls setjmp or
197 /// any other similar functions with attribute "returns twice" without
198 /// having the attribute itself.
199 bool exposesReturnsTwice() const {
200 return ExposesReturnsTwice;
201 }
202
203 /// setCallsSetJmp - Set a flag that indicates if there's a call to
204 /// a "returns twice" function.
205 void setExposesReturnsTwice(bool B) {
206 ExposesReturnsTwice = B;
203207 }
204208
205209 /// getInfo - Keep track of various per-function pieces of information for
231231 /// from the specified function.
232232 void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) {
233233 // If this function contains a call that "returns twice" (e.g., setjmp or
234 // _setjmp), never inline it. This is a hack because we depend on the user
235 // marking their local variables as volatile if they are live across a setjmp
236 // call, and they probably won't do this in callers.
237 callsSetJmp = F->callsFunctionThatReturnsTwice();
234 // _setjmp) and it isn't marked with "returns twice" itself, never inline it.
235 // This is a hack because we depend on the user marking their local variables
236 // as volatile if they are live across a setjmp call, and they probably
237 // won't do this in callers.
238 exposesReturnsTwice = F->callsFunctionThatReturnsTwice() &&
239 !F->hasFnAttr(Attribute::ReturnsTwice);
238240
239241 // Look at the size of the callee.
240242 for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
264266 /// NeverInline - returns true if the function should never be inlined into
265267 /// any caller
266268 bool InlineCostAnalyzer::FunctionInfo::NeverInline() {
267 return (Metrics.callsSetJmp || Metrics.isRecursive ||
269 return (Metrics.exposesReturnsTwice || Metrics.isRecursive ||
268270 Metrics.containsIndirectBr);
269271 }
270272 // getSpecializationBonus - The heuristic used to determine the per-call
633635
634636 // FIXME: If any of these three are true for the callee, the callee was
635637 // not inlined into the caller, so I think they're redundant here.
636 CallerMetrics.callsSetJmp |= CalleeMetrics.callsSetJmp;
638 CallerMetrics.exposesReturnsTwice |= CalleeMetrics.exposesReturnsTwice;
637639 CallerMetrics.isRecursive |= CalleeMetrics.isRecursive;
638640 CallerMetrics.containsIndirectBr |= CalleeMetrics.containsIndirectBr;
639641
451451 }
452452
453453 // Determine if there is a call to setjmp in the machine function.
454 MF->setCallsSetJmp(Fn.callsFunctionThatReturnsTwice());
454 MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice());
455455
456456 // Replace forward-declared registers with the registers containing
457457 // the desired value.
425425 // coloring. The stack could be modified before the longjmp is executed,
426426 // resulting in the wrong value being used afterwards. (See
427427 // .)
428 if (MF.callsSetJmp())
428 if (MF.exposesReturnsTwice())
429429 return false;
430430
431431 // Gather spill slot references
0 ; RUN: opt < %s -inline -S | FileCheck %s
1
2 ; Check that functions with "returns_twice" calls are only inlined,
3 ; if they are themselve marked as such.
4
5 declare i32 @a() returns_twice
6 declare i32 @b() returns_twice
7
8 define i32 @f() {
9 entry:
10 %call = call i32 @a() returns_twice
11 %add = add nsw i32 1, %call
12 ret i32 %add
13 }
14
15 define i32 @g() {
16 entry:
17 ; CHECK: define i32 @g
18 ; CHECK: call i32 @f()
19 ; CHECK-NOT: call i32 @a()
20 %call = call i32 @f()
21 %add = add nsw i32 1, %call
22 ret i32 %add
23 }
24
25 define i32 @h() returns_twice {
26 entry:
27 %call = call i32 @b() returns_twice
28 %add = add nsw i32 1, %call
29 ret i32 %add
30 }
31
32 define i32 @i() {
33 entry:
34 ; CHECK: define i32 @i
35 ; CHECK: call i32 @b()
36 ; CHECK-NOT: call i32 @h()
37 %call = call i32 @h() returns_twice
38 %add = add nsw i32 1, %call
39 ret i32 %add
40 }