X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FIR%2FVerifier.cpp;h=5ed137abd0e539adf884d0c7f39864b993f288b1;hb=872808e946f3f8be1b30a6672697c2ba8e12f9e1;hp=af79984f59a5077b3adf0165e9df182e31b5066c;hpb=cefca100398ac2f0a1598f3ba83fcdac2e32b0b6;p=oota-llvm.git diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index af79984f59a..5ed137abd0e 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -87,10 +87,9 @@ 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), EverBroken(false) {} + : OS(OS), M(nullptr), Broken(false) {} private: void Write(const Value *V) { @@ -111,6 +110,10 @@ private: OS << '\n'; } + template void Write(const MDTupleTypedArrayWrapper &MD) { + Write(MD.get()); + } + void Write(const NamedMDNode *NMD) { if (!NMD) return; @@ -145,7 +148,7 @@ public: /// something is not correct. void CheckFailed(const Twine &Message) { OS << Message << '\n'; - EverBroken = Broken = true; + Broken = true; } /// \brief A check failed (with values to print). @@ -175,6 +178,9 @@ class Verifier : public InstVisitor, VerifierSupport { /// \brief Keep track of the metadata nodes that have been checked already. SmallPtrSet MDNodes; + /// \brief Track unresolved string-based type references. + SmallDenseMap UnresolvedTypeRefs; + /// \brief The personality function referenced by the LandingPadInsts. /// All LandingPadInsts within the same function must use the same /// personality function. @@ -268,8 +274,8 @@ public: visitModuleFlags(M); visitModuleIdents(M); - // Verify debug info last. - verifyDebugInfo(); + // Verify type referneces last. + verifyTypeRefs(); return !Broken; } @@ -296,11 +302,37 @@ private: void visitBasicBlock(BasicBlock &BB); void visitRangeMetadata(Instruction& I, MDNode* Range, Type* Ty); + template bool isValidMetadataArray(const MDTuple &N); #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); + void visitDIScope(const DIScope &N); + void visitDIDerivedTypeBase(const DIDerivedTypeBase &N); + void visitDIVariable(const DIVariable &N); + void visitDILexicalBlockBase(const DILexicalBlockBase &N); + void visitDITemplateParameter(const DITemplateParameter &N); + + void visitTemplateParams(const MDNode &N, const Metadata &RawParams); + + /// \brief Check for a valid string-based type reference. + /// + /// Checks if \c MD is a string-based type reference. If it is, keeps track + /// of it (and its user, \c N) for error messages later. + bool isValidUUID(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid type reference. + /// + /// Checks for subclasses of \a DIType, or \a isValidUUID(). + bool isTypeRef(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid scope reference. + /// + /// Checks for subclasses of \a DIScope, or \a isValidUUID(). + bool isScopeRef(const MDNode &N, const Metadata *MD); + + /// \brief Check for a valid debug info reference. + /// + /// Checks for subclasses of \a DINode, or \a isValidUUID(). + bool isDIRef(const MDNode &N, const Metadata *MD); // InstVisitor overrides... using InstVisitor::visit; @@ -368,15 +400,19 @@ private: bool isReturnValue, const Value *V); void VerifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs, const Value *V); + void VerifyFunctionMetadata( + const SmallVector, 4> MDs); void VerifyConstantExprBitcastType(const ConstantExpr *CE); void VerifyStatepoint(ImmutableCallSite CS); void verifyFrameRecoverIndices(); // Module-level debug info verification... - void verifyDebugInfo(); - void processInstructions(DebugInfoFinder &Finder); - void processCallInst(DebugInfoFinder &Finder, const CallInst &CI); + void verifyTypeRefs(); + template + void verifyBitPieceExpression(const DbgInfoIntrinsic &I, + const MapTy &TypeRefs); + void visitUnresolvedTypeRef(const MDString *S, const MDNode *N); }; } // End anonymous namespace @@ -403,7 +439,7 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { if (GV.hasAppendingLinkage()) { const GlobalVariable *GVar = dyn_cast(&GV); - Assert(GVar && GVar->getType()->getElementType()->isArrayTy(), + Assert(GVar && GVar->getValueType()->isArrayTy(), "Only global arrays can have appending linkage!", GVar); } } @@ -435,7 +471,7 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { "invalid linkage for intrinsic global variable", &GV); // Don't worry about emitting an error for it not being an array, // visitGlobalValue will complain on appending non-array. - if (ArrayType *ATy = dyn_cast(GV.getType()->getElementType())) { + if (ArrayType *ATy = dyn_cast(GV.getValueType())) { StructType *STy = dyn_cast(ATy->getElementType()); PointerType *FuncPtrTy = FunctionType::get(Type::getVoidTy(*Context), false)->getPointerTo(); @@ -458,7 +494,7 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { GV.getName() == "llvm.compiler.used")) { Assert(!GV.hasInitializer() || GV.hasAppendingLinkage(), "invalid linkage for intrinsic global variable", &GV); - Type *GVType = GV.getType()->getElementType(); + Type *GVType = GV.getValueType(); if (ArrayType *ATy = dyn_cast(GVType)) { PointerType *PTy = dyn_cast(ATy->getElementType()); Assert(PTy, "wrong type for intrinsic global variable", &GV); @@ -569,13 +605,14 @@ void Verifier::visitGlobalAlias(const GlobalAlias &GA) { void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) { MDNode *MD = NMD.getOperand(i); - if (!MD) - continue; if (NMD.getName() == "llvm.dbg.cu") { - Assert(isa(MD), "invalid compile unit", &NMD, MD); + Assert(MD && isa(MD), "invalid compile unit", &NMD, MD); } + if (!MD) + continue; + visitMDNode(*MD); } } @@ -661,66 +698,121 @@ void Verifier::visitMetadataAsValue(const MetadataAsValue &MDV, Function *F) { visitValueAsMetadata(*V, F); } +bool Verifier::isValidUUID(const MDNode &N, const Metadata *MD) { + auto *S = dyn_cast(MD); + if (!S) + return false; + if (S->getString().empty()) + return false; + + // Keep track of names of types referenced via UUID so we can check that they + // actually exist. + UnresolvedTypeRefs.insert(std::make_pair(S, &N)); + return true; +} + /// \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); +bool Verifier::isTypeRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || 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); +bool Verifier::isScopeRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || isa(MD); +} + +/// \brief Check if a value can be a debug info ref. +bool Verifier::isDIRef(const MDNode &N, const Metadata *MD) { + return !MD || isValidUUID(N, MD) || isa(MD); +} + +template +bool isValidMetadataArrayImpl(const MDTuple &N, bool AllowNull) { + for (Metadata *MD : N.operands()) { + if (MD) { + if (!isa(MD)) + return false; + } else { + if (!AllowNull) + return false; + } + } + return true; +} + +template +bool isValidMetadataArray(const MDTuple &N) { + return isValidMetadataArrayImpl(N, /* AllowNull */ false); } -void Verifier::visitMDLocation(const MDLocation &N) { - Assert(N.getRawScope() && isa(N.getRawScope()), +template +bool isValidMetadataNullArray(const MDTuple &N) { + return isValidMetadataArrayImpl(N, /* AllowNull */ true); +} + +void Verifier::visitDILocation(const DILocation &N) { + 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); + Assert(isa(IA), "inlined-at should be a location", &N, IA); } -void Verifier::visitGenericDebugNode(const GenericDebugNode &N) { +void Verifier::visitGenericDINode(const GenericDINode &N) { Assert(N.getTag(), "invalid tag", &N); } -void Verifier::visitMDScope(const MDScope &N) { +void Verifier::visitDIScope(const DIScope &N) { if (auto *F = N.getRawFile()) - Assert(isa(F), "invalid file", &N, F); + Assert(isa(F), "invalid file", &N, F); } -void Verifier::visitMDSubrange(const MDSubrange &N) { +void Verifier::visitDISubrange(const DISubrange &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) { +void Verifier::visitDIEnumerator(const DIEnumerator &N) { Assert(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N); } -void Verifier::visitMDBasicType(const MDBasicType &N) { +void Verifier::visitDIBasicType(const DIBasicType &N) { Assert(N.getTag() == dwarf::DW_TAG_base_type || N.getTag() == dwarf::DW_TAG_unspecified_type, "invalid tag", &N); } -void Verifier::visitMDDerivedTypeBase(const MDDerivedTypeBase &N) { +void Verifier::visitDIDerivedTypeBase(const DIDerivedTypeBase &N) { // Common scope checks. - visitMDScope(N); + visitDIScope(N); - Assert(isScopeRef(N.getScope()), "invalid scope", &N, N.getScope()); - Assert(isTypeRef(N.getBaseType()), "invalid base type", &N, N.getBaseType()); -} + Assert(isScopeRef(N, N.getScope()), "invalid scope", &N, N.getScope()); + Assert(isTypeRef(N, N.getBaseType()), "invalid base type", &N, + N.getBaseType()); -void Verifier::visitMDDerivedType(const MDDerivedType &N) { + // FIXME: Sink this into the subclass verifies. + if (!N.getFile() || N.getFile()->getFilename().empty()) { + // Check whether the filename is allowed to be empty. + uint16_t Tag = N.getTag(); + Assert( + Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || + Tag == dwarf::DW_TAG_pointer_type || + Tag == dwarf::DW_TAG_ptr_to_member_type || + Tag == dwarf::DW_TAG_reference_type || + Tag == dwarf::DW_TAG_rvalue_reference_type || + Tag == dwarf::DW_TAG_restrict_type || + Tag == dwarf::DW_TAG_array_type || + Tag == dwarf::DW_TAG_enumeration_type || + Tag == dwarf::DW_TAG_subroutine_type || + Tag == dwarf::DW_TAG_inheritance || Tag == dwarf::DW_TAG_friend || + Tag == dwarf::DW_TAG_structure_type || + Tag == dwarf::DW_TAG_member || Tag == dwarf::DW_TAG_typedef, + "derived/composite type requires a filename", &N, N.getFile()); + } +} + +void Verifier::visitDIDerivedType(const DIDerivedType &N) { // Common derived type checks. - visitMDDerivedTypeBase(N); + visitDIDerivedTypeBase(N); Assert(N.getTag() == dwarf::DW_TAG_typedef || N.getTag() == dwarf::DW_TAG_pointer_type || @@ -734,11 +826,29 @@ void Verifier::visitMDDerivedType(const MDDerivedType &N) { N.getTag() == dwarf::DW_TAG_inheritance || N.getTag() == dwarf::DW_TAG_friend, "invalid tag", &N); + if (N.getTag() == dwarf::DW_TAG_ptr_to_member_type) { + Assert(isTypeRef(N, N.getExtraData()), "invalid pointer to member type", &N, + N.getExtraData()); + } +} + +static bool hasConflictingReferenceFlags(unsigned Flags) { + return (Flags & DINode::FlagLValueReference) && + (Flags & DINode::FlagRValueReference); +} + +void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) { + auto *Params = dyn_cast(&RawParams); + Assert(Params, "invalid template params", &N, &RawParams); + for (Metadata *Op : Params->operands()) { + Assert(Op && isa(Op), "invalid template parameter", &N, + Params, Op); + } } -void Verifier::visitMDCompositeType(const MDCompositeType &N) { +void Verifier::visitDICompositeType(const DICompositeType &N) { // Common derived type checks. - visitMDDerivedTypeBase(N); + visitDIDerivedTypeBase(N); Assert(N.getTag() == dwarf::DW_TAG_array_type || N.getTag() == dwarf::DW_TAG_structure_type || @@ -750,33 +860,46 @@ void Verifier::visitMDCompositeType(const MDCompositeType &N) { Assert(!N.getRawElements() || isa(N.getRawElements()), "invalid composite elements", &N, N.getRawElements()); - Assert(isTypeRef(N.getRawVTableHolder()), "invalid vtable holder", &N, + Assert(isTypeRef(N, N.getRawVTableHolder()), "invalid vtable holder", &N, N.getRawVTableHolder()); Assert(!N.getRawElements() || isa(N.getRawElements()), "invalid composite elements", &N, N.getRawElements()); + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); + if (auto *Params = N.getRawTemplateParams()) + visitTemplateParams(N, *Params); } -void Verifier::visitMDSubroutineType(const MDSubroutineType &N) { +void Verifier::visitDISubroutineType(const DISubroutineType &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); + Assert(isTypeRef(N, Ty), "invalid subroutine type ref", &N, Types, Ty); } } + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); } -void Verifier::visitMDFile(const MDFile &N) { +void Verifier::visitDIFile(const DIFile &N) { Assert(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); } -void Verifier::visitMDCompileUnit(const MDCompileUnit &N) { +void Verifier::visitDICompileUnit(const DICompileUnit &N) { Assert(N.getTag() == dwarf::DW_TAG_compile_unit, "invalid tag", &N); + // Don't bother verifying the compilation directory or producer string + // as those could be empty. + Assert(N.getRawFile() && isa(N.getRawFile()), "invalid file", &N, + N.getRawFile()); + Assert(!N.getFile()->getFilename().empty(), "invalid filename", &N, + N.getFile()); + 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); + auto *Enum = dyn_cast_or_null(Op); Assert(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type, "invalid enum type", &N, N.getEnumTypes(), Op); } @@ -784,110 +907,198 @@ void Verifier::visitMDCompileUnit(const MDCompileUnit &N) { 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); + 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); + 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, + 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, + Assert(Op && isa(Op), "invalid imported entity ref", &N, Op); } } } -void Verifier::visitMDSubprogram(const MDSubprogram &N) { +void Verifier::visitDISubprogram(const DISubprogram &N) { Assert(N.getTag() == dwarf::DW_TAG_subprogram, "invalid tag", &N); + Assert(isScopeRef(N, N.getRawScope()), "invalid scope", &N, N.getRawScope()); + if (auto *T = N.getRawType()) + Assert(isa(T), "invalid subroutine type", &N, T); + Assert(isTypeRef(N, N.getRawContainingType()), "invalid containing type", &N, + N.getRawContainingType()); + if (auto *RawF = N.getRawFunction()) { + auto *FMD = dyn_cast(RawF); + auto *F = FMD ? FMD->getValue() : nullptr; + auto *FT = F ? dyn_cast(F->getType()) : nullptr; + Assert(F && FT && isa(FT->getElementType()), + "invalid function", &N, F, FT); + } + if (auto *Params = N.getRawTemplateParams()) + visitTemplateParams(N, *Params); + if (auto *S = N.getRawDeclaration()) { + Assert(isa(S) && !cast(S)->isDefinition(), + "invalid subprogram declaration", &N, S); + } + if (auto *RawVars = N.getRawVariables()) { + auto *Vars = dyn_cast(RawVars); + Assert(Vars, "invalid variable list", &N, RawVars); + for (Metadata *Op : Vars->operands()) { + Assert(Op && isa(Op), "invalid local variable", &N, Vars, + Op); + } + } + Assert(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", + &N); + + auto *F = N.getFunction(); + if (!F) + return; + + // Check that all !dbg attachments lead to back to N (or, at least, another + // subprogram that describes the same function). + // + // FIXME: Check this incrementally while visiting !dbg attachments. + // FIXME: Only check when N is the canonical subprogram for F. + SmallPtrSet Seen; + for (auto &BB : *F) + for (auto &I : BB) { + // Be careful about using DILocation here since we might be dealing with + // broken code (this is the Verifier after all). + DILocation *DL = + dyn_cast_or_null(I.getDebugLoc().getAsMDNode()); + if (!DL) + continue; + if (!Seen.insert(DL).second) + continue; + + DILocalScope *Scope = DL->getInlinedAtScope(); + if (Scope && !Seen.insert(Scope).second) + continue; + + DISubprogram *SP = Scope ? Scope->getSubprogram() : nullptr; + if (SP && !Seen.insert(SP).second) + continue; + + // FIXME: Once N is canonical, check "SP == &N". + Assert(SP->describes(F), + "!dbg attachment points at wrong subprogram for function", &N, F, + &I, DL, Scope, SP); + } } -void Verifier::visitMDLexicalBlock(const MDLexicalBlock &N) { +void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) { Assert(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N); + Assert(N.getRawScope() && isa(N.getRawScope()), + "invalid local scope", &N, N.getRawScope()); } -void Verifier::visitMDLexicalBlockFile(const MDLexicalBlockFile &N) { - Assert(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N); +void Verifier::visitDILexicalBlock(const DILexicalBlock &N) { + visitDILexicalBlockBase(N); + + Assert(N.getLine() || !N.getColumn(), + "cannot have column info without line info", &N); +} + +void Verifier::visitDILexicalBlockFile(const DILexicalBlockFile &N) { + visitDILexicalBlockBase(N); } -void Verifier::visitMDNamespace(const MDNamespace &N) { +void Verifier::visitDINamespace(const DINamespace &N) { Assert(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N); + if (auto *S = N.getRawScope()) + Assert(isa(S), "invalid scope ref", &N, S); } -void Verifier::visitMDTemplateTypeParameter(const MDTemplateTypeParameter &N) { +void Verifier::visitDITemplateParameter(const DITemplateParameter &N) { + Assert(isTypeRef(N, N.getType()), "invalid type ref", &N, N.getType()); +} + +void Verifier::visitDITemplateTypeParameter(const DITemplateTypeParameter &N) { + visitDITemplateParameter(N); + Assert(N.getTag() == dwarf::DW_TAG_template_type_parameter, "invalid tag", &N); } -void Verifier::visitMDTemplateValueParameter( - const MDTemplateValueParameter &N) { +void Verifier::visitDITemplateValueParameter( + const DITemplateValueParameter &N) { + visitDITemplateParameter(N); + Assert(N.getTag() == dwarf::DW_TAG_template_value_parameter || N.getTag() == dwarf::DW_TAG_GNU_template_template_param || N.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack, "invalid tag", &N); } -void Verifier::visitMDVariable(const MDVariable &N) { +void Verifier::visitDIVariable(const DIVariable &N) { if (auto *S = N.getRawScope()) - Assert(isa(S), "invalid scope", &N, S); - Assert(isTypeRef(N.getRawType()), "invalid type ref", &N, N.getRawType()); + Assert(isa(S), "invalid scope", &N, S); + Assert(isTypeRef(N, N.getRawType()), "invalid type ref", &N, N.getRawType()); if (auto *F = N.getRawFile()) - Assert(isa(F), "invalid file", &N, F); + Assert(isa(F), "invalid file", &N, F); } -void Verifier::visitMDGlobalVariable(const MDGlobalVariable &N) { +void Verifier::visitDIGlobalVariable(const DIGlobalVariable &N) { // Checks common to all variables. - visitMDVariable(N); + visitDIVariable(N); Assert(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); + Assert(!N.getName().empty(), "missing global variable name", &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", + Assert(isa(Member), "invalid static data member declaration", &N, Member); } } -void Verifier::visitMDLocalVariable(const MDLocalVariable &N) { +void Verifier::visitDILocalVariable(const DILocalVariable &N) { // Checks common to all variables. - visitMDVariable(N); + visitDIVariable(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()), + 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) { +void Verifier::visitDIExpression(const DIExpression &N) { Assert(N.isValid(), "invalid expression", &N); } -void Verifier::visitMDObjCProperty(const MDObjCProperty &N) { +void Verifier::visitDIObjCProperty(const DIObjCProperty &N) { Assert(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N); + if (auto *T = N.getRawType()) + Assert(isa(T), "invalid type ref", &N, T); + if (auto *F = N.getRawFile()) + Assert(isa(F), "invalid file", &N, F); } -void Verifier::visitMDImportedEntity(const MDImportedEntity &N) { +void Verifier::visitDIImportedEntity(const DIImportedEntity &N) { Assert(N.getTag() == dwarf::DW_TAG_imported_module || N.getTag() == dwarf::DW_TAG_imported_declaration, "invalid tag", &N); + if (auto *S = N.getRawScope()) + Assert(isa(S), "invalid scope for imported entity", &N, S); + Assert(isDIRef(N, N.getEntity()), "invalid imported entity", &N, + N.getEntity()); } void Verifier::visitComdat(const Comdat &C) { @@ -1057,7 +1268,8 @@ void Verifier::VerifyAttributeTypes(AttributeSet Attrs, unsigned Idx, I->getKindAsEnum() == Attribute::NoBuiltin || I->getKindAsEnum() == Attribute::Cold || I->getKindAsEnum() == Attribute::OptimizeNone || - I->getKindAsEnum() == Attribute::JumpTable) { + I->getKindAsEnum() == Attribute::JumpTable || + I->getKindAsEnum() == Attribute::Convergent) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + "' only applies to functions!", V); @@ -1141,9 +1353,10 @@ void Verifier::VerifyParameterAttrs(AttributeSet Attrs, unsigned Idx, Type *Ty, V); Assert(!AttrBuilder(Attrs, Idx) - .hasAttributes(AttributeFuncs::typeIncompatible(Ty, Idx), Idx), + .overlaps(AttributeFuncs::typeIncompatible(Ty)), "Wrong types for attribute: " + - AttributeFuncs::typeIncompatible(Ty, Idx).getAsString(Idx), + AttributeSet::get(*Context, Idx, + AttributeFuncs::typeIncompatible(Ty)).getAsString(Idx), V); if (PointerType *PTy = dyn_cast(Ty)) { @@ -1253,6 +1466,36 @@ void Verifier::VerifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs, } } +void Verifier::VerifyFunctionMetadata( + const SmallVector, 4> MDs) { + if (MDs.empty()) + return; + + for (unsigned i = 0; i < MDs.size(); i++) { + if (MDs[i].first == LLVMContext::MD_prof) { + MDNode *MD = MDs[i].second; + Assert(MD->getNumOperands() == 2, + "!prof annotations should have exactly 2 operands", MD); + + // Check first operand. + Assert(MD->getOperand(0) != nullptr, "first operand should not be null", + MD); + Assert(isa(MD->getOperand(0)), + "expected string with name of the !prof annotation", MD); + MDString *MDS = cast(MD->getOperand(0)); + StringRef ProfName = MDS->getString(); + Assert(ProfName.equals("function_entry_count"), + "first operand should be 'function_entry_count'", MD); + + // Check second operand. + Assert(MD->getOperand(1) != nullptr, "second operand should not be null", + MD); + Assert(isa(MD->getOperand(1)), + "expected integer argument to function_entry_count", MD); + } + } +} + void Verifier::VerifyConstantExprBitcastType(const ConstantExpr *CE) { if (CE->getOpcode() != Instruction::BitCast) return; @@ -1289,13 +1532,34 @@ void Verifier::VerifyStatepoint(ImmutableCallSite CS) { "reordering restrictions required by safepoint semantics", &CI); - const Value *Target = CS.getArgument(0); + const Value *IDV = CS.getArgument(0); + Assert(isa(IDV), "gc.statepoint ID must be a constant integer", + &CI); + + const Value *NumPatchBytesV = CS.getArgument(1); + Assert(isa(NumPatchBytesV), + "gc.statepoint number of patchable bytes must be a constant integer", + &CI); + const int64_t NumPatchBytes = + cast(NumPatchBytesV)->getSExtValue(); + assert(isInt<32>(NumPatchBytes) && "NumPatchBytesV is an i32!"); + Assert(NumPatchBytes >= 0, "gc.statepoint number of patchable bytes must be " + "positive", + &CI); + + const Value *Target = CS.getArgument(2); const PointerType *PT = dyn_cast(Target->getType()); Assert(PT && PT->getElementType()->isFunctionTy(), "gc.statepoint callee must be of function pointer type", &CI, Target); FunctionType *TargetFuncType = cast(PT->getElementType()); - const Value *NumCallArgsV = CS.getArgument(1); + if (NumPatchBytes) + Assert(isa(Target->stripPointerCasts()), + "gc.statepoint must have null as call target if number of patchable " + "bytes is non zero", + &CI); + + const Value *NumCallArgsV = CS.getArgument(3); Assert(isa(NumCallArgsV), "gc.statepoint number of arguments to underlying call " "must be constant integer", @@ -1319,22 +1583,38 @@ void Verifier::VerifyStatepoint(ImmutableCallSite CS) { Assert(NumCallArgs == NumParams, "gc.statepoint mismatch in number of call args", &CI); - const Value *Unused = CS.getArgument(2); - Assert(isa(Unused) && cast(Unused)->isNullValue(), - "gc.statepoint parameter #3 must be zero", &CI); + const Value *FlagsV = CS.getArgument(4); + Assert(isa(FlagsV), + "gc.statepoint flags must be constant integer", &CI); + const uint64_t Flags = cast(FlagsV)->getZExtValue(); + Assert((Flags & ~(uint64_t)StatepointFlags::MaskAll) == 0, + "unknown flag used in gc.statepoint flags argument", &CI); // Verify that the types of the call parameter arguments match // the type of the wrapped callee. for (int i = 0; i < NumParams; i++) { Type *ParamType = TargetFuncType->getParamType(i); - Type *ArgType = CS.getArgument(3+i)->getType(); + Type *ArgType = CS.getArgument(5 + i)->getType(); Assert(ArgType == ParamType, "gc.statepoint call argument does not match wrapped " "function type", &CI); } - const int EndCallArgsInx = 2+NumCallArgs; - const Value *NumDeoptArgsV = CS.getArgument(EndCallArgsInx+1); + + const int EndCallArgsInx = 4 + NumCallArgs; + + const Value *NumTransitionArgsV = CS.getArgument(EndCallArgsInx+1); + Assert(isa(NumTransitionArgsV), + "gc.statepoint number of transition arguments " + "must be constant integer", + &CI); + const int NumTransitionArgs = + cast(NumTransitionArgsV)->getZExtValue(); + Assert(NumTransitionArgs >= 0, + "gc.statepoint number of transition arguments must be positive", &CI); + const int EndTransitionArgsInx = EndCallArgsInx + 1 + NumTransitionArgs; + + const Value *NumDeoptArgsV = CS.getArgument(EndTransitionArgsInx+1); Assert(isa(NumDeoptArgsV), "gc.statepoint number of deoptimization arguments " "must be constant integer", @@ -1344,7 +1624,9 @@ void Verifier::VerifyStatepoint(ImmutableCallSite CS) { "must be positive", &CI); - Assert(4 + NumCallArgs + NumDeoptArgs <= (int)CS.arg_size(), + const int ExpectedNumArgs = + 7 + NumCallArgs + NumTransitionArgs + NumDeoptArgs; + Assert(ExpectedNumArgs <= (int)CS.arg_size(), "gc.statepoint too few arguments according to length fields", &CI); // Check that the only uses of this gc.statepoint are gc.result or @@ -1460,11 +1742,21 @@ void Verifier::visitFunction(const Function &F) { "Function takes metadata but isn't an intrinsic", I, &F); } + // Get the function metadata attachments. + SmallVector, 4> MDs; + F.getAllMetadata(MDs); + assert(F.hasMetadata() != MDs.empty() && "Bit out-of-sync"); + VerifyFunctionMetadata(MDs); + if (F.isMaterializable()) { // Function has a body somewhere we can't see. + Assert(MDs.empty(), "unmaterialized function cannot have metadata", &F, + MDs.empty() ? nullptr : MDs.front().second); } else if (F.isDeclaration()) { Assert(F.hasExternalLinkage() || F.hasExternalWeakLinkage(), "invalid linkage type for function declaration", &F); + Assert(MDs.empty(), "function without a body cannot have metadata", &F, + MDs.empty() ? nullptr : MDs.front().second); } else { // Verify that this function (which has a body) is not named "llvm.*". It // is not legal to define intrinsics. @@ -1480,6 +1772,10 @@ void Verifier::visitFunction(const Function &F) { Assert(!BlockAddress::lookup(Entry)->isConstantUsed(), "blockaddress may not be used with the entry block!", Entry); } + + // Visit metadata attachments. + for (const auto &I : MDs) + visitMDNode(*I.second); } // If this function is actually an intrinsic, verify that it is only used in @@ -1892,8 +2188,8 @@ void Verifier::visitPHINode(PHINode &PN) { // Check that all of the values of the PHI node have the same type as the // result, and that the incoming blocks are really basic blocks. - for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { - Assert(PN.getType() == PN.getIncomingValue(i)->getType(), + for (Value *IncValue : PN.incoming_values()) { + Assert(PN.getType() == IncValue->getType(), "PHI node operands are not the same type as the result!", &PN); } @@ -1911,7 +2207,11 @@ void Verifier::VerifyCallSite(CallSite CS) { Assert(FPTy->getElementType()->isFunctionTy(), "Called function is not pointer to function type!", I); - FunctionType *FTy = cast(FPTy->getElementType()); + + Assert(FPTy->getElementType() == CS.getFunctionType(), + "Called function is not the same type as the call!", I); + + FunctionType *FTy = CS.getFunctionType(); // Verify that the correct number of arguments are being passed if (FTy->isVarArg()) @@ -2030,12 +2330,8 @@ void Verifier::verifyMustTailCall(CallInst &CI) { // parameters or return types may differ in pointee type, but not // address space. Function *F = CI.getParent()->getParent(); - auto GetFnTy = [](Value *V) { - return cast( - cast(V->getType())->getElementType()); - }; - FunctionType *CallerTy = GetFnTy(F); - FunctionType *CalleeTy = GetFnTy(CI.getCalledValue()); + FunctionType *CallerTy = F->getFunctionType(); + FunctionType *CalleeTy = CI.getFunctionType(); Assert(CallerTy->getNumParams() == CalleeTy->getNumParams(), "cannot guarantee tail call due to mismatched parameter counts", &CI); Assert(CallerTy->isVarArg() == CalleeTy->isVarArg(), @@ -2095,7 +2391,7 @@ void Verifier::visitCallInst(CallInst &CI) { verifyMustTailCall(CI); if (Function *F = CI.getCalledFunction()) - if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) + if (Intrinsic::ID ID = F->getIntrinsicID()) visitIntrinsicFunctionCall(ID, CI); } @@ -2242,20 +2538,18 @@ void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) { Assert(isa(TargetTy), "GEP base pointer is not a vector or a vector of pointers", &GEP); - Assert(cast(TargetTy)->getElementType()->isSized(), - "GEP into unsized type!", &GEP); + Assert(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP); Assert(GEP.getPointerOperandType()->isVectorTy() == GEP.getType()->isVectorTy(), "Vector GEP must return a vector value", &GEP); SmallVector Idxs(GEP.idx_begin(), GEP.idx_end()); Type *ElTy = - GetElementPtrInst::getIndexedType(GEP.getPointerOperandType(), Idxs); + GetElementPtrInst::getIndexedType(GEP.getSourceElementType(), Idxs); Assert(ElTy, "Invalid indices for GEP pointer type!", &GEP); Assert(GEP.getType()->getScalarType()->isPointerTy() && - cast(GEP.getType()->getScalarType()) - ->getElementType() == ElTy, + GEP.getResultElementType() == ElTy, "GEP is not of right type for indices!", &GEP, ElTy); if (GEP.getPointerOperandType()->isVectorTy()) { @@ -2331,9 +2625,7 @@ void Verifier::visitRangeMetadata(Instruction& I, void Verifier::visitLoadInst(LoadInst &LI) { PointerType *PTy = dyn_cast(LI.getOperand(0)->getType()); Assert(PTy, "Load operand must be a pointer.", &LI); - Type *ElTy = PTy->getElementType(); - Assert(ElTy == LI.getType(), - "Load result type does not match pointer operand type!", &LI, ElTy); + Type *ElTy = LI.getType(); Assert(LI.getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", &LI); if (LI.isAtomic()) { @@ -2391,7 +2683,7 @@ void Verifier::visitAllocaInst(AllocaInst &AI) { Assert(PTy->getAddressSpace() == 0, "Allocation instruction pointer not in the generic address space!", &AI); - Assert(PTy->getElementType()->isSized(&Visited), + Assert(AI.getAllocatedType()->isSized(&Visited), "Cannot allocate unsized type", &AI); Assert(AI.getArraySize()->getType()->isIntegerTy(), "Alloca array size must have integer type", &AI); @@ -2686,7 +2978,7 @@ void Verifier::visitInstruction(Instruction &I) { } if (MDNode *N = I.getDebugLoc().getAsMDNode()) { - Assert(isa(N), "invalid !dbg metadata attachment", &I, N); + Assert(isa(N), "invalid !dbg metadata attachment", &I, N); visitMDNode(*N); } @@ -2829,8 +3121,8 @@ bool Verifier::VerifyIntrinsicType(Type *Ty, dyn_cast(ThisArgVecTy->getVectorElementType()); if (!ThisArgEltTy) return true; - return (!(ThisArgEltTy->getElementType() == - ReferenceType->getVectorElementType())); + return ThisArgEltTy->getElementType() != + ReferenceType->getVectorElementType(); } } llvm_unreachable("unhandled"); @@ -2956,7 +3248,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { Assert(AI, "llvm.gcroot parameter #1 must be an alloca.", &CI); Assert(isa(CI.getArgOperand(1)), "llvm.gcroot parameter #2 must be a constant.", &CI); - if (!AI->getType()->getElementType()->isPointerTy()) { + if (!AI->getAllocatedType()->isPointerTy()) { Assert(!isa(CI.getArgOperand(1)), "llvm.gcroot parameter #1 must either be a pointer alloca, " "or argument #2 must be a non-null constant.", @@ -3002,6 +3294,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { Assert(!SawFrameEscape, "multiple calls to llvm.frameescape in one function", &CI); for (Value *Arg : CI.arg_operands()) { + if (isa(Arg)) + continue; // Null values are allowed as placeholders. auto *AI = dyn_cast(Arg->stripPointerCasts()); Assert(AI && AI->isStaticAlloca(), "llvm.frameescape only accepts static allocas", &CI); @@ -3026,20 +3320,6 @@ 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); @@ -3065,7 +3345,7 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { CI.getArgOperand(0)); // Assert that result type matches wrapped callee. - const Value *Target = StatepointCS.getArgument(0); + const Value *Target = StatepointCS.getArgument(2); const PointerType *PT = cast(Target->getType()); const FunctionType *TargetFuncType = cast(PT->getElementType()); @@ -3085,17 +3365,17 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { "gc relocate on unwind path incorrectly linked to the statepoint", &CI); - const BasicBlock *invokeBB = + const BasicBlock *InvokeBB = ExtractValue->getParent()->getUniquePredecessor(); // Landingpad relocates should have only one predecessor with invoke // statepoint terminator - Assert(invokeBB, "safepoints should have unique landingpads", + Assert(InvokeBB, "safepoints should have unique landingpads", ExtractValue->getParent()); - Assert(invokeBB->getTerminator(), "safepoint block should be well formed", - invokeBB); - Assert(isStatepoint(invokeBB->getTerminator()), - "gc relocate should be linked to a statepoint", invokeBB); + Assert(InvokeBB->getTerminator(), "safepoint block should be well formed", + InvokeBB); + Assert(isStatepoint(InvokeBB->getTerminator()), + "gc relocate should be linked to a statepoint", InvokeBB); } else { // In all other cases relocate should be tied to the statepoint directly. @@ -3108,8 +3388,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { // Verify rest of the relocate arguments - GCRelocateOperands ops(&CI); - ImmutableCallSite StatepointCS(ops.statepoint()); + GCRelocateOperands Ops(&CI); + ImmutableCallSite StatepointCS(Ops.getStatepoint()); // Both the base and derived must be piped through the safepoint Value* Base = CI.getArgOperand(1); @@ -3132,18 +3412,25 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { // section of the statepoint's argument Assert(StatepointCS.arg_size() > 0, "gc.statepoint: insufficient arguments"); - Assert(isa(StatepointCS.getArgument(1)), + Assert(isa(StatepointCS.getArgument(3)), "gc.statement: number of call arguments must be constant integer"); const unsigned NumCallArgs = - cast(StatepointCS.getArgument(1))->getZExtValue(); - Assert(StatepointCS.arg_size() > NumCallArgs+3, + cast(StatepointCS.getArgument(3))->getZExtValue(); + Assert(StatepointCS.arg_size() > NumCallArgs + 5, "gc.statepoint: mismatch in number of call arguments"); - Assert(isa(StatepointCS.getArgument(NumCallArgs+3)), + Assert(isa(StatepointCS.getArgument(NumCallArgs + 5)), + "gc.statepoint: number of transition arguments must be " + "a constant integer"); + const int NumTransitionArgs = + cast(StatepointCS.getArgument(NumCallArgs + 5)) + ->getZExtValue(); + const int DeoptArgsStart = 4 + NumCallArgs + 1 + NumTransitionArgs + 1; + Assert(isa(StatepointCS.getArgument(DeoptArgsStart)), "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; + cast(StatepointCS.getArgument(DeoptArgsStart))->getZExtValue(); + const int GCParamArgsStart = DeoptArgsStart + 1 + NumDeoptArgs; const int GCParamArgsEnd = StatepointCS.arg_size(); Assert(GCParamArgsStart <= BaseIndex && BaseIndex < GCParamArgsEnd, "gc.relocate: statepoint base index doesn't fall within the " @@ -3154,82 +3441,202 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { "'gc parameters' section of the statepoint call", &CI); - // Assert that the result type matches the type of the relocated pointer + // 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(&CI); - Assert(Operands.derivedPtr()->getType() == CI.getType(), - "gc.relocate: relocating a pointer shouldn't change its type", &CI); + Assert(Operands.getDerivedPtr()->getType()->isPointerTy(), + "gc.relocate: relocated value must be a gc pointer", &CI); + + // gc_relocate return type must be a pointer type, and is verified earlier in + // VerifyIntrinsicType(). + Assert(cast(CI.getType())->getAddressSpace() == + cast(Operands.getDerivedPtr()->getType())->getAddressSpace(), + "gc.relocate: relocating a pointer shouldn't change its address space", &CI); break; } }; } +/// \brief Carefully grab the subprogram from a local scope. +/// +/// This carefully grabs the subprogram from a local scope, avoiding the +/// built-in assertions that would typically fire. +static DISubprogram *getSubprogram(Metadata *LocalScope) { + if (!LocalScope) + return nullptr; + + if (auto *SP = dyn_cast(LocalScope)) + return SP; + + if (auto *LB = dyn_cast(LocalScope)) + return getSubprogram(LB->getRawScope()); + + // Just return null; broken scope chains are checked elsewhere. + assert(!isa(LocalScope) && "Unknown type of local scope"); + return nullptr; +} + 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()), + Assert(isa(DII.getRawVariable()), "invalid llvm.dbg." + Kind + " intrinsic variable", &DII, DII.getRawVariable()); - Assert(isa(DII.getRawExpression()), + 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; + // Ignore broken !dbg attachments; they're checked elsewhere. + if (MDNode *N = DII.getDebugLoc().getAsMDNode()) + if (!isa(N)) + return; - DebugInfoFinder Finder; - Finder.processModule(*M); - processInstructions(Finder); + BasicBlock *BB = DII.getParent(); + Function *F = BB ? BB->getParent() : nullptr; + + // The scopes for variables and !dbg attachments must agree. + DILocalVariable *Var = DII.getVariable(); + DILocation *Loc = DII.getDebugLoc(); + Assert(Loc, "llvm.dbg." + Kind + " intrinsic requires a !dbg attachment", + &DII, BB, F); + + DISubprogram *VarSP = getSubprogram(Var->getRawScope()); + DISubprogram *LocSP = getSubprogram(Loc->getRawScope()); + if (!VarSP || !LocSP) + return; // Broken scope chains are checked elsewhere. + + Assert(VarSP == LocSP, "mismatched subprogram between llvm.dbg." + Kind + + " variable and !dbg attachment", + &DII, BB, F, Var, Var->getScope()->getSubprogram(), Loc, + Loc->getScope()->getSubprogram()); +} + +template +static uint64_t getVariableSize(const DILocalVariable &V, const MapTy &Map) { + // Be careful of broken types (checked elsewhere). + const Metadata *RawType = V.getRawType(); + while (RawType) { + // Try to get the size directly. + if (auto *T = dyn_cast(RawType)) + if (uint64_t Size = T->getSizeInBits()) + return Size; + + if (auto *DT = dyn_cast(RawType)) { + // Look at the base type. + RawType = DT->getRawBaseType(); + continue; + } - // Verify Debug Info. - // - // NOTE: The loud braces are necessary for MSVC compatibility. - for (DICompileUnit CU : Finder.compile_units()) { - Assert(CU.Verify(), "DICompileUnit does not Verify!", CU); - } - for (DISubprogram S : Finder.subprograms()) { - Assert(S.Verify(), "DISubprogram does not Verify!", S); - } - for (DIGlobalVariable GV : Finder.global_variables()) { - Assert(GV.Verify(), "DIGlobalVariable does not Verify!", GV); - } - for (DIType T : Finder.types()) { - Assert(T.Verify(), "DIType does not Verify!", T); + if (auto *S = dyn_cast(RawType)) { + // Don't error on missing types (checked elsewhere). + RawType = Map.lookup(S); + continue; + } + + // Missing type or size. + break; } - for (DIScope S : Finder.scopes()) { - Assert(S.Verify(), "DIScope does not Verify!", S); + + // Fail gracefully. + return 0; +} + +template +void Verifier::verifyBitPieceExpression(const DbgInfoIntrinsic &I, + const MapTy &TypeRefs) { + DILocalVariable *V; + DIExpression *E; + if (auto *DVI = dyn_cast(&I)) { + V = dyn_cast_or_null(DVI->getRawVariable()); + E = dyn_cast_or_null(DVI->getRawExpression()); + } else { + auto *DDI = cast(&I); + V = dyn_cast_or_null(DDI->getRawVariable()); + E = dyn_cast_or_null(DDI->getRawExpression()); } + + // We don't know whether this intrinsic verified correctly. + if (!V || !E || !E->isValid()) + return; + + // Nothing to do if this isn't a bit piece expression. + if (!E->isBitPiece()) + return; + + // The frontend helps out GDB by emitting the members of local anonymous + // unions as artificial local variables with shared storage. When SROA splits + // the storage for artificial local variables that are smaller than the entire + // union, the overhang piece will be outside of the allotted space for the + // variable and this check fails. + // FIXME: Remove this check as soon as clang stops doing this; it hides bugs. + if (V->isArtificial()) + return; + + // If there's no size, the type is broken, but that should be checked + // elsewhere. + uint64_t VarSize = getVariableSize(*V, TypeRefs); + if (!VarSize) + return; + + unsigned PieceSize = E->getBitPieceSize(); + unsigned PieceOffset = E->getBitPieceOffset(); + Assert(PieceSize + PieceOffset <= VarSize, + "piece is larger than or outside of variable", &I, V, E); + Assert(PieceSize != VarSize, "piece covers entire variable", &I, V, E); } -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)) - Finder.processLocation(*M, DILocation(MD)); - if (const CallInst *CI = dyn_cast(&*I)) - processCallInst(Finder, *CI); - } +void Verifier::visitUnresolvedTypeRef(const MDString *S, const MDNode *N) { + // This is in its own function so we get an error for each bad type ref (not + // just the first). + Assert(false, "unresolved type ref", S, N); } -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: - Finder.processDeclare(*M, cast(&CI)); - break; - case Intrinsic::dbg_value: - Finder.processValue(*M, cast(&CI)); - break; - default: - break; - } +void Verifier::verifyTypeRefs() { + auto *CUs = M->getNamedMetadata("llvm.dbg.cu"); + if (!CUs) + return; + + // Visit all the compile units again to map the type references. + SmallDenseMap TypeRefs; + for (auto *CU : CUs->operands()) + if (auto Ts = cast(CU)->getRetainedTypes()) + for (DIType *Op : Ts) + if (auto *T = dyn_cast(Op)) + if (auto *S = T->getRawIdentifier()) { + UnresolvedTypeRefs.erase(S); + TypeRefs.insert(std::make_pair(S, T)); + } + + // Verify debug info intrinsic bit piece expressions. This needs a second + // pass through the intructions, since we haven't built TypeRefs yet when + // verifying functions, and simply queuing the DbgInfoIntrinsics to evaluate + // later/now would queue up some that could be later deleted. + for (const Function &F : *M) + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + if (auto *DII = dyn_cast(&I)) + verifyBitPieceExpression(*DII, TypeRefs); + + // Return early if all typerefs were resolved. + if (UnresolvedTypeRefs.empty()) + return; + + // Sort the unresolved references by name so the output is deterministic. + typedef std::pair TypeRef; + SmallVector Unresolved(UnresolvedTypeRefs.begin(), + UnresolvedTypeRefs.end()); + std::sort(Unresolved.begin(), Unresolved.end(), + [](const TypeRef &LHS, const TypeRef &RHS) { + return LHS.first->getString() < RHS.first->getString(); + }); + + // Visit the unresolved refs (printing out the errors). + for (const TypeRef &TR : Unresolved) + visitUnresolvedTypeRef(TR.first, TR.second); } //===----------------------------------------------------------------------===//