/// given function and the largest index passed to llvm.localrecover.
DenseMap<Function *, std::pair<unsigned, unsigned>> FrameEscapeInfo;
+ /// Cache of constants visited in search of ConstantExprs.
+ SmallPtrSet<const Constant *, 32> ConstantExprVisited;
+
+ void checkAtomicMemAccessSize(const Module *M, Type *Ty,
+ const Instruction *I);
public:
explicit Verifier(raw_ostream &OS)
: VerifierSupport(OS), Context(nullptr), LandingPadResultTy(nullptr),
void visitEHPadPredecessors(Instruction &I);
void visitLandingPadInst(LandingPadInst &LPI);
void visitCatchPadInst(CatchPadInst &CPI);
- void visitCatchEndPadInst(CatchEndPadInst &CEPI);
+ void visitCatchReturnInst(CatchReturnInst &CatchReturn);
void visitCleanupPadInst(CleanupPadInst &CPI);
- void visitCleanupEndPadInst(CleanupEndPadInst &CEPI);
+ void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch);
void visitCleanupReturnInst(CleanupReturnInst &CRI);
- void visitTerminatePadInst(TerminatePadInst &TPI);
void VerifyCallSite(CallSite CS);
void verifyMustTailCall(CallInst &CI);
void VerifyFunctionMetadata(
const SmallVector<std::pair<unsigned, MDNode *>, 4> MDs);
- void VerifyConstantExprBitcastType(const ConstantExpr *CE);
+ void visitConstantExprsRecursively(const Constant *EntryC);
+ void visitConstantExpr(const ConstantExpr *CE);
void VerifyStatepoint(ImmutableCallSite CS);
void verifyFrameRecoverIndices();
}
// Walk any aggregate initializers looking for bitcasts between address spaces
- SmallPtrSet<const Value *, 4> Visited;
- SmallVector<const Value *, 4> WorkStack;
- WorkStack.push_back(cast<Value>(GV.getInitializer()));
-
- while (!WorkStack.empty()) {
- const Value *V = WorkStack.pop_back_val();
- if (!Visited.insert(V).second)
- continue;
-
- if (const User *U = dyn_cast<User>(V)) {
- WorkStack.append(U->op_begin(), U->op_end());
- }
-
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
- VerifyConstantExprBitcastType(CE);
- if (Broken)
- return;
- }
- }
+ visitConstantExprsRecursively(GV.getInitializer());
visitGlobalValue(GV);
}
}
if (const auto *CE = dyn_cast<ConstantExpr>(&C))
- VerifyConstantExprBitcastType(CE);
+ visitConstantExprsRecursively(CE);
for (const Use &U : C.operands()) {
Value *V = &*U;
I->getKindAsEnum() == Attribute::JumpTable ||
I->getKindAsEnum() == Attribute::Convergent ||
I->getKindAsEnum() == Attribute::ArgMemOnly ||
- I->getKindAsEnum() == Attribute::NoRecurse) {
+ I->getKindAsEnum() == Attribute::NoRecurse ||
+ I->getKindAsEnum() == Attribute::InaccessibleMemOnly ||
+ I->getKindAsEnum() == Attribute::InaccessibleMemOrArgMemOnly) {
if (!isFunction) {
CheckFailed("Attribute '" + I->getAsString() +
"' only applies to functions!", V);
Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly)),
"Attributes 'readnone and readonly' are incompatible!", V);
+ Assert(
+ !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
+ Attrs.hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::InaccessibleMemOrArgMemOnly)),
+ "Attributes 'readnone and inaccessiblemem_or_argmemonly' are incompatible!", V);
+
+ Assert(
+ !(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
+ Attrs.hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::InaccessibleMemOnly)),
+ "Attributes 'readnone and inaccessiblememonly' are incompatible!", V);
+
Assert(
!(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::NoInline) &&
Attrs.hasAttribute(AttributeSet::FunctionIndex,
}
}
-void Verifier::VerifyConstantExprBitcastType(const ConstantExpr *CE) {
+void Verifier::visitConstantExprsRecursively(const Constant *EntryC) {
+ if (!ConstantExprVisited.insert(EntryC).second)
+ return;
+
+ SmallVector<const Constant *, 16> Stack;
+ Stack.push_back(EntryC);
+
+ while (!Stack.empty()) {
+ const Constant *C = Stack.pop_back_val();
+
+ // Check this constant expression.
+ if (const auto *CE = dyn_cast<ConstantExpr>(C))
+ visitConstantExpr(CE);
+
+ // Visit all sub-expressions.
+ for (const Use &U : C->operands()) {
+ const auto *OpC = dyn_cast<Constant>(U);
+ if (!OpC)
+ continue;
+ if (isa<GlobalValue>(OpC))
+ continue; // Global values get visited separately.
+ if (!ConstantExprVisited.insert(OpC).second)
+ continue;
+ Stack.push_back(OpC);
+ }
+ }
+}
+
+void Verifier::visitConstantExpr(const ConstantExpr *CE) {
if (CE->getOpcode() != Instruction::BitCast)
return;
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);
}
// If this function is actually an intrinsic, verify that it is only used in
// direct call/invokes, never having its "address taken".
- if (F.getIntrinsicID()) {
+ // Only do this if the module is materialized, otherwise we don't have all the
+ // uses.
+ if (F.getIntrinsicID() && F.getParent()->isMaterialized()) {
const User *U;
if (F.hasAddressTaken(&U))
Assert(0, "Invalid user of intrinsic instruction!", U);
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
visitIntrinsicCallSite(ID, CS);
- // Verify that a callsite has at most one "deopt" operand bundle.
- bool FoundDeoptBundle = false;
+ // Verify that a callsite has at most one "deopt" and one "funclet" operand
+ // bundle.
+ bool FoundDeoptBundle = false, FoundFuncletBundle = false;
for (unsigned i = 0, e = CS.getNumOperandBundles(); i < e; ++i) {
- if (CS.getOperandBundleAt(i).getTagID() == LLVMContext::OB_deopt) {
+ OperandBundleUse BU = CS.getOperandBundleAt(i);
+ uint32_t Tag = BU.getTagID();
+ if (Tag == LLVMContext::OB_deopt) {
Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I);
FoundDeoptBundle = true;
}
+ if (Tag == LLVMContext::OB_funclet) {
+ Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", I);
+ FoundFuncletBundle = true;
+ Assert(BU.Inputs.size() == 1,
+ "Expected exactly one funclet bundle operand", I);
+ Assert(isa<FuncletPadInst>(BU.Inputs.front()),
+ "Funclet bundle operands should correspond to a FuncletPadInst",
+ I);
+ }
}
visitInstruction(*I);
}
}
+void Verifier::checkAtomicMemAccessSize(const Module *M, Type *Ty,
+ const Instruction *I) {
+ unsigned Size = M->getDataLayout().getTypeSizeInBits(Ty);
+ Assert(Size >= 8, "atomic memory access' size must be byte-sized", Ty, I);
+ Assert(!(Size & (Size - 1)),
+ "atomic memory access' operand must have a power-of-two size", Ty, I);
+}
+
void Verifier::visitLoadInst(LoadInst &LI) {
PointerType *PTy = dyn_cast<PointerType>(LI.getOperand(0)->getType());
Assert(PTy, "Load operand must be a pointer.", &LI);
"Load cannot have Release ordering", &LI);
Assert(LI.getAlignment() != 0,
"Atomic load must specify explicit alignment", &LI);
- if (!ElTy->isPointerTy()) {
- Assert(ElTy->isIntegerTy(), "atomic load operand must have integer type!",
- &LI, ElTy);
- unsigned Size = ElTy->getPrimitiveSizeInBits();
- Assert(Size >= 8 && !(Size & (Size - 1)),
- "atomic load operand must be power-of-two byte-sized integer", &LI,
- ElTy);
- }
+ Assert(ElTy->isIntegerTy() || ElTy->isPointerTy() ||
+ ElTy->isFloatingPointTy(),
+ "atomic load operand must have integer, pointer, or floating point "
+ "type!",
+ ElTy, &LI);
+ checkAtomicMemAccessSize(M, ElTy, &LI);
} else {
Assert(LI.getSynchScope() == CrossThread,
"Non-atomic load cannot have SynchronizationScope specified", &LI);
"Store cannot have Acquire ordering", &SI);
Assert(SI.getAlignment() != 0,
"Atomic store must specify explicit alignment", &SI);
- if (!ElTy->isPointerTy()) {
- Assert(ElTy->isIntegerTy(),
- "atomic store operand must have integer type!", &SI, ElTy);
- unsigned Size = ElTy->getPrimitiveSizeInBits();
- Assert(Size >= 8 && !(Size & (Size - 1)),
- "atomic store operand must be power-of-two byte-sized integer",
- &SI, ElTy);
- }
+ Assert(ElTy->isIntegerTy() || ElTy->isPointerTy() ||
+ ElTy->isFloatingPointTy(),
+ "atomic store operand must have integer, pointer, or floating point "
+ "type!",
+ ElTy, &SI);
+ checkAtomicMemAccessSize(M, ElTy, &SI);
} else {
Assert(SI.getSynchScope() == CrossThread,
"Non-atomic store cannot have SynchronizationScope specified", &SI);
Type *ElTy = PTy->getElementType();
Assert(ElTy->isIntegerTy(), "cmpxchg operand must have integer type!", &CXI,
ElTy);
- unsigned Size = ElTy->getPrimitiveSizeInBits();
- Assert(Size >= 8 && !(Size & (Size - 1)),
- "cmpxchg operand must be power-of-two byte-sized integer", &CXI, ElTy);
+ checkAtomicMemAccessSize(M, ElTy, &CXI);
Assert(ElTy == CXI.getOperand(1)->getType(),
"Expected value type does not match pointer operand type!", &CXI,
ElTy);
Type *ElTy = PTy->getElementType();
Assert(ElTy->isIntegerTy(), "atomicrmw operand must have integer type!",
&RMWI, ElTy);
- unsigned Size = ElTy->getPrimitiveSizeInBits();
- Assert(Size >= 8 && !(Size & (Size - 1)),
- "atomicrmw operand must be power-of-two byte-sized integer", &RMWI,
- ElTy);
+ checkAtomicMemAccessSize(M, ElTy, &RMWI);
Assert(ElTy == RMWI.getOperand(1)->getType(),
"Argument value type does not match pointer operand type!", &RMWI,
ElTy);
}
return;
}
+ if (auto *CPI = dyn_cast<CatchPadInst>(&I)) {
+ if (!pred_empty(BB))
+ Assert(BB->getUniquePredecessor() == CPI->getCatchSwitch()->getParent(),
+ "Block containg CatchPadInst must be jumped to "
+ "only by its catchswitch.",
+ CPI);
+ return;
+ }
for (BasicBlock *PredBB : predecessors(BB)) {
TerminatorInst *TI = PredBB->getTerminator();
- if (auto *II = dyn_cast<InvokeInst>(TI))
+ if (auto *II = dyn_cast<InvokeInst>(TI)) {
Assert(II->getUnwindDest() == BB && II->getNormalDest() != BB,
"EH pad must be jumped to via an unwind edge", &I, II);
- else if (auto *CPI = dyn_cast<CatchPadInst>(TI))
- Assert(CPI->getUnwindDest() == BB && CPI->getNormalDest() != BB,
- "EH pad must be jumped to via an unwind edge", &I, CPI);
- else if (isa<CatchEndPadInst>(TI))
- ;
- else if (isa<CleanupReturnInst>(TI))
- ;
- else if (isa<CleanupEndPadInst>(TI))
- ;
- else if (isa<TerminatePadInst>(TI))
- ;
- else
+ } else if (!isa<CleanupReturnInst>(TI) && !isa<CatchSwitchInst>(TI)) {
Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI);
+ }
}
}
visitEHPadPredecessors(CPI);
BasicBlock *BB = CPI.getParent();
+
Function *F = BB->getParent();
Assert(F->hasPersonalityFn(),
"CatchPadInst needs to be in a function with a personality.", &CPI);
+ Assert(isa<CatchSwitchInst>(CPI.getParentPad()),
+ "CatchPadInst needs to be directly nested in a CatchSwitchInst.",
+ CPI.getParentPad());
+
// The catchpad instruction must be the first non-PHI instruction in the
// block.
Assert(BB->getFirstNonPHI() == &CPI,
- "CatchPadInst not the first non-PHI instruction in the block.",
- &CPI);
-
- if (!BB->getSinglePredecessor())
- for (BasicBlock *PredBB : predecessors(BB)) {
- Assert(!isa<CatchPadInst>(PredBB->getTerminator()),
- "CatchPadInst with CatchPadInst predecessor cannot have any other "
- "predecessors.",
- &CPI);
- }
-
- BasicBlock *UnwindDest = CPI.getUnwindDest();
- Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- isa<CatchPadInst>(I) || isa<CatchEndPadInst>(I),
- "CatchPadInst must unwind to a CatchPadInst or a CatchEndPadInst.",
- &CPI);
+ "CatchPadInst not the first non-PHI instruction in the block.", &CPI);
- visitTerminatorInst(CPI);
+ visitInstruction(CPI);
}
-void Verifier::visitCatchEndPadInst(CatchEndPadInst &CEPI) {
- visitEHPadPredecessors(CEPI);
-
- BasicBlock *BB = CEPI.getParent();
- Function *F = BB->getParent();
- Assert(F->hasPersonalityFn(),
- "CatchEndPadInst needs to be in a function with a personality.",
- &CEPI);
-
- // The catchendpad instruction must be the first non-PHI instruction in the
- // block.
- Assert(BB->getFirstNonPHI() == &CEPI,
- "CatchEndPadInst not the first non-PHI instruction in the block.",
- &CEPI);
-
- unsigned CatchPadsSeen = 0;
- for (BasicBlock *PredBB : predecessors(BB))
- if (isa<CatchPadInst>(PredBB->getTerminator()))
- ++CatchPadsSeen;
-
- Assert(CatchPadsSeen <= 1, "CatchEndPadInst must have no more than one "
- "CatchPadInst predecessor.",
- &CEPI);
-
- if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) {
- Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- I->isEHPad() && !isa<LandingPadInst>(I),
- "CatchEndPad must unwind to an EH block which is not a landingpad.",
- &CEPI);
- }
+void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) {
+ Assert(isa<CatchPadInst>(CatchReturn.getOperand(0)),
+ "CatchReturnInst needs to be provided a CatchPad", &CatchReturn,
+ CatchReturn.getOperand(0));
- visitTerminatorInst(CEPI);
+ visitTerminatorInst(CatchReturn);
}
void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
"CleanupPadInst not the first non-PHI instruction in the block.",
&CPI);
+ auto *ParentPad = CPI.getParentPad();
+ Assert(isa<ConstantTokenNone>(ParentPad) || isa<FuncletPadInst>(ParentPad),
+ "CleanupPadInst has an invalid parent.", &CPI);
+
User *FirstUser = nullptr;
BasicBlock *FirstUnwindDest = nullptr;
for (User *U : CPI.users()) {
BasicBlock *UnwindDest;
if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
UnwindDest = CRI->getUnwindDest();
+ } else if (isa<CleanupPadInst>(U) || isa<CatchSwitchInst>(U)) {
+ continue;
+ } else if (CallSite(U)) {
+ continue;
} else {
- UnwindDest = cast<CleanupEndPadInst>(U)->getUnwindDest();
+ Assert(false, "bogus cleanuppad use", &CPI);
}
if (!FirstUser) {
FirstUser = U;
FirstUnwindDest = UnwindDest;
} else {
- Assert(UnwindDest == FirstUnwindDest,
- "Cleanuprets/cleanupendpads from the same cleanuppad must "
- "have the same unwind destination",
- FirstUser, U);
+ Assert(
+ UnwindDest == FirstUnwindDest,
+ "cleanupret instructions from the same cleanuppad must have the same "
+ "unwind destination",
+ FirstUser, U);
}
}
visitInstruction(CPI);
}
-void Verifier::visitCleanupEndPadInst(CleanupEndPadInst &CEPI) {
- visitEHPadPredecessors(CEPI);
+void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) {
+ visitEHPadPredecessors(CatchSwitch);
+
+ BasicBlock *BB = CatchSwitch.getParent();
- BasicBlock *BB = CEPI.getParent();
Function *F = BB->getParent();
Assert(F->hasPersonalityFn(),
- "CleanupEndPadInst needs to be in a function with a personality.",
- &CEPI);
+ "CatchSwitchInst needs to be in a function with a personality.",
+ &CatchSwitch);
- // The cleanupendpad instruction must be the first non-PHI instruction in the
+ // The catchswitch instruction must be the first non-PHI instruction in the
// block.
- Assert(BB->getFirstNonPHI() == &CEPI,
- "CleanupEndPadInst not the first non-PHI instruction in the block.",
- &CEPI);
+ Assert(BB->getFirstNonPHI() == &CatchSwitch,
+ "CatchSwitchInst not the first non-PHI instruction in the block.",
+ &CatchSwitch);
- if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) {
+ if (BasicBlock *UnwindDest = CatchSwitch.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(
- I->isEHPad() && !isa<LandingPadInst>(I),
- "CleanupEndPad must unwind to an EH block which is not a landingpad.",
- &CEPI);
+ Assert(I->isEHPad() && !isa<LandingPadInst>(I),
+ "CatchSwitchInst must unwind to an EH block which is not a "
+ "landingpad.",
+ &CatchSwitch);
}
- visitTerminatorInst(CEPI);
+ auto *ParentPad = CatchSwitch.getParentPad();
+ Assert(isa<ConstantTokenNone>(ParentPad) || isa<FuncletPadInst>(ParentPad),
+ "CatchSwitchInst has an invalid parent.", ParentPad);
+
+ Assert(CatchSwitch.getNumHandlers() != 0,
+ "CatchSwitchInst cannot have empty handler list", &CatchSwitch);
+
+ for (BasicBlock *Handler : CatchSwitch.handlers()) {
+ Assert(isa<CatchPadInst>(Handler->getFirstNonPHI()),
+ "CatchSwitchInst handlers must be catchpads", &CatchSwitch, Handler);
+ }
+
+ visitTerminatorInst(CatchSwitch);
}
void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) {
+ Assert(isa<CleanupPadInst>(CRI.getOperand(0)),
+ "CleanupReturnInst needs to be provided a CleanupPad", &CRI,
+ CRI.getOperand(0));
+
if (BasicBlock *UnwindDest = CRI.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHPad() && !isa<LandingPadInst>(I),
visitTerminatorInst(CRI);
}
-void Verifier::visitTerminatePadInst(TerminatePadInst &TPI) {
- visitEHPadPredecessors(TPI);
-
- BasicBlock *BB = TPI.getParent();
- Function *F = BB->getParent();
- Assert(F->hasPersonalityFn(),
- "TerminatePadInst needs to be in a function with a personality.",
- &TPI);
-
- // The terminatepad instruction must be the first non-PHI instruction in the
- // block.
- Assert(BB->getFirstNonPHI() == &TPI,
- "TerminatePadInst not the first non-PHI instruction in the block.",
- &TPI);
-
- if (BasicBlock *UnwindDest = TPI.getUnwindDest()) {
- Instruction *I = UnwindDest->getFirstNonPHI();
- Assert(I->isEHPad() && !isa<LandingPadInst>(I),
- "TerminatePadInst must unwind to an EH block which is not a "
- "landingpad.",
- &TPI);
- }
-
- visitTerminatorInst(TPI);
-}
-
void Verifier::verifyDominatesUse(Instruction &I, unsigned i) {
Instruction *Op = cast<Instruction>(I.getOperand(i));
// If the we have an invalid invoke, don't try to compute the dominance.
if (CE->getType()->isPtrOrPtrVectorTy()) {
// If we have a ConstantExpr pointer, we need to see if it came from an
// illegal bitcast (inttoptr <constant int> )
- SmallVector<const ConstantExpr *, 4> Stack;
- SmallPtrSet<const ConstantExpr *, 4> Visited;
- Stack.push_back(CE);
-
- while (!Stack.empty()) {
- const ConstantExpr *V = Stack.pop_back_val();
- if (!Visited.insert(V).second)
- continue;
-
- VerifyConstantExprBitcastType(V);
-
- for (unsigned I = 0, N = V->getNumOperands(); I != N; ++I) {
- if (ConstantExpr *Op = dyn_cast<ConstantExpr>(V->getOperand(I)))
- Stack.push_back(Op);
- }
- }
+ visitConstantExprsRecursively(CE);
}
}
}
VerifyStatepoint(CS);
break;
- case Intrinsic::experimental_gc_result_int:
- case Intrinsic::experimental_gc_result_float:
- case Intrinsic::experimental_gc_result_ptr:
case Intrinsic::experimental_gc_result: {
Assert(CS.getParent()->getParent()->hasGC(),
"Enclosing function does not use GC.", CS);
// Check that this relocate is correctly tied to the statepoint
// This is case for relocate on the unwinding path of an invoke statepoint
- if (ExtractValueInst *ExtractValue =
- dyn_cast<ExtractValueInst>(CS.getArgOperand(0))) {
- Assert(isa<LandingPadInst>(ExtractValue->getAggregateOperand()),
- "gc relocate on unwind path incorrectly linked to the statepoint",
- CS);
+ if (LandingPadInst *LandingPad =
+ dyn_cast<LandingPadInst>(CS.getArgOperand(0))) {
const BasicBlock *InvokeBB =
- ExtractValue->getParent()->getUniquePredecessor();
+ LandingPad->getParent()->getUniquePredecessor();
// Landingpad relocates should have only one predecessor with invoke
// statepoint terminator
Assert(InvokeBB, "safepoints should have unique landingpads",
- ExtractValue->getParent());
+ LandingPad->getParent());
Assert(InvokeBB->getTerminator(), "safepoint block should be well formed",
InvokeBB);
Assert(isStatepoint(InvokeBB->getTerminator()),
// 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;
}