diff --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h --- a/llvm/include/llvm/Transforms/IPO/IROutliner.h +++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h @@ -156,6 +156,14 @@ /// containing the called function. void reattachCandidate(); + /// Find a corresponding value for \p V in similar OutlinableRegion \p Other. + /// + /// \param Other [in] - The OutlinableRegion to find the corresponding Value + /// in. + /// \param V [in] - The Value to look for in the other region. + /// \return The corresponding Value to \p V if it exists, otherwise nullptr. + Value *findCorrespondingValueIn(const OutlinableRegion &Other, Value *V); + /// Get the size of the code removed from the region. /// /// \param [in] TTI - The TargetTransformInfo for the parent function. diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp --- a/llvm/lib/Transforms/IPO/IROutliner.cpp +++ b/llvm/lib/Transforms/IPO/IROutliner.cpp @@ -163,6 +163,16 @@ }); } +Value *OutlinableRegion::findCorrespondingValueIn(const OutlinableRegion &Other, + Value *V) { + Optional GVN = Candidate->getGVN(V); + assert(GVN.hasValue() && "No GVN for incoming value"); + Optional CanonNum = Candidate->getCanonicalNum(*GVN); + Optional FirstGVN = Other.Candidate->fromCanonicalNum(*CanonNum); + Optional FoundValueOpt = Other.Candidate->fromGVN(*FirstGVN); + return FoundValueOpt.getValueOr(nullptr); +} + void OutlinableRegion::splitCandidate() { assert(!CandidateSplit && "Candidate already split!"); @@ -1129,12 +1139,25 @@ auto VBBIt = OutputBBs.find(RetVal); assert(VBBIt != OutputBBs.end() && "Could not find output value!"); - Instruction *NewI = I->clone(); + // If this is storing a PHINode, we must make sure it is included in the + // overall function. + StoreInst *SI = cast(I); + + Value *ValueOperand = SI->getValueOperand(); + + StoreInst *NewI = cast(I->clone()); NewI->setDebugLoc(DebugLoc()); BasicBlock *OutputBB = VBBIt->second; OutputBB->getInstList().push_back(NewI); LLVM_DEBUG(dbgs() << "Move store for instruction " << *I << " to " << *OutputBB << "\n"); + + if (FirstFunction) + continue; + Value *CorrVal = + Region.findCorrespondingValueIn(*Group.Regions[0], ValueOperand); + assert(CorrVal && "Value is nullptr?"); + NewI->setOperand(0, CorrVal); } // If we added an edge for basic blocks without a predecessor, we remove it @@ -1181,34 +1204,6 @@ } } -/// For the given function, find all the nondebug or lifetime instructions, -/// and return them as a vector. Exclude any blocks in \p ExludeBlocks. -/// -/// \param [in] F - The function we collect the instructions from. -/// \param [in] ExcludeBlocks - BasicBlocks to ignore. -/// \returns the list of instructions extracted. -static std::vector -collectRelevantInstructions(Function &F, - DenseSet &ExcludeBlocks) { - std::vector RelevantInstructions; - - for (BasicBlock &BB : F) { - if (ExcludeBlocks.contains(&BB)) - continue; - - for (Instruction &Inst : BB) { - if (Inst.isLifetimeStartOrEnd()) - continue; - if (isa(Inst)) - continue; - - RelevantInstructions.push_back(&Inst); - } - } - - return RelevantInstructions; -} - /// It is possible that there is a basic block that already performs the same /// stores. This returns a duplicate block, if it exists /// @@ -1323,51 +1318,6 @@ DenseMap &EndBBs, const DenseMap &OutputMappings, std::vector> &OutputStoreBBs) { - DenseSet ValuesToFind(Region.GVNStores.begin(), - Region.GVNStores.end()); - - // We iterate over the instructions in the extracted function, and find the - // global value number of the instructions. If we find a value that should - // be contained in a store, we replace the uses of the value with the value - // from the overall function, so that the store is storing the correct - // value from the overall function. - DenseSet ExcludeBBs; - for (DenseMap &BBMap : OutputStoreBBs) - for (std::pair &VBPair : BBMap) - ExcludeBBs.insert(VBPair.second); - for (std::pair &VBPair : OutputBBs) - ExcludeBBs.insert(VBPair.second); - - std::vector ExtractedFunctionInsts = - collectRelevantInstructions(*(Region.ExtractedFunction), ExcludeBBs); - std::vector OverallFunctionInsts = - collectRelevantInstructions(*OG.OutlinedFunction, ExcludeBBs); - - assert(ExtractedFunctionInsts.size() == OverallFunctionInsts.size() && - "Number of relevant instructions not equal!"); - - unsigned NumInstructions = ExtractedFunctionInsts.size(); - for (unsigned Idx = 0; Idx < NumInstructions; Idx++) { - Value *V = ExtractedFunctionInsts[Idx]; - - if (OutputMappings.find(V) != OutputMappings.end()) - V = OutputMappings.find(V)->second; - Optional GVN = Region.Candidate->getGVN(V); - - // If we have found one of the stored values for output, replace the value - // with the corresponding one from the overall function. - if (GVN.hasValue() && ValuesToFind.erase(GVN.getValue())) { - V->replaceAllUsesWith(OverallFunctionInsts[Idx]); - if (ValuesToFind.size() == 0) - break; - } - - if (ValuesToFind.size() == 0) - break; - } - - assert(ValuesToFind.size() == 0 && "Not all store values were handled!"); - // If none of the output blocks have any instructions, this means that we do // not have to determine if it matches any of the other output schemes, and we // don't have to do anything else.