diff options
Diffstat (limited to 'lib/IR/Verifier.cpp')
-rw-r--r-- | lib/IR/Verifier.cpp | 349 |
1 files changed, 205 insertions, 144 deletions
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 534104686d81..e5231bb78a36 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -55,6 +55,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -206,7 +207,7 @@ private: template <typename... Ts> void WriteTs() {} public: - /// \brief A check failed, so printout out the condition and the message. + /// 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. @@ -216,7 +217,7 @@ public: Broken = true; } - /// \brief A check failed (with values to print). + /// A check failed (with values to print). /// /// This calls the Message-only version so that the above is easier to set a /// breakpoint on. @@ -254,14 +255,14 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { DominatorTree DT; - /// \brief When verifying a basic block, keep track of all of the + /// When verifying a basic block, keep track of all of the /// instructions we have seen so far. /// /// This allows us to do efficient dominance checks for the case when an /// instruction has an operand that is an instruction in the same block. SmallPtrSet<Instruction *, 16> InstsInThisBlock; - /// \brief Keep track of the metadata nodes that have been checked already. + /// Keep track of the metadata nodes that have been checked already. SmallPtrSet<const Metadata *, 32> MDNodes; /// Keep track which DISubprogram is attached to which function. @@ -270,10 +271,10 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// Track all DICompileUnits visited. SmallPtrSet<const Metadata *, 2> CUVisited; - /// \brief The result type for a landingpad. + /// The result type for a landingpad. Type *LandingPadResultTy; - /// \brief Whether we've seen a call to @llvm.localescape in this function + /// Whether we've seen a call to @llvm.localescape in this function /// already. bool SawFrameEscape; @@ -408,6 +409,7 @@ private: void visitModuleFlag(const MDNode *Op, DenseMap<const MDString *, const MDNode *> &SeenIDs, SmallVectorImpl<const MDNode *> &Requirements); + void visitModuleFlagCGProfileEntry(const MDOperand &MDO); void visitFunction(const Function &F); void visitBasicBlock(BasicBlock &BB); void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty); @@ -466,6 +468,7 @@ private: void visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS); void visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI); void visitDbgIntrinsic(StringRef Kind, DbgInfoIntrinsic &DII); + void visitDbgLabelIntrinsic(StringRef Kind, DbgLabelInst &DLI); void visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI); void visitAtomicRMWInst(AtomicRMWInst &RMWI); void visitFenceInst(FenceInst &FI); @@ -565,10 +568,24 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { if (GV.isDeclarationForLinker()) Assert(!GV.hasComdat(), "Declaration may not be in a Comdat!", &GV); - if (GV.hasDLLImportStorageClass()) + if (GV.hasDLLImportStorageClass()) { Assert(!GV.isDSOLocal(), "GlobalValue with DLLImport Storage is dso_local!", &GV); + Assert((GV.isDeclaration() && GV.hasExternalLinkage()) || + GV.hasAvailableExternallyLinkage(), + "Global is marked as dllimport, but not external", &GV); + } + + if (GV.hasLocalLinkage()) + Assert(GV.isDSOLocal(), + "GlobalValue with private or internal linkage must be dso_local!", + &GV); + + if (!GV.hasDefaultVisibility() && !GV.hasExternalWeakLinkage()) + Assert(GV.isDSOLocal(), + "GlobalValue with non default visibility must be dso_local!", &GV); + forEachUser(&GV, GlobalValueVisited, [&](const Value *V) -> bool { if (const Instruction *I = dyn_cast<Instruction>(V)) { if (!I->getParent() || !I->getParent()->getParent()) @@ -655,11 +672,6 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { } } - Assert(!GV.hasDLLImportStorageClass() || - (GV.isDeclaration() && GV.hasExternalLinkage()) || - GV.hasAvailableExternallyLinkage(), - "Global is marked as dllimport, but not external", &GV); - // Visit any debug info attachments. SmallVector<MDNode *, 1> MDs; GV.getMetadata(LLVMContext::MD_dbg, MDs); @@ -858,7 +870,12 @@ void Verifier::visitDIScope(const DIScope &N) { void Verifier::visitDISubrange(const DISubrange &N) { AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); - AssertDI(N.getCount() >= -1, "invalid subrange count", &N); + auto Count = N.getCount(); + AssertDI(Count, "Count must either be a signed constant or a DIVariable", + &N); + AssertDI(!Count.is<ConstantInt*>() || + Count.get<ConstantInt*>()->getSExtValue() >= -1, + "invalid subrange count", &N); } void Verifier::visitDIEnumerator(const DIEnumerator &N) { @@ -905,9 +922,12 @@ void Verifier::visitDIDerivedType(const DIDerivedType &N) { } } +/// Detect mutually exclusive flags. static bool hasConflictingReferenceFlags(unsigned Flags) { - return (Flags & DINode::FlagLValueReference) && - (Flags & DINode::FlagRValueReference); + return ((Flags & DINode::FlagLValueReference) && + (Flags & DINode::FlagRValueReference)) || + ((Flags & DINode::FlagTypePassByValue) && + (Flags & DINode::FlagTypePassByReference)); } void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) { @@ -927,7 +947,8 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { N.getTag() == dwarf::DW_TAG_structure_type || N.getTag() == dwarf::DW_TAG_union_type || N.getTag() == dwarf::DW_TAG_enumeration_type || - N.getTag() == dwarf::DW_TAG_class_type, + N.getTag() == dwarf::DW_TAG_class_type || + N.getTag() == dwarf::DW_TAG_variant_part, "invalid tag", &N); AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope()); @@ -940,6 +961,14 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { N.getRawVTableHolder()); AssertDI(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", &N); + + if (N.isVector()) { + const DINodeArray Elements = N.getElements(); + AssertDI(Elements.size() == 1 && + Elements[0]->getTag() == dwarf::DW_TAG_subrange_type, + "invalid vector, expected one element of type subrange", &N); + } + if (auto *Params = N.getRawTemplateParams()) visitTemplateParams(N, *Params); @@ -948,6 +977,11 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { AssertDI(N.getFile() && !N.getFile()->getFilename().empty(), "class/union requires a filename", &N, N.getFile()); } + + if (auto *D = N.getRawDiscriminator()) { + AssertDI(isa<DIDerivedType>(D) && N.getTag() == dwarf::DW_TAG_variant_part, + "discriminator can only appear on variant part"); + } } void Verifier::visitDISubroutineType(const DISubroutineType &N) { @@ -964,8 +998,23 @@ void Verifier::visitDISubroutineType(const DISubroutineType &N) { void Verifier::visitDIFile(const DIFile &N) { AssertDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); - AssertDI((N.getChecksumKind() != DIFile::CSK_None || - N.getChecksum().empty()), "invalid checksum kind", &N); + Optional<DIFile::ChecksumInfo<StringRef>> Checksum = N.getChecksum(); + if (Checksum) { + AssertDI(Checksum->Kind <= DIFile::ChecksumKind::CSK_Last, + "invalid checksum kind", &N); + size_t Size; + switch (Checksum->Kind) { + case DIFile::CSK_MD5: + Size = 32; + break; + case DIFile::CSK_SHA1: + Size = 40; + break; + } + AssertDI(Checksum->Value.size() == Size, "invalid checksum length", &N); + AssertDI(Checksum->Value.find_if_not(llvm::isHexDigit) == StringRef::npos, + "invalid checksum", &N); + } } void Verifier::visitDICompileUnit(const DICompileUnit &N) { @@ -1038,12 +1087,13 @@ void Verifier::visitDISubprogram(const DISubprogram &N) { if (auto *S = N.getRawDeclaration()) AssertDI(isa<DISubprogram>(S) && !cast<DISubprogram>(S)->isDefinition(), "invalid subprogram declaration", &N, S); - if (auto *RawVars = N.getRawVariables()) { - auto *Vars = dyn_cast<MDTuple>(RawVars); - AssertDI(Vars, "invalid variable list", &N, RawVars); - for (Metadata *Op : Vars->operands()) { - AssertDI(Op && isa<DILocalVariable>(Op), "invalid local variable", &N, - Vars, Op); + if (auto *RawNode = N.getRawRetainedNodes()) { + auto *Node = dyn_cast<MDTuple>(RawNode); + AssertDI(Node, "invalid retained nodes list", &N, RawNode); + for (Metadata *Op : Node->operands()) { + AssertDI(Op && (isa<DILocalVariable>(Op) || isa<DILabel>(Op)), + "invalid retained nodes, expected DILocalVariable or DILabel", + &N, Node, Op); } } AssertDI(!hasConflictingReferenceFlags(N.getFlags()), @@ -1175,6 +1225,17 @@ void Verifier::visitDILocalVariable(const DILocalVariable &N) { "local variable requires a valid scope", &N, N.getRawScope()); } +void Verifier::visitDILabel(const DILabel &N) { + if (auto *S = N.getRawScope()) + AssertDI(isa<DIScope>(S), "invalid scope", &N, S); + if (auto *F = N.getRawFile()) + AssertDI(isa<DIFile>(F), "invalid file", &N, F); + + AssertDI(N.getTag() == dwarf::DW_TAG_label, "invalid tag", &N); + AssertDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()), + "label requires a valid scope", &N, N.getRawScope()); +} + void Verifier::visitDIExpression(const DIExpression &N) { AssertDI(N.isValid(), "invalid expression", &N); } @@ -1351,12 +1412,35 @@ Verifier::visitModuleFlag(const MDNode *Op, Assert(M.getNamedMetadata("llvm.linker.options"), "'Linker Options' named metadata no longer supported"); } + + if (ID->getString() == "CG Profile") { + for (const MDOperand &MDO : cast<MDNode>(Op->getOperand(2))->operands()) + visitModuleFlagCGProfileEntry(MDO); + } +} + +void Verifier::visitModuleFlagCGProfileEntry(const MDOperand &MDO) { + auto CheckFunction = [&](const MDOperand &FuncMDO) { + if (!FuncMDO) + return; + auto F = dyn_cast<ValueAsMetadata>(FuncMDO); + Assert(F && isa<Function>(F->getValue()), "expected a Function or null", + FuncMDO); + }; + auto Node = dyn_cast_or_null<MDNode>(MDO); + Assert(Node && Node->getNumOperands() == 3, "expected a MDNode triple", MDO); + CheckFunction(Node->getOperand(0)); + CheckFunction(Node->getOperand(1)); + auto Count = dyn_cast_or_null<ConstantAsMetadata>(Node->getOperand(2)); + Assert(Count && Count->getType()->isIntegerTy(), + "expected an integer constant", Node->getOperand(2)); } /// Return true if this attribute kind only applies to functions. static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::NoReturn: + case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: case Attribute::AlwaysInline: @@ -1365,6 +1449,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::StackProtectReq: case Attribute::StackProtectStrong: case Attribute::SafeStack: + case Attribute::ShadowCallStack: case Attribute::NoRedZone: case Attribute::NoImplicitFloat: case Attribute::Naked: @@ -1382,6 +1467,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::Builtin: case Attribute::NoBuiltin: case Attribute::Cold: + case Attribute::OptForFuzzing: case Attribute::OptimizeNone: case Attribute::JumpTable: case Attribute::Convergent: @@ -1692,8 +1778,11 @@ void Verifier::verifyFunctionMetadata( "expected string with name of the !prof annotation", MD); MDString *MDS = cast<MDString>(MD->getOperand(0)); StringRef ProfName = MDS->getString(); - Assert(ProfName.equals("function_entry_count"), - "first operand should be 'function_entry_count'", MD); + Assert(ProfName.equals("function_entry_count") || + ProfName.equals("synthetic_function_entry_count"), + "first operand should be 'function_entry_count'" + " or 'synthetic_function_entry_count'", + MD); // Check second operand. Assert(MD->getOperand(1) != nullptr, "second operand should not be null", @@ -2151,11 +2240,6 @@ void Verifier::visitFunction(const Function &F) { Assert(false, "Invalid user of intrinsic instruction!", U); } - Assert(!F.hasDLLImportStorageClass() || - (F.isDeclaration() && F.hasExternalLinkage()) || - F.hasAvailableExternallyLinkage(), - "Function is marked as dllimport, but not external.", &F); - auto *N = F.getSubprogram(); HasDebugInfo = (N != nullptr); if (!HasDebugInfo) @@ -2209,26 +2293,25 @@ void Verifier::visitBasicBlock(BasicBlock &BB) { if (isa<PHINode>(BB.front())) { SmallVector<BasicBlock*, 8> Preds(pred_begin(&BB), pred_end(&BB)); SmallVector<std::pair<BasicBlock*, Value*>, 8> Values; - std::sort(Preds.begin(), Preds.end()); - PHINode *PN; - for (BasicBlock::iterator I = BB.begin(); (PN = dyn_cast<PHINode>(I));++I) { + llvm::sort(Preds.begin(), Preds.end()); + for (const PHINode &PN : BB.phis()) { // Ensure that PHI nodes have at least one entry! - Assert(PN->getNumIncomingValues() != 0, + Assert(PN.getNumIncomingValues() != 0, "PHI nodes must have at least one entry. If the block is dead, " "the PHI should be removed!", - PN); - Assert(PN->getNumIncomingValues() == Preds.size(), + &PN); + Assert(PN.getNumIncomingValues() == Preds.size(), "PHINode should have one entry for each predecessor of its " "parent basic block!", - PN); + &PN); // Get and sort all incoming values in the PHI node... Values.clear(); - Values.reserve(PN->getNumIncomingValues()); - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) - Values.push_back(std::make_pair(PN->getIncomingBlock(i), - PN->getIncomingValue(i))); - std::sort(Values.begin(), Values.end()); + Values.reserve(PN.getNumIncomingValues()); + for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) + Values.push_back( + std::make_pair(PN.getIncomingBlock(i), PN.getIncomingValue(i))); + llvm::sort(Values.begin(), Values.end()); for (unsigned i = 0, e = Values.size(); i != e; ++i) { // Check to make sure that if there is more than one entry for a @@ -2239,12 +2322,12 @@ void Verifier::visitBasicBlock(BasicBlock &BB) { Values[i].second == Values[i - 1].second, "PHI node has multiple entries for the same basic block with " "different incoming values!", - PN, Values[i].first, Values[i].second, Values[i - 1].second); + &PN, Values[i].first, Values[i].second, Values[i - 1].second); // Check to make sure that the predecessors and PHI node entries are // matched up. Assert(Values[i].first == Preds[i], - "PHI node entries do not match predecessors!", PN, + "PHI node entries do not match predecessors!", &PN, Values[i].first, Preds[i]); } } @@ -2820,17 +2903,20 @@ void Verifier::verifyMustTailCall(CallInst &CI) { Function *F = CI.getParent()->getParent(); FunctionType *CallerTy = F->getFunctionType(); FunctionType *CalleeTy = CI.getFunctionType(); - Assert(CallerTy->getNumParams() == CalleeTy->getNumParams(), - "cannot guarantee tail call due to mismatched parameter counts", &CI); + if (!CI.getCalledFunction() || !CI.getCalledFunction()->isIntrinsic()) { + Assert(CallerTy->getNumParams() == CalleeTy->getNumParams(), + "cannot guarantee tail call due to mismatched parameter counts", + &CI); + for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) { + Assert( + isTypeCongruent(CallerTy->getParamType(I), CalleeTy->getParamType(I)), + "cannot guarantee tail call due to mismatched parameter types", &CI); + } + } Assert(CallerTy->isVarArg() == CalleeTy->isVarArg(), "cannot guarantee tail call due to mismatched varargs", &CI); Assert(isTypeCongruent(CallerTy->getReturnType(), CalleeTy->getReturnType()), "cannot guarantee tail call due to mismatched return types", &CI); - for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) { - Assert( - isTypeCongruent(CallerTy->getParamType(I), CalleeTy->getParamType(I)), - "cannot guarantee tail call due to mismatched parameter types", &CI); - } // - The calling conventions of the caller and callee must match. Assert(F->getCallingConv() == CI.getCallingConv(), @@ -2866,7 +2952,7 @@ void Verifier::verifyMustTailCall(CallInst &CI) { // Check the return. ReturnInst *Ret = dyn_cast_or_null<ReturnInst>(Next); - Assert(Ret, "musttail call must be precede a ret with an optional bitcast", + Assert(Ret, "musttail call must precede a ret with an optional bitcast", &CI); Assert(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal, "musttail call result must be returned", Ret); @@ -3120,8 +3206,7 @@ void Verifier::visitLoadInst(LoadInst &LI) { "Load cannot have Release ordering", &LI); Assert(LI.getAlignment() != 0, "Atomic load must specify explicit alignment", &LI); - Assert(ElTy->isIntegerTy() || ElTy->isPointerTy() || - ElTy->isFloatingPointTy(), + Assert(ElTy->isIntOrPtrTy() || ElTy->isFloatingPointTy(), "atomic load operand must have integer, pointer, or floating point " "type!", ElTy, &LI); @@ -3149,8 +3234,7 @@ void Verifier::visitStoreInst(StoreInst &SI) { "Store cannot have Acquire ordering", &SI); Assert(SI.getAlignment() != 0, "Atomic store must specify explicit alignment", &SI); - Assert(ElTy->isIntegerTy() || ElTy->isPointerTy() || - ElTy->isFloatingPointTy(), + Assert(ElTy->isIntOrPtrTy() || ElTy->isFloatingPointTy(), "atomic store operand must have integer, pointer, or floating point " "type!", ElTy, &SI); @@ -3241,9 +3325,8 @@ void Verifier::visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI) { PointerType *PTy = dyn_cast<PointerType>(CXI.getOperand(0)->getType()); Assert(PTy, "First cmpxchg operand must be a pointer.", &CXI); Type *ElTy = PTy->getElementType(); - Assert(ElTy->isIntegerTy() || ElTy->isPointerTy(), - "cmpxchg operand must have integer or pointer type", - ElTy, &CXI); + Assert(ElTy->isIntOrPtrTy(), + "cmpxchg operand must have integer or pointer type", ElTy, &CXI); checkAtomicMemAccessSize(ElTy, &CXI); Assert(ElTy == CXI.getOperand(1)->getType(), "Expected value type does not match pointer operand type!", &CXI, @@ -4015,96 +4098,36 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { case Intrinsic::dbg_value: // llvm.dbg.value visitDbgIntrinsic("value", cast<DbgInfoIntrinsic>(*CS.getInstruction())); break; + case Intrinsic::dbg_label: // llvm.dbg.label + visitDbgLabelIntrinsic("label", cast<DbgLabelInst>(*CS.getInstruction())); + break; case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: { - ConstantInt *AlignCI = dyn_cast<ConstantInt>(CS.getArgOperand(3)); - Assert(AlignCI, - "alignment argument of memory intrinsics must be a constant int", - CS); - 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(4)), - "isvolatile argument of memory intrinsics must be a constant int", - CS); - break; - } - case Intrinsic::memcpy_element_unordered_atomic: { - const AtomicMemCpyInst *MI = cast<AtomicMemCpyInst>(CS.getInstruction()); - - ConstantInt *ElementSizeCI = - dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); - Assert(ElementSizeCI, - "element size of the element-wise unordered atomic memory " - "intrinsic must be a constant int", - CS); - const APInt &ElementSizeVal = ElementSizeCI->getValue(); - Assert(ElementSizeVal.isPowerOf2(), - "element size of the element-wise atomic memory intrinsic " - "must be a power of 2", - CS); - - if (auto *LengthCI = dyn_cast<ConstantInt>(MI->getLength())) { - uint64_t Length = LengthCI->getZExtValue(); - uint64_t ElementSize = MI->getElementSizeInBytes(); - Assert((Length % ElementSize) == 0, - "constant length must be a multiple of the element size in the " - "element-wise atomic memory intrinsic", - CS); - } - - auto IsValidAlignment = [&](uint64_t Alignment) { - return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment); + const auto *MI = cast<MemIntrinsic>(CS.getInstruction()); + auto IsValidAlignment = [&](unsigned Alignment) -> bool { + return Alignment == 0 || isPowerOf2_32(Alignment); }; - uint64_t DstAlignment = CS.getParamAlignment(0), - SrcAlignment = CS.getParamAlignment(1); - Assert(IsValidAlignment(DstAlignment), - "incorrect alignment of the destination argument", CS); - Assert(IsValidAlignment(SrcAlignment), - "incorrect alignment of the source argument", CS); - break; - } - case Intrinsic::memmove_element_unordered_atomic: { - auto *MI = cast<AtomicMemMoveInst>(CS.getInstruction()); - - ConstantInt *ElementSizeCI = - dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); - Assert(ElementSizeCI, - "element size of the element-wise unordered atomic memory " - "intrinsic must be a constant int", - CS); - const APInt &ElementSizeVal = ElementSizeCI->getValue(); - Assert(ElementSizeVal.isPowerOf2(), - "element size of the element-wise atomic memory intrinsic " - "must be a power of 2", + Assert(IsValidAlignment(MI->getDestAlignment()), + "alignment of arg 0 of memory intrinsic must be 0 or a power of 2", CS); - - if (auto *LengthCI = dyn_cast<ConstantInt>(MI->getLength())) { - uint64_t Length = LengthCI->getZExtValue(); - uint64_t ElementSize = MI->getElementSizeInBytes(); - Assert((Length % ElementSize) == 0, - "constant length must be a multiple of the element size in the " - "element-wise atomic memory intrinsic", + if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { + Assert(IsValidAlignment(MTI->getSourceAlignment()), + "alignment of arg 1 of memory intrinsic must be 0 or a power of 2", CS); } - - auto IsValidAlignment = [&](uint64_t Alignment) { - return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment); - }; - uint64_t DstAlignment = CS.getParamAlignment(0), - SrcAlignment = CS.getParamAlignment(1); - Assert(IsValidAlignment(DstAlignment), - "incorrect alignment of the destination argument", CS); - Assert(IsValidAlignment(SrcAlignment), - "incorrect alignment of the source argument", CS); + Assert(isa<ConstantInt>(CS.getArgOperand(3)), + "isvolatile argument of memory intrinsics must be a constant int", + CS); break; } + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: case Intrinsic::memset_element_unordered_atomic: { - auto *MI = cast<AtomicMemSetInst>(CS.getInstruction()); + const auto *AMI = cast<AtomicMemIntrinsic>(CS.getInstruction()); ConstantInt *ElementSizeCI = - dyn_cast<ConstantInt>(MI->getRawElementSizeInBytes()); + dyn_cast<ConstantInt>(AMI->getRawElementSizeInBytes()); Assert(ElementSizeCI, "element size of the element-wise unordered atomic memory " "intrinsic must be a constant int", @@ -4115,9 +4138,9 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { "must be a power of 2", CS); - if (auto *LengthCI = dyn_cast<ConstantInt>(MI->getLength())) { + if (auto *LengthCI = dyn_cast<ConstantInt>(AMI->getLength())) { uint64_t Length = LengthCI->getZExtValue(); - uint64_t ElementSize = MI->getElementSizeInBytes(); + uint64_t ElementSize = AMI->getElementSizeInBytes(); Assert((Length % ElementSize) == 0, "constant length must be a multiple of the element size in the " "element-wise atomic memory intrinsic", @@ -4127,9 +4150,14 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { auto IsValidAlignment = [&](uint64_t Alignment) { return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment); }; - uint64_t DstAlignment = CS.getParamAlignment(0); + uint64_t DstAlignment = AMI->getDestAlignment(); Assert(IsValidAlignment(DstAlignment), "incorrect alignment of the destination argument", CS); + if (const auto *AMT = dyn_cast<AtomicMemTransferInst>(AMI)) { + uint64_t SrcAlignment = AMT->getSourceAlignment(); + Assert(IsValidAlignment(SrcAlignment), + "incorrect alignment of the source argument", CS); + } break; } case Intrinsic::gcroot: @@ -4429,7 +4457,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) { }; } -/// \brief Carefully grab the subprogram from a local scope. +/// 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. @@ -4486,8 +4514,8 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgInfoIntrinsic &DII) { // 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); + AssertDI(Loc, "llvm.dbg." + Kind + " intrinsic requires a !dbg attachment", + &DII, BB, F); DISubprogram *VarSP = getSubprogram(Var->getRawScope()); DISubprogram *LocSP = getSubprogram(Loc->getRawScope()); @@ -4502,7 +4530,40 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgInfoIntrinsic &DII) { verifyFnArgs(DII); } +void Verifier::visitDbgLabelIntrinsic(StringRef Kind, DbgLabelInst &DLI) { + AssertDI(isa<DILabel>(DLI.getRawVariable()), + "invalid llvm.dbg." + Kind + " intrinsic variable", &DLI, + DLI.getRawVariable()); + + // Ignore broken !dbg attachments; they're checked elsewhere. + if (MDNode *N = DLI.getDebugLoc().getAsMDNode()) + if (!isa<DILocation>(N)) + return; + + BasicBlock *BB = DLI.getParent(); + Function *F = BB ? BB->getParent() : nullptr; + + // The scopes for variables and !dbg attachments must agree. + DILabel *Label = DLI.getLabel(); + DILocation *Loc = DLI.getDebugLoc(); + Assert(Loc, "llvm.dbg." + Kind + " intrinsic requires a !dbg attachment", + &DLI, BB, F); + + DISubprogram *LabelSP = getSubprogram(Label->getRawScope()); + DISubprogram *LocSP = getSubprogram(Loc->getRawScope()); + if (!LabelSP || !LocSP) + return; + + AssertDI(LabelSP == LocSP, "mismatched subprogram between llvm.dbg." + Kind + + " label and !dbg attachment", + &DLI, BB, F, Label, Label->getScope()->getSubprogram(), Loc, + Loc->getScope()->getSubprogram()); +} + void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { + if (dyn_cast<DbgLabelInst>(&I)) + return; + DILocalVariable *V = dyn_cast_or_null<DILocalVariable>(I.getRawVariable()); DIExpression *E = dyn_cast_or_null<DIExpression>(I.getRawExpression()); |