diff options
-rw-r--r-- | lib/Transforms/Scalar/SCCP.cpp | 50 | ||||
-rw-r--r-- | test/Transforms/SCCP/ipsccp-basic.ll | 20 |
2 files changed, 51 insertions, 19 deletions
diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 2ee4bbc95b..15b5bb5bc4 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -174,6 +174,9 @@ class SCCPSolver : public InstVisitor<SCCPSolver> { /// that return multiple values. DenseMap<std::pair<Function*, unsigned>, LatticeVal> TrackedMultipleRetVals; + /// TrackingIncomingArguments - This is the set of functions that are + SmallPtrSet<Function*, 16> TrackingIncomingArguments; + /// The reason for two worklists is that overdefined is the lowest state /// on the lattice, and moving things to overdefined as fast as possible /// makes SCCP converge much faster. @@ -235,6 +238,10 @@ public: TrackedRetVals.insert(std::make_pair(F, LatticeVal())); } + void AddArgumentTrackedFunction(Function *F) { + TrackingIncomingArguments.insert(F); + } + /// Solve - Solve for constants and executable blocks. /// void Solve(); @@ -1190,6 +1197,27 @@ CallOverdefined: return markOverdefined(I); } + // If this is a local function that doesn't have its address taken, mark its + // entry block executable and merge in the actual arguments to the call into + // the formal arguments of the function. + if (!TrackingIncomingArguments.empty() && TrackingIncomingArguments.count(F)){ + MarkBlockExecutable(F->begin()); + + // Propagate information from this call site into the callee. + CallSite::arg_iterator CAI = CS.arg_begin(); + for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); + AI != E; ++AI, ++CAI) { + // If this argument is byval, and if the function is not readonly, there + // will be an implicit copy formed of the input aggregate. + if (AI->hasByValAttr() && !F->onlyReadsMemory()) { + markOverdefined(AI); + continue; + } + + mergeInValue(AI, getValueState(*CAI)); + } + } + // If this is a single/zero retval case, see if we're tracking the function. DenseMap<Function*, LatticeVal>::iterator TFRVI = TrackedRetVals.find(F); if (TFRVI != TrackedRetVals.end()) { @@ -1228,24 +1256,6 @@ CallOverdefined: // common path above. goto CallOverdefined; } - - // Finally, if this is the first call to the function hit, mark its entry - // block executable. - MarkBlockExecutable(F->begin()); - - // Propagate information from this call site into the callee. - CallSite::arg_iterator CAI = CS.arg_begin(); - for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); - AI != E; ++AI, ++CAI) { - // If this argument is byval, and if the function is not readonly, there - // will be an implicit copy formed of the input aggregate. - if (AI->hasByValAttr() && !F->onlyReadsMemory()) { - markOverdefined(AI); - continue; - } - - mergeInValue(AI, getValueState(*CAI)); - } } void SCCPSolver::Solve() { @@ -1656,8 +1666,10 @@ bool IPSCCP::runOnModule(Module &M) { // If this function only has direct calls that we can see, we can track its // arguments and return value aggressively, and can assume it is not called // unless we see evidence to the contrary. - if (F->hasLocalLinkage() && !AddressIsTaken(F)) + if (F->hasLocalLinkage() && !AddressIsTaken(F)) { + Solver.AddArgumentTrackedFunction(F); continue; + } // Assume the function is called. Solver.MarkBlockExecutable(F->begin()); diff --git a/test/Transforms/SCCP/ipsccp-basic.ll b/test/Transforms/SCCP/ipsccp-basic.ll index ec349e91d2..2442c56e01 100644 --- a/test/Transforms/SCCP/ipsccp-basic.ll +++ b/test/Transforms/SCCP/ipsccp-basic.ll @@ -174,4 +174,24 @@ define i32 @test7b() { ; CHECK-NEXT: ret i32 36 } +;;======================== test8 + + +define internal {} @test8a(i32 %A, i32* %P) { + store i32 %A, i32* %P + ret {} {} +; CHECK: @test8a +; CHECK-NEXT: store i32 5, +; CHECK-NEXT: ret +} + +define void @test8b(i32* %P) { + %X = call {} @test8a(i32 5, i32* %P) + ret void +; CHECK: define void @test8b +; CHECK-NEXT: call {} @test8a +; CHECK-NEXT: ret void +} + + |