Write(&*I);
}
+ void Write(const Module *M) {
+ if (!M)
+ return;
+ OS << "; ModuleID = '" << M->getModuleIdentifier() << "'\n";
+ }
+
void Write(const Value *V) {
if (!V)
return;
/// 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;
+
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 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);
}
void Verifier::visitAliaseeSubExpr(SmallPtrSetImpl<const GlobalAlias*> &Visited,
const GlobalAlias &GA, const Constant &C) {
if (const auto *GV = dyn_cast<GlobalValue>(&C)) {
- Assert(!GV->isDeclaration(), "Alias must point to a definition", &GA);
+ Assert(!GV->isDeclarationForLinker(), "Alias must point to a definition",
+ &GA);
if (const auto *GA2 = dyn_cast<GlobalAlias>(GV)) {
Assert(Visited.insert(GA2).second, "Aliases cannot form a cycle", &GA);
}
if (const auto *CE = dyn_cast<ConstantExpr>(&C))
- VerifyConstantExprBitcastType(CE);
+ visitConstantExprsRecursively(CE);
for (const Use &U : C.operands()) {
Value *V = &*U;
"invalid composite elements", &N, N.getRawElements());
Assert(isTypeRef(N, N.getRawVTableHolder()), "invalid vtable holder", &N,
N.getRawVTableHolder());
- Assert(!N.getRawElements() || isa<MDTuple>(N.getRawElements()),
- "invalid composite elements", &N, N.getRawElements());
Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags",
&N);
if (auto *Params = N.getRawTemplateParams())
Op);
}
}
+ if (auto *Array = N.getRawMacros()) {
+ Assert(isa<MDTuple>(Array), "invalid macro list", &N, Array);
+ for (Metadata *Op : N.getMacros()->operands()) {
+ Assert(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
+ }
+ }
}
void Verifier::visitDISubprogram(const DISubprogram &N) {
Assert(isa<DIScope>(S), "invalid scope ref", &N, S);
}
+void Verifier::visitDIMacro(const DIMacro &N) {
+ Assert(N.getMacinfoType() == dwarf::DW_MACINFO_define ||
+ N.getMacinfoType() == dwarf::DW_MACINFO_undef,
+ "invalid macinfo type", &N);
+ Assert(!N.getName().empty(), "anonymous macro", &N);
+}
+
+void Verifier::visitDIMacroFile(const DIMacroFile &N) {
+ Assert(N.getMacinfoType() == dwarf::DW_MACINFO_start_file,
+ "invalid macinfo type", &N);
+ if (auto *F = N.getRawFile())
+ Assert(isa<DIFile>(F), "invalid file", &N, F);
+
+ if (auto *Array = N.getRawElements()) {
+ Assert(isa<MDTuple>(Array), "invalid macro list", &N, Array);
+ for (Metadata *Op : N.getElements()->operands()) {
+ Assert(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
+ }
+ }
+}
+
void Verifier::visitDIModule(const DIModule &N) {
Assert(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N);
Assert(!N.getName().empty(), "anonymous module", &N);
}
}
-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;
auto *Per = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
if (Per)
Assert(Per->getParent() == F.getParent(),
- "Referencing personality function in another module!", &F, Per);
+ "Referencing personality function in another module!",
+ &F, F.getParent(), Per, Per->getParent());
}
if (F.isMaterializable()) {
continue;
DISubprogram *SP = Scope ? Scope->getSubprogram() : nullptr;
- if (SP && !Seen.insert(SP).second)
+
+ // Scope and SP could be the same MDNode and we don't want to skip
+ // validation in that case
+ if (SP && ((Scope != SP) && !Seen.insert(SP).second))
continue;
// FIXME: Once N is canonical, check "SP == &N".
}
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<TerminatePadInst>(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);
+ "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);
-
- 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);
+void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) {
+ Assert(isa<CatchPadInst>(CatchReturn.getOperand(0)),
+ "CatchReturnInst needs to be provided a CatchPad", &CatchReturn,
+ CatchReturn.getOperand(0));
- 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);
- }
-
- 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<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(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) ||
+ isa<TerminatePadInst>(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<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad),
+ "CatchSwitchInst has an invalid parent.", ParentPad);
+
+ 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),
&TPI);
}
+ auto *ParentPad = TPI.getParentPad();
+ Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) ||
+ isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad),
+ "TerminatePadInst has an invalid parent.", ParentPad);
+
visitTerminatorInst(TPI);
}
" donothing or patchpoint",
&I);
Assert(F->getParent() == M, "Referencing function in another module!",
- &I);
+ &I, M, F, F->getParent());
} else if (BasicBlock *OpBB = dyn_cast<BasicBlock>(I.getOperand(i))) {
Assert(OpBB->getParent() == BB->getParent(),
"Referring to a basic block in another function!", &I);
Assert(OpArg->getParent() == BB->getParent(),
"Referring to an argument in another function!", &I);
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(I.getOperand(i))) {
- Assert(GV->getParent() == M, "Referencing global in another module!", &I);
+ Assert(GV->getParent() == M, "Referencing global in another module!", &I, M, GV, GV->getParent());
} else if (isa<Instruction>(I.getOperand(i))) {
verifyDominatesUse(I, i);
} else if (isa<InlineAsm>(I.getOperand(i))) {
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);
}
}
}
const APInt &AlignVal = AlignCI->getValue();
Assert(AlignCI->isZero() || AlignVal.isPowerOf2(),
"alignment argument of memory intrinsics must be a power of 2", CS);
- Assert(isa<ConstantInt>(CS.getArgOperand(3)),
+ Assert(isa<ConstantInt>(CS.getArgOperand(4)),
"isvolatile argument of memory intrinsics must be a constant int",
CS);
break;