X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FIR%2FVerifier.cpp;h=af79984f59a5077b3adf0165e9df182e31b5066c;hb=19d058836a6029705d7329d0d62bff3f3b49ab4e;hp=1b66fa0b1b8e930e1f25abd1919b255ffeb992a8;hpb=fab98a48437d2bea44f71e84fff3135826913d04;p=oota-llvm.git diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 1b66fa0b1b8..af79984f59a 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -78,7 +78,7 @@ #include using namespace llvm; -static cl::opt VerifyDebugInfo("verify-debug-info", cl::init(false)); +static cl::opt VerifyDebugInfo("verify-debug-info", cl::init(true)); namespace { struct VerifierSupport { @@ -87,9 +87,10 @@ struct VerifierSupport { /// \brief Track the brokenness of the module while recursively visiting. bool Broken; + bool EverBroken; explicit VerifierSupport(raw_ostream &OS) - : OS(OS), M(nullptr), Broken(false) {} + : OS(OS), M(nullptr), Broken(false), EverBroken(false) {} private: void Write(const Value *V) { @@ -106,7 +107,14 @@ private: void Write(const Metadata *MD) { if (!MD) return; - MD->printAsOperand(OS, true, M); + MD->print(OS, M); + OS << '\n'; + } + + void Write(const NamedMDNode *NMD) { + if (!NMD) + return; + NMD->print(OS); OS << '\n'; } @@ -131,14 +139,23 @@ private: template void WriteTs() {} public: - // CheckFailed - A check failed, so print out the condition and the message - // that failed. This provides a nice place to put a breakpoint if you want - // to see why something is not correct. - template - void CheckFailed(const Twine &Message, const Ts &... Vs) { + /// \brief A check failed, so printout out the condition and the message. + /// + /// This provides a nice place to put a breakpoint if you want to see why + /// something is not correct. + void CheckFailed(const Twine &Message) { OS << Message << '\n'; - WriteTs(Vs...); - Broken = true; + EverBroken = Broken = true; + } + + /// \brief A check failed (with values to print). + /// + /// This calls the Message-only version so that the above is easier to set a + /// breakpoint on. + template + void CheckFailed(const Twine &Message, const T1 &V1, const Ts &... Vs) { + CheckFailed(Message); + WriteTs(V1, Vs...); } }; @@ -172,7 +189,7 @@ class Verifier : public InstVisitor, VerifierSupport { DenseMap> FrameEscapeInfo; public: - explicit Verifier(raw_ostream &OS = dbgs()) + explicit Verifier(raw_ostream &OS) : VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr), SawFrameEscape(false) {} @@ -251,6 +268,9 @@ public: visitModuleFlags(M); visitModuleIdents(M); + // Verify debug info last. + verifyDebugInfo(); + return !Broken; } @@ -278,6 +298,9 @@ private: #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N); #include "llvm/IR/Metadata.def" + void visitMDScope(const MDScope &N); + void visitMDDerivedTypeBase(const MDDerivedTypeBase &N); + void visitMDVariable(const MDVariable &N); // InstVisitor overrides... using InstVisitor::visit; @@ -320,6 +343,8 @@ private: void visitUserOp1(Instruction &I); void visitUserOp2(Instruction &I) { visitUserOp1(I); } void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI); + template + void visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII); void visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI); void visitAtomicRMWInst(AtomicRMWInst &RMWI); void visitFenceInst(FenceInst &FI); @@ -347,18 +372,8 @@ private: void VerifyConstantExprBitcastType(const ConstantExpr *CE); void VerifyStatepoint(ImmutableCallSite CS); void verifyFrameRecoverIndices(); -}; -class DebugInfoVerifier : public VerifierSupport { -public: - explicit DebugInfoVerifier(raw_ostream &OS = dbgs()) : VerifierSupport(OS) {} - bool verify(const Module &M) { - this->M = &M; - verifyDebugInfo(); - return !Broken; - } - -private: + // Module-level debug info verification... void verifyDebugInfo(); void processInstructions(DebugInfoFinder &Finder); void processCallInst(DebugInfoFinder &Finder, const CallInst &CI); @@ -557,6 +572,10 @@ void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { if (!MD) continue; + if (NMD.getName() == "llvm.dbg.cu") { + Assert(isa(MD), "invalid compile unit", &NMD, MD); + } + visitMDNode(*MD); } } @@ -642,9 +661,28 @@ void Verifier::visitMetadataAsValue(const MetadataAsValue &MDV, Function *F) { visitValueAsMetadata(*V, F); } +/// \brief Check if a value can be a reference to a type. +static bool isTypeRef(const Metadata *MD) { + if (!MD) + return true; + if (auto *S = dyn_cast(MD)) + return !S->getString().empty(); + return isa(MD); +} + +/// \brief Check if a value can be a ScopeRef. +static bool isScopeRef(const Metadata *MD) { + if (!MD) + return true; + if (auto *S = dyn_cast(MD)) + return !S->getString().empty(); + return isa(MD); +} + void Verifier::visitMDLocation(const MDLocation &N) { - Assert(N.getScope(), "location requires a valid scope", &N); - if (auto *IA = N.getInlinedAt()) + Assert(N.getRawScope() && isa(N.getRawScope()), + "location requires a valid scope", &N, N.getRawScope()); + if (auto *IA = N.getRawInlinedAt()) Assert(isa(IA), "inlined-at should be a location", &N, IA); } @@ -652,8 +690,14 @@ void Verifier::visitGenericDebugNode(const GenericDebugNode &N) { Assert(N.getTag(), "invalid tag", &N); } +void Verifier::visitMDScope(const MDScope &N) { + if (auto *F = N.getRawFile()) + Assert(isa(F), "invalid file", &N, F); +} + void Verifier::visitMDSubrange(const MDSubrange &N) { Assert(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); + Assert(N.getCount() >= -1, "invalid subrange count", &N); } void Verifier::visitMDEnumerator(const MDEnumerator &N) { @@ -666,7 +710,18 @@ void Verifier::visitMDBasicType(const MDBasicType &N) { "invalid tag", &N); } +void Verifier::visitMDDerivedTypeBase(const MDDerivedTypeBase &N) { + // Common scope checks. + visitMDScope(N); + + Assert(isScopeRef(N.getScope()), "invalid scope", &N, N.getScope()); + Assert(isTypeRef(N.getBaseType()), "invalid base type", &N, N.getBaseType()); +} + void Verifier::visitMDDerivedType(const MDDerivedType &N) { + // Common derived type checks. + visitMDDerivedTypeBase(N); + Assert(N.getTag() == dwarf::DW_TAG_typedef || N.getTag() == dwarf::DW_TAG_pointer_type || N.getTag() == dwarf::DW_TAG_ptr_to_member_type || @@ -682,6 +737,9 @@ void Verifier::visitMDDerivedType(const MDDerivedType &N) { } void Verifier::visitMDCompositeType(const MDCompositeType &N) { + // Common derived type checks. + visitMDDerivedTypeBase(N); + Assert(N.getTag() == dwarf::DW_TAG_array_type || N.getTag() == dwarf::DW_TAG_structure_type || N.getTag() == dwarf::DW_TAG_union_type || @@ -689,10 +747,23 @@ void Verifier::visitMDCompositeType(const MDCompositeType &N) { N.getTag() == dwarf::DW_TAG_subroutine_type || N.getTag() == dwarf::DW_TAG_class_type, "invalid tag", &N); + + Assert(!N.getRawElements() || isa(N.getRawElements()), + "invalid composite elements", &N, N.getRawElements()); + Assert(isTypeRef(N.getRawVTableHolder()), "invalid vtable holder", &N, + N.getRawVTableHolder()); + Assert(!N.getRawElements() || isa(N.getRawElements()), + "invalid composite elements", &N, N.getRawElements()); } void Verifier::visitMDSubroutineType(const MDSubroutineType &N) { Assert(N.getTag() == dwarf::DW_TAG_subroutine_type, "invalid tag", &N); + if (auto *Types = N.getRawTypeArray()) { + Assert(isa(Types), "invalid composite elements", &N, Types); + for (Metadata *Ty : N.getTypeArray()->operands()) { + Assert(isTypeRef(Ty), "invalid subroutine type ref", &N, Types, Ty); + } + } } void Verifier::visitMDFile(const MDFile &N) { @@ -701,6 +772,41 @@ void Verifier::visitMDFile(const MDFile &N) { void Verifier::visitMDCompileUnit(const MDCompileUnit &N) { Assert(N.getTag() == dwarf::DW_TAG_compile_unit, "invalid tag", &N); + + if (auto *Array = N.getRawEnumTypes()) { + Assert(isa(Array), "invalid enum list", &N, Array); + for (Metadata *Op : N.getEnumTypes()->operands()) { + auto *Enum = dyn_cast_or_null(Op); + Assert(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type, + "invalid enum type", &N, N.getEnumTypes(), Op); + } + } + if (auto *Array = N.getRawRetainedTypes()) { + Assert(isa(Array), "invalid retained type list", &N, Array); + for (Metadata *Op : N.getRetainedTypes()->operands()) { + Assert(Op && isa(Op), "invalid retained type", &N, Op); + } + } + if (auto *Array = N.getRawSubprograms()) { + Assert(isa(Array), "invalid subprogram list", &N, Array); + for (Metadata *Op : N.getSubprograms()->operands()) { + Assert(Op && isa(Op), "invalid subprogram ref", &N, Op); + } + } + if (auto *Array = N.getRawGlobalVariables()) { + Assert(isa(Array), "invalid global variable list", &N, Array); + for (Metadata *Op : N.getGlobalVariables()->operands()) { + Assert(Op && isa(Op), "invalid global variable ref", &N, + Op); + } + } + if (auto *Array = N.getRawImportedEntities()) { + Assert(isa(Array), "invalid imported entity list", &N, Array); + for (Metadata *Op : N.getImportedEntities()->operands()) { + Assert(Op && isa(Op), "invalid imported entity ref", &N, + Op); + } + } } void Verifier::visitMDSubprogram(const MDSubprogram &N) { @@ -732,18 +838,45 @@ void Verifier::visitMDTemplateValueParameter( "invalid tag", &N); } +void Verifier::visitMDVariable(const MDVariable &N) { + if (auto *S = N.getRawScope()) + Assert(isa(S), "invalid scope", &N, S); + Assert(isTypeRef(N.getRawType()), "invalid type ref", &N, N.getRawType()); + if (auto *F = N.getRawFile()) + Assert(isa(F), "invalid file", &N, F); +} + void Verifier::visitMDGlobalVariable(const MDGlobalVariable &N) { + // Checks common to all variables. + visitMDVariable(N); + Assert(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); + if (auto *V = N.getRawVariable()) { + Assert(isa(V) && + !isa(cast(V)->getValue()), + "invalid global varaible ref", &N, V); + } + if (auto *Member = N.getRawStaticDataMemberDeclaration()) { + Assert(isa(Member), "invalid static data member declaration", + &N, Member); + } } void Verifier::visitMDLocalVariable(const MDLocalVariable &N) { + // Checks common to all variables. + visitMDVariable(N); + Assert(N.getTag() == dwarf::DW_TAG_auto_variable || N.getTag() == dwarf::DW_TAG_arg_variable, "invalid tag", &N); + Assert(N.getRawScope() && isa(N.getRawScope()), + "local variable requires a valid scope", &N, N.getRawScope()); + if (auto *IA = N.getRawInlinedAt()) + Assert(isa(IA), "local variable requires a valid scope", &N, + IA); } void Verifier::visitMDExpression(const MDExpression &N) { - Assert(N.getTag() == dwarf::DW_TAG_expression, "invalid tag", &N); Assert(N.isValid(), "invalid expression", &N); } @@ -1014,7 +1147,8 @@ void Verifier::VerifyParameterAttrs(AttributeSet Attrs, unsigned Idx, Type *Ty, V); if (PointerType *PTy = dyn_cast(Ty)) { - if (!PTy->getElementType()->isSized()) { + SmallPtrSet Visited; + if (!PTy->getElementType()->isSized(&Visited)) { Assert(!Attrs.hasAttribute(Idx, Attribute::ByVal) && !Attrs.hasAttribute(Idx, Attribute::InAlloca), "Attributes 'byval' and 'inalloca' do not support unsized types!", @@ -2551,6 +2685,11 @@ void Verifier::visitInstruction(Instruction &I) { &I); } + if (MDNode *N = I.getDebugLoc().getAsMDNode()) { + Assert(isa(N), "invalid !dbg metadata attachment", &I, N); + visitMDNode(*N); + } + InstsInThisBlock.insert(&I); } @@ -2709,7 +2848,7 @@ Verifier::VerifyIntrinsicIsVarArg(bool isVarArg, // If there are no descriptors left, then it can't be a vararg. if (Infos.empty()) - return isVarArg ? true : false; + return isVarArg; // There should be only one descriptor remaining at this point. if (Infos.size() != 1) @@ -2719,7 +2858,7 @@ Verifier::VerifyIntrinsicIsVarArg(bool isVarArg, IITDescriptor D = Infos.front(); Infos = Infos.slice(1); if (D.Kind == IITDescriptor::VarArg) - return isVarArg ? false : true; + return !isVarArg; return true; } @@ -2785,10 +2924,14 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { "constant int", &CI); break; - case Intrinsic::dbg_declare: { // llvm.dbg.declare - Assert(CI.getArgOperand(0) && isa(CI.getArgOperand(0)), + case Intrinsic::dbg_declare: // llvm.dbg.declare + Assert(isa(CI.getArgOperand(0)), "invalid llvm.dbg.declare intrinsic call 1", &CI); - } break; + visitDbgIntrinsic("declare", cast(CI)); + break; + case Intrinsic::dbg_value: // llvm.dbg.value + visitDbgIntrinsic("value", cast(CI)); + break; case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: { @@ -2883,9 +3026,25 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { break; } + case Intrinsic::eh_parentframe: { + auto *AI = dyn_cast(CI.getArgOperand(0)->stripPointerCasts()); + Assert(AI && AI->isStaticAlloca(), + "llvm.eh.parentframe requires a static alloca", &CI); + break; + } + + case Intrinsic::eh_unwindhelp: { + auto *AI = dyn_cast(CI.getArgOperand(0)->stripPointerCasts()); + Assert(AI && AI->isStaticAlloca(), + "llvm.eh.unwindhelp requires a static alloca", &CI); + break; + } + case Intrinsic::experimental_gc_statepoint: Assert(!CI.isInlineAsm(), "gc.statepoint support for inline assembly unimplemented", &CI); + Assert(CI.getParent()->getParent()->hasGC(), + "Enclosing function does not use GC.", &CI); VerifyStatepoint(ImmutableCallSite(&CI)); break; @@ -2893,6 +3052,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { case Intrinsic::experimental_gc_result_float: case Intrinsic::experimental_gc_result_ptr: case Intrinsic::experimental_gc_result: { + Assert(CI.getParent()->getParent()->hasGC(), + "Enclosing function does not use GC.", &CI); // Are we tied to a statepoint properly? CallSite StatepointCS(CI.getArgOperand(0)); const Function *StatepointFn = @@ -2969,8 +3130,17 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { // Check that BaseIndex and DerivedIndex fall within the 'gc parameters' // section of the statepoint's argument - const int NumCallArgs = + Assert(StatepointCS.arg_size() > 0, + "gc.statepoint: insufficient arguments"); + Assert(isa(StatepointCS.getArgument(1)), + "gc.statement: number of call arguments must be constant integer"); + const unsigned NumCallArgs = cast(StatepointCS.getArgument(1))->getZExtValue(); + Assert(StatepointCS.arg_size() > NumCallArgs+3, + "gc.statepoint: mismatch in number of call arguments"); + Assert(isa(StatepointCS.getArgument(NumCallArgs+3)), + "gc.statepoint: number of deoptimization arguments must be " + "a constant integer"); const int NumDeoptArgs = cast(StatepointCS.getArgument(NumCallArgs + 3))->getZExtValue(); const int GCParamArgsStart = NumCallArgs + NumDeoptArgs + 4; @@ -2993,8 +3163,24 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { }; } -void DebugInfoVerifier::verifyDebugInfo() { - if (!VerifyDebugInfo) +template +void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { + auto *MD = cast(DII.getArgOperand(0))->getMetadata(); + Assert(isa(MD) || + (isa(MD) && !cast(MD)->getNumOperands()), + "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD); + Assert(isa(DII.getRawVariable()), + "invalid llvm.dbg." + Kind + " intrinsic variable", &DII, + DII.getRawVariable()); + Assert(isa(DII.getRawExpression()), + "invalid llvm.dbg." + Kind + " intrinsic expression", &DII, + DII.getRawExpression()); +} + +void Verifier::verifyDebugInfo() { + // Run the debug info verifier only if the regular verifier succeeds, since + // sometimes checks that have already failed will cause crashes here. + if (EverBroken || !VerifyDebugInfo) return; DebugInfoFinder Finder; @@ -3021,7 +3207,7 @@ void DebugInfoVerifier::verifyDebugInfo() { } } -void DebugInfoVerifier::processInstructions(DebugInfoFinder &Finder) { +void Verifier::processInstructions(DebugInfoFinder &Finder) { for (const Function &F : *M) for (auto I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { if (MDNode *MD = I->getMetadata(LLVMContext::MD_dbg)) @@ -3031,25 +3217,16 @@ void DebugInfoVerifier::processInstructions(DebugInfoFinder &Finder) { } } -void DebugInfoVerifier::processCallInst(DebugInfoFinder &Finder, - const CallInst &CI) { +void Verifier::processCallInst(DebugInfoFinder &Finder, const CallInst &CI) { if (Function *F = CI.getCalledFunction()) if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) switch (ID) { - case Intrinsic::dbg_declare: { - auto *DDI = cast(&CI); - Finder.processDeclare(*M, DDI); - if (auto E = DDI->getExpression()) - Assert(DIExpression(E).Verify(), "DIExpression does not Verify!", E); + case Intrinsic::dbg_declare: + Finder.processDeclare(*M, cast(&CI)); break; - } - case Intrinsic::dbg_value: { - auto *DVI = cast(&CI); - Finder.processValue(*M, DVI); - if (auto E = DVI->getExpression()) - Assert(DIExpression(E).Verify(), "DIExpression does not Verify!", E); + case Intrinsic::dbg_value: + Finder.processValue(*M, cast(&CI)); break; - } default: break; } @@ -3082,8 +3259,7 @@ bool llvm::verifyModule(const Module &M, raw_ostream *OS) { // Note that this function's return value is inverted from what you would // expect of a function called "verify". - DebugInfoVerifier DIV(OS ? *OS : NullStr); - return !V.verify(M) || !DIV.verify(M) || Broken; + return !V.verify(M) || Broken; } namespace { @@ -3093,7 +3269,7 @@ struct VerifierLegacyPass : public FunctionPass { Verifier V; bool FatalErrors; - VerifierLegacyPass() : FunctionPass(ID), FatalErrors(true) { + VerifierLegacyPass() : FunctionPass(ID), V(dbgs()), FatalErrors(true) { initializeVerifierLegacyPassPass(*PassRegistry::getPassRegistry()); } explicit VerifierLegacyPass(bool FatalErrors) @@ -3119,48 +3295,15 @@ struct VerifierLegacyPass : public FunctionPass { AU.setPreservesAll(); } }; -struct DebugInfoVerifierLegacyPass : public ModulePass { - static char ID; - - DebugInfoVerifier V; - bool FatalErrors; - - DebugInfoVerifierLegacyPass() : ModulePass(ID), FatalErrors(true) { - initializeDebugInfoVerifierLegacyPassPass(*PassRegistry::getPassRegistry()); - } - explicit DebugInfoVerifierLegacyPass(bool FatalErrors) - : ModulePass(ID), V(dbgs()), FatalErrors(FatalErrors) { - initializeDebugInfoVerifierLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - bool runOnModule(Module &M) override { - if (!V.verify(M) && FatalErrors) - report_fatal_error("Broken debug info found, compilation aborted!"); - - return false; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } -}; } char VerifierLegacyPass::ID = 0; INITIALIZE_PASS(VerifierLegacyPass, "verify", "Module Verifier", false, false) -char DebugInfoVerifierLegacyPass::ID = 0; -INITIALIZE_PASS(DebugInfoVerifierLegacyPass, "verify-di", "Debug Info Verifier", - false, false) - FunctionPass *llvm::createVerifierPass(bool FatalErrors) { return new VerifierLegacyPass(FatalErrors); } -ModulePass *llvm::createDebugInfoVerifierPass(bool FatalErrors) { - return new DebugInfoVerifierLegacyPass(FatalErrors); -} - PreservedAnalyses VerifierPass::run(Module &M) { if (verifyModule(M, &dbgs()) && FatalErrors) report_fatal_error("Broken module found, compilation aborted!");