diff options
Diffstat (limited to 'include/llvm/IR/Statepoint.h')
-rw-r--r-- | include/llvm/IR/Statepoint.h | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h new file mode 100644 index 0000000..38720ed --- /dev/null +++ b/include/llvm/IR/Statepoint.h @@ -0,0 +1,298 @@ +//===-- llvm/IR/Statepoint.h - gc.statepoint utilities ------ --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains utility functions and a wrapper class analogous to +// CallSite for accessing the fields of gc.statepoint, gc.relocate, and +// gc.result intrinsics +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_IR_STATEPOINT_H +#define __LLVM_IR_STATEPOINT_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class GCRelocateOperands; +class ImmutableStatepoint; + +bool isStatepoint(const ImmutableCallSite &CS); +bool isStatepoint(const Value *inst); +bool isStatepoint(const Value &inst); + +bool isGCRelocate(const Value *inst); +bool isGCRelocate(const ImmutableCallSite &CS); + +bool isGCResult(const Value *inst); +bool isGCResult(const ImmutableCallSite &CS); + +/// Analogous to CallSiteBase, 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. This is structured analogous to CallSite +/// rather than the IntrinsicInst.h helpers since we want to support +/// invokable statepoints in the near future. +/// TODO: This does not currently allow the if(Statepoint S = ...) +/// idiom used with CallSites. Consider refactoring to support. +template <typename InstructionTy, typename ValueTy, typename CallSiteTy> +class StatepointBase { + CallSiteTy StatepointCS; + void *operator new(size_t, unsigned) = delete; + void *operator new(size_t s) = delete; + + protected: + explicit StatepointBase(InstructionTy *I) : StatepointCS(I) { + assert(isStatepoint(I)); + } + explicit StatepointBase(CallSiteTy CS) : StatepointCS(CS) { + assert(isStatepoint(CS)); + } + + public: + typedef typename CallSiteTy::arg_iterator arg_iterator; + + /// Return the underlying CallSite. + CallSiteTy getCallSite() { + return StatepointCS; + } + + /// Return the value actually being called or invoked. + ValueTy *actualCallee() { + return StatepointCS.getArgument(0); + } + /// Number of arguments to be passed to the actual callee. + int numCallArgs() { + return cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue(); + } + /// Number of additional arguments excluding those intended + /// for garbage collection. + int numTotalVMSArgs() { + return cast<ConstantInt>(StatepointCS.getArgument(3 + numCallArgs()))->getZExtValue(); + } + + typename CallSiteTy::arg_iterator call_args_begin() { + // 3 = callTarget, #callArgs, flag + int Offset = 3; + assert(Offset <= (int)StatepointCS.arg_size()); + return StatepointCS.arg_begin() + Offset; + } + typename CallSiteTy::arg_iterator call_args_end() { + int Offset = 3 + numCallArgs(); + assert(Offset <= (int)StatepointCS.arg_size()); + return StatepointCS.arg_begin() + Offset; + } + + /// range adapter for call arguments + iterator_range<arg_iterator> call_args() { + return iterator_range<arg_iterator>(call_args_begin(), call_args_end()); + } + + typename CallSiteTy::arg_iterator vm_state_begin() { + return call_args_end(); + } + typename CallSiteTy::arg_iterator vm_state_end() { + int Offset = 3 + numCallArgs() + 1 + numTotalVMSArgs(); + assert(Offset <= (int)StatepointCS.arg_size()); + return StatepointCS.arg_begin() + Offset; + } + + /// range adapter for vm state arguments + iterator_range<arg_iterator> vm_state_args() { + return iterator_range<arg_iterator>(vm_state_begin(), vm_state_end()); + } + + typename CallSiteTy::arg_iterator first_vm_state_stack_begin() { + // 6 = numTotalVMSArgs, 1st_objectID, 1st_bci, + // 1st_#stack, 1st_#local, 1st_#monitor + return vm_state_begin() + 6; + } + + typename CallSiteTy::arg_iterator gc_args_begin() { + return vm_state_end(); + } + typename CallSiteTy::arg_iterator gc_args_end() { + return StatepointCS.arg_end(); + } + + /// range adapter for gc arguments + iterator_range<arg_iterator> gc_args() { + return iterator_range<arg_iterator>(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<GCRelocateOperands> getRelocates(ImmutableStatepoint &IS); + +#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(numCallArgs() >= 0 && + "number of arguments to actually callee can't be negative"); + + // The internal asserts in the iterator accessors do the rest. + (void)call_args_begin(); + (void)call_args_end(); + (void)vm_state_begin(); + (void)vm_state_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 Instruction, const Value, + ImmutableCallSite> { + typedef StatepointBase<const Instruction, const Value, ImmutableCallSite> + Base; + +public: + explicit ImmutableStatepoint(const Instruction *I) : Base(I) {} + explicit ImmutableStatepoint(ImmutableCallSite CS) : Base(CS) {} +}; + +/// A specialization of it's base class for read-write access +/// to a gc.statepoint. +class Statepoint : public StatepointBase<Instruction, Value, CallSite> { + typedef StatepointBase<Instruction, Value, CallSite> Base; + +public: + explicit Statepoint(Instruction *I) : Base(I) {} + explicit Statepoint(CallSite CS) : Base(CS) {} +}; + +/// Wraps a call to a gc.relocate and provides access to it's operands. +/// TODO: This should likely be refactored to resememble the wrappers in +/// InstrinsicInst.h. +class GCRelocateOperands { + ImmutableCallSite RelocateCS; + + public: + GCRelocateOperands(const User* U) : RelocateCS(U) { + assert(isGCRelocate(U)); + } + GCRelocateOperands(const Instruction *inst) : RelocateCS(inst) { + assert(isGCRelocate(inst)); + } + GCRelocateOperands(CallSite CS) : RelocateCS(CS) { + 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<ExtractValueInst>(Token) || + isa<InvokeInst>(Token); + } + + /// Get enclosed relocate intrinsic + ImmutableCallSite getUnderlyingCallSite() { + return RelocateCS; + } + + /// The statepoint with which this gc.relocate is associated. + const Instruction *statepoint() { + 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<ExtractValueInst>(token)) { + return cast<Instruction>(token); + } + + // This relocate is on exceptional path of an invoke statepoint + const BasicBlock *invokeBB = + cast<Instruction>(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 + /// relocation this gc.relocate describes. + unsigned basePtrIndex() { + return cast<ConstantInt>(RelocateCS.getArgument(1))->getZExtValue(); + } + /// The index into the associate statepoint's argument list which + /// contains the pointer whose relocation this gc.relocate describes. + unsigned derivedPtrIndex() { + return cast<ConstantInt>(RelocateCS.getArgument(2))->getZExtValue(); + } + Value *basePtr() { + ImmutableCallSite CS(statepoint()); + return *(CS.arg_begin() + basePtrIndex()); + } + Value *derivedPtr() { + ImmutableCallSite CS(statepoint()); + return *(CS.arg_begin() + derivedPtrIndex()); + } +}; + +template <typename InstructionTy, typename ValueTy, typename CallSiteTy> +std::vector<GCRelocateOperands> + StatepointBase<InstructionTy, ValueTy, CallSiteTy>:: + getRelocates(ImmutableStatepoint &IS) { + + std::vector<GCRelocateOperands> 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<InvokeInst>(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<ExtractValueInst>(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 |