aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/Scalar/SCCP.cpp50
-rw-r--r--test/Transforms/SCCP/ipsccp-basic.ll20
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
+}
+
+