diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Diffstat (limited to 'lib/Transforms/Scalar/RewriteStatepointsForGC.cpp')
-rw-r--r-- | lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 254 |
1 files changed, 137 insertions, 117 deletions
diff --git a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index 42d7ed5bc534..c358258d24cf 100644 --- a/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1,9 +1,8 @@ //===- RewriteStatepointsForGC.cpp - Make GC relocations explicit ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -26,18 +25,17 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" -#include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/DomTreeUpdater.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -286,9 +284,9 @@ struct PartiallyConstructedSafepointRecord { } // end anonymous namespace -static ArrayRef<Use> GetDeoptBundleOperands(ImmutableCallSite CS) { +static ArrayRef<Use> GetDeoptBundleOperands(const CallBase *Call) { Optional<OperandBundleUse> DeoptBundle = - CS.getOperandBundle(LLVMContext::OB_deopt); + Call->getOperandBundle(LLVMContext::OB_deopt); if (!DeoptBundle.hasValue()) { assert(AllowStatepointWithNoDeoptInfo && @@ -370,14 +368,11 @@ static std::string suffixed_name_or(Value *V, StringRef Suffix, // given instruction. The analysis is performed immediately before the // given instruction. Values defined by that instruction are not considered // live. Values used by that instruction are considered live. -static void -analyzeParsePointLiveness(DominatorTree &DT, - GCPtrLivenessData &OriginalLivenessData, CallSite CS, - PartiallyConstructedSafepointRecord &Result) { - Instruction *Inst = CS.getInstruction(); - +static void analyzeParsePointLiveness( + DominatorTree &DT, GCPtrLivenessData &OriginalLivenessData, CallBase *Call, + PartiallyConstructedSafepointRecord &Result) { StatepointLiveSetTy LiveSet; - findLiveSetAtInst(Inst, OriginalLivenessData, LiveSet); + findLiveSetAtInst(Call, OriginalLivenessData, LiveSet); if (PrintLiveSet) { dbgs() << "Live Variables:\n"; @@ -385,7 +380,7 @@ analyzeParsePointLiveness(DominatorTree &DT, dbgs() << " " << V->getName() << " " << *V << "\n"; } if (PrintLiveSetSize) { - dbgs() << "Safepoint For: " << CS.getCalledValue()->getName() << "\n"; + dbgs() << "Safepoint For: " << Call->getCalledValue()->getName() << "\n"; dbgs() << "Number live values: " << LiveSet.size() << "\n"; } Result.LiveSet = LiveSet; @@ -1178,7 +1173,7 @@ findBasePointers(const StatepointLiveSetTy &live, /// Find the required based pointers (and adjust the live set) for the given /// parse point. static void findBasePointers(DominatorTree &DT, DefiningValueMapTy &DVCache, - CallSite CS, + CallBase *Call, PartiallyConstructedSafepointRecord &result) { MapVector<Value *, Value *> PointerToBase; findBasePointers(result.LiveSet, PointerToBase, &DT, DVCache); @@ -1200,11 +1195,11 @@ static void findBasePointers(DominatorTree &DT, DefiningValueMapTy &DVCache, /// Given an updated version of the dataflow liveness results, update the /// liveset and base pointer maps for the call site CS. static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, - CallSite CS, + CallBase *Call, PartiallyConstructedSafepointRecord &result); static void recomputeLiveInValues( - Function &F, DominatorTree &DT, ArrayRef<CallSite> toUpdate, + Function &F, DominatorTree &DT, ArrayRef<CallBase *> toUpdate, MutableArrayRef<struct PartiallyConstructedSafepointRecord> records) { // TODO-PERF: reuse the original liveness, then simply run the dataflow // again. The old values are still live and will help it stabilize quickly. @@ -1307,7 +1302,7 @@ static void CreateGCRelocates(ArrayRef<Value *> LiveVariables, // Lazily populated map from input types to the canonicalized form mentioned // in the comment above. This should probably be cached somewhere more // broadly. - DenseMap<Type*, Value*> TypeToDeclMap; + DenseMap<Type *, Function *> TypeToDeclMap; for (unsigned i = 0; i < LiveVariables.size(); i++) { // Generate the gc.relocate call and save the result @@ -1318,7 +1313,7 @@ static void CreateGCRelocates(ArrayRef<Value *> LiveVariables, Type *Ty = LiveVariables[i]->getType(); if (!TypeToDeclMap.count(Ty)) TypeToDeclMap[Ty] = getGCRelocateDecl(Ty); - Value *GCRelocateDecl = TypeToDeclMap[Ty]; + Function *GCRelocateDecl = TypeToDeclMap[Ty]; // only specify a debug name if we can give a useful one CallInst *Reloc = Builder.CreateCall( @@ -1399,16 +1394,16 @@ public: } // end anonymous namespace -static StringRef getDeoptLowering(CallSite CS) { +static StringRef getDeoptLowering(CallBase *Call) { const char *DeoptLowering = "deopt-lowering"; - if (CS.hasFnAttr(DeoptLowering)) { - // FIXME: CallSite has a *really* confusing interface around attributes + if (Call->hasFnAttr(DeoptLowering)) { + // FIXME: Calls have a *really* confusing interface around attributes // with values. - const AttributeList &CSAS = CS.getAttributes(); + const AttributeList &CSAS = Call->getAttributes(); if (CSAS.hasAttribute(AttributeList::FunctionIndex, DeoptLowering)) return CSAS.getAttribute(AttributeList::FunctionIndex, DeoptLowering) .getValueAsString(); - Function *F = CS.getCalledFunction(); + Function *F = Call->getCalledFunction(); assert(F && F->hasFnAttribute(DeoptLowering)); return F->getFnAttribute(DeoptLowering).getValueAsString(); } @@ -1416,7 +1411,7 @@ static StringRef getDeoptLowering(CallSite CS) { } static void -makeStatepointExplicitImpl(const CallSite CS, /* to replace */ +makeStatepointExplicitImpl(CallBase *Call, /* to replace */ const SmallVectorImpl<Value *> &BasePtrs, const SmallVectorImpl<Value *> &LiveVariables, PartiallyConstructedSafepointRecord &Result, @@ -1427,19 +1422,18 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // immediately before the previous instruction under the assumption that all // arguments will be available here. We can't insert afterwards since we may // be replacing a terminator. - Instruction *InsertBefore = CS.getInstruction(); - IRBuilder<> Builder(InsertBefore); + IRBuilder<> Builder(Call); ArrayRef<Value *> GCArgs(LiveVariables); uint64_t StatepointID = StatepointDirectives::DefaultStatepointID; uint32_t NumPatchBytes = 0; uint32_t Flags = uint32_t(StatepointFlags::None); - ArrayRef<Use> CallArgs(CS.arg_begin(), CS.arg_end()); - ArrayRef<Use> DeoptArgs = GetDeoptBundleOperands(CS); + ArrayRef<Use> CallArgs(Call->arg_begin(), Call->arg_end()); + ArrayRef<Use> DeoptArgs = GetDeoptBundleOperands(Call); ArrayRef<Use> TransitionArgs; if (auto TransitionBundle = - CS.getOperandBundle(LLVMContext::OB_gc_transition)) { + Call->getOperandBundle(LLVMContext::OB_gc_transition)) { Flags |= uint32_t(StatepointFlags::GCTransition); TransitionArgs = TransitionBundle->Inputs; } @@ -1450,21 +1444,21 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ bool IsDeoptimize = false; StatepointDirectives SD = - parseStatepointDirectivesFromAttrs(CS.getAttributes()); + parseStatepointDirectivesFromAttrs(Call->getAttributes()); if (SD.NumPatchBytes) NumPatchBytes = *SD.NumPatchBytes; if (SD.StatepointID) StatepointID = *SD.StatepointID; // Pass through the requested lowering if any. The default is live-through. - StringRef DeoptLowering = getDeoptLowering(CS); + StringRef DeoptLowering = getDeoptLowering(Call); if (DeoptLowering.equals("live-in")) Flags |= uint32_t(StatepointFlags::DeoptLiveIn); else { assert(DeoptLowering.equals("live-through") && "Unsupported value!"); } - Value *CallTarget = CS.getCalledValue(); + Value *CallTarget = Call->getCalledValue(); if (Function *F = dyn_cast<Function>(CallTarget)) { if (F->getIntrinsicID() == Intrinsic::experimental_deoptimize) { // Calls to llvm.experimental.deoptimize are lowered to calls to the @@ -1481,8 +1475,9 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // calls to @llvm.experimental.deoptimize with different argument types in // the same module. This is fine -- we assume the frontend knew what it // was doing when generating this kind of IR. - CallTarget = - F->getParent()->getOrInsertFunction("__llvm_deoptimize", FTy); + CallTarget = F->getParent() + ->getOrInsertFunction("__llvm_deoptimize", FTy) + .getCallee(); IsDeoptimize = true; } @@ -1490,57 +1485,56 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // Create the statepoint given all the arguments Instruction *Token = nullptr; - if (CS.isCall()) { - CallInst *ToReplace = cast<CallInst>(CS.getInstruction()); - CallInst *Call = Builder.CreateGCStatepointCall( + if (auto *CI = dyn_cast<CallInst>(Call)) { + CallInst *SPCall = Builder.CreateGCStatepointCall( StatepointID, NumPatchBytes, CallTarget, Flags, CallArgs, TransitionArgs, DeoptArgs, GCArgs, "safepoint_token"); - Call->setTailCallKind(ToReplace->getTailCallKind()); - Call->setCallingConv(ToReplace->getCallingConv()); + SPCall->setTailCallKind(CI->getTailCallKind()); + SPCall->setCallingConv(CI->getCallingConv()); // Currently we will fail on parameter attributes and on certain // function attributes. In case if we can handle this set of attributes - // set up function attrs directly on statepoint and return attrs later for // gc_result intrinsic. - Call->setAttributes(legalizeCallAttributes(ToReplace->getAttributes())); + SPCall->setAttributes(legalizeCallAttributes(CI->getAttributes())); - Token = Call; + Token = SPCall; // Put the following gc_result and gc_relocate calls immediately after the // the old call (which we're about to delete) - assert(ToReplace->getNextNode() && "Not a terminator, must have next!"); - Builder.SetInsertPoint(ToReplace->getNextNode()); - Builder.SetCurrentDebugLocation(ToReplace->getNextNode()->getDebugLoc()); + assert(CI->getNextNode() && "Not a terminator, must have next!"); + Builder.SetInsertPoint(CI->getNextNode()); + Builder.SetCurrentDebugLocation(CI->getNextNode()->getDebugLoc()); } else { - InvokeInst *ToReplace = cast<InvokeInst>(CS.getInstruction()); + auto *II = cast<InvokeInst>(Call); // Insert the new invoke into the old block. We'll remove the old one in a // moment at which point this will become the new terminator for the // original block. - InvokeInst *Invoke = Builder.CreateGCStatepointInvoke( - StatepointID, NumPatchBytes, CallTarget, ToReplace->getNormalDest(), - ToReplace->getUnwindDest(), Flags, CallArgs, TransitionArgs, DeoptArgs, - GCArgs, "statepoint_token"); + InvokeInst *SPInvoke = Builder.CreateGCStatepointInvoke( + StatepointID, NumPatchBytes, CallTarget, II->getNormalDest(), + II->getUnwindDest(), Flags, CallArgs, TransitionArgs, DeoptArgs, GCArgs, + "statepoint_token"); - Invoke->setCallingConv(ToReplace->getCallingConv()); + SPInvoke->setCallingConv(II->getCallingConv()); // Currently we will fail on parameter attributes and on certain // function attributes. In case if we can handle this set of attributes - // set up function attrs directly on statepoint and return attrs later for // gc_result intrinsic. - Invoke->setAttributes(legalizeCallAttributes(ToReplace->getAttributes())); + SPInvoke->setAttributes(legalizeCallAttributes(II->getAttributes())); - Token = Invoke; + Token = SPInvoke; // Generate gc relocates in exceptional path - BasicBlock *UnwindBlock = ToReplace->getUnwindDest(); + BasicBlock *UnwindBlock = II->getUnwindDest(); assert(!isa<PHINode>(UnwindBlock->begin()) && UnwindBlock->getUniquePredecessor() && "can't safely insert in this block!"); Builder.SetInsertPoint(&*UnwindBlock->getFirstInsertionPt()); - Builder.SetCurrentDebugLocation(ToReplace->getDebugLoc()); + Builder.SetCurrentDebugLocation(II->getDebugLoc()); // Attach exceptional gc relocates to the landingpad. Instruction *ExceptionalToken = UnwindBlock->getLandingPadInst(); @@ -1551,7 +1545,7 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ Builder); // Generate gc relocates and returns for normal block - BasicBlock *NormalDest = ToReplace->getNormalDest(); + BasicBlock *NormalDest = II->getNormalDest(); assert(!isa<PHINode>(NormalDest->begin()) && NormalDest->getUniquePredecessor() && "can't safely insert in this block!"); @@ -1568,16 +1562,15 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // transform the tail-call like structure to a call to a void function // followed by unreachable to get better codegen. Replacements.push_back( - DeferredReplacement::createDeoptimizeReplacement(CS.getInstruction())); + DeferredReplacement::createDeoptimizeReplacement(Call)); } else { Token->setName("statepoint_token"); - if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) { - StringRef Name = - CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : ""; - CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name); + if (!Call->getType()->isVoidTy() && !Call->use_empty()) { + StringRef Name = Call->hasName() ? Call->getName() : ""; + CallInst *GCResult = Builder.CreateGCResult(Token, Call->getType(), Name); GCResult->setAttributes( AttributeList::get(GCResult->getContext(), AttributeList::ReturnIndex, - CS.getAttributes().getRetAttributes())); + Call->getAttributes().getRetAttributes())); // We cannot RAUW or delete CS.getInstruction() because it could be in the // live set of some other safepoint, in which case that safepoint's @@ -1586,10 +1579,9 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // after the live sets have been made explicit in the IR, and we no longer // have raw pointers to worry about. Replacements.emplace_back( - DeferredReplacement::createRAUW(CS.getInstruction(), GCResult)); + DeferredReplacement::createRAUW(Call, GCResult)); } else { - Replacements.emplace_back( - DeferredReplacement::createDelete(CS.getInstruction())); + Replacements.emplace_back(DeferredReplacement::createDelete(Call)); } } @@ -1606,7 +1598,7 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // WARNING: Does not do any fixup to adjust users of the original live // values. That's the callers responsibility. static void -makeStatepointExplicit(DominatorTree &DT, CallSite CS, +makeStatepointExplicit(DominatorTree &DT, CallBase *Call, PartiallyConstructedSafepointRecord &Result, std::vector<DeferredReplacement> &Replacements) { const auto &LiveSet = Result.LiveSet; @@ -1625,7 +1617,7 @@ makeStatepointExplicit(DominatorTree &DT, CallSite CS, assert(LiveVec.size() == BaseVec.size()); // Do the actual rewriting and delete the old statepoint - makeStatepointExplicitImpl(CS, BaseVec, LiveVec, Result, Replacements); + makeStatepointExplicitImpl(Call, BaseVec, LiveVec, Result, Replacements); } // Helper function for the relocationViaAlloca. @@ -1636,7 +1628,7 @@ makeStatepointExplicit(DominatorTree &DT, CallSite CS, // for sanity checking. static void insertRelocationStores(iterator_range<Value::user_iterator> GCRelocs, - DenseMap<Value *, Value *> &AllocaMap, + DenseMap<Value *, AllocaInst *> &AllocaMap, DenseSet<Value *> &VisitedLiveValues) { for (User *U : GCRelocs) { GCRelocateInst *Relocate = dyn_cast<GCRelocateInst>(U); @@ -1671,7 +1663,7 @@ insertRelocationStores(iterator_range<Value::user_iterator> GCRelocs, // "insertRelocationStores" but works for rematerialized values. static void insertRematerializationStores( const RematerializedValueMapTy &RematerializedValues, - DenseMap<Value *, Value *> &AllocaMap, + DenseMap<Value *, AllocaInst *> &AllocaMap, DenseSet<Value *> &VisitedLiveValues) { for (auto RematerializedValuePair: RematerializedValues) { Instruction *RematerializedValue = RematerializedValuePair.first; @@ -1704,7 +1696,7 @@ static void relocationViaAlloca( #endif // TODO-PERF: change data structures, reserve - DenseMap<Value *, Value *> AllocaMap; + DenseMap<Value *, AllocaInst *> AllocaMap; SmallVector<AllocaInst *, 200> PromotableAllocas; // Used later to chack that we have enough allocas to store all values std::size_t NumRematerializedValues = 0; @@ -1774,7 +1766,7 @@ static void relocationViaAlloca( SmallVector<AllocaInst *, 64> ToClobber; for (auto Pair : AllocaMap) { Value *Def = Pair.first; - AllocaInst *Alloca = cast<AllocaInst>(Pair.second); + AllocaInst *Alloca = Pair.second; // This value was relocated if (VisitedLiveValues.count(Def)) { @@ -1806,7 +1798,7 @@ static void relocationViaAlloca( // Update use with load allocas and add store for gc_relocated. for (auto Pair : AllocaMap) { Value *Def = Pair.first; - Value *Alloca = Pair.second; + AllocaInst *Alloca = Pair.second; // We pre-record the uses of allocas so that we dont have to worry about // later update that changes the user information.. @@ -1834,13 +1826,15 @@ static void relocationViaAlloca( PHINode *Phi = cast<PHINode>(Use); for (unsigned i = 0; i < Phi->getNumIncomingValues(); i++) { if (Def == Phi->getIncomingValue(i)) { - LoadInst *Load = new LoadInst( - Alloca, "", Phi->getIncomingBlock(i)->getTerminator()); + LoadInst *Load = + new LoadInst(Alloca->getAllocatedType(), Alloca, "", + Phi->getIncomingBlock(i)->getTerminator()); Phi->setIncomingValue(i, Load); } } } else { - LoadInst *Load = new LoadInst(Alloca, "", Use); + LoadInst *Load = + new LoadInst(Alloca->getAllocatedType(), Alloca, "", Use); Use->replaceUsesOfWith(Def, Load); } } @@ -1893,25 +1887,25 @@ template <typename T> static void unique_unsorted(SmallVectorImpl<T> &Vec) { /// Insert holders so that each Value is obviously live through the entire /// lifetime of the call. -static void insertUseHolderAfter(CallSite &CS, const ArrayRef<Value *> Values, +static void insertUseHolderAfter(CallBase *Call, const ArrayRef<Value *> Values, SmallVectorImpl<CallInst *> &Holders) { if (Values.empty()) // No values to hold live, might as well not insert the empty holder return; - Module *M = CS.getInstruction()->getModule(); + Module *M = Call->getModule(); // Use a dummy vararg function to actually hold the values live - Function *Func = cast<Function>(M->getOrInsertFunction( - "__tmp_use", FunctionType::get(Type::getVoidTy(M->getContext()), true))); - if (CS.isCall()) { + FunctionCallee Func = M->getOrInsertFunction( + "__tmp_use", FunctionType::get(Type::getVoidTy(M->getContext()), true)); + if (isa<CallInst>(Call)) { // For call safepoints insert dummy calls right after safepoint - Holders.push_back(CallInst::Create(Func, Values, "", - &*++CS.getInstruction()->getIterator())); + Holders.push_back( + CallInst::Create(Func, Values, "", &*++Call->getIterator())); return; } // For invoke safepooints insert dummy calls both in normal and // exceptional destination blocks - auto *II = cast<InvokeInst>(CS.getInstruction()); + auto *II = cast<InvokeInst>(Call); Holders.push_back(CallInst::Create( Func, Values, "", &*II->getNormalDest()->getFirstInsertionPt())); Holders.push_back(CallInst::Create( @@ -1919,7 +1913,7 @@ static void insertUseHolderAfter(CallSite &CS, const ArrayRef<Value *> Values, } static void findLiveReferences( - Function &F, DominatorTree &DT, ArrayRef<CallSite> toUpdate, + Function &F, DominatorTree &DT, ArrayRef<CallBase *> toUpdate, MutableArrayRef<struct PartiallyConstructedSafepointRecord> records) { GCPtrLivenessData OriginalLivenessData; computeLiveInValues(DT, F, OriginalLivenessData); @@ -2022,7 +2016,7 @@ static bool AreEquivalentPhiNodes(PHINode &OrigRootPhi, PHINode &AlternateRootPh // to relocate. Remove this values from the live set, rematerialize them after // statepoint and record them in "Info" structure. Note that similar to // relocated values we don't do any user adjustments here. -static void rematerializeLiveValues(CallSite CS, +static void rematerializeLiveValues(CallBase *Call, PartiallyConstructedSafepointRecord &Info, TargetTransformInfo &TTI) { const unsigned int ChainLengthThreshold = 10; @@ -2076,7 +2070,7 @@ static void rematerializeLiveValues(CallSite CS, // For invokes we need to rematerialize each chain twice - for normal and // for unwind basic blocks. Model this by multiplying cost by two. - if (CS.isInvoke()) { + if (isa<InvokeInst>(Call)) { Cost *= 2; } // If it's too expensive - skip it @@ -2144,14 +2138,14 @@ static void rematerializeLiveValues(CallSite CS, // Different cases for calls and invokes. For invokes we need to clone // instructions both on normal and unwind path. - if (CS.isCall()) { - Instruction *InsertBefore = CS.getInstruction()->getNextNode(); + if (isa<CallInst>(Call)) { + Instruction *InsertBefore = Call->getNextNode(); assert(InsertBefore); Instruction *RematerializedValue = rematerializeChain( InsertBefore, RootOfChain, Info.PointerToBase[LiveValue]); Info.RematerializedValues[RematerializedValue] = LiveValue; } else { - InvokeInst *Invoke = cast<InvokeInst>(CS.getInstruction()); + auto *Invoke = cast<InvokeInst>(Call); Instruction *NormalInsertBefore = &*Invoke->getNormalDest()->getFirstInsertionPt(); @@ -2176,25 +2170,25 @@ static void rematerializeLiveValues(CallSite CS, static bool insertParsePoints(Function &F, DominatorTree &DT, TargetTransformInfo &TTI, - SmallVectorImpl<CallSite> &ToUpdate) { + SmallVectorImpl<CallBase *> &ToUpdate) { #ifndef NDEBUG // sanity check the input - std::set<CallSite> Uniqued; + std::set<CallBase *> Uniqued; Uniqued.insert(ToUpdate.begin(), ToUpdate.end()); assert(Uniqued.size() == ToUpdate.size() && "no duplicates please!"); - for (CallSite CS : ToUpdate) - assert(CS.getInstruction()->getFunction() == &F); + for (CallBase *Call : ToUpdate) + assert(Call->getFunction() == &F); #endif // When inserting gc.relocates for invokes, we need to be able to insert at // the top of the successor blocks. See the comment on // normalForInvokeSafepoint on exactly what is needed. Note that this step // may restructure the CFG. - for (CallSite CS : ToUpdate) { - if (!CS.isInvoke()) + for (CallBase *Call : ToUpdate) { + auto *II = dyn_cast<InvokeInst>(Call); + if (!II) continue; - auto *II = cast<InvokeInst>(CS.getInstruction()); normalizeForInvokeSafepoint(II->getNormalDest(), II->getParent(), DT); normalizeForInvokeSafepoint(II->getUnwindDest(), II->getParent(), DT); } @@ -2207,17 +2201,17 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, // actual safepoint insertion as arguments. This ensures reference operands // in the deopt argument list are considered live through the safepoint (and // thus makes sure they get relocated.) - for (CallSite CS : ToUpdate) { + for (CallBase *Call : ToUpdate) { SmallVector<Value *, 64> DeoptValues; - for (Value *Arg : GetDeoptBundleOperands(CS)) { + for (Value *Arg : GetDeoptBundleOperands(Call)) { assert(!isUnhandledGCPointerType(Arg->getType()) && "support for FCA unimplemented"); if (isHandledGCPointerType(Arg->getType())) DeoptValues.push_back(Arg); } - insertUseHolderAfter(CS, DeoptValues, Holders); + insertUseHolderAfter(Call, DeoptValues, Holders); } SmallVector<PartiallyConstructedSafepointRecord, 64> Records(ToUpdate.size()); @@ -2319,7 +2313,7 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, for (size_t i = 0; i < Records.size(); i++) makeStatepointExplicit(DT, ToUpdate[i], Records[i], Replacements); - ToUpdate.clear(); // prevent accident use of invalid CallSites + ToUpdate.clear(); // prevent accident use of invalid calls. for (auto &PR : Replacements) PR.doReplacement(); @@ -2384,7 +2378,7 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, return !Records.empty(); } -// Handles both return values and arguments for Functions and CallSites. +// Handles both return values and arguments for Functions and calls. template <typename AttrHolder> static void RemoveNonValidAttrAtIndex(LLVMContext &Ctx, AttrHolder &AH, unsigned Index) { @@ -2476,12 +2470,13 @@ static void stripNonValidDataFromBody(Function &F) { stripInvalidMetadataFromInstruction(I); - if (CallSite CS = CallSite(&I)) { - for (int i = 0, e = CS.arg_size(); i != e; i++) - if (isa<PointerType>(CS.getArgument(i)->getType())) - RemoveNonValidAttrAtIndex(Ctx, CS, i + AttributeList::FirstArgIndex); - if (isa<PointerType>(CS.getType())) - RemoveNonValidAttrAtIndex(Ctx, CS, AttributeList::ReturnIndex); + if (auto *Call = dyn_cast<CallBase>(&I)) { + for (int i = 0, e = Call->arg_size(); i != e; i++) + if (isa<PointerType>(Call->getArgOperand(i)->getType())) + RemoveNonValidAttrAtIndex(Ctx, *Call, + i + AttributeList::FirstArgIndex); + if (isa<PointerType>(Call->getType())) + RemoveNonValidAttrAtIndex(Ctx, *Call, AttributeList::ReturnIndex); } } @@ -2526,12 +2521,11 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, assert(shouldRewriteStatepointsIn(F) && "mismatch in rewrite decision"); auto NeedsRewrite = [&TLI](Instruction &I) { - if (ImmutableCallSite CS = ImmutableCallSite(&I)) - return !callsGCLeafFunction(CS, TLI) && !isStatepoint(CS); + if (const auto *Call = dyn_cast<CallBase>(&I)) + return !callsGCLeafFunction(Call, TLI) && !isStatepoint(Call); return false; }; - // Delete any unreachable statepoints so that we don't have unrewritten // statepoints surviving this pass. This makes testing easier and the // resulting IR less confusing to human readers. @@ -2543,7 +2537,7 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, // Gather all the statepoints which need rewritten. Be careful to only // consider those in reachable code since we need to ask dominance queries // when rewriting. We'll delete the unreachable ones in a moment. - SmallVector<CallSite, 64> ParsePointNeeded; + SmallVector<CallBase *, 64> ParsePointNeeded; for (Instruction &I : instructions(F)) { // TODO: only the ones with the flag set! if (NeedsRewrite(I)) { @@ -2553,7 +2547,7 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, // isReachableFromEntry() returns true. assert(DT.isReachableFromEntry(I.getParent()) && "no unreachable blocks expected"); - ParsePointNeeded.push_back(CallSite(&I)); + ParsePointNeeded.push_back(cast<CallBase>(&I)); } } @@ -2602,6 +2596,33 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, } } + // Nasty workaround - The base computation code in the main algorithm doesn't + // consider the fact that a GEP can be used to convert a scalar to a vector. + // The right fix for this is to integrate GEPs into the base rewriting + // algorithm properly, this is just a short term workaround to prevent + // crashes by canonicalizing such GEPs into fully vector GEPs. + for (Instruction &I : instructions(F)) { + if (!isa<GetElementPtrInst>(I)) + continue; + + unsigned VF = 0; + for (unsigned i = 0; i < I.getNumOperands(); i++) + if (I.getOperand(i)->getType()->isVectorTy()) { + assert(VF == 0 || + VF == I.getOperand(i)->getType()->getVectorNumElements()); + VF = I.getOperand(i)->getType()->getVectorNumElements(); + } + + // It's the vector to scalar traversal through the pointer operand which + // confuses base pointer rewriting, so limit ourselves to that case. + if (!I.getOperand(0)->getType()->isVectorTy() && VF != 0) { + IRBuilder<> B(&I); + auto *Splat = B.CreateVectorSplat(VF, I.getOperand(0)); + I.setOperand(0, Splat); + MadeChange = true; + } + } + MadeChange |= insertParsePoints(F, DT, TTI, ParsePointNeeded); return MadeChange; } @@ -2786,11 +2807,10 @@ static void findLiveSetAtInst(Instruction *Inst, GCPtrLivenessData &Data, } static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, - CallSite CS, + CallBase *Call, PartiallyConstructedSafepointRecord &Info) { - Instruction *Inst = CS.getInstruction(); StatepointLiveSetTy Updated; - findLiveSetAtInst(Inst, RevisedLivenessData, Updated); + findLiveSetAtInst(Call, RevisedLivenessData, Updated); // We may have base pointers which are now live that weren't before. We need // to update the PointerToBase structure to reflect this. |