#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Compiler.h"
MaskAll = GCTransition ///< A bitmask that includes all valid flags.
};
-class GCRelocateOperands;
+class GCRelocateInst;
class ImmutableStatepoint;
bool isStatepoint(const ImmutableCallSite &CS);
bool isStatepoint(const Value *V);
bool isStatepoint(const Value &V);
-bool isGCRelocate(const Value *V);
bool isGCRelocate(const ImmutableCallSite &CS);
bool isGCResult(const Value *V);
/// 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() const;
+ std::vector<const GCRelocateInst *> getRelocates() 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
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;
-
+/// This represents the gc.relocate intrinsic.
+class GCRelocateInst : public IntrinsicInst {
public:
- GCRelocateOperands(const User *U) : RelocateCS(U) { assert(isGCRelocate(U)); }
- GCRelocateOperands(const Instruction *inst) : RelocateCS(inst) {
- assert(isGCRelocate(inst));
+ static inline bool classof(const IntrinsicInst *I) {
+ return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate;
+ }
+ static inline bool classof(const Value *V) {
+ return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
- 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);
+ const Value *Token = getArgOperand(0);
return isa<LandingPadInst>(Token) || isa<InvokeInst>(Token);
}
- /// Get enclosed relocate intrinsic
- ImmutableCallSite getUnderlyingCallSite() { return RelocateCS; }
-
/// The statepoint with which this gc.relocate is associated.
- const Instruction *getStatepoint() {
- const Value *Token = RelocateCS.getArgument(0);
+ const Instruction *getStatepoint() const {
+ const Value *Token = getArgOperand(0);
// This takes care both of relocates for call statepoints and relocates
// on normal path of invoke statepoint.
/// The index into the associate statepoint's argument list
/// which contains the base pointer of the pointer whose
/// relocation this gc.relocate describes.
- unsigned getBasePtrIndex() {
- return cast<ConstantInt>(RelocateCS.getArgument(1))->getZExtValue();
+ unsigned getBasePtrIndex() const {
+ return cast<ConstantInt>(getArgOperand(1))->getZExtValue();
}
/// The index into the associate statepoint's argument list which
/// contains the pointer whose relocation this gc.relocate describes.
- unsigned getDerivedPtrIndex() {
- return cast<ConstantInt>(RelocateCS.getArgument(2))->getZExtValue();
+ unsigned getDerivedPtrIndex() const {
+ return cast<ConstantInt>(getArgOperand(2))->getZExtValue();
}
- Value *getBasePtr() {
+ Value *getBasePtr() const {
ImmutableCallSite CS(getStatepoint());
return *(CS.arg_begin() + getBasePtrIndex());
}
- Value *getDerivedPtr() {
+ Value *getDerivedPtr() const {
ImmutableCallSite CS(getStatepoint());
return *(CS.arg_begin() + getDerivedPtrIndex());
}
template <typename FunTy, typename InstructionTy, typename ValueTy,
typename CallSiteTy>
-std::vector<GCRelocateOperands>
+std::vector<const GCRelocateInst *>
StatepointBase<FunTy, InstructionTy, ValueTy, CallSiteTy>::getRelocates()
const {
- std::vector<GCRelocateOperands> Result;
+ std::vector<const GCRelocateInst *> Result;
CallSiteTy StatepointCS = getCallSite();
// gc_relocates ensures that we only get pairs which are actually relocated
// and used after the statepoint.
for (const User *U : getInstruction()->users())
- if (isGCRelocate(U))
- Result.push_back(GCRelocateOperands(U));
+ if (auto *Relocate = dyn_cast<GCRelocateInst>(U))
+ Result.push_back(Relocate);
if (!StatepointCS.isInvoke())
return Result;
// Search for gc relocates that are attached to this landingpad.
for (const User *LandingPadUser : LandingPad->users()) {
- if (isGCRelocate(LandingPadUser))
- Result.push_back(GCRelocateOperands(LandingPadUser));
+ if (auto *Relocate = dyn_cast<GCRelocateInst>(LandingPadUser))
+ Result.push_back(Relocate);
}
return Result;
}
}
// For gc.relocate, look through relocations
- if (const IntrinsicInst *I = dyn_cast<IntrinsicInst>(V))
- if (I->getIntrinsicID() == Intrinsic::experimental_gc_relocate) {
- GCRelocateOperands RelocateInst(I);
- return isDereferenceableAndAlignedPointer(
- RelocateInst.getDerivedPtr(), Align, DL, CtxI, DT, TLI, Visited);
- }
+ if (const GCRelocateInst *RelocateInst = dyn_cast<GCRelocateInst>(V))
+ return isDereferenceableAndAlignedPointer(
+ RelocateInst->getDerivedPtr(), Align, DL, CtxI, DT, TLI, Visited);
if (const AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(V))
return isDereferenceableAndAlignedPointer(ASC->getOperand(0), Align, DL,
// Computes a map of base pointer relocation instructions to corresponding
// derived pointer relocation instructions given a vector of all relocate calls
static void computeBaseDerivedRelocateMap(
- const SmallVectorImpl<User *> &AllRelocateCalls,
- DenseMap<IntrinsicInst *, SmallVector<IntrinsicInst *, 2>> &
- RelocateInstMap) {
+ const SmallVectorImpl<GCRelocateInst *> &AllRelocateCalls,
+ DenseMap<GCRelocateInst *, SmallVector<GCRelocateInst *, 2>>
+ &RelocateInstMap) {
// Collect information in two maps: one primarily for locating the base object
// while filling the second map; the second map is the final structure holding
// a mapping between Base and corresponding Derived relocate calls
- DenseMap<std::pair<unsigned, unsigned>, IntrinsicInst *> RelocateIdxMap;
- for (auto &U : AllRelocateCalls) {
- GCRelocateOperands ThisRelocate(U);
- IntrinsicInst *I = cast<IntrinsicInst>(U);
- auto K = std::make_pair(ThisRelocate.getBasePtrIndex(),
- ThisRelocate.getDerivedPtrIndex());
- RelocateIdxMap.insert(std::make_pair(K, I));
+ DenseMap<std::pair<unsigned, unsigned>, GCRelocateInst *> RelocateIdxMap;
+ for (auto *ThisRelocate : AllRelocateCalls) {
+ auto K = std::make_pair(ThisRelocate->getBasePtrIndex(),
+ ThisRelocate->getDerivedPtrIndex());
+ RelocateIdxMap.insert(std::make_pair(K, ThisRelocate));
}
for (auto &Item : RelocateIdxMap) {
std::pair<unsigned, unsigned> Key = Item.first;
// Base relocation: nothing to insert
continue;
- IntrinsicInst *I = Item.second;
+ GCRelocateInst *I = Item.second;
auto BaseKey = std::make_pair(Key.first, Key.first);
// We're iterating over RelocateIdxMap so we cannot modify it.
// Takes a RelocatedBase (base pointer relocation instruction) and Targets to
// replace, computes a replacement, and affects it.
static bool
-simplifyRelocatesOffABase(IntrinsicInst *RelocatedBase,
- const SmallVectorImpl<IntrinsicInst *> &Targets) {
+simplifyRelocatesOffABase(GCRelocateInst *RelocatedBase,
+ const SmallVectorImpl<GCRelocateInst *> &Targets) {
bool MadeChange = false;
- for (auto &ToReplace : Targets) {
- GCRelocateOperands MasterRelocate(RelocatedBase);
- GCRelocateOperands ThisRelocate(ToReplace);
-
- assert(ThisRelocate.getBasePtrIndex() == MasterRelocate.getBasePtrIndex() &&
+ for (GCRelocateInst *ToReplace : Targets) {
+ assert(ToReplace->getBasePtrIndex() == RelocatedBase->getBasePtrIndex() &&
"Not relocating a derived object of the original base object");
- if (ThisRelocate.getBasePtrIndex() == ThisRelocate.getDerivedPtrIndex()) {
+ if (ToReplace->getBasePtrIndex() == ToReplace->getDerivedPtrIndex()) {
// A duplicate relocate call. TODO: coalesce duplicates.
continue;
}
continue;
}
- Value *Base = ThisRelocate.getBasePtr();
- auto Derived = dyn_cast<GetElementPtrInst>(ThisRelocate.getDerivedPtr());
+ Value *Base = ToReplace->getBasePtr();
+ auto Derived = dyn_cast<GetElementPtrInst>(ToReplace->getDerivedPtr());
if (!Derived || Derived->getPointerOperand() != Base)
continue;
// %val = load %ptr'
bool CodeGenPrepare::simplifyOffsetableRelocate(Instruction &I) {
bool MadeChange = false;
- SmallVector<User *, 2> AllRelocateCalls;
+ SmallVector<GCRelocateInst *, 2> AllRelocateCalls;
for (auto *U : I.users())
- if (isGCRelocate(dyn_cast<Instruction>(U)))
+ if (GCRelocateInst *Relocate = dyn_cast<GCRelocateInst>(U))
// Collect all the relocate calls associated with a statepoint
- AllRelocateCalls.push_back(U);
+ AllRelocateCalls.push_back(Relocate);
// We need atleast one base pointer relocation + one derived pointer
// relocation to mangle
// RelocateInstMap is a mapping from the base relocate instruction to the
// corresponding derived relocate instructions
- DenseMap<IntrinsicInst *, SmallVector<IntrinsicInst *, 2>> RelocateInstMap;
+ DenseMap<GCRelocateInst *, SmallVector<GCRelocateInst *, 2>> RelocateInstMap;
computeBaseDerivedRelocateMap(AllRelocateCalls, RelocateInstMap);
if (RelocateInstMap.empty())
return false;
return nullptr;
}
case Intrinsic::experimental_gc_relocate: {
- visitGCRelocate(I);
+ visitGCRelocate(cast<GCRelocateInst>(I));
return nullptr;
}
case Intrinsic::instrprof_increment:
// These three are implemented in StatepointLowering.cpp
void visitStatepoint(const CallInst &I);
- void visitGCRelocate(const CallInst &I);
+ void visitGCRelocate(const GCRelocateInst &I);
void visitGCResult(const CallInst &I);
void visitUserOp1(const Instruction &I) {
return Optional<int>();
// Spill location is known for gc relocates
- if (isGCRelocate(Val)) {
- GCRelocateOperands RelocOps(cast<Instruction>(Val));
-
+ if (const auto *Relocate = dyn_cast<GCRelocateInst>(Val)) {
FunctionLoweringInfo::StatepointSpilledValueMapTy &SpillMap =
- Builder.FuncInfo.StatepointRelocatedValues[RelocOps.getStatepoint()];
+ Builder.FuncInfo.StatepointRelocatedValues[Relocate->getStatepoint()];
- auto It = SpillMap.find(RelocOps.getDerivedPtr());
+ auto It = SpillMap.find(Relocate->getDerivedPtr());
if (It == SpillMap.end())
return Optional<int>();
SmallVectorImpl<const Value *> &Bases, SmallVectorImpl<const Value *> &Ptrs,
SmallVectorImpl<const Value *> &Relocs, ImmutableStatepoint StatepointSite,
SelectionDAGBuilder &Builder) {
- for (GCRelocateOperands relocateOpers : StatepointSite.getRelocates()) {
- Relocs.push_back(relocateOpers.getUnderlyingCallSite().getInstruction());
- Bases.push_back(relocateOpers.getBasePtr());
- Ptrs.push_back(relocateOpers.getDerivedPtr());
+ for (const GCRelocateInst *Relocate : StatepointSite.getRelocates()) {
+ Relocs.push_back(Relocate);
+ Bases.push_back(Relocate->getBasePtr());
+ Ptrs.push_back(Relocate->getDerivedPtr());
}
// Remove any redundant llvm::Values which map to the same SDValue as another
FunctionLoweringInfo::StatepointSpilledValueMapTy &SpillMap =
Builder.FuncInfo.StatepointRelocatedValues[StatepointInstr];
- for (GCRelocateOperands RelocateOpers : StatepointSite.getRelocates()) {
- const Value *V = RelocateOpers.getDerivedPtr();
+ for (const GCRelocateInst *Relocate : StatepointSite.getRelocates()) {
+ const Value *V = Relocate->getDerivedPtr();
SDValue SDV = Builder.getValue(V);
SDValue Loc = Builder.StatepointLowering.getLocation(SDV);
// uses of the corresponding values so that it would automatically
// export them. Relocates of the spilled values does not use original
// value.
- if (RelocateOpers.getUnderlyingCallSite().getParent() !=
- StatepointInstr->getParent())
+ if (Relocate->getParent() != StatepointInstr->getParent())
Builder.ExportFromCurrentBlock(V);
}
}
// statepoint.
for (const User *U : CS->users()) {
const CallInst *Call = cast<CallInst>(U);
- if (isGCRelocate(Call) && Call->getParent() == CS.getParent())
+ if (isa<GCRelocateInst>(Call) && Call->getParent() == CS.getParent())
StatepointLowering.scheduleRelocCall(*Call);
}
#endif
}
}
-void SelectionDAGBuilder::visitGCRelocate(const CallInst &CI) {
- GCRelocateOperands RelocateOpers(&CI);
-
+void SelectionDAGBuilder::visitGCRelocate(const GCRelocateInst &Relocate) {
#ifndef NDEBUG
// Consistency check
// We skip this check for relocates not in the same basic block as thier
// statepoint. It would be too expensive to preserve validation info through
// different basic blocks.
- if (RelocateOpers.getStatepoint()->getParent() == CI.getParent()) {
- StatepointLowering.relocCallVisited(CI);
+ if (Relocate.getStatepoint()->getParent() == Relocate.getParent()) {
+ StatepointLowering.relocCallVisited(Relocate);
}
#endif
- const Value *DerivedPtr = RelocateOpers.getDerivedPtr();
+ const Value *DerivedPtr = Relocate.getDerivedPtr();
SDValue SD = getValue(DerivedPtr);
FunctionLoweringInfo::StatepointSpilledValueMapTy &SpillMap =
- FuncInfo.StatepointRelocatedValues[RelocateOpers.getStatepoint()];
+ FuncInfo.StatepointRelocatedValues[Relocate.getStatepoint()];
// We should have recorded location for this pointer
assert(SpillMap.count(DerivedPtr) && "Relocating not lowered gc value");
// We didn't need to spill these special cases (constants and allocas).
// See the handling in spillIncomingValueForStatepoint for detail.
if (!DerivedPtrLocation) {
- setValue(&CI, SD);
+ setValue(&Relocate, SD);
return;
}
DAG.setRoot(SpillLoad.getValue(1));
assert(SpillLoad.getNode());
- setValue(&CI, SpillLoad);
+ setValue(&Relocate, SpillLoad);
}
// printGCRelocateComment - print comment after call to the gc.relocate
// intrinsic indicating base and derived pointer names.
- void printGCRelocateComment(const Value &V);
+ void printGCRelocateComment(const GCRelocateInst &Relocate);
};
} // namespace
/// printGCRelocateComment - print comment after call to the gc.relocate
/// intrinsic indicating base and derived pointer names.
-void AssemblyWriter::printGCRelocateComment(const Value &V) {
- assert(isGCRelocate(&V));
- GCRelocateOperands GCOps(cast<Instruction>(&V));
-
+void AssemblyWriter::printGCRelocateComment(const GCRelocateInst &Relocate) {
Out << " ; (";
- writeOperand(GCOps.getBasePtr(), false);
+ writeOperand(Relocate.getBasePtr(), false);
Out << ", ";
- writeOperand(GCOps.getDerivedPtr(), false);
+ writeOperand(Relocate.getDerivedPtr(), false);
Out << ")";
}
/// which slot it occupies.
///
void AssemblyWriter::printInfoComment(const Value &V) {
- if (isGCRelocate(&V))
- printGCRelocateComment(V);
+ if (const auto *Relocate = dyn_cast<GCRelocateInst>(&V))
+ printGCRelocateComment(*Relocate);
if (AnnotationWriter)
AnnotationWriter->printInfoComment(V, Out);
}
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 Value *inst) {
- if (const CallInst *call = dyn_cast<CallInst>(inst)) {
- if (const Function *F = call->getCalledFunction()) {
- return F->getIntrinsicID() == Intrinsic::experimental_gc_relocate;
- }
- }
- return false;
+ return CS.getInstruction() && isa<GCRelocateInst>(CS.getInstruction());
}
bool llvm::isGCResult(const ImmutableCallSite &CS) {
const CallInst *Call = dyn_cast<const CallInst>(U);
Assert(Call, "illegal use of statepoint token", &CI, U);
if (!Call) continue;
- Assert(isGCRelocate(Call) || isGCResult(Call),
+ Assert(isa<GCRelocateInst>(Call) || isGCResult(Call),
"gc.result or gc.relocate are the only value uses"
"of a gc.statepoint",
&CI, U);
if (isGCResult(Call)) {
Assert(Call->getArgOperand(0) == &CI,
"gc.result connected to wrong gc.statepoint", &CI, Call);
- } else if (isGCRelocate(Call)) {
+ } else if (isa<GCRelocateInst>(Call)) {
Assert(Call->getArgOperand(0) == &CI,
"gc.relocate connected to wrong gc.statepoint", &CI, Call);
}
// Verify rest of the relocate arguments
- GCRelocateOperands Ops(CS);
- ImmutableCallSite StatepointCS(Ops.getStatepoint());
+ ImmutableCallSite StatepointCS(
+ cast<GCRelocateInst>(*CS.getInstruction()).getStatepoint());
// Both the base and derived must be piped through the safepoint
Value* Base = CS.getArgOperand(1);
// Relocated value must be a pointer type, but gc_relocate does not need to return the
// same pointer type as the relocated pointer. It can be casted to the correct type later
// if it's desired. However, they must have the same address space.
- GCRelocateOperands Operands(CS);
- Assert(Operands.getDerivedPtr()->getType()->isPointerTy(),
+ GCRelocateInst &Relocate = cast<GCRelocateInst>(*CS.getInstruction());
+ Assert(Relocate.getDerivedPtr()->getType()->isPointerTy(),
"gc.relocate: relocated value must be a gc pointer", CS);
// gc_relocate return type must be a pointer type, and is verified earlier in
// VerifyIntrinsicType().
Assert(cast<PointerType>(CS.getType())->getAddressSpace() ==
- cast<PointerType>(Operands.getDerivedPtr()->getType())->getAddressSpace(),
+ cast<PointerType>(Relocate.getDerivedPtr()->getType())->getAddressSpace(),
"gc.relocate: relocating a pointer shouldn't change its address space", CS);
break;
}
// Translate facts known about a pointer before relocating into
// facts about the relocate value, while being careful to
// preserve relocation semantics.
- GCRelocateOperands Operands(II);
- Value *DerivedPtr = Operands.getDerivedPtr();
+ Value *DerivedPtr = cast<GCRelocateInst>(II)->getDerivedPtr();
auto *GCRelocateType = cast<PointerType>(II->getType());
// Remove the relocation if unused, note that this check is required
DenseSet<Value *> &VisitedLiveValues) {
for (User *U : GCRelocs) {
- if (!isa<IntrinsicInst>(U))
+ GCRelocateInst *Relocate = dyn_cast<GCRelocateInst>(U);
+ if (!Relocate)
continue;
- IntrinsicInst *RelocatedValue = cast<IntrinsicInst>(U);
-
- // We only care about relocates
- if (RelocatedValue->getIntrinsicID() !=
- Intrinsic::experimental_gc_relocate) {
- continue;
- }
-
- GCRelocateOperands RelocateOperands(RelocatedValue);
- Value *OriginalValue =
- const_cast<Value *>(RelocateOperands.getDerivedPtr());
+ Value *OriginalValue = const_cast<Value *>(Relocate->getDerivedPtr());
assert(AllocaMap.count(OriginalValue));
Value *Alloca = AllocaMap[OriginalValue];
// Emit store into the related alloca
// All gc_relocates are i8 addrspace(1)* typed, and it must be bitcasted to
// the correct type according to alloca.
- assert(RelocatedValue->getNextNode() &&
+ assert(Relocate->getNextNode() &&
"Should always have one since it's not a terminator");
- IRBuilder<> Builder(RelocatedValue->getNextNode());
+ IRBuilder<> Builder(Relocate->getNextNode());
Value *CastedRelocatedValue =
- Builder.CreateBitCast(RelocatedValue,
+ Builder.CreateBitCast(Relocate,
cast<AllocaInst>(Alloca)->getAllocatedType(),
- suffixed_name_or(RelocatedValue, ".casted", ""));
+ suffixed_name_or(Relocate, ".casted", ""));
StoreInst *Store = new StoreInst(CastedRelocatedValue, Alloca);
Store->insertAfter(cast<Instruction>(CastedRelocatedValue));