diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/include/llvm/IR/Statepoint.h | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'llvm/include/llvm/IR/Statepoint.h')
-rw-r--r-- | llvm/include/llvm/IR/Statepoint.h | 309 |
1 files changed, 123 insertions, 186 deletions
diff --git a/llvm/include/llvm/IR/Statepoint.h b/llvm/include/llvm/IR/Statepoint.h index 89f130bc3351..1ace39c10701 100644 --- a/llvm/include/llvm/IR/Statepoint.h +++ b/llvm/include/llvm/IR/Statepoint.h @@ -55,37 +55,25 @@ enum class StatepointFlags { class GCRelocateInst; class GCResultInst; -bool isStatepoint(const CallBase *Call); -bool isStatepoint(const Value *V); -bool isStatepoint(const Value &V); - -bool isGCRelocate(const CallBase *Call); -bool isGCRelocate(const Value *V); - -bool isGCResult(const CallBase *Call); -bool isGCResult(const Value *V); - -/// A wrapper around a GC intrinsic call, this provides most of the actual -/// functionality for Statepoint and ImmutableStatepoint. It is -/// templatized to allow easily specializing of const and non-const -/// concrete subtypes. -template <typename FunTy, typename InstructionTy, typename ValueTy, - typename CallBaseTy> -class StatepointBase { - CallBaseTy *StatepointCall; +/// Represents a gc.statepoint intrinsic call. This extends directly from +/// CallBase as the IntrinsicInst only supports calls and gc.statepoint is +/// invokable. +class GCStatepointInst : public CallBase { +public: + GCStatepointInst() = delete; + GCStatepointInst(const GCStatepointInst &) = delete; + GCStatepointInst &operator=(const GCStatepointInst &) = delete; -protected: - explicit StatepointBase(InstructionTy *I) { - StatepointCall = isStatepoint(I) ? cast<CallBaseTy>(I) : nullptr; + static bool classof(const CallBase *I) { + if (const Function *CF = I->getCalledFunction()) + return CF->getIntrinsicID() == Intrinsic::experimental_gc_statepoint; + return false; } - explicit StatepointBase(CallBaseTy *Call) { - StatepointCall = isStatepoint(Call) ? Call : nullptr; + static bool classof(const Value *V) { + return isa<CallBase>(V) && classof(cast<CallBase>(V)); } -public: - using arg_iterator = typename CallBaseTy::const_op_iterator; - enum { IDPos = 0, NumPatchBytesPos = 1, @@ -95,220 +83,172 @@ public: CallArgsBeginPos = 5, }; - void *operator new(size_t, unsigned) = delete; - void *operator new(size_t s) = delete; - - explicit operator bool() const { - // We do not assign non-statepoint call instructions to StatepointCall. - return (bool)StatepointCall; - } - - /// Return the underlying call instruction. - CallBaseTy *getCall() const { - assert(*this && "check validity first!"); - return StatepointCall; - } - - uint64_t getFlags() const { - return cast<ConstantInt>(getCall()->getArgOperand(FlagsPos)) - ->getZExtValue(); - } - /// Return the ID associated with this statepoint. uint64_t getID() const { - const Value *IDVal = getCall()->getArgOperand(IDPos); - return cast<ConstantInt>(IDVal)->getZExtValue(); + return cast<ConstantInt>(getArgOperand(IDPos))->getZExtValue(); } /// Return the number of patchable bytes associated with this statepoint. uint32_t getNumPatchBytes() const { - const Value *NumPatchBytesVal = getCall()->getArgOperand(NumPatchBytesPos); + const Value *NumPatchBytesVal = getArgOperand(NumPatchBytesPos); uint64_t NumPatchBytes = cast<ConstantInt>(NumPatchBytesVal)->getZExtValue(); assert(isInt<32>(NumPatchBytes) && "should fit in 32 bits!"); return NumPatchBytes; } - /// Return the value actually being called or invoked. - ValueTy *getCalledValue() const { - return getCall()->getArgOperand(CalledFunctionPos); + /// Number of arguments to be passed to the actual callee. + int getNumCallArgs() const { + return cast<ConstantInt>(getArgOperand(NumCallArgsPos))->getZExtValue(); } - // FIXME: Migrate users of this to `getCall` and remove it. - InstructionTy *getInstruction() const { return getCall(); } - - /// Return the function being called if this is a direct call, otherwise - /// return null (if it's an indirect call). - FunTy *getCalledFunction() const { - return dyn_cast<Function>(getCalledValue()); + uint64_t getFlags() const { + return cast<ConstantInt>(getArgOperand(FlagsPos))->getZExtValue(); } - /// Return the caller function for this statepoint. - FunTy *getCaller() const { return getCall()->getCaller(); } + /// Return the value actually being called or invoked. + Value *getActualCalledOperand() const { + return getArgOperand(CalledFunctionPos); + } - /// Determine if the statepoint cannot unwind. - bool doesNotThrow() const { - Function *F = getCalledFunction(); - return getCall()->doesNotThrow() || (F ? F->doesNotThrow() : false); + /// Returns the function called if this is a wrapping a direct call, and null + /// otherwise. + Function *getActualCalledFunction() const { + return dyn_cast_or_null<Function>(getActualCalledOperand()); } /// Return the type of the value returned by the call underlying the /// statepoint. Type *getActualReturnType() const { - auto *FTy = cast<FunctionType>( - cast<PointerType>(getCalledValue()->getType())->getElementType()); - return FTy->getReturnType(); + auto *CalleeTy = + cast<PointerType>(getActualCalledOperand()->getType())->getElementType(); + return cast<FunctionType>(CalleeTy)->getReturnType(); } - /// Number of arguments to be passed to the actual callee. - int getNumCallArgs() const { - const Value *NumCallArgsVal = getCall()->getArgOperand(NumCallArgsPos); - return cast<ConstantInt>(NumCallArgsVal)->getZExtValue(); - } - size_t arg_size() const { return getNumCallArgs(); } - arg_iterator arg_begin() const { - assert(CallArgsBeginPos <= (int)getCall()->arg_size()); - return getCall()->arg_begin() + CallArgsBeginPos; + /// Return the number of arguments to the underlying call. + size_t actual_arg_size() const { return getNumCallArgs(); } + /// Return an iterator to the begining of the arguments to the underlying call + const_op_iterator actual_arg_begin() const { + assert(CallArgsBeginPos <= (int)arg_size()); + return arg_begin() + CallArgsBeginPos; } - arg_iterator arg_end() const { - auto I = arg_begin() + arg_size(); - assert((getCall()->arg_end() - I) >= 0); + /// Return an end iterator of the arguments to the underlying call + const_op_iterator actual_arg_end() const { + auto I = actual_arg_begin() + actual_arg_size(); + assert((arg_end() - I) >= 0); return I; } - - ValueTy *getArgument(unsigned Index) { - assert(Index < arg_size() && "out of bounds!"); - return *(arg_begin() + Index); + /// range adapter for actual call arguments + iterator_range<const_op_iterator> actual_args() const { + return make_range(actual_arg_begin(), actual_arg_end()); } - /// range adapter for call arguments - iterator_range<arg_iterator> call_args() const { - return make_range(arg_begin(), arg_end()); - } - - /// Return true if the call or the callee has the given attribute. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const { - Function *F = getCalledFunction(); - return getCall()->paramHasAttr(i + CallArgsBeginPos, A) || - (F ? F->getAttributes().hasAttribute(i, A) : false); - } - - /// Number of GC transition args. - int getNumTotalGCTransitionArgs() const { - const Value *NumGCTransitionArgs = *arg_end(); - return cast<ConstantInt>(NumGCTransitionArgs)->getZExtValue(); - } - arg_iterator gc_transition_args_begin() const { - auto I = arg_end() + 1; - assert((getCall()->arg_end() - I) >= 0); + const_op_iterator gc_transition_args_begin() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_gc_transition)) + return Opt->Inputs.begin(); + auto I = actual_arg_end() + 1; + assert((arg_end() - I) >= 0); return I; } - arg_iterator gc_transition_args_end() const { - auto I = gc_transition_args_begin() + getNumTotalGCTransitionArgs(); - assert((getCall()->arg_end() - I) >= 0); + const_op_iterator gc_transition_args_end() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_gc_transition)) + return Opt->Inputs.end(); + auto I = gc_transition_args_begin() + getNumDeoptArgs(); + assert((arg_end() - I) >= 0); return I; } /// range adapter for GC transition arguments - iterator_range<arg_iterator> gc_transition_args() const { + iterator_range<const_op_iterator> gc_transition_args() const { return make_range(gc_transition_args_begin(), gc_transition_args_end()); } - /// Number of additional arguments excluding those intended - /// for garbage collection. - int getNumTotalVMSArgs() const { - const Value *NumVMSArgs = *gc_transition_args_end(); - return cast<ConstantInt>(NumVMSArgs)->getZExtValue(); - } - - arg_iterator deopt_begin() const { - auto I = gc_transition_args_end() + 1; - assert((getCall()->arg_end() - I) >= 0); + const_op_iterator deopt_begin() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_deopt)) + return Opt->Inputs.begin(); + // The current format has two length prefix bundles between call args and + // start of gc args. This will be removed in the near future. + uint64_t NumTrans = getNumGCTransitionArgs(); + const_op_iterator I = actual_arg_end() + 2 + NumTrans; + assert((arg_end() - I) >= 0); return I; } - arg_iterator deopt_end() const { - auto I = deopt_begin() + getNumTotalVMSArgs(); - assert((getCall()->arg_end() - I) >= 0); + const_op_iterator deopt_end() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_deopt)) + return Opt->Inputs.end(); + auto I = deopt_begin() + getNumDeoptArgs(); + assert((arg_end() - I) >= 0); return I; } /// range adapter for vm state arguments - iterator_range<arg_iterator> deopt_operands() const { + iterator_range<const_op_iterator> deopt_operands() const { return make_range(deopt_begin(), deopt_end()); } - arg_iterator gc_args_begin() const { return deopt_end(); } - arg_iterator gc_args_end() const { return getCall()->arg_end(); } + /// Returns an iterator to the begining of the argument range describing gc + /// values for the statepoint. + const_op_iterator gc_args_begin() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_gc_live)) + return Opt->Inputs.begin(); + + // The current format has two length prefix bundles between call args and + // start of gc args. This will be removed in the near future. + uint64_t NumTrans = getNumGCTransitionArgs(); + uint64_t NumDeopt = getNumDeoptArgs(); + auto I = actual_arg_end() + 2 + NumTrans + NumDeopt; + assert((arg_end() - I) >= 0); + return I; + } + + /// Return an end iterator for the gc argument range + const_op_iterator gc_args_end() const { + if (auto Opt = getOperandBundle(LLVMContext::OB_gc_live)) + return Opt->Inputs.end(); + return arg_end(); + } + + /// Return the operand index at which the gc args begin unsigned gcArgsStartIdx() const { - return gc_args_begin() - getCall()->op_begin(); + assert(!getOperandBundle(LLVMContext::OB_gc_live)); + return gc_args_begin() - op_begin(); } /// range adapter for gc arguments - iterator_range<arg_iterator> gc_args() const { + iterator_range<const_op_iterator> gc_args() const { return make_range(gc_args_begin(), gc_args_end()); } + /// Get list of all gc reloactes linked to this statepoint /// May contain several relocations for the same base/derived pair. /// For example this could happen due to relocations on unwinding /// path of invoke. - std::vector<const GCRelocateInst *> getRelocates() const; + inline std::vector<const GCRelocateInst *> getGCRelocates() const; - /// Get the experimental_gc_result call tied to this statepoint. Can be - /// nullptr if there isn't a gc_result tied to this statepoint. Guaranteed to - /// be a CallInst if non-null. + /// Get the experimental_gc_result call tied to this statepoint if there is + /// one, otherwise return nullptr. const GCResultInst *getGCResult() const { - for (auto *U : getInstruction()->users()) + for (auto *U : users()) if (auto *GRI = dyn_cast<GCResultInst>(U)) return GRI; return nullptr; } -#ifndef NDEBUG - /// Asserts if this statepoint is malformed. Common cases for failure - /// include incorrect length prefixes for variable length sections or - /// illegal values for parameters. - void verify() { - assert(getNumCallArgs() >= 0 && - "number of arguments to actually callee can't be negative"); - - // The internal asserts in the iterator accessors do the rest. - (void)arg_begin(); - (void)arg_end(); - (void)gc_transition_args_begin(); - (void)gc_transition_args_end(); - (void)deopt_begin(); - (void)deopt_end(); - (void)gc_args_begin(); - (void)gc_args_end(); - } -#endif -}; - -/// A specialization of it's base class for read only access -/// to a gc.statepoint. -class ImmutableStatepoint - : public StatepointBase<const Function, const Instruction, const Value, - const CallBase> { - using Base = StatepointBase<const Function, const Instruction, const Value, - const CallBase>; - -public: - explicit ImmutableStatepoint(const Instruction *I) : Base(I) {} - explicit ImmutableStatepoint(const CallBase *Call) : Base(Call) {} -}; - -/// A specialization of it's base class for read-write access -/// to a gc.statepoint. -class Statepoint - : public StatepointBase<Function, Instruction, Value, CallBase> { - using Base = StatepointBase<Function, Instruction, Value, CallBase>; +private: + int getNumGCTransitionArgs() const { + const Value *NumGCTransitionArgs = *actual_arg_end(); + return cast<ConstantInt>(NumGCTransitionArgs)->getZExtValue(); + } -public: - explicit Statepoint(Instruction *I) : Base(I) {} - explicit Statepoint(CallBase *Call) : Base(Call) {} + int getNumDeoptArgs() const { + uint64_t NumTrans = getNumGCTransitionArgs(); + const_op_iterator trans_end = actual_arg_end() + 1 + NumTrans; + const Value *NumDeoptArgs = *trans_end; + return cast<ConstantInt>(NumDeoptArgs)->getZExtValue(); + } }; /// Common base class for representing values projected from a statepoint. @@ -333,15 +273,13 @@ public: } /// The statepoint with which this gc.relocate is associated. - const CallBase *getStatepoint() const { + const GCStatepointInst *getStatepoint() const { const Value *Token = getArgOperand(0); // This takes care both of relocates for call statepoints and relocates // on normal path of invoke statepoint. - if (!isa<LandingPadInst>(Token)) { - assert(isStatepoint(Token)); - return cast<CallBase>(Token); - } + if (!isa<LandingPadInst>(Token)) + return cast<GCStatepointInst>(Token); // This relocate is on exceptional path of an invoke statepoint const BasicBlock *InvokeBB = @@ -350,9 +288,8 @@ public: assert(InvokeBB && "safepoints should have unique landingpads"); assert(InvokeBB->getTerminator() && "safepoint block should be well formed"); - assert(isStatepoint(InvokeBB->getTerminator())); - return cast<CallBase>(InvokeBB->getTerminator()); + return cast<GCStatepointInst>(InvokeBB->getTerminator()); } }; @@ -381,10 +318,14 @@ public: } Value *getBasePtr() const { + if (auto Opt = getStatepoint()->getOperandBundle(LLVMContext::OB_gc_live)) + return *(Opt->Inputs.begin() + getBasePtrIndex()); return *(getStatepoint()->arg_begin() + getBasePtrIndex()); } Value *getDerivedPtr() const { + if (auto Opt = getStatepoint()->getOperandBundle(LLVMContext::OB_gc_live)) + return *(Opt->Inputs.begin() + getDerivedPtrIndex()); return *(getStatepoint()->arg_begin() + getDerivedPtrIndex()); } }; @@ -401,21 +342,17 @@ public: } }; -template <typename FunTy, typename InstructionTy, typename ValueTy, - typename CallBaseTy> -std::vector<const GCRelocateInst *> -StatepointBase<FunTy, InstructionTy, ValueTy, CallBaseTy>::getRelocates() - const { +std::vector<const GCRelocateInst *> GCStatepointInst::getGCRelocates() const { std::vector<const GCRelocateInst *> Result; // Search for relocated pointers. Note that working backwards from the // gc_relocates ensures that we only get pairs which are actually relocated // and used after the statepoint. - for (const User *U : StatepointCall->users()) + for (const User *U : users()) if (auto *Relocate = dyn_cast<GCRelocateInst>(U)) Result.push_back(Relocate); - auto *StatepointInvoke = dyn_cast<InvokeInst>(StatepointCall); + auto *StatepointInvoke = dyn_cast<InvokeInst>(this); if (!StatepointInvoke) return Result; |