From 8cf8d64d1989526f66185d8752b6142ac4fadd31 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Sun, 18 Dec 2011 20:35:43 +0000 Subject: [PATCH] Allow inlining of functions with returns_twice calls, if they have the attribute themselve. llvm-svn: 146851 --- include/llvm/Analysis/CodeMetrics.h | 7 ++-- include/llvm/CodeGen/MachineFunction.h | 26 +++++++----- lib/Analysis/InlineCost.cpp | 14 ++++--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 2 +- lib/CodeGen/StackSlotColoring.cpp | 2 +- .../Transforms/Inline/inline_returns_twice.ll | 41 +++++++++++++++++++ 6 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 test/Transforms/Inline/inline_returns_twice.ll diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h index 5f78021f3d2..c01507f0a92 100644 --- a/include/llvm/Analysis/CodeMetrics.h +++ b/include/llvm/Analysis/CodeMetrics.h @@ -31,8 +31,9 @@ namespace llvm { /// caller. // bool NeverInline; - // True if this function contains a call to setjmp or _setjmp - bool callsSetJmp; + // True if this function contains a call to setjmp or other functions + // with attribute "returns twice" without having the attribute by itself. + bool exposesReturnsTwice; // True if this function calls itself bool isRecursive; @@ -66,7 +67,7 @@ namespace llvm { /// NumRets - Keep track of how many Ret instructions the block contains. unsigned NumRets; - CodeMetrics() : callsSetJmp(false), isRecursive(false), + CodeMetrics() : exposesReturnsTwice(false), isRecursive(false), containsIndirectBr(false), usesDynamicAlloca(false), NumInsts(0), NumBlocks(0), NumCalls(0), NumInlineCandidates(0), NumVectorInsts(0), diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 3a4568a59dc..fd4cac8c12e 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -120,10 +120,12 @@ class MachineFunction { /// Alignment - The alignment of the function. unsigned Alignment; - /// CallsSetJmp - True if the function calls setjmp or sigsetjmp. This is used - /// to limit optimizations which cannot reason about the control flow of - /// setjmp. - bool CallsSetJmp; + /// ExposesReturnsTwice - True if the function calls setjmp or related + /// functions with attribute "returns twice", but doesn't have + /// the attribute itself. + /// This is used to limit optimizations which cannot reason + /// about the control flow of such functions. + bool ExposesReturnsTwice; MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT void operator=(const MachineFunction&); // DO NOT IMPLEMENT @@ -192,15 +194,17 @@ public: if (Alignment < A) Alignment = A; } - /// callsSetJmp - Returns true if the function calls setjmp or sigsetjmp. - bool callsSetJmp() const { - return CallsSetJmp; + /// exposesReturnsTwice - Returns true if the function calls setjmp or + /// any other similar functions with attribute "returns twice" without + /// having the attribute itself. + bool exposesReturnsTwice() const { + return ExposesReturnsTwice; } - /// setCallsSetJmp - Set a flag that indicates if there's a call to setjmp or - /// sigsetjmp. - void setCallsSetJmp(bool B) { - CallsSetJmp = B; + /// setCallsSetJmp - Set a flag that indicates if there's a call to + /// a "returns twice" function. + void setExposesReturnsTwice(bool B) { + ExposesReturnsTwice = B; } /// getInfo - Keep track of various per-function pieces of information for diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 1f332e84e6e..7f0b0cc3bf1 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -232,10 +232,12 @@ unsigned CodeMetrics::CountCodeReductionForAlloca(Value *V) { /// from the specified function. void CodeMetrics::analyzeFunction(Function *F, const TargetData *TD) { // If this function contains a call that "returns twice" (e.g., setjmp or - // _setjmp), never inline it. This is a hack because we depend on the user - // marking their local variables as volatile if they are live across a setjmp - // call, and they probably won't do this in callers. - callsSetJmp = F->callsFunctionThatReturnsTwice(); + // _setjmp) and it isn't marked with "returns twice" itself, never inline it. + // This is a hack because we depend on the user marking their local variables + // as volatile if they are live across a setjmp call, and they probably + // won't do this in callers. + exposesReturnsTwice = F->callsFunctionThatReturnsTwice() && + !F->hasFnAttr(Attribute::ReturnsTwice); // Look at the size of the callee. for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) @@ -265,7 +267,7 @@ void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F, /// NeverInline - returns true if the function should never be inlined into /// any caller bool InlineCostAnalyzer::FunctionInfo::NeverInline() { - return (Metrics.callsSetJmp || Metrics.isRecursive || + return (Metrics.exposesReturnsTwice || Metrics.isRecursive || Metrics.containsIndirectBr); } // getSpecializationBonus - The heuristic used to determine the per-call @@ -634,7 +636,7 @@ InlineCostAnalyzer::growCachedCostInfo(Function *Caller, Function *Callee) { // FIXME: If any of these three are true for the callee, the callee was // not inlined into the caller, so I think they're redundant here. - CallerMetrics.callsSetJmp |= CalleeMetrics.callsSetJmp; + CallerMetrics.exposesReturnsTwice |= CalleeMetrics.exposesReturnsTwice; CallerMetrics.isRecursive |= CalleeMetrics.isRecursive; CallerMetrics.containsIndirectBr |= CalleeMetrics.containsIndirectBr; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 3c950595b6d..aa6ef673571 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -452,7 +452,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { } // Determine if there is a call to setjmp in the machine function. - MF->setCallsSetJmp(Fn.callsFunctionThatReturnsTwice()); + MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice()); // Replace forward-declared registers with the registers containing // the desired value. diff --git a/lib/CodeGen/StackSlotColoring.cpp b/lib/CodeGen/StackSlotColoring.cpp index f8177a228ce..ae3fa2acb79 100644 --- a/lib/CodeGen/StackSlotColoring.cpp +++ b/lib/CodeGen/StackSlotColoring.cpp @@ -426,7 +426,7 @@ bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) { // coloring. The stack could be modified before the longjmp is executed, // resulting in the wrong value being used afterwards. (See // .) - if (MF.callsSetJmp()) + if (MF.exposesReturnsTwice()) return false; // Gather spill slot references diff --git a/test/Transforms/Inline/inline_returns_twice.ll b/test/Transforms/Inline/inline_returns_twice.ll new file mode 100644 index 00000000000..ab2e954af15 --- /dev/null +++ b/test/Transforms/Inline/inline_returns_twice.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -inline -S | FileCheck %s + +; Check that functions with "returns_twice" calls are only inlined, +; if they are themselve marked as such. + +declare i32 @a() returns_twice +declare i32 @b() returns_twice + +define i32 @f() { +entry: + %call = call i32 @a() returns_twice + %add = add nsw i32 1, %call + ret i32 %add +} + +define i32 @g() { +entry: +; CHECK: define i32 @g +; CHECK: call i32 @f() +; CHECK-NOT: call i32 @a() + %call = call i32 @f() + %add = add nsw i32 1, %call + ret i32 %add +} + +define i32 @h() returns_twice { +entry: + %call = call i32 @b() returns_twice + %add = add nsw i32 1, %call + ret i32 %add +} + +define i32 @i() { +entry: +; CHECK: define i32 @i +; CHECK: call i32 @b() +; CHECK-NOT: call i32 @h() + %call = call i32 @h() returns_twice + %add = add nsw i32 1, %call + ret i32 %add +}