From 7c490d4104baf6984ff04cf6a60f2f8825c54812 Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Tue, 11 Mar 2008 05:46:42 +0000 Subject: [PATCH] Initial multiple return values support. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48210 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/SCCP.cpp | 114 ++++++++++++++++++++---- test/Transforms/SCCP/2008-03-10-sret.ll | 12 +++ 2 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 test/Transforms/SCCP/2008-03-10-sret.ll diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 6493f0e4080..24ba0bd0961 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -129,6 +129,21 @@ public: } }; +/// LatticeValIndex - LatticeVal and associated Index. This is used +/// to track individual operand Lattice values for multi value ret instructions. +class VISIBILITY_HIDDEN LatticeValIndexed { + public: + LatticeValIndexed(unsigned I = 0) { Index = I; } + LatticeVal &getLatticeVal() { return LV; } + unsigned getIndex() const { return Index; } + + void setLatticeVal(LatticeVal &L) { LV = L; } + void setIndex(unsigned I) { Index = I; } + + private: + LatticeVal LV; + unsigned Index; +}; //===----------------------------------------------------------------------===// // /// SCCPSolver - This class is a general purpose solver for Sparse Conditional @@ -144,10 +159,14 @@ class SCCPSolver : public InstVisitor { /// overdefined, it's entry is simply removed from this map. DenseMap TrackedGlobals; - /// TrackedFunctionRetVals - If we are tracking arguments into and the return + /// TrackedRetVals - If we are tracking arguments into and the return /// value out of a function, it will have an entry in this map, indicating /// what the known return value for the function is. - DenseMap TrackedFunctionRetVals; + DenseMap TrackedRetVals; + + /// TrackedMultipleRetVals - Same as TrackedRetVals, but used for functions + /// that return multiple values. + std::multimap TrackedMultipleRetVals; // The reason for two worklists is that overdefined is the lowest state // on the lattice, and moving things to overdefined as fast as possible @@ -198,7 +217,13 @@ public: void AddTrackedFunction(Function *F) { assert(F->hasInternalLinkage() && "Can only track internal functions!"); // Add an entry, F -> undef. - TrackedFunctionRetVals[F]; + if (const StructType *STy = dyn_cast(F->getReturnType())) { + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) + TrackedMultipleRetVals.insert(std::pair + (F, LatticeValIndexed(i))); + } + else + TrackedRetVals[F]; } /// Solve - Solve for constants and executable blocks. @@ -224,10 +249,10 @@ public: return ValueState; } - /// getTrackedFunctionRetVals - Get the inferred return value map. + /// getTrackedRetVals - Get the inferred return value map. /// - const DenseMap &getTrackedFunctionRetVals() { - return TrackedFunctionRetVals; + const DenseMap &getTrackedRetVals() { + return TrackedRetVals; } /// getTrackedGlobals - Get and return the set of inferred initializers for @@ -374,6 +399,7 @@ private: void visitTerminatorInst(TerminatorInst &TI); void visitCastInst(CastInst &I); + void visitGetResultInst(GetResultInst &GRI); void visitSelectInst(SelectInst &I); void visitBinaryOperator(Instruction &I); void visitCmpInst(CmpInst &I); @@ -608,20 +634,35 @@ void SCCPSolver::visitPHINode(PHINode &PN) { void SCCPSolver::visitReturnInst(ReturnInst &I) { if (I.getNumOperands() == 0) return; // Ret void - // If we are tracking the return value of this function, merge it in. Function *F = I.getParent()->getParent(); - if (F->hasInternalLinkage() && !TrackedFunctionRetVals.empty()) { + // If we are tracking the return value of this function, merge it in. + if (!F->hasInternalLinkage()) + return; + + if (!TrackedRetVals.empty()) { DenseMap::iterator TFRVI = - TrackedFunctionRetVals.find(F); - if (TFRVI != TrackedFunctionRetVals.end() && + TrackedRetVals.find(F); + if (TFRVI != TrackedRetVals.end() && !TFRVI->second.isOverdefined()) { LatticeVal &IV = getValueState(I.getOperand(0)); mergeInValue(TFRVI->second, F, IV); + return; + } + } + + // Handle function that returns multiple values. + std::multimap::iterator It, E; + tie(It, E) = TrackedMultipleRetVals.equal_range(F); + if (It != E) { + for (; It != E; ++It) { + LatticeValIndexed &LV = It->second; + unsigned Idx = LV.getIndex(); + Value *V = I.getOperand(Idx); + mergeInValue(LV.getLatticeVal(), V, getValueState(V)); } } } - void SCCPSolver::visitTerminatorInst(TerminatorInst &TI) { SmallVector SuccFeasible; getFeasibleSuccessors(TI, SuccFeasible); @@ -644,6 +685,30 @@ void SCCPSolver::visitCastInst(CastInst &I) { VState.getConstant(), I.getType())); } +void SCCPSolver::visitGetResultInst(GetResultInst &GRI) { + unsigned Idx = GRI.getIndex(); + Value *Aggr = GRI.getOperand(0); + Function *F = NULL; + if (CallInst *CI = dyn_cast(Aggr)) + F = CI->getCalledFunction(); + else if (InvokeInst *II = dyn_cast(Aggr)) + F = II->getCalledFunction(); + + assert (F && "Invalid GetResultInst operands!"); + + std::multimap::iterator It, E; + tie(It, E) = TrackedMultipleRetVals.equal_range(F); + if (It == E) + return; + + for (; It != E; ++It) { + LatticeValIndexed &LIV = It->second; + if (LIV.getIndex() == Idx) { + mergeInValue(&GRI, LIV.getLatticeVal()); + } + } +} + void SCCPSolver::visitSelectInst(SelectInst &I) { LatticeVal &CondValue = getValueState(I.getCondition()); if (CondValue.isUndefined()) @@ -1061,18 +1126,28 @@ void SCCPSolver::visitLoadInst(LoadInst &I) { void SCCPSolver::visitCallSite(CallSite CS) { Function *F = CS.getCalledFunction(); + DenseMap::iterator TFRVI =TrackedRetVals.end(); // If we are tracking this function, we must make sure to bind arguments as // appropriate. - DenseMap::iterator TFRVI =TrackedFunctionRetVals.end(); - if (F && F->hasInternalLinkage()) - TFRVI = TrackedFunctionRetVals.find(F); + bool FirstCall = false; + if (F && F->hasInternalLinkage()) { + TFRVI = TrackedRetVals.find(F); + if (TFRVI != TrackedRetVals.end()) + FirstCall = true; + else { + std::multimap::iterator It, E; + tie(It, E) = TrackedMultipleRetVals.equal_range(F); + if (It != E) + FirstCall = true; + } + } - if (TFRVI != TrackedFunctionRetVals.end()) { + if (FirstCall) { // If this is the first call to the function hit, mark its entry block // executable. if (!BBExecutable.count(F->begin())) MarkBlockExecutable(F->begin()); - + CallSite::arg_iterator CAI = CS.arg_begin(); for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); AI != E; ++AI, ++CAI) { @@ -1091,8 +1166,9 @@ void SCCPSolver::visitCallSite(CallSite CS) { LatticeVal &IV = ValueState[I]; if (IV.isOverdefined()) return; - // Propagate the return value of the function to the value of the instruction. - if (TFRVI != TrackedFunctionRetVals.end()) { + // Propagate the single return value of the function to the value of the + // instruction. + if (TFRVI != TrackedRetVals.end()) { mergeInValue(IV, I, TFRVI->second); return; } @@ -1684,7 +1760,7 @@ bool IPSCCP::runOnModule(Module &M) { // all call uses with the inferred value. This means we don't need to bother // actually returning anything from the function. Replace all return // instructions with return undef. - const DenseMap &RV =Solver.getTrackedFunctionRetVals(); + const DenseMap &RV = Solver.getTrackedRetVals(); for (DenseMap::const_iterator I = RV.begin(), E = RV.end(); I != E; ++I) if (!I->second.isOverdefined() && diff --git a/test/Transforms/SCCP/2008-03-10-sret.ll b/test/Transforms/SCCP/2008-03-10-sret.ll new file mode 100644 index 00000000000..284a5900c50 --- /dev/null +++ b/test/Transforms/SCCP/2008-03-10-sret.ll @@ -0,0 +1,12 @@ +; RUN: llvm-as < %s | opt -ipsccp -disable-output + +define internal {i32, i32} @bar(i32 %A) { + %X = add i32 1, 2 + ret i32 %A, i32 %A +} + +define i32 @foo() { + %X = call {i32, i32} @bar(i32 17) + %Y = getresult {i32, i32} %X, 0 + ret i32 %Y +}