diff options
Diffstat (limited to 'llvm/lib/Transforms/Utils/InlineFunction.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/InlineFunction.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index dfb7da9..5c9511c 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -1767,6 +1767,94 @@ static void fixupLineNumbers(Function *Fn, Function::iterator FI, } } +#undef DEBUG_TYPE +#define DEBUG_TYPE "assignment-tracking" +/// Find Alloca and linked DbgAssignIntrinsic for locals escaped by \p CB. +static at::StorageToVarsMap collectEscapedLocals(const DataLayout &DL, + const CallBase &CB) { + at::StorageToVarsMap EscapedLocals; + SmallPtrSet<const Value *, 4> SeenBases; + + LLVM_DEBUG( + errs() << "# Finding caller local variables escaped by callee\n"); + for (const Value *Arg : CB.args()) { + LLVM_DEBUG(errs() << "INSPECT: " << *Arg << "\n"); + if (!Arg->getType()->isPointerTy()) { + LLVM_DEBUG(errs() << " | SKIP: Not a pointer\n"); + continue; + } + + const Instruction *I = dyn_cast<Instruction>(Arg); + if (!I) { + LLVM_DEBUG(errs() << " | SKIP: Not result of instruction\n"); + continue; + } + + // Walk back to the base storage. + assert(Arg->getType()->isPtrOrPtrVectorTy()); + APInt TmpOffset(DL.getIndexTypeSizeInBits(Arg->getType()), 0, false); + const AllocaInst *Base = dyn_cast<AllocaInst>( + Arg->stripAndAccumulateConstantOffsets(DL, TmpOffset, true)); + if (!Base) { + LLVM_DEBUG(errs() << " | SKIP: Couldn't walk back to base storage\n"); + continue; + } + + assert(Base); + LLVM_DEBUG(errs() << " | BASE: " << *Base << "\n"); + // We only need to process each base address once - skip any duplicates. + if (!SeenBases.insert(Base).second) + continue; + + // Find all local variables associated with the backing storage. + for (auto *DAI : at::getAssignmentMarkers(Base)) { + // Skip variables from inlined functions - they are not local variables. + if (DAI->getDebugLoc().getInlinedAt()) + continue; + LLVM_DEBUG(errs() << " > DEF : " << *DAI << "\n"); + EscapedLocals[Base].insert(at::VarRecord(DAI)); + } + } + return EscapedLocals; +} + +static void trackInlinedStores(Function::iterator Start, Function::iterator End, + const CallBase &CB) { + LLVM_DEBUG(errs() << "trackInlinedStores into " + << Start->getParent()->getName() << " from " + << CB.getCalledFunction()->getName() << "\n"); + std::unique_ptr<DataLayout> DL = std::make_unique<DataLayout>(CB.getModule()); + at::trackAssignments(Start, End, collectEscapedLocals(*DL, CB), *DL); +} + +/// Update inlined instructions' DIAssignID metadata. We need to do this +/// otherwise a function inlined more than once into the same function +/// will cause DIAssignID to be shared by many instructions. +static void fixupAssignments(Function::iterator Start, Function::iterator End) { + // Map {Old, New} metadata. Not used directly - use GetNewID. + DenseMap<DIAssignID *, DIAssignID *> Map; + auto GetNewID = [&Map](Metadata *Old) { + DIAssignID *OldID = cast<DIAssignID>(Old); + if (DIAssignID *NewID = Map.lookup(OldID)) + return NewID; + DIAssignID *NewID = DIAssignID::getDistinct(OldID->getContext()); + Map[OldID] = NewID; + return NewID; + }; + // Loop over all the inlined instructions. If we find a DIAssignID + // attachment or use, replace it with a new version. + for (auto BBI = Start; BBI != End; ++BBI) { + for (Instruction &I : *BBI) { + if (auto *ID = I.getMetadata(LLVMContext::MD_DIAssignID)) + I.setMetadata(LLVMContext::MD_DIAssignID, GetNewID(ID)); + else if (auto *DAI = dyn_cast<DbgAssignIntrinsic>(&I)) + DAI->setAssignId(GetNewID(DAI->getAssignID())); + } + } +} +#undef DEBUG_TYPE +#define DEBUG_TYPE "inline-function" + /// Update the block frequencies of the caller after a callee has been inlined. /// /// Each block cloned into the caller has its block frequency scaled by the @@ -2252,6 +2340,15 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, fixupLineNumbers(Caller, FirstNewBlock, &CB, CalledFunc->getSubprogram() != nullptr); + if (getEnableAssignmentTracking()) { + // Interpret inlined stores to caller-local variables as assignments. + trackInlinedStores(FirstNewBlock, Caller->end(), CB); + + // Update DIAssignID metadata attachments and uses so that they are + // unique to this inlined instance. + fixupAssignments(FirstNewBlock, Caller->end()); + } + // Now clone the inlined noalias scope metadata. SAMetadataCloner.clone(); SAMetadataCloner.remap(FirstNewBlock, Caller->end()); |