Index: llvm/trunk/include/llvm/IR/Statepoint.h =================================================================== --- llvm/trunk/include/llvm/IR/Statepoint.h +++ llvm/trunk/include/llvm/IR/Statepoint.h @@ -24,14 +24,17 @@ 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 Instruction *inst); +bool isGCRelocate(const Value *inst); bool isGCRelocate(const ImmutableCallSite &CS); -bool isGCResult(const Instruction *inst); +bool isGCResult(const Value *inst); bool isGCResult(const ImmutableCallSite &CS); /// Analogous to CallSiteBase, this provides most of the actual @@ -127,6 +130,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 unwinding + /// path of invoke. + std::vector getRelocates(ImmutableStatepoint &IS); #ifndef NDEBUG /// Asserts if this statepoint is malformed. Common cases for failure @@ -187,9 +195,39 @@ assert(isGCRelocate(CS)); } + /// Return true if this relocate is tied to the invoke statepoint. + /// This includes relocates which are on the unwinding path. + 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); + + // This takes care both of relocates for call statepoints and relocates + // on normal path of invoke statepoint. + 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,49 @@ 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)); + } + } + + if (!StatepointCS.isInvoke()) { + return res; + } + + // We need to scan thorough exceptional relocations if it is invoke statepoint + 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: llvm/trunk/lib/IR/Statepoint.cpp =================================================================== --- llvm/trunk/lib/IR/Statepoint.cpp +++ llvm/trunk/lib/IR/Statepoint.cpp @@ -20,24 +20,34 @@ using namespace llvm; bool llvm::isStatepoint(const ImmutableCallSite &CS) { + if (!CS.getInstruction()) { + // This is not a call site + return false; + } + 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::isGCRelocate(const ImmutableCallSite &CS) { + if (!CS.getInstruction()) { + // This is not a call site + return false; + } + 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; @@ -47,9 +57,14 @@ } bool llvm::isGCResult(const ImmutableCallSite &CS) { + if (!CS.getInstruction()) { + // This is not a call site + return false; + } + 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 ||