mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-05 18:49:06 +00:00
fix an IPSCCP bug I introduced when I changed IPSCCP to start working on
functions that don't have local linkage. Basically, we need to be more careful about propagating argument information to functions whose results we aren't tracking. This fixes a miscompilation of LLVMCConfigurationEmitter.cpp when built with an llvm-gcc that has ipsccp enabled. llvm-svn: 85923
This commit is contained in:
parent
d4b8f9ee93
commit
2aa5962af6
@ -174,6 +174,9 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
|
|||||||
/// that return multiple values.
|
/// that return multiple values.
|
||||||
DenseMap<std::pair<Function*, unsigned>, LatticeVal> TrackedMultipleRetVals;
|
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
|
/// The reason for two worklists is that overdefined is the lowest state
|
||||||
/// on the lattice, and moving things to overdefined as fast as possible
|
/// on the lattice, and moving things to overdefined as fast as possible
|
||||||
/// makes SCCP converge much faster.
|
/// makes SCCP converge much faster.
|
||||||
@ -235,6 +238,10 @@ public:
|
|||||||
TrackedRetVals.insert(std::make_pair(F, LatticeVal()));
|
TrackedRetVals.insert(std::make_pair(F, LatticeVal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddArgumentTrackedFunction(Function *F) {
|
||||||
|
TrackingIncomingArguments.insert(F);
|
||||||
|
}
|
||||||
|
|
||||||
/// Solve - Solve for constants and executable blocks.
|
/// Solve - Solve for constants and executable blocks.
|
||||||
///
|
///
|
||||||
void Solve();
|
void Solve();
|
||||||
@ -1190,6 +1197,27 @@ CallOverdefined:
|
|||||||
return markOverdefined(I);
|
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.
|
// If this is a single/zero retval case, see if we're tracking the function.
|
||||||
DenseMap<Function*, LatticeVal>::iterator TFRVI = TrackedRetVals.find(F);
|
DenseMap<Function*, LatticeVal>::iterator TFRVI = TrackedRetVals.find(F);
|
||||||
if (TFRVI != TrackedRetVals.end()) {
|
if (TFRVI != TrackedRetVals.end()) {
|
||||||
@ -1228,24 +1256,6 @@ CallOverdefined:
|
|||||||
// common path above.
|
// common path above.
|
||||||
goto CallOverdefined;
|
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() {
|
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
|
// 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
|
// arguments and return value aggressively, and can assume it is not called
|
||||||
// unless we see evidence to the contrary.
|
// unless we see evidence to the contrary.
|
||||||
if (F->hasLocalLinkage() && !AddressIsTaken(F))
|
if (F->hasLocalLinkage() && !AddressIsTaken(F)) {
|
||||||
|
Solver.AddArgumentTrackedFunction(F);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Assume the function is called.
|
// Assume the function is called.
|
||||||
Solver.MarkBlockExecutable(F->begin());
|
Solver.MarkBlockExecutable(F->begin());
|
||||||
|
@ -174,4 +174,24 @@ define i32 @test7b() {
|
|||||||
; CHECK-NEXT: ret i32 36
|
; 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user