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.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index cf7541f..da1ce85 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -27,6 +27,7 @@
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/MemoryProfileInfo.h"
#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
#include "llvm/Analysis/ObjCARCUtil.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
@@ -74,7 +75,10 @@
#include <utility>
#include <vector>
+#define DEBUG_TYPE "inline-function"
+
using namespace llvm;
+using namespace llvm::memprof;
using ProfileCount = Function::ProfileCount;
static cl::opt<bool>
@@ -782,6 +786,174 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock,
UnwindDest->removePredecessor(InvokeBB);
}
+static bool haveCommonPrefix(MDNode *MIBStackContext,
+ MDNode *CallsiteStackContext) {
+ assert(MIBStackContext->getNumOperands() > 0 &&
+ CallsiteStackContext->getNumOperands() > 0);
+ // Because of the context trimming performed during matching, the callsite
+ // context could have more stack ids than the MIB. We match up to the end of
+ // the shortest stack context.
+ for (auto MIBStackIter = MIBStackContext->op_begin(),
+ CallsiteStackIter = CallsiteStackContext->op_begin();
+ MIBStackIter != MIBStackContext->op_end() &&
+ CallsiteStackIter != CallsiteStackContext->op_end();
+ MIBStackIter++, CallsiteStackIter++) {
+ auto *Val1 = mdconst::dyn_extract<ConstantInt>(*MIBStackIter);
+ auto *Val2 = mdconst::dyn_extract<ConstantInt>(*CallsiteStackIter);
+ assert(Val1 && Val2);
+ if (Val1->getZExtValue() != Val2->getZExtValue())
+ return false;
+ }
+ return true;
+}
+
+static void removeMemProfMetadata(CallBase *Call) {
+ Call->setMetadata(LLVMContext::MD_memprof, nullptr);
+}
+
+static void removeCallsiteMetadata(CallBase *Call) {
+ Call->setMetadata(LLVMContext::MD_callsite, nullptr);
+}
+
+static void updateMemprofMetadata(CallBase *CI,
+ const std::vector<Metadata *> &MIBList) {
+ assert(!MIBList.empty());
+ // Remove existing memprof, which will either be replaced or may not be needed
+ // if we are able to use a single allocation type function attribute.
+ removeMemProfMetadata(CI);
+ CallStackTrie CallStack;
+ for (Metadata *MIB : MIBList)
+ CallStack.addCallStack(cast<MDNode>(MIB));
+ bool MemprofMDAttached = CallStack.buildAndAttachMIBMetadata(CI);
+ assert(MemprofMDAttached == CI->hasMetadata(LLVMContext::MD_memprof));
+ if (!MemprofMDAttached)
+ // If we used a function attribute remove the callsite metadata as well.
+ removeCallsiteMetadata(CI);
+}
+
+// Update the metadata on the inlined copy ClonedCall of a call OrigCall in the
+// inlined callee body, based on the callsite metadata InlinedCallsiteMD from
+// the call that was inlined.
+static void
+propagateMemProfHelper(const CallBase *OrigCall, CallBase *ClonedCall,
+ MDNode *InlinedCallsiteMD,
+ std::map<const CallBase *, std::vector<Metadata *>>
+ &OrigCallToNewMemProfMDMap) {
+ MDNode *OrigCallsiteMD = ClonedCall->getMetadata(LLVMContext::MD_callsite);
+ MDNode *ClonedCallsiteMD = nullptr;
+ // Check if the call originally had callsite metadata, and update it for the
+ // new call in the inlined body.
+ if (OrigCallsiteMD) {
+ // The cloned call's context is now the concatenation of the original call's
+ // callsite metadata and the callsite metadata on the call where it was
+ // inlined.
+ ClonedCallsiteMD = MDNode::concatenate(OrigCallsiteMD, InlinedCallsiteMD);
+ ClonedCall->setMetadata(LLVMContext::MD_callsite, ClonedCallsiteMD);
+ }
+
+ // Update any memprof metadata on the cloned call.
+ MDNode *OrigMemProfMD = ClonedCall->getMetadata(LLVMContext::MD_memprof);
+ if (!OrigMemProfMD)
+ return;
+ // We currently expect that allocations with memprof metadata also have
+ // callsite metadata for the allocation's part of the context.
+ assert(OrigCallsiteMD);
+
+ // New call's MIB list.
+ std::vector<Metadata *> NewMIBList;
+ // Updated MIB list for the original call in the out-of-line callee.
+ std::vector<Metadata *> UpdatedOrigMIBList;
+
+ // For each MIB metadata, check if its call stack context starts with the
+ // new clone's callsite metadata. If so, that MIB goes onto the cloned call in
+ // the inlined body. If not, it stays on the out-of-line original call.
+ for (auto &MIBOp : OrigMemProfMD->operands()) {
+ MDNode *MIB = dyn_cast<MDNode>(MIBOp);
+ // Stack is first operand of MIB.
+ MDNode *StackMD = getMIBStackNode(MIB);
+ assert(StackMD);
+ // See if the new cloned callsite context matches this profiled context.
+ if (haveCommonPrefix(StackMD, ClonedCallsiteMD))
+ // Add it to the cloned call's MIB list.
+ NewMIBList.push_back(MIB);
+ else
+ // Keep it on the original call.
+ UpdatedOrigMIBList.push_back(MIB);
+ }
+ if (NewMIBList.empty()) {
+ removeMemProfMetadata(ClonedCall);
+ removeCallsiteMetadata(ClonedCall);
+ return;
+ }
+ if (NewMIBList.size() < OrigMemProfMD->getNumOperands()) {
+ assert(!UpdatedOrigMIBList.empty());
+ OrigCallToNewMemProfMDMap[OrigCall] = UpdatedOrigMIBList;
+ updateMemprofMetadata(ClonedCall, NewMIBList);
+ } else
+ OrigCallToNewMemProfMDMap[OrigCall] = {};
+}
+
+// Update memprof related metadata (!memprof and !callsite) based on the
+// inlining of Callee into the callsite at CB. The updates include merging the
+// inlined callee's callsite metadata with that of the inlined call,
+// and moving the subset of any memprof contexts to the inlined callee
+// allocations if they match the new inlined call stack.
+// FIXME: Replace memprof metadata with function attribute if all MIB end up
+// having the same behavior. Do other context trimming/merging optimizations
+// too.
+static void
+propagateMemProfMetadata(Function *Callee, CallBase &CB,
+ bool ContainsMemProfMetadata,
+ const ValueMap<const Value *, WeakTrackingVH> &VMap) {
+ MDNode *CallsiteMD = CB.getMetadata(LLVMContext::MD_callsite);
+ // Only need to update if the inlined callsite had callsite metadata, or if
+ // there was any memprof metadata inlined.
+ if (!CallsiteMD && !ContainsMemProfMetadata)
+ return;
+
+ // Propagate metadata onto the cloned calls in the inlined callee.
+ // Can't update the original call using the VMap since it holds a const
+ // pointer, those will be updated in the subsequent loop.
+ std::map<const CallBase *, std::vector<Metadata *>> OrigCallToNewMemProfMDMap;
+ for (const auto &Entry : VMap) {
+ // See if this is a call that has been inlined and remapped, and not
+ // simplified away in the process.
+ auto *OrigCall = dyn_cast_or_null<CallBase>(Entry.first);
+ auto *ClonedCall = dyn_cast_or_null<CallBase>(Entry.second);
+ if (!OrigCall || !ClonedCall)
+ continue;
+ // If the inlined callsite did not have any callsite metadata, then it isn't
+ // involved in any profiled call contexts, and we can remove any memprof
+ // metadata on the cloned call.
+ if (!CallsiteMD) {
+ removeMemProfMetadata(ClonedCall);
+ removeCallsiteMetadata(ClonedCall);
+ continue;
+ }
+ propagateMemProfHelper(OrigCall, ClonedCall, CallsiteMD,
+ OrigCallToNewMemProfMDMap);
+ }
+
+ // Update memprof MD on calls within the original callee function to remove
+ // MIB with stacks that matched the inlined context (those moved to a new
+ // memprof MD on the inlined version of the call).
+ for (BasicBlock &BB : *Callee) {
+ for (Instruction &I : BB) {
+ CallBase *Call = dyn_cast<CallBase>(&I);
+ if (!Call || !OrigCallToNewMemProfMDMap.count(Call))
+ continue;
+ std::vector<Metadata *> &UpdatedMemProfMD =
+ OrigCallToNewMemProfMDMap[Call];
+ if (!UpdatedMemProfMD.empty())
+ updateMemprofMetadata(Call, UpdatedMemProfMD);
+ else {
+ removeMemProfMetadata(Call);
+ removeCallsiteMetadata(Call);
+ }
+ }
+ }
+}
+
/// When inlining a call site that has !llvm.mem.parallel_loop_access,
/// !llvm.access.group, !alias.scope or !noalias metadata, that metadata should
/// be propagated to all memory-accessing cloned instructions.
@@ -2091,6 +2263,9 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
// function which feed into its return value.
AddReturnAttributes(CB, VMap);
+ propagateMemProfMetadata(CalledFunc, CB,
+ InlinedFunctionInfo.ContainsMemProfMetadata, VMap);
+
// Propagate metadata on the callsite if necessary.
PropagateCallSiteMetadata(CB, FirstNewBlock, Caller->end());