Index: include/llvm/IR/Statepoint.h =================================================================== --- include/llvm/IR/Statepoint.h +++ include/llvm/IR/Statepoint.h @@ -24,13 +24,20 @@ namespace llvm { +class GCRelocateOperands; +class ImmutableStatepoint; + bool isStatepoint(const ImmutableCallSite &CS); bool isStatepoint(const Instruction *inst); bool isStatepoint(const Instruction &inst); +bool isStatepoint(const Value *inst); +bool isStatepoint(const Value &inst); +bool isGCRelocate(const Value *inst); bool isGCRelocate(const Instruction *inst); bool isGCRelocate(const ImmutableCallSite &CS); +bool isGCResult(const Value *inst); bool isGCResult(const Instruction *inst); bool isGCResult(const ImmutableCallSite &CS); @@ -127,6 +134,11 @@ return iterator_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 exceptional + /// path of invoke. + std::vector getRelocates(ImmutableStatepoint &IS); #ifndef NDEBUG /// Asserts if this statepoint is malformed. Common cases for failure @@ -187,9 +199,35 @@ assert(isGCRelocate(CS)); } + bool isTiedToInvoke() const { + const Value *Token = RelocateCS.getArgument(0); + + return isa(Token) || + isa(Token); + } + + /// Get enclosed relocate intrinsic + ImmutableCallSite getUnderlyingCallSite() { + return RelocateCS; + } + /// The statepoint with which this gc.relocate is associated. const Instruction *statepoint() { - return cast(RelocateCS.getArgument(0)); + const Value *token = RelocateCS.getArgument(0); + + if (!isa(token)) { + return cast(token); + } + + // This relocate is on exceptional path of an invoke statepoint + const BasicBlock *invokeBB = + cast(token)->getParent()->getUniquePredecessor(); + + assert(invokeBB && "safepoints should have unique landingpads"); + assert(invokeBB->getTerminator() && "safepoint block should be well formed"); + assert(isStatepoint(invokeBB->getTerminator())); + + return invokeBB->getTerminator(); } /// The index into the associate statepoint's argument list /// which contains the base pointer of the pointer whose @@ -211,5 +249,47 @@ return *(CS.arg_begin() + derivedPtrIndex()); } }; + +template +std::vector + StatepointBase:: + getRelocates(ImmutableStatepoint &IS) { + + std::vector res; + + ImmutableCallSite StatepointCS = IS.getCallSite(); + + // 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 : StatepointCS.getInstruction()->users()) { + if (isGCRelocate(U)) { + res.push_back(GCRelocateOperands(U)); + } + } + + // Scan thorough exceptional relocations if it is invoke statepoint + if (StatepointCS.isInvoke()) { + LandingPadInst *landingpad = + cast(StatepointCS.getInstruction())->getLandingPadInst(); + + // Search for extract value from landingpad instruction to which + // gc relocates will be attached + for (const User *landingpadUser : landingpad->users()) { + if (!isa(landingpadUser)) { + continue; + } + + // gc relocates should be attached to this extract value + for (const User *U : landingpadUser->users()) { + if (isGCRelocate(U)) { + res.push_back(GCRelocateOperands(U)); + } + } + } + } + return res; +} + } #endif Index: lib/IR/Statepoint.cpp =================================================================== --- lib/IR/Statepoint.cpp +++ lib/IR/Statepoint.cpp @@ -23,21 +23,27 @@ const Function *F = CS.getCalledFunction(); return (F && F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint); } -bool llvm::isStatepoint(const Instruction *inst) { +bool llvm::isStatepoint(const Value *inst) { if (isa(inst) || isa(inst)) { ImmutableCallSite CS(inst); return isStatepoint(CS); } return false; } -bool llvm::isStatepoint(const Instruction &inst) { +bool llvm::isStatepoint(const Value &inst) { return isStatepoint(&inst); } +bool llvm::isStatepoint(const Instruction *inst) { + return isStatepoint(static_cast(inst)); +} +bool llvm::isStatepoint(const Instruction &inst) { + return isStatepoint(static_cast(&inst)); +} bool llvm::isGCRelocate(const ImmutableCallSite &CS) { return isGCRelocate(CS.getInstruction()); } -bool llvm::isGCRelocate(const Instruction *inst) { +bool llvm::isGCRelocate(const Value *inst) { if (const CallInst *call = dyn_cast(inst)) { if (const Function *F = call->getCalledFunction()) { return F->getIntrinsicID() == Intrinsic::experimental_gc_relocate; @@ -45,11 +51,14 @@ } return false; } +bool llvm::isGCRelocate(const Instruction *inst) { + return isGCRelocate(static_cast(inst)); +} bool llvm::isGCResult(const ImmutableCallSite &CS) { return isGCResult(CS.getInstruction()); } -bool llvm::isGCResult(const Instruction *inst) { +bool llvm::isGCResult(const Value *inst) { if (const CallInst *call = dyn_cast(inst)) { if (Function *F = call->getCalledFunction()) { return (F->getIntrinsicID() == Intrinsic::experimental_gc_result_int || @@ -60,3 +69,6 @@ } return false; } +bool llvm::isGCResult(const Instruction *inst) { + return isGCResult(static_cast(inst)); +}