aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/InlineFunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Utils/InlineFunction.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp97
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());