blob: 25cb99f0f9bd8b5fc99db2acc4b2aa34ef5b1550 [file] [log] [blame]
//===-- Verifier.cpp - Implement the Module Verifier -----------------------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the function verifier interface, that can be used for some
// basic correctness checking of input to the system.
//
// Note that this does not provide full `Java style' security and verifications,
// instead it just tries to ensure that code is well-formed.
//
// * Both of a binary operator's parameters are of the same type
// * Verify that the indices of mem access instructions match other operands
// * Verify that arithmetic and other things are only performed on first-class
// types. Verify that shifts & logicals only happen on integrals f.e.
// * All of the constants in a switch statement are of the correct type
// * The code is in valid SSA form
// * It should be illegal to put a label into any other type (like a structure)
// or to return one. [except constant arrays!]
// * Only phi nodes can be self referential: 'add i32 %0, %0 ; <int>:0' is bad
// * PHI nodes must have an entry for each predecessor, with no extras.
// * PHI nodes must be the first thing in a basic block, all grouped together
// * All basic blocks should only end with terminator insts, not contain them
// * The entry node to a function must not have predecessors
// * All Instructions must be embedded into a basic block
// * Functions cannot take a void-typed parameter
// * Verify that a function's argument list agrees with it's declared type.
// * It is illegal to specify a name for a void value.
// * It is illegal to have a internal global value with no initializer
// * It is illegal to have a ret instruction that returns a value that does not
// agree with the function return value type.
// * Function call argument types match the function prototype
// * A landing pad is defined by a landingpad instruction, and can be jumped to
// only by the unwind edge of an invoke instruction.
// * A landingpad instruction must be the first non-PHI instruction in the
// block.
// * Landingpad instructions must be in a function with a personality function.
// * Convergence control intrinsics are introduced in ConvergentOperations.rst.
// The applied restrictions are too numerous to list here.
// * The convergence entry intrinsic and the loop heart must be the first
// non-PHI instruction in their respective block. This does not conflict with
// the landing pads, since these two kinds cannot occur in the same block.
// * All other things that are tested by asserts spread about the code...
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/Verifier.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#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"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/AttributeMask.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/ConvergenceVerifier.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/EHPersonalities.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GCStrategy.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/IntrinsicsAMDGPU.h"
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Statepoint.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/VFABIDemangler.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
using namespace llvm;
static cl::opt<bool> VerifyNoAliasScopeDomination(
"verify-noalias-scope-decl-dom", cl::Hidden, cl::init(false),
cl::desc("Ensure that llvm.experimental.noalias.scope.decl for identical "
"scopes are not dominating"));
namespace llvm {
struct VerifierSupport {
raw_ostream *OS;
const Module &M;
ModuleSlotTracker MST;
Triple TT;
const DataLayout &DL;
LLVMContext &Context;
/// Track the brokenness of the module while recursively visiting.
bool Broken = false;
/// Broken debug info can be "recovered" from by stripping the debug info.
bool BrokenDebugInfo = false;
/// Whether to treat broken debug info as an error.
bool TreatBrokenDebugInfoAsError = true;
explicit VerifierSupport(raw_ostream *OS, const Module &M)
: OS(OS), M(M), MST(&M), TT(M.getTargetTriple()), DL(M.getDataLayout()),
Context(M.getContext()) {}
private:
void Write(const Module *M) {
*OS << "; ModuleID = '" << M->getModuleIdentifier() << "'\n";
}
void Write(const Value *V) {
if (V)
Write(*V);
}
void Write(const Value &V) {
if (isa<Instruction>(V)) {
V.print(*OS, MST);
*OS << '\n';
} else {
V.printAsOperand(*OS, true, MST);
*OS << '\n';
}
}
void Write(const DbgRecord *DR) {
if (DR) {
DR->print(*OS, MST, false);
*OS << '\n';
}
}
void Write(DbgVariableRecord::LocationType Type) {
switch (Type) {
case DbgVariableRecord::LocationType::Value:
*OS << "value";
break;
case DbgVariableRecord::LocationType::Declare:
*OS << "declare";
break;
case DbgVariableRecord::LocationType::Assign:
*OS << "assign";
break;
case DbgVariableRecord::LocationType::End:
*OS << "end";
break;
case DbgVariableRecord::LocationType::Any:
*OS << "any";
break;
};
}
void Write(const Metadata *MD) {
if (!MD)
return;
MD->print(*OS, MST, &M);
*OS << '\n';
}
template <class T> void Write(const MDTupleTypedArrayWrapper<T> &MD) {
Write(MD.get());
}
void Write(const NamedMDNode *NMD) {
if (!NMD)
return;
NMD->print(*OS, MST);
*OS << '\n';
}
void Write(Type *T) {
if (!T)
return;
*OS << ' ' << *T;
}
void Write(const Comdat *C) {
if (!C)
return;
*OS << *C;
}
void Write(const APInt *AI) {
if (!AI)
return;
*OS << *AI << '\n';
}
void Write(const unsigned i) { *OS << i << '\n'; }
// NOLINTNEXTLINE(readability-identifier-naming)
void Write(const Attribute *A) {
if (!A)
return;
*OS << A->getAsString() << '\n';
}
// NOLINTNEXTLINE(readability-identifier-naming)
void Write(const AttributeSet *AS) {
if (!AS)
return;
*OS << AS->getAsString() << '\n';
}
// NOLINTNEXTLINE(readability-identifier-naming)
void Write(const AttributeList *AL) {
if (!AL)
return;
AL->print(*OS);
}
void Write(Printable P) { *OS << P << '\n'; }
template <typename T> void Write(ArrayRef<T> Vs) {
for (const T &V : Vs)
Write(V);
}
template <typename T1, typename... Ts>
void WriteTs(const T1 &V1, const Ts &... Vs) {
Write(V1);
WriteTs(Vs...);
}
template <typename... Ts> void WriteTs() {}
public:
/// 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) {
if (OS)
*OS << Message << '\n';
Broken = true;
}
/// 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 <typename T1, typename... Ts>
void CheckFailed(const Twine &Message, const T1 &V1, const Ts &... Vs) {
CheckFailed(Message);
if (OS)
WriteTs(V1, Vs...);
}
/// A debug info check failed.
void DebugInfoCheckFailed(const Twine &Message) {
if (OS)
*OS << Message << '\n';
Broken |= TreatBrokenDebugInfoAsError;
BrokenDebugInfo = true;
}
/// A debug info check failed (with values to print).
template <typename T1, typename... Ts>
void DebugInfoCheckFailed(const Twine &Message, const T1 &V1,
const Ts &... Vs) {
DebugInfoCheckFailed(Message);
if (OS)
WriteTs(V1, Vs...);
}
};
} // namespace llvm
namespace {
class Verifier : public InstVisitor<Verifier>, VerifierSupport {
friend class InstVisitor<Verifier>;
// ISD::ArgFlagsTy::MemAlign only have 4 bits for alignment, so
// the alignment size should not exceed 2^15. Since encode(Align)
// would plus the shift value by 1, the alignment size should
// not exceed 2^14, otherwise it can NOT be properly lowered
// in backend.
static constexpr unsigned ParamMaxAlignment = 1 << 14;
DominatorTree DT;
/// 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;
/// 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.
DenseMap<const DISubprogram *, const Function *> DISubprogramAttachments;
/// Track all DICompileUnits visited.
SmallPtrSet<const Metadata *, 2> CUVisited;
/// The result type for a landingpad.
Type *LandingPadResultTy;
/// Whether we've seen a call to @llvm.localescape in this function
/// already.
bool SawFrameEscape;
/// Whether the current function has a DISubprogram attached to it.
bool HasDebugInfo = false;
/// The current source language.
dwarf::SourceLanguage CurrentSourceLang = dwarf::DW_LANG_lo_user;
/// Stores the count of how many objects were passed to llvm.localescape for a
/// given function and the largest index passed to llvm.localrecover.
DenseMap<Function *, std::pair<unsigned, unsigned>> FrameEscapeInfo;
// Maps catchswitches and cleanuppads that unwind to siblings to the
// terminators that indicate the unwind, used to detect cycles therein.
MapVector<Instruction *, Instruction *> SiblingFuncletInfo;
/// Cache which blocks are in which funclet, if an EH funclet personality is
/// in use. Otherwise empty.
DenseMap<BasicBlock *, ColorVector> BlockEHFuncletColors;
/// Cache of constants visited in search of ConstantExprs.
SmallPtrSet<const Constant *, 32> ConstantExprVisited;
/// Cache of declarations of the llvm.experimental.deoptimize.<ty> intrinsic.
SmallVector<const Function *, 4> DeoptimizeDeclarations;
/// Cache of attribute lists verified.
SmallPtrSet<const void *, 32> AttributeListsVisited;
// Verify that this GlobalValue is only used in this module.
// This map is used to avoid visiting uses twice. We can arrive at a user
// twice, if they have multiple operands. In particular for very large
// constant expressions, we can arrive at a particular user many times.
SmallPtrSet<const Value *, 32> GlobalValueVisited;
// Keeps track of duplicate function argument debug info.
SmallVector<const DILocalVariable *, 16> DebugFnArgs;
TBAAVerifier TBAAVerifyHelper;
ConvergenceVerifier ConvergenceVerifyHelper;
SmallVector<IntrinsicInst *, 4> NoAliasScopeDecls;
void checkAtomicMemAccessSize(Type *Ty, const Instruction *I);
public:
explicit Verifier(raw_ostream *OS, bool ShouldTreatBrokenDebugInfoAsError,
const Module &M)
: VerifierSupport(OS, M), LandingPadResultTy(nullptr),
SawFrameEscape(false), TBAAVerifyHelper(this) {
TreatBrokenDebugInfoAsError = ShouldTreatBrokenDebugInfoAsError;
}
bool hasBrokenDebugInfo() const { return BrokenDebugInfo; }
bool verify(const Function &F) {
assert(F.getParent() == &M &&
"An instance of this class only works with a specific module!");
// First ensure the function is well-enough formed to compute dominance
// information, and directly compute a dominance tree. We don't rely on the
// pass manager to provide this as it isolates us from a potentially
// out-of-date dominator tree and makes it significantly more complex to run
// this code outside of a pass manager.
// FIXME: It's really gross that we have to cast away constness here.
if (!F.empty())
DT.recalculate(const_cast<Function &>(F));
for (const BasicBlock &BB : F) {
if (!BB.empty() && BB.back().isTerminator())
continue;
if (OS) {
*OS << "Basic Block in function '" << F.getName()
<< "' does not have terminator!\n";
BB.printAsOperand(*OS, true, MST);
*OS << "\n";
}
return false;
}
auto FailureCB = [this](const Twine &Message) {
this->CheckFailed(Message);
};
ConvergenceVerifyHelper.initialize(OS, FailureCB, F);
Broken = false;
// FIXME: We strip const here because the inst visitor strips const.
visit(const_cast<Function &>(F));
verifySiblingFuncletUnwinds();
if (ConvergenceVerifyHelper.sawTokens())
ConvergenceVerifyHelper.verify(DT);
InstsInThisBlock.clear();
DebugFnArgs.clear();
LandingPadResultTy = nullptr;
SawFrameEscape = false;
SiblingFuncletInfo.clear();
verifyNoAliasScopeDecl();
NoAliasScopeDecls.clear();
return !Broken;
}
/// Verify the module that this instance of \c Verifier was initialized with.
bool verify() {
Broken = false;
// Collect all declarations of the llvm.experimental.deoptimize intrinsic.
for (const Function &F : M)
if (F.getIntrinsicID() == Intrinsic::experimental_deoptimize)
DeoptimizeDeclarations.push_back(&F);
// Now that we've visited every function, verify that we never asked to
// recover a frame index that wasn't escaped.
verifyFrameRecoverIndices();
for (const GlobalVariable &GV : M.globals())
visitGlobalVariable(GV);
for (const GlobalAlias &GA : M.aliases())
visitGlobalAlias(GA);
for (const GlobalIFunc &GI : M.ifuncs())
visitGlobalIFunc(GI);
for (const NamedMDNode &NMD : M.named_metadata())
visitNamedMDNode(NMD);
for (const StringMapEntry<Comdat> &SMEC : M.getComdatSymbolTable())
visitComdat(SMEC.getValue());
visitModuleFlags();
visitModuleIdents();
visitModuleCommandLines();
verifyCompileUnits();
verifyDeoptimizeCallingConvs();
DISubprogramAttachments.clear();
return !Broken;
}
private:
/// Whether a metadata node is allowed to be, or contain, a DILocation.
enum class AreDebugLocsAllowed { No, Yes };
// Verification methods...
void visitGlobalValue(const GlobalValue &GV);
void visitGlobalVariable(const GlobalVariable &GV);
void visitGlobalAlias(const GlobalAlias &GA);
void visitGlobalIFunc(const GlobalIFunc &GI);
void visitAliaseeSubExpr(const GlobalAlias &A, const Constant &C);
void visitAliaseeSubExpr(SmallPtrSetImpl<const GlobalAlias *> &Visited,
const GlobalAlias &A, const Constant &C);
void visitNamedMDNode(const NamedMDNode &NMD);
void visitMDNode(const MDNode &MD, AreDebugLocsAllowed AllowLocs);
void visitMetadataAsValue(const MetadataAsValue &MD, Function *F);
void visitValueAsMetadata(const ValueAsMetadata &MD, Function *F);
void visitDIArgList(const DIArgList &AL, Function *F);
void visitComdat(const Comdat &C);
void visitModuleIdents();
void visitModuleCommandLines();
void visitModuleFlags();
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 verifyRangeMetadata(const Value &V, const MDNode *Range, Type *Ty,
bool IsAbsoluteSymbol);
void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty);
void visitDereferenceableMetadata(Instruction &I, MDNode *MD);
void visitProfMetadata(Instruction &I, MDNode *MD);
void visitCallStackMetadata(MDNode *MD);
void visitMemProfMetadata(Instruction &I, MDNode *MD);
void visitCallsiteMetadata(Instruction &I, MDNode *MD);
void visitDIAssignIDMetadata(Instruction &I, MDNode *MD);
void visitAnnotationMetadata(MDNode *Annotation);
void visitAliasScopeMetadata(const MDNode *MD);
void visitAliasScopeListMetadata(const MDNode *MD);
void visitAccessGroupMetadata(const MDNode *MD);
template <class Ty> bool isValidMetadataArray(const MDTuple &N);
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
#include "llvm/IR/Metadata.def"
void visitDIScope(const DIScope &N);
void visitDIVariable(const DIVariable &N);
void visitDILexicalBlockBase(const DILexicalBlockBase &N);
void visitDITemplateParameter(const DITemplateParameter &N);
void visitTemplateParams(const MDNode &N, const Metadata &RawParams);
void visit(DbgLabelRecord &DLR);
void visit(DbgVariableRecord &DVR);
// InstVisitor overrides...
using InstVisitor<Verifier>::visit;
void visitDbgRecords(Instruction &I);
void visit(Instruction &I);
void visitTruncInst(TruncInst &I);
void visitZExtInst(ZExtInst &I);
void visitSExtInst(SExtInst &I);
void visitFPTruncInst(FPTruncInst &I);
void visitFPExtInst(FPExtInst &I);
void visitFPToUIInst(FPToUIInst &I);
void visitFPToSIInst(FPToSIInst &I);
void visitUIToFPInst(UIToFPInst &I);
void visitSIToFPInst(SIToFPInst &I);
void visitIntToPtrInst(IntToPtrInst &I);
void visitPtrToIntInst(PtrToIntInst &I);
void visitBitCastInst(BitCastInst &I);
void visitAddrSpaceCastInst(AddrSpaceCastInst &I);
void visitPHINode(PHINode &PN);
void visitCallBase(CallBase &Call);
void visitUnaryOperator(UnaryOperator &U);
void visitBinaryOperator(BinaryOperator &B);
void visitICmpInst(ICmpInst &IC);
void visitFCmpInst(FCmpInst &FC);
void visitExtractElementInst(ExtractElementInst &EI);
void visitInsertElementInst(InsertElementInst &EI);
void visitShuffleVectorInst(ShuffleVectorInst &EI);
void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
void visitCallInst(CallInst &CI);
void visitInvokeInst(InvokeInst &II);
void visitGetElementPtrInst(GetElementPtrInst &GEP);
void visitLoadInst(LoadInst &LI);
void visitStoreInst(StoreInst &SI);
void verifyDominatesUse(Instruction &I, unsigned i);
void visitInstruction(Instruction &I);
void visitTerminator(Instruction &I);
void visitBranchInst(BranchInst &BI);
void visitReturnInst(ReturnInst &RI);
void visitSwitchInst(SwitchInst &SI);
void visitIndirectBrInst(IndirectBrInst &BI);
void visitCallBrInst(CallBrInst &CBI);
void visitSelectInst(SelectInst &SI);
void visitUserOp1(Instruction &I);
void visitUserOp2(Instruction &I) { visitUserOp1(I); }
void visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call);
void visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI);
void visitVPIntrinsic(VPIntrinsic &VPI);
void visitDbgIntrinsic(StringRef Kind, DbgVariableIntrinsic &DII);
void visitDbgLabelIntrinsic(StringRef Kind, DbgLabelInst &DLI);
void visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI);
void visitAtomicRMWInst(AtomicRMWInst &RMWI);
void visitFenceInst(FenceInst &FI);
void visitAllocaInst(AllocaInst &AI);
void visitExtractValueInst(ExtractValueInst &EVI);
void visitInsertValueInst(InsertValueInst &IVI);
void visitEHPadPredecessors(Instruction &I);
void visitLandingPadInst(LandingPadInst &LPI);
void visitResumeInst(ResumeInst &RI);
void visitCatchPadInst(CatchPadInst &CPI);
void visitCatchReturnInst(CatchReturnInst &CatchReturn);
void visitCleanupPadInst(CleanupPadInst &CPI);
void visitFuncletPadInst(FuncletPadInst &FPI);
void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch);
void visitCleanupReturnInst(CleanupReturnInst &CRI);
void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal);
void verifySwiftErrorValue(const Value *SwiftErrorVal);
void verifyTailCCMustTailAttrs(const AttrBuilder &Attrs, StringRef Context);
void verifyMustTailCall(CallInst &CI);
bool verifyAttributeCount(AttributeList Attrs, unsigned Params);
void verifyAttributeTypes(AttributeSet Attrs, const Value *V);
void verifyParameterAttrs(AttributeSet Attrs, Type *Ty, const Value *V);
void checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr,
const Value *V);
void verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
const Value *V, bool IsIntrinsic, bool IsInlineAsm);
void verifyFunctionMetadata(ArrayRef<std::pair<unsigned, MDNode *>> MDs);
void visitConstantExprsRecursively(const Constant *EntryC);
void visitConstantExpr(const ConstantExpr *CE);
void verifyInlineAsmCall(const CallBase &Call);
void verifyStatepoint(const CallBase &Call);
void verifyFrameRecoverIndices();
void verifySiblingFuncletUnwinds();
void verifyFragmentExpression(const DbgVariableIntrinsic &I);
void verifyFragmentExpression(const DbgVariableRecord &I);
template <typename ValueOrMetadata>
void verifyFragmentExpression(const DIVariable &V,
DIExpression::FragmentInfo Fragment,
ValueOrMetadata *Desc);
void verifyFnArgs(const DbgVariableIntrinsic &I);
void verifyFnArgs(const DbgVariableRecord &DVR);
void verifyNotEntryValue(const DbgVariableIntrinsic &I);
void verifyNotEntryValue(const DbgVariableRecord &I);
/// Module-level debug info verification...
void verifyCompileUnits();
/// Module-level verification that all @llvm.experimental.deoptimize
/// declarations share the same calling convention.
void verifyDeoptimizeCallingConvs();
void verifyAttachedCallBundle(const CallBase &Call,
const OperandBundleUse &BU);
/// Verify the llvm.experimental.noalias.scope.decl declarations
void verifyNoAliasScopeDecl();
};
} // end anonymous namespace
/// We know that cond should be true, if not print an error message.
#define Check(C, ...) \
do { \
if (!(C)) { \
CheckFailed(__VA_ARGS__); \
return; \
} \
} while (false)
/// We know that a debug info condition should be true, if not print
/// an error message.
#define CheckDI(C, ...) \
do { \
if (!(C)) { \
DebugInfoCheckFailed(__VA_ARGS__); \
return; \
} \
} while (false)
void Verifier::visitDbgRecords(Instruction &I) {
if (!I.DebugMarker)
return;
CheckDI(I.DebugMarker->MarkedInstr == &I,
"Instruction has invalid DebugMarker", &I);
CheckDI(!isa<PHINode>(&I) || !I.hasDbgRecords(),
"PHI Node must not have any attached DbgRecords", &I);
for (DbgRecord &DR : I.getDbgRecordRange()) {
CheckDI(DR.getMarker() == I.DebugMarker,
"DbgRecord had invalid DebugMarker", &I, &DR);
if (auto *Loc =
dyn_cast_or_null<DILocation>(DR.getDebugLoc().getAsMDNode()))
visitMDNode(*Loc, AreDebugLocsAllowed::Yes);
if (auto *DVR = dyn_cast<DbgVariableRecord>(&DR)) {
visit(*DVR);
// These have to appear after `visit` for consistency with existing
// intrinsic behaviour.
verifyFragmentExpression(*DVR);
verifyNotEntryValue(*DVR);
} else if (auto *DLR = dyn_cast<DbgLabelRecord>(&DR)) {
visit(*DLR);
}
}
}
void Verifier::visit(Instruction &I) {
visitDbgRecords(I);
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i)
Check(I.getOperand(i) != nullptr, "Operand is null", &I);
InstVisitor<Verifier>::visit(I);
}
// Helper to iterate over indirect users. By returning false, the callback can ask to stop traversing further.
static void forEachUser(const Value *User,
SmallPtrSet<const Value *, 32> &Visited,
llvm::function_ref<bool(const Value *)> Callback) {
if (!Visited.insert(User).second)
return;
SmallVector<const Value *> WorkList;
append_range(WorkList, User->materialized_users());
while (!WorkList.empty()) {
const Value *Cur = WorkList.pop_back_val();
if (!Visited.insert(Cur).second)
continue;
if (Callback(Cur))
append_range(WorkList, Cur->materialized_users());
}
}
void Verifier::visitGlobalValue(const GlobalValue &GV) {
Check(!GV.isDeclaration() || GV.hasValidDeclarationLinkage(),
"Global is external, but doesn't have external or weak linkage!", &GV);
if (const GlobalObject *GO = dyn_cast<GlobalObject>(&GV)) {
if (MaybeAlign A = GO->getAlign()) {
Check(A->value() <= Value::MaximumAlignment,
"huge alignment values are unsupported", GO);
}
if (const MDNode *Associated =
GO->getMetadata(LLVMContext::MD_associated)) {
Check(Associated->getNumOperands() == 1,
"associated metadata must have one operand", &GV, Associated);
const Metadata *Op = Associated->getOperand(0).get();
Check(Op, "associated metadata must have a global value", GO, Associated);
const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
Check(VM, "associated metadata must be ValueAsMetadata", GO, Associated);
if (VM) {
Check(isa<PointerType>(VM->getValue()->getType()),
"associated value must be pointer typed", GV, Associated);
const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
"associated metadata must point to a GlobalObject", GO, Stripped);
Check(Stripped != GO,
"global values should not associate to themselves", GO,
Associated);
}
}
// FIXME: Why is getMetadata on GlobalValue protected?
if (const MDNode *AbsoluteSymbol =
GO->getMetadata(LLVMContext::MD_absolute_symbol)) {
verifyRangeMetadata(*GO, AbsoluteSymbol, DL.getIntPtrType(GO->getType()),
true);
}
}
Check(!GV.hasAppendingLinkage() || isa<GlobalVariable>(GV),
"Only global variables can have appending linkage!", &GV);
if (GV.hasAppendingLinkage()) {
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(&GV);
Check(GVar && GVar->getValueType()->isArrayTy(),
"Only global arrays can have appending linkage!", GVar);
}
if (GV.isDeclarationForLinker())
Check(!GV.hasComdat(), "Declaration may not be in a Comdat!", &GV);
if (GV.hasDLLExportStorageClass()) {
Check(!GV.hasHiddenVisibility(),
"dllexport GlobalValue must have default or protected visibility",
&GV);
}
if (GV.hasDLLImportStorageClass()) {
Check(GV.hasDefaultVisibility(),
"dllimport GlobalValue must have default visibility", &GV);
Check(!GV.isDSOLocal(), "GlobalValue with DLLImport Storage is dso_local!",
&GV);
Check((GV.isDeclaration() &&
(GV.hasExternalLinkage() || GV.hasExternalWeakLinkage())) ||
GV.hasAvailableExternallyLinkage(),
"Global is marked as dllimport, but not external", &GV);
}
if (GV.isImplicitDSOLocal())
Check(GV.isDSOLocal(),
"GlobalValue with local linkage or 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())
CheckFailed("Global is referenced by parentless instruction!", &GV, &M,
I);
else if (I->getParent()->getParent()->getParent() != &M)
CheckFailed("Global is referenced in a different module!", &GV, &M, I,
I->getParent()->getParent(),
I->getParent()->getParent()->getParent());
return false;
} else if (const Function *F = dyn_cast<Function>(V)) {
if (F->getParent() != &M)
CheckFailed("Global is used by function in a different module", &GV, &M,
F, F->getParent());
return false;
}
return true;
});
}
void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
if (GV.hasInitializer()) {
Check(GV.getInitializer()->getType() == GV.getValueType(),
"Global variable initializer type does not match global "
"variable type!",
&GV);
// If the global has common linkage, it must have a zero initializer and
// cannot be constant.
if (GV.hasCommonLinkage()) {
Check(GV.getInitializer()->isNullValue(),
"'common' global must have a zero initializer!", &GV);
Check(!GV.isConstant(), "'common' global may not be marked constant!",
&GV);
Check(!GV.hasComdat(), "'common' global may not be in a Comdat!", &GV);
}
}
if (GV.hasName() && (GV.getName() == "llvm.global_ctors" ||
GV.getName() == "llvm.global_dtors")) {
Check(!GV.hasInitializer() || GV.hasAppendingLinkage(),
"invalid linkage for intrinsic global variable", &GV);
Check(GV.materialized_use_empty(),
"invalid uses of 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<ArrayType>(GV.getValueType())) {
StructType *STy = dyn_cast<StructType>(ATy->getElementType());
PointerType *FuncPtrTy =
PointerType::get(Context, DL.getProgramAddressSpace());
Check(STy && (STy->getNumElements() == 2 || STy->getNumElements() == 3) &&
STy->getTypeAtIndex(0u)->isIntegerTy(32) &&
STy->getTypeAtIndex(1) == FuncPtrTy,
"wrong type for intrinsic global variable", &GV);
Check(STy->getNumElements() == 3,
"the third field of the element type is mandatory, "
"specify ptr null to migrate from the obsoleted 2-field form");
Type *ETy = STy->getTypeAtIndex(2);
Check(ETy->isPointerTy(), "wrong type for intrinsic global variable",
&GV);
}
}
if (GV.hasName() && (GV.getName() == "llvm.used" ||
GV.getName() == "llvm.compiler.used")) {
Check(!GV.hasInitializer() || GV.hasAppendingLinkage(),
"invalid linkage for intrinsic global variable", &GV);
Check(GV.materialized_use_empty(),
"invalid uses of intrinsic global variable", &GV);
Type *GVType = GV.getValueType();
if (ArrayType *ATy = dyn_cast<ArrayType>(GVType)) {
PointerType *PTy = dyn_cast<PointerType>(ATy->getElementType());
Check(PTy, "wrong type for intrinsic global variable", &GV);
if (GV.hasInitializer()) {
const Constant *Init = GV.getInitializer();
const ConstantArray *InitArray = dyn_cast<ConstantArray>(Init);
Check(InitArray, "wrong initalizer for intrinsic global variable",
Init);
for (Value *Op : InitArray->operands()) {
Value *V = Op->stripPointerCasts();
Check(isa<GlobalVariable>(V) || isa<Function>(V) ||
isa<GlobalAlias>(V),
Twine("invalid ") + GV.getName() + " member", V);
Check(V->hasName(),
Twine("members of ") + GV.getName() + " must be named", V);
}
}
}
}
// Visit any debug info attachments.
SmallVector<MDNode *, 1> MDs;
GV.getMetadata(LLVMContext::MD_dbg, MDs);
for (auto *MD : MDs) {
if (auto *GVE = dyn_cast<DIGlobalVariableExpression>(MD))
visitDIGlobalVariableExpression(*GVE);
else
CheckDI(false, "!dbg attachment of global variable must be a "
"DIGlobalVariableExpression");
}
// Scalable vectors cannot be global variables, since we don't know
// the runtime size.
Check(!GV.getValueType()->isScalableTy(),
"Globals cannot contain scalable types", &GV);
// Check if it's a target extension type that disallows being used as a
// global.
if (auto *TTy = dyn_cast<TargetExtType>(GV.getValueType()))
Check(TTy->hasProperty(TargetExtType::CanBeGlobal),
"Global @" + GV.getName() + " has illegal target extension type",
TTy);
if (!GV.hasInitializer()) {
visitGlobalValue(GV);
return;
}
// Walk any aggregate initializers looking for bitcasts between address spaces
visitConstantExprsRecursively(GV.getInitializer());
visitGlobalValue(GV);
}
void Verifier::visitAliaseeSubExpr(const GlobalAlias &GA, const Constant &C) {
SmallPtrSet<const GlobalAlias*, 4> Visited;
Visited.insert(&GA);
visitAliaseeSubExpr(Visited, GA, C);
}
void Verifier::visitAliaseeSubExpr(SmallPtrSetImpl<const GlobalAlias*> &Visited,
const GlobalAlias &GA, const Constant &C) {
if (GA.hasAvailableExternallyLinkage()) {
Check(isa<GlobalValue>(C) &&
cast<GlobalValue>(C).hasAvailableExternallyLinkage(),
"available_externally alias must point to available_externally "
"global value",
&GA);
}
if (const auto *GV = dyn_cast<GlobalValue>(&C)) {
if (!GA.hasAvailableExternallyLinkage()) {
Check(!GV->isDeclarationForLinker(), "Alias must point to a definition",
&GA);
}
if (const auto *GA2 = dyn_cast<GlobalAlias>(GV)) {
Check(Visited.insert(GA2).second, "Aliases cannot form a cycle", &GA);
Check(!GA2->isInterposable(),
"Alias cannot point to an interposable alias", &GA);
} else {
// Only continue verifying subexpressions of GlobalAliases.
// Do not recurse into global initializers.
return;
}
}
if (const auto *CE = dyn_cast<ConstantExpr>(&C))
visitConstantExprsRecursively(CE);
for (const Use &U : C.operands()) {
Value *V = &*U;
if (const auto *GA2 = dyn_cast<GlobalAlias>(V))
visitAliaseeSubExpr(Visited, GA, *GA2->getAliasee());
else if (const auto *C2 = dyn_cast<Constant>(V))
visitAliaseeSubExpr(Visited, GA, *C2);
}
}
void Verifier::visitGlobalAlias(const GlobalAlias &GA) {
Check(GlobalAlias::isValidLinkage(GA.getLinkage()),
"Alias should have private, internal, linkonce, weak, linkonce_odr, "
"weak_odr, external, or available_externally linkage!",
&GA);
const Constant *Aliasee = GA.getAliasee();
Check(Aliasee, "Aliasee cannot be NULL!", &GA);
Check(GA.getType() == Aliasee->getType(),
"Alias and aliasee types should match!", &GA);
Check(isa<GlobalValue>(Aliasee) || isa<ConstantExpr>(Aliasee),
"Aliasee should be either GlobalValue or ConstantExpr", &GA);
visitAliaseeSubExpr(GA, *Aliasee);
visitGlobalValue(GA);
}
void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
Check(GlobalIFunc::isValidLinkage(GI.getLinkage()),
"IFunc should have private, internal, linkonce, weak, linkonce_odr, "
"weak_odr, or external linkage!",
&GI);
// Pierce through ConstantExprs and GlobalAliases and check that the resolver
// is a Function definition.
const Function *Resolver = GI.getResolverFunction();
Check(Resolver, "IFunc must have a Function resolver", &GI);
Check(!Resolver->isDeclarationForLinker(),
"IFunc resolver must be a definition", &GI);
// Check that the immediate resolver operand (prior to any bitcasts) has the
// correct type.
const Type *ResolverTy = GI.getResolver()->getType();
Check(isa<PointerType>(Resolver->getFunctionType()->getReturnType()),
"IFunc resolver must return a pointer", &GI);
const Type *ResolverFuncTy =
GlobalIFunc::getResolverFunctionType(GI.getValueType());
Check(ResolverTy == ResolverFuncTy->getPointerTo(GI.getAddressSpace()),
"IFunc resolver has incorrect type", &GI);
}
void Verifier::visitNamedMDNode(const NamedMDNode &NMD) {
// There used to be various other llvm.dbg.* nodes, but we don't support
// upgrading them and we want to reserve the namespace for future uses.
if (NMD.getName().starts_with("llvm.dbg."))
CheckDI(NMD.getName() == "llvm.dbg.cu",
"unrecognized named metadata node in the llvm.dbg namespace", &NMD);
for (const MDNode *MD : NMD.operands()) {
if (NMD.getName() == "llvm.dbg.cu")
CheckDI(MD && isa<DICompileUnit>(MD), "invalid compile unit", &NMD, MD);
if (!MD)
continue;
visitMDNode(*MD, AreDebugLocsAllowed::Yes);
}
}
void Verifier::visitMDNode(const MDNode &MD, AreDebugLocsAllowed AllowLocs) {
// Only visit each node once. Metadata can be mutually recursive, so this
// avoids infinite recursion here, as well as being an optimization.
if (!MDNodes.insert(&MD).second)
return;
Check(&MD.getContext() == &Context,
"MDNode context does not match Module context!", &MD);
switch (MD.getMetadataID()) {
default:
llvm_unreachable("Invalid MDNode subclass");
case Metadata::MDTupleKind:
break;
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) \
case Metadata::CLASS##Kind: \
visit##CLASS(cast<CLASS>(MD)); \
break;
#include "llvm/IR/Metadata.def"
}
for (const Metadata *Op : MD.operands()) {
if (!Op)
continue;
Check(!isa<LocalAsMetadata>(Op), "Invalid operand for global metadata!",
&MD, Op);
CheckDI(!isa<DILocation>(Op) || AllowLocs == AreDebugLocsAllowed::Yes,
"DILocation not allowed within this metadata node", &MD, Op);
if (auto *N = dyn_cast<MDNode>(Op)) {
visitMDNode(*N, AllowLocs);
continue;
}
if (auto *V = dyn_cast<ValueAsMetadata>(Op)) {
visitValueAsMetadata(*V, nullptr);
continue;
}
}
// Check these last, so we diagnose problems in operands first.
Check(!MD.isTemporary(), "Expected no forward declarations!", &MD);
Check(MD.isResolved(), "All nodes should be resolved!", &MD);
}
void Verifier::visitValueAsMetadata(const ValueAsMetadata &MD, Function *F) {
Check(MD.getValue(), "Expected valid value", &MD);
Check(!MD.getValue()->getType()->isMetadataTy(),
"Unexpected metadata round-trip through values", &MD, MD.getValue());
auto *L = dyn_cast<LocalAsMetadata>(&MD);
if (!L)
return;
Check(F, "function-local metadata used outside a function", L);
// If this was an instruction, bb, or argument, verify that it is in the
// function that we expect.
Function *ActualF = nullptr;
if (Instruction *I = dyn_cast<Instruction>(L->getValue())) {
Check(I->getParent(), "function-local metadata not in basic block", L, I);
ActualF = I->getParent()->getParent();
} else if (BasicBlock *BB = dyn_cast<BasicBlock>(L->getValue()))
ActualF = BB->getParent();
else if (Argument *A = dyn_cast<Argument>(L->getValue()))
ActualF = A->getParent();
assert(ActualF && "Unimplemented function local metadata case!");
Check(ActualF == F, "function-local metadata used in wrong function", L);
}
void Verifier::visitDIArgList(const DIArgList &AL, Function *F) {
for (const ValueAsMetadata *VAM : AL.getArgs())
visitValueAsMetadata(*VAM, F);
}
void Verifier::visitMetadataAsValue(const MetadataAsValue &MDV, Function *F) {
Metadata *MD = MDV.getMetadata();
if (auto *N = dyn_cast<MDNode>(MD)) {
visitMDNode(*N, AreDebugLocsAllowed::No);
return;
}
// Only visit each node once. Metadata can be mutually recursive, so this
// avoids infinite recursion here, as well as being an optimization.
if (!MDNodes.insert(MD).second)
return;
if (auto *V = dyn_cast<ValueAsMetadata>(MD))
visitValueAsMetadata(*V, F);
if (auto *AL = dyn_cast<DIArgList>(MD))
visitDIArgList(*AL, F);
}
static bool isType(const Metadata *MD) { return !MD || isa<DIType>(MD); }
static bool isScope(const Metadata *MD) { return !MD || isa<DIScope>(MD); }
static bool isDINode(const Metadata *MD) { return !MD || isa<DINode>(MD); }
void Verifier::visitDILocation(const DILocation &N) {
CheckDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
"location requires a valid scope", &N, N.getRawScope());
if (auto *IA = N.getRawInlinedAt())
CheckDI(isa<DILocation>(IA), "inlined-at should be a location", &N, IA);
if (auto *SP = dyn_cast<DISubprogram>(N.getRawScope()))
CheckDI(SP->isDefinition(), "scope points into the type hierarchy", &N);
}
void Verifier::visitGenericDINode(const GenericDINode &N) {
CheckDI(N.getTag(), "invalid tag", &N);
}
void Verifier::visitDIScope(const DIScope &N) {
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
}
void Verifier::visitDISubrange(const DISubrange &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N);
bool HasAssumedSizedArraySupport = dwarf::isFortran(CurrentSourceLang);
CheckDI(HasAssumedSizedArraySupport || N.getRawCountNode() ||
N.getRawUpperBound(),
"Subrange must contain count or upperBound", &N);
CheckDI(!N.getRawCountNode() || !N.getRawUpperBound(),
"Subrange can have any one of count or upperBound", &N);
auto *CBound = N.getRawCountNode();
CheckDI(!CBound || isa<ConstantAsMetadata>(CBound) ||
isa<DIVariable>(CBound) || isa<DIExpression>(CBound),
"Count must be signed constant or DIVariable or DIExpression", &N);
auto Count = N.getCount();
CheckDI(!Count || !isa<ConstantInt *>(Count) ||
cast<ConstantInt *>(Count)->getSExtValue() >= -1,
"invalid subrange count", &N);
auto *LBound = N.getRawLowerBound();
CheckDI(!LBound || isa<ConstantAsMetadata>(LBound) ||
isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
"LowerBound must be signed constant or DIVariable or DIExpression",
&N);
auto *UBound = N.getRawUpperBound();
CheckDI(!UBound || isa<ConstantAsMetadata>(UBound) ||
isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
"UpperBound must be signed constant or DIVariable or DIExpression",
&N);
auto *Stride = N.getRawStride();
CheckDI(!Stride || isa<ConstantAsMetadata>(Stride) ||
isa<DIVariable>(Stride) || isa<DIExpression>(Stride),
"Stride must be signed constant or DIVariable or DIExpression", &N);
}
void Verifier::visitDIGenericSubrange(const DIGenericSubrange &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_generic_subrange, "invalid tag", &N);
CheckDI(N.getRawCountNode() || N.getRawUpperBound(),
"GenericSubrange must contain count or upperBound", &N);
CheckDI(!N.getRawCountNode() || !N.getRawUpperBound(),
"GenericSubrange can have any one of count or upperBound", &N);
auto *CBound = N.getRawCountNode();
CheckDI(!CBound || isa<DIVariable>(CBound) || isa<DIExpression>(CBound),
"Count must be signed constant or DIVariable or DIExpression", &N);
auto *LBound = N.getRawLowerBound();
CheckDI(LBound, "GenericSubrange must contain lowerBound", &N);
CheckDI(isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
"LowerBound must be signed constant or DIVariable or DIExpression",
&N);
auto *UBound = N.getRawUpperBound();
CheckDI(!UBound || isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
"UpperBound must be signed constant or DIVariable or DIExpression",
&N);
auto *Stride = N.getRawStride();
CheckDI(Stride, "GenericSubrange must contain stride", &N);
CheckDI(isa<DIVariable>(Stride) || isa<DIExpression>(Stride),
"Stride must be signed constant or DIVariable or DIExpression", &N);
}
void Verifier::visitDIEnumerator(const DIEnumerator &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N);
}
void Verifier::visitDIBasicType(const DIBasicType &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_base_type ||
N.getTag() == dwarf::DW_TAG_unspecified_type ||
N.getTag() == dwarf::DW_TAG_string_type,
"invalid tag", &N);
}
void Verifier::visitDIStringType(const DIStringType &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_string_type, "invalid tag", &N);
CheckDI(!(N.isBigEndian() && N.isLittleEndian()), "has conflicting flags",
&N);
}
void Verifier::visitDIDerivedType(const DIDerivedType &N) {
// Common scope checks.
visitDIScope(N);
CheckDI(N.getTag() == dwarf::DW_TAG_typedef ||
N.getTag() == dwarf::DW_TAG_pointer_type ||
N.getTag() == dwarf::DW_TAG_ptr_to_member_type ||
N.getTag() == dwarf::DW_TAG_reference_type ||
N.getTag() == dwarf::DW_TAG_rvalue_reference_type ||
N.getTag() == dwarf::DW_TAG_const_type ||
N.getTag() == dwarf::DW_TAG_immutable_type ||
N.getTag() == dwarf::DW_TAG_volatile_type ||
N.getTag() == dwarf::DW_TAG_restrict_type ||
N.getTag() == dwarf::DW_TAG_atomic_type ||
N.getTag() == dwarf::DW_TAG_LLVM_ptrauth_type ||
N.getTag() == dwarf::DW_TAG_member ||
(N.getTag() == dwarf::DW_TAG_variable && N.isStaticMember()) ||
N.getTag() == dwarf::DW_TAG_inheritance ||
N.getTag() == dwarf::DW_TAG_friend ||
N.getTag() == dwarf::DW_TAG_set_type,
"invalid tag", &N);
if (N.getTag() == dwarf::DW_TAG_ptr_to_member_type) {
CheckDI(isType(N.getRawExtraData()), "invalid pointer to member type", &N,
N.getRawExtraData());
}
if (N.getTag() == dwarf::DW_TAG_set_type) {
if (auto *T = N.getRawBaseType()) {
auto *Enum = dyn_cast_or_null<DICompositeType>(T);
auto *Basic = dyn_cast_or_null<DIBasicType>(T);
CheckDI(
(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type) ||
(Basic && (Basic->getEncoding() == dwarf::DW_ATE_unsigned ||
Basic->getEncoding() == dwarf::DW_ATE_signed ||
Basic->getEncoding() == dwarf::DW_ATE_unsigned_char ||
Basic->getEncoding() == dwarf::DW_ATE_signed_char ||
Basic->getEncoding() == dwarf::DW_ATE_boolean)),
"invalid set base type", &N, T);
}
}
CheckDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
CheckDI(isType(N.getRawBaseType()), "invalid base type", &N,
N.getRawBaseType());
if (N.getDWARFAddressSpace()) {
CheckDI(N.getTag() == dwarf::DW_TAG_pointer_type ||
N.getTag() == dwarf::DW_TAG_reference_type ||
N.getTag() == dwarf::DW_TAG_rvalue_reference_type,
"DWARF address space only applies to pointer or reference types",
&N);
}
}
/// Detect mutually exclusive flags.
static bool hasConflictingReferenceFlags(unsigned Flags) {
return ((Flags & DINode::FlagLValueReference) &&
(Flags & DINode::FlagRValueReference)) ||
((Flags & DINode::FlagTypePassByValue) &&
(Flags & DINode::FlagTypePassByReference));
}
void Verifier::visitTemplateParams(const MDNode &N, const Metadata &RawParams) {
auto *Params = dyn_cast<MDTuple>(&RawParams);
CheckDI(Params, "invalid template params", &N, &RawParams);
for (Metadata *Op : Params->operands()) {
CheckDI(Op && isa<DITemplateParameter>(Op), "invalid template parameter",
&N, Params, Op);
}
}
void Verifier::visitDICompositeType(const DICompositeType &N) {
// Common scope checks.
visitDIScope(N);
CheckDI(N.getTag() == dwarf::DW_TAG_array_type ||
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_variant_part ||
N.getTag() == dwarf::DW_TAG_namelist,
"invalid tag", &N);
CheckDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
CheckDI(isType(N.getRawBaseType()), "invalid base type", &N,
N.getRawBaseType());
CheckDI(!N.getRawElements() || isa<MDTuple>(N.getRawElements()),
"invalid composite elements", &N, N.getRawElements());
CheckDI(isType(N.getRawVTableHolder()), "invalid vtable holder", &N,
N.getRawVTableHolder());
CheckDI(!hasConflictingReferenceFlags(N.getFlags()),
"invalid reference flags", &N);
unsigned DIBlockByRefStruct = 1 << 4;
CheckDI((N.getFlags() & DIBlockByRefStruct) == 0,
"DIBlockByRefStruct on DICompositeType is no longer supported", &N);
if (N.isVector()) {
const DINodeArray Elements = N.getElements();
CheckDI(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);
if (auto *D = N.getRawDiscriminator()) {
CheckDI(isa<DIDerivedType>(D) && N.getTag() == dwarf::DW_TAG_variant_part,
"discriminator can only appear on variant part");
}
if (N.getRawDataLocation()) {
CheckDI(N.getTag() == dwarf::DW_TAG_array_type,
"dataLocation can only appear in array type");
}
if (N.getRawAssociated()) {
CheckDI(N.getTag() == dwarf::DW_TAG_array_type,
"associated can only appear in array type");
}
if (N.getRawAllocated()) {
CheckDI(N.getTag() == dwarf::DW_TAG_array_type,
"allocated can only appear in array type");
}
if (N.getRawRank()) {
CheckDI(N.getTag() == dwarf::DW_TAG_array_type,
"rank can only appear in array type");
}
if (N.getTag() == dwarf::DW_TAG_array_type) {
CheckDI(N.getRawBaseType(), "array types must have a base type", &N);
}
}
void Verifier::visitDISubroutineType(const DISubroutineType &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_subroutine_type, "invalid tag", &N);
if (auto *Types = N.getRawTypeArray()) {
CheckDI(isa<MDTuple>(Types), "invalid composite elements", &N, Types);
for (Metadata *Ty : N.getTypeArray()->operands()) {
CheckDI(isType(Ty), "invalid subroutine type ref", &N, Types, Ty);
}
}
CheckDI(!hasConflictingReferenceFlags(N.getFlags()),
"invalid reference flags", &N);
}
void Verifier::visitDIFile(const DIFile &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N);
std::optional<DIFile::ChecksumInfo<StringRef>> Checksum = N.getChecksum();
if (Checksum) {
CheckDI(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;
case DIFile::CSK_SHA256:
Size = 64;
break;
}
CheckDI(Checksum->Value.size() == Size, "invalid checksum length", &N);
CheckDI(Checksum->Value.find_if_not(llvm::isHexDigit) == StringRef::npos,
"invalid checksum", &N);
}
}
void Verifier::visitDICompileUnit(const DICompileUnit &N) {
CheckDI(N.isDistinct(), "compile units must be distinct", &N);
CheckDI(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.
CheckDI(N.getRawFile() && isa<DIFile>(N.getRawFile()), "invalid file", &N,
N.getRawFile());
CheckDI(!N.getFile()->getFilename().empty(), "invalid filename", &N,
N.getFile());
CurrentSourceLang = (dwarf::SourceLanguage)N.getSourceLanguage();
CheckDI((N.getEmissionKind() <= DICompileUnit::LastEmissionKind),
"invalid emission kind", &N);
if (auto *Array = N.getRawEnumTypes()) {
CheckDI(isa<MDTuple>(Array), "invalid enum list", &N, Array);
for (Metadata *Op : N.getEnumTypes()->operands()) {
auto *Enum = dyn_cast_or_null<DICompositeType>(Op);
CheckDI(Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type,
"invalid enum type", &N, N.getEnumTypes(), Op);
}
}
if (auto *Array = N.getRawRetainedTypes()) {
CheckDI(isa<MDTuple>(Array), "invalid retained type list", &N, Array);
for (Metadata *Op : N.getRetainedTypes()->operands()) {
CheckDI(
Op && (isa<DIType>(Op) || (isa<DISubprogram>(Op) &&
!cast<DISubprogram>(Op)->isDefinition())),
"invalid retained type", &N, Op);
}
}
if (auto *Array = N.getRawGlobalVariables()) {
CheckDI(isa<MDTuple>(Array), "invalid global variable list", &N, Array);
for (Metadata *Op : N.getGlobalVariables()->operands()) {
CheckDI(Op && (isa<DIGlobalVariableExpression>(Op)),
"invalid global variable ref", &N, Op);
}
}
if (auto *Array = N.getRawImportedEntities()) {
CheckDI(isa<MDTuple>(Array), "invalid imported entity list", &N, Array);
for (Metadata *Op : N.getImportedEntities()->operands()) {
CheckDI(Op && isa<DIImportedEntity>(Op), "invalid imported entity ref",
&N, Op);
}
}
if (auto *Array = N.getRawMacros()) {
CheckDI(isa<MDTuple>(Array), "invalid macro list", &N, Array);
for (Metadata *Op : N.getMacros()->operands()) {
CheckDI(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
}
}
CUVisited.insert(&N);
}
void Verifier::visitDISubprogram(const DISubprogram &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_subprogram, "invalid tag", &N);
CheckDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope());
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
else
CheckDI(N.getLine() == 0, "line specified with no file", &N, N.getLine());
if (auto *T = N.getRawType())
CheckDI(isa<DISubroutineType>(T), "invalid subroutine type", &N, T);
CheckDI(isType(N.getRawContainingType()), "invalid containing type", &N,
N.getRawContainingType());
if (auto *Params = N.getRawTemplateParams())
visitTemplateParams(N, *Params);
if (auto *S = N.getRawDeclaration())
CheckDI(isa<DISubprogram>(S) && !cast<DISubprogram>(S)->isDefinition(),
"invalid subprogram declaration", &N, S);
if (auto *RawNode = N.getRawRetainedNodes()) {
auto *Node = dyn_cast<MDTuple>(RawNode);
CheckDI(Node, "invalid retained nodes list", &N, RawNode);
for (Metadata *Op : Node->operands()) {
CheckDI(Op && (isa<DILocalVariable>(Op) || isa<DILabel>(Op) ||
isa<DIImportedEntity>(Op)),
"invalid retained nodes, expected DILocalVariable, DILabel or "
"DIImportedEntity",
&N, Node, Op);
}
}
CheckDI(!hasConflictingReferenceFlags(N.getFlags()),
"invalid reference flags", &N);
auto *Unit = N.getRawUnit();
if (N.isDefinition()) {
// Subprogram definitions (not part of the type hierarchy).
CheckDI(N.isDistinct(), "subprogram definitions must be distinct", &N);
CheckDI(Unit, "subprogram definitions must have a compile unit", &N);
CheckDI(isa<DICompileUnit>(Unit), "invalid unit type", &N, Unit);
// There's no good way to cross the CU boundary to insert a nested
// DISubprogram definition in one CU into a type defined in another CU.
auto *CT = dyn_cast_or_null<DICompositeType>(N.getRawScope());
if (CT && CT->getRawIdentifier() &&
M.getContext().isODRUniquingDebugTypes())
CheckDI(N.getDeclaration(),
"definition subprograms cannot be nested within DICompositeType "
"when enabling ODR",
&N);
} else {
// Subprogram declarations (part of the type hierarchy).
CheckDI(!Unit, "subprogram declarations must not have a compile unit", &N);
CheckDI(!N.getRawDeclaration(),
"subprogram declaration must not have a declaration field");
}
if (auto *RawThrownTypes = N.getRawThrownTypes()) {
auto *ThrownTypes = dyn_cast<MDTuple>(RawThrownTypes);
CheckDI(ThrownTypes, "invalid thrown types list", &N, RawThrownTypes);
for (Metadata *Op : ThrownTypes->operands())
CheckDI(Op && isa<DIType>(Op), "invalid thrown type", &N, ThrownTypes,
Op);
}
if (N.areAllCallsDescribed())
CheckDI(N.isDefinition(),
"DIFlagAllCallsDescribed must be attached to a definition");
}
void Verifier::visitDILexicalBlockBase(const DILexicalBlockBase &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_lexical_block, "invalid tag", &N);
CheckDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
"invalid local scope", &N, N.getRawScope());
if (auto *SP = dyn_cast<DISubprogram>(N.getRawScope()))
CheckDI(SP->isDefinition(), "scope points into the type hierarchy", &N);
}
void Verifier::visitDILexicalBlock(const DILexicalBlock &N) {
visitDILexicalBlockBase(N);
CheckDI(N.getLine() || !N.getColumn(),
"cannot have column info without line info", &N);
}
void Verifier::visitDILexicalBlockFile(const DILexicalBlockFile &N) {
visitDILexicalBlockBase(N);
}
void Verifier::visitDICommonBlock(const DICommonBlock &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_common_block, "invalid tag", &N);
if (auto *S = N.getRawScope())
CheckDI(isa<DIScope>(S), "invalid scope ref", &N, S);
if (auto *S = N.getRawDecl())
CheckDI(isa<DIGlobalVariable>(S), "invalid declaration", &N, S);
}
void Verifier::visitDINamespace(const DINamespace &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N);
if (auto *S = N.getRawScope())
CheckDI(isa<DIScope>(S), "invalid scope ref", &N, S);
}
void Verifier::visitDIMacro(const DIMacro &N) {
CheckDI(N.getMacinfoType() == dwarf::DW_MACINFO_define ||
N.getMacinfoType() == dwarf::DW_MACINFO_undef,
"invalid macinfo type", &N);
CheckDI(!N.getName().empty(), "anonymous macro", &N);
if (!N.getValue().empty()) {
assert(N.getValue().data()[0] != ' ' && "Macro value has a space prefix");
}
}
void Verifier::visitDIMacroFile(const DIMacroFile &N) {
CheckDI(N.getMacinfoType() == dwarf::DW_MACINFO_start_file,
"invalid macinfo type", &N);
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
if (auto *Array = N.getRawElements()) {
CheckDI(isa<MDTuple>(Array), "invalid macro list", &N, Array);
for (Metadata *Op : N.getElements()->operands()) {
CheckDI(Op && isa<DIMacroNode>(Op), "invalid macro ref", &N, Op);
}
}
}
void Verifier::visitDIModule(const DIModule &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N);
CheckDI(!N.getName().empty(), "anonymous module", &N);
}
void Verifier::visitDITemplateParameter(const DITemplateParameter &N) {
CheckDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
}
void Verifier::visitDITemplateTypeParameter(const DITemplateTypeParameter &N) {
visitDITemplateParameter(N);
CheckDI(N.getTag() == dwarf::DW_TAG_template_type_parameter, "invalid tag",
&N);
}
void Verifier::visitDITemplateValueParameter(
const DITemplateValueParameter &N) {
visitDITemplateParameter(N);
CheckDI(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::visitDIVariable(const DIVariable &N) {
if (auto *S = N.getRawScope())
CheckDI(isa<DIScope>(S), "invalid scope", &N, S);
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
}
void Verifier::visitDIGlobalVariable(const DIGlobalVariable &N) {
// Checks common to all variables.
visitDIVariable(N);
CheckDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
CheckDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
// Check only if the global variable is not an extern
if (N.isDefinition())
CheckDI(N.getType(), "missing global variable type", &N);
if (auto *Member = N.getRawStaticDataMemberDeclaration()) {
CheckDI(isa<DIDerivedType>(Member),
"invalid static data member declaration", &N, Member);
}
}
void Verifier::visitDILocalVariable(const DILocalVariable &N) {
// Checks common to all variables.
visitDIVariable(N);
CheckDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
CheckDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
CheckDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
"local variable requires a valid scope", &N, N.getRawScope());
if (auto Ty = N.getType())
CheckDI(!isa<DISubroutineType>(Ty), "invalid type", &N, N.getType());
}
void Verifier::visitDIAssignID(const DIAssignID &N) {
CheckDI(!N.getNumOperands(), "DIAssignID has no arguments", &N);
CheckDI(N.isDistinct(), "DIAssignID must be distinct", &N);
}
void Verifier::visitDILabel(const DILabel &N) {
if (auto *S = N.getRawScope())
CheckDI(isa<DIScope>(S), "invalid scope", &N, S);
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
CheckDI(N.getTag() == dwarf::DW_TAG_label, "invalid tag", &N);
CheckDI(N.getRawScope() && isa<DILocalScope>(N.getRawScope()),
"label requires a valid scope", &N, N.getRawScope());
}
void Verifier::visitDIExpression(const DIExpression &N) {
CheckDI(N.isValid(), "invalid expression", &N);
}
void Verifier::visitDIGlobalVariableExpression(
const DIGlobalVariableExpression &GVE) {
CheckDI(GVE.getVariable(), "missing variable");
if (auto *Var = GVE.getVariable())
visitDIGlobalVariable(*Var);
if (auto *Expr = GVE.getExpression()) {
visitDIExpression(*Expr);
if (auto Fragment = Expr->getFragmentInfo())
verifyFragmentExpression(*GVE.getVariable(), *Fragment, &GVE);
}
}
void Verifier::visitDIObjCProperty(const DIObjCProperty &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N);
if (auto *T = N.getRawType())
CheckDI(isType(T), "invalid type ref", &N, T);
if (auto *F = N.getRawFile())
CheckDI(isa<DIFile>(F), "invalid file", &N, F);
}
void Verifier::visitDIImportedEntity(const DIImportedEntity &N) {
CheckDI(N.getTag() == dwarf::DW_TAG_imported_module ||
N.getTag() == dwarf::DW_TAG_imported_declaration,
"invalid tag", &N);
if (auto *S = N.getRawScope())
CheckDI(isa<DIScope>(S), "invalid scope for imported entity", &N, S);
CheckDI(isDINode(N.getRawEntity()), "invalid imported entity", &N,
N.getRawEntity());
}
void Verifier::visitComdat(const Comdat &C) {
// In COFF the Module is invalid if the GlobalValue has private linkage.
// Entities with private linkage don't have entries in the symbol table.
if (TT.isOSBinFormatCOFF())
if (const GlobalValue *GV = M.getNamedValue(C.getName()))
Check(!GV->hasPrivateLinkage(), "comdat global value has private linkage",
GV);
}
void Verifier::visitModuleIdents() {
const NamedMDNode *Idents = M.getNamedMetadata("llvm.ident");
if (!Idents)
return;
// llvm.ident takes a list of metadata entry. Each entry has only one string.
// Scan each llvm.ident entry and make sure that this requirement is met.
for (const MDNode *N : Idents->operands()) {
Check(N->getNumOperands() == 1,
"incorrect number of operands in llvm.ident metadata", N);
Check(dyn_cast_or_null<MDString>(N->getOperand(0)),
("invalid value for llvm.ident metadata entry operand"
"(the operand should be a string)"),
N->getOperand(0));
}
}
void Verifier::visitModuleCommandLines() {
const NamedMDNode *CommandLines = M.getNamedMetadata("llvm.commandline");
if (!CommandLines)
return;
// llvm.commandline takes a list of metadata entry. Each entry has only one
// string. Scan each llvm.commandline entry and make sure that this
// requirement is met.
for (const MDNode *N : CommandLines->operands()) {
Check(N->getNumOperands() == 1,
"incorrect number of operands in llvm.commandline metadata", N);
Check(dyn_cast_or_null<MDString>(N->getOperand(0)),
("invalid value for llvm.commandline metadata entry operand"
"(the operand should be a string)"),
N->getOperand(0));
}
}
void Verifier::visitModuleFlags() {
const NamedMDNode *Flags = M.getModuleFlagsMetadata();
if (!Flags) return;
// Scan each flag, and track the flags and requirements.
DenseMap<const MDString*, const MDNode*> SeenIDs;
SmallVector<const MDNode*, 16> Requirements;
uint64_t PAuthABIPlatform = -1;
uint64_t PAuthABIVersion = -1;
for (const MDNode *MDN : Flags->operands()) {
visitModuleFlag(MDN, SeenIDs, Requirements);
if (MDN->getNumOperands() != 3)
continue;
if (const auto *FlagName = dyn_cast_or_null<MDString>(MDN->getOperand(1))) {
if (FlagName->getString() == "aarch64-elf-pauthabi-platform") {
if (const auto *PAP =
mdconst::dyn_extract_or_null<ConstantInt>(MDN->getOperand(2)))
PAuthABIPlatform = PAP->getZExtValue();
} else if (FlagName->getString() == "aarch64-elf-pauthabi-version") {
if (const auto *PAV =
mdconst::dyn_extract_or_null<ConstantInt>(MDN->getOperand(2)))
PAuthABIVersion = PAV->getZExtValue();
}
}
}
if ((PAuthABIPlatform == uint64_t(-1)) != (PAuthABIVersion == uint64_t(-1)))
CheckFailed("either both or no 'aarch64-elf-pauthabi-platform' and "
"'aarch64-elf-pauthabi-version' module flags must be present");
// Validate that the requirements in the module are valid.
for (const MDNode *Requirement : Requirements) {
const MDString *Flag = cast<MDString>(Requirement->getOperand(0));
const Metadata *ReqValue = Requirement->getOperand(1);
const MDNode *Op = SeenIDs.lookup(Flag);
if (!Op) {
CheckFailed("invalid requirement on flag, flag is not present in module",
Flag);
continue;
}
if (Op->getOperand(2) != ReqValue) {
CheckFailed(("invalid requirement on flag, "
"flag does not have the required value"),
Flag);
continue;
}
}
}
void
Verifier::visitModuleFlag(const MDNode *Op,
DenseMap<const MDString *, const MDNode *> &SeenIDs,
SmallVectorImpl<const MDNode *> &Requirements) {
// Each module flag should have three arguments, the merge behavior (a
// constant int), the flag ID (an MDString), and the value.
Check(Op->getNumOperands() == 3,
"incorrect number of operands in module flag", Op);
Module::ModFlagBehavior MFB;
if (!Module::isValidModFlagBehavior(Op->getOperand(0), MFB)) {
Check(mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(0)),
"invalid behavior operand in module flag (expected constant integer)",
Op->getOperand(0));
Check(false,
"invalid behavior operand in module flag (unexpected constant)",
Op->getOperand(0));
}
MDString *ID = dyn_cast_or_null<MDString>(Op->getOperand(1));
Check(ID, "invalid ID operand in module flag (expected metadata string)",
Op->getOperand(1));
// Check the values for behaviors with additional requirements.
switch (MFB) {
case Module::Error:
case Module::Warning:
case Module::Override:
// These behavior types accept any value.
break;
case Module::Min: {
auto *V = mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2));
Check(V && V->getValue().isNonNegative(),
"invalid value for 'min' module flag (expected constant non-negative "
"integer)",
Op->getOperand(2));
break;
}
case Module::Max: {
Check(mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2)),
"invalid value for 'max' module flag (expected constant integer)",
Op->getOperand(2));
break;
}
case Module::Require: {
// The value should itself be an MDNode with two operands, a flag ID (an
// MDString), and a value.
MDNode *Value = dyn_cast<MDNode>(Op->getOperand(2));
Check(Value && Value->getNumOperands() == 2,
"invalid value for 'require' module flag (expected metadata pair)",
Op->getOperand(2));
Check(isa<MDString>(Value->getOperand(0)),
("invalid value for 'require' module flag "
"(first value operand should be a string)"),
Value->getOperand(0));
// Append it to the list of requirements, to check once all module flags are
// scanned.
Requirements.push_back(Value);
break;
}
case Module::Append:
case Module::AppendUnique: {
// These behavior types require the operand be an MDNode.
Check(isa<MDNode>(Op->getOperand(2)),
"invalid value for 'append'-type module flag "
"(expected a metadata node)",
Op->getOperand(2));
break;
}
}
// Unless this is a "requires" flag, check the ID is unique.
if (MFB != Module::Require) {
bool Inserted = SeenIDs.insert(std::make_pair(ID, Op)).second;
Check(Inserted,
"module flag identifiers must be unique (or of 'require' type)", ID);
}
if (ID->getString() == "wchar_size") {
ConstantInt *Value
= mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2));
Check(Value, "wchar_size metadata requires constant integer argument");
}
if (ID->getString() == "Linker Options") {
// If the llvm.linker.options named metadata exists, we assume that the
// bitcode reader has upgraded the module flag. Otherwise the flag might
// have been created by a client directly.
Check(M.getNamedMetadata("llvm.linker.options"),
"'Linker Options' named metadata no longer supported");
}
if (ID->getString() == "SemanticInterposition") {
ConstantInt *Value =
mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(2));
Check(Value,
"SemanticInterposition metadata requires constant integer argument");
}
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);
Check(F && isa<Function>(F->getValue()->stripPointerCasts()),
"expected a Function or null", FuncMDO);
};
auto Node = dyn_cast_or_null<MDNode>(MDO);
Check(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));
Check(Count && Count->getType()->isIntegerTy(),
"expected an integer constant", Node->getOperand(2));
}
void Verifier::verifyAttributeTypes(AttributeSet Attrs, const Value *V) {
for (Attribute A : Attrs) {
if (A.isStringAttribute()) {
#define GET_ATTR_NAMES
#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)
#define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME) \
if (A.getKindAsString() == #DISPLAY_NAME) { \
auto V = A.getValueAsString(); \
if (!(V.empty() || V == "true" || V == "false")) \
CheckFailed("invalid value for '" #DISPLAY_NAME "' attribute: " + V + \
""); \
}
#include "llvm/IR/Attributes.inc"
continue;
}
if (A.isIntAttribute() != Attribute::isIntAttrKind(A.getKindAsEnum())) {
CheckFailed("Attribute '" + A.getAsString() + "' should have an Argument",
V);
return;
}
}
}
// VerifyParameterAttrs - Check the given attributes for an argument or return
// value of the specified type. The value V is printed in error messages.
void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
const Value *V) {
if (!Attrs.hasAttributes())
return;
verifyAttributeTypes(Attrs, V);
for (Attribute Attr : Attrs)
Check(Attr.isStringAttribute() ||
Attribute::canUseAsParamAttr(Attr.getKindAsEnum()),
"Attribute '" + Attr.getAsString() + "' does not apply to parameters",
V);
if (Attrs.hasAttribute(Attribute::ImmArg)) {
Check(Attrs.getNumAttributes() == 1,
"Attribute 'immarg' is incompatible with other attributes", V);
}
// Check for mutually incompatible attributes. Only inreg is compatible with
// sret.
unsigned AttrCount = 0;
AttrCount += Attrs.hasAttribute(Attribute::ByVal);
AttrCount += Attrs.hasAttribute(Attribute::InAlloca);
AttrCount += Attrs.hasAttribute(Attribute::Preallocated);
AttrCount += Attrs.hasAttribute(Attribute::StructRet) ||
Attrs.hasAttribute(Attribute::InReg);
AttrCount += Attrs.hasAttribute(Attribute::Nest);
AttrCount += Attrs.hasAttribute(Attribute::ByRef);
Check(AttrCount <= 1,
"Attributes 'byval', 'inalloca', 'preallocated', 'inreg', 'nest', "
"'byref', and 'sret' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::InAlloca) &&
Attrs.hasAttribute(Attribute::ReadOnly)),
"Attributes "
"'inalloca and readonly' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::StructRet) &&
Attrs.hasAttribute(Attribute::Returned)),
"Attributes "
"'sret and returned' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::ZExt) &&
Attrs.hasAttribute(Attribute::SExt)),
"Attributes "
"'zeroext and signext' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::ReadNone) &&
Attrs.hasAttribute(Attribute::ReadOnly)),
"Attributes "
"'readnone and readonly' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::ReadNone) &&
Attrs.hasAttribute(Attribute::WriteOnly)),
"Attributes "
"'readnone and writeonly' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::ReadOnly) &&
Attrs.hasAttribute(Attribute::WriteOnly)),
"Attributes "
"'readonly and writeonly' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::NoInline) &&
Attrs.hasAttribute(Attribute::AlwaysInline)),
"Attributes "
"'noinline and alwaysinline' are incompatible!",
V);
Check(!(Attrs.hasAttribute(Attribute::Writable) &&
Attrs.hasAttribute(Attribute::ReadNone)),
"Attributes writable and readnone are incompatible!", V);
Check(!(Attrs.hasAttribute(Attribute::Writable) &&
Attrs.hasAttribute(Attribute::ReadOnly)),
"Attributes writable and readonly are incompatible!", V);
AttributeMask IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty);
for (Attribute Attr : Attrs) {
if (!Attr.isStringAttribute() &&
IncompatibleAttrs.contains(Attr.getKindAsEnum())) {
CheckFailed("Attribute '" + Attr.getAsString() +
"' applied to incompatible type!", V);
return;
}
}
if (isa<PointerType>(Ty)) {
if (Attrs.hasAttribute(Attribute::ByVal)) {
if (Attrs.hasAttribute(Attribute::Alignment)) {
Align AttrAlign = Attrs.getAlignment().valueOrOne();
Align MaxAlign(ParamMaxAlignment);
Check(AttrAlign <= MaxAlign,
"Attribute 'align' exceed the max size 2^14", V);
}
SmallPtrSet<Type *, 4> Visited;
Check(Attrs.getByValType()->isSized(&Visited),
"Attribute 'byval' does not support unsized types!", V);
}
if (Attrs.hasAttribute(Attribute::ByRef)) {
SmallPtrSet<Type *, 4> Visited;
Check(Attrs.getByRefType()->isSized(&Visited),
"Attribute 'byref' does not support unsized types!", V);
}
if (Attrs.hasAttribute(Attribute::InAlloca)) {
SmallPtrSet<Type *, 4> Visited;
Check(Attrs.getInAllocaType()->isSized(&Visited),
"Attribute 'inalloca' does not support unsized types!", V);
}
if (Attrs.hasAttribute(Attribute::Preallocated)) {
SmallPtrSet<Type *, 4> Visited;
Check(Attrs.getPreallocatedType()->isSized(&Visited),
"Attribute 'preallocated' does not support unsized types!", V);
}
}
if (Attrs.hasAttribute(Attribute::NoFPClass)) {
uint64_t Val = Attrs.getAttribute(Attribute::NoFPClass).getValueAsInt();
Check(Val != 0, "Attribute 'nofpclass' must have at least one test bit set",
V);
Check((Val & ~static_cast<unsigned>(fcAllFlags)) == 0,
"Invalid value for 'nofpclass' test mask", V);
}
if (Attrs.hasAttribute(Attribute::Range)) {
auto CR = Attrs.getAttribute(Attribute::Range).getValueAsConstantRange();
Check(Ty->isIntOrIntVectorTy(CR.getBitWidth()),
"Range bit width must match type bit width!", V);
}
}
void Verifier::checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr,
const Value *V) {
if (Attrs.hasFnAttr(Attr)) {
StringRef S = Attrs.getFnAttr(Attr).getValueAsString();
unsigned N;
if (S.getAsInteger(10, N))
CheckFailed("\"" + Attr + "\" takes an unsigned integer: " + S, V);
}
}
// Check parameter attributes against a function type.
// The value V is printed in error messages.
void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
const Value *V, bool IsIntrinsic,
bool IsInlineAsm) {
if (Attrs.isEmpty())
return;
if (AttributeListsVisited.insert(Attrs.getRawPointer()).second) {
Check(Attrs.hasParentContext(Context),
"Attribute list does not match Module context!", &Attrs, V);
for (const auto &AttrSet : Attrs) {
Check(!AttrSet.hasAttributes() || AttrSet.hasParentContext(Context),
"Attribute set does not match Module context!", &AttrSet, V);
for (const auto &A : AttrSet) {
Check(A.hasParentContext(Context),
"Attribute does not match Module context!", &A, V);
}
}
}
bool SawNest = false;
bool SawReturned = false;
bool SawSRet = false;
bool SawSwiftSelf = false;
bool SawSwiftAsync = false;
bool SawSwiftError = false;
// Verify return value attributes.
AttributeSet RetAttrs = Attrs.getRetAttrs();
for (Attribute RetAttr : RetAttrs)
Check(RetAttr.isStringAttribute() ||
Attribute::canUseAsRetAttr(RetAttr.getKindAsEnum()),
"Attribute '" + RetAttr.getAsString() +
"' does not apply to function return values",
V);
unsigned MaxParameterWidth = 0;
auto GetMaxParameterWidth = [&MaxParameterWidth](Type *Ty) {
if (Ty->isVectorTy()) {
if (auto *VT = dyn_cast<FixedVectorType>(Ty)) {
unsigned Size = VT->getPrimitiveSizeInBits().getFixedValue();
if (Size > MaxParameterWidth)
MaxParameterWidth = Size;
}
}
};
GetMaxParameterWidth(FT->getReturnType());
verifyParameterAttrs(RetAttrs, FT->getReturnType(), V);
// Verify parameter attributes.
for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
Type *Ty = FT->getParamType(i);
AttributeSet ArgAttrs = Attrs.getParamAttrs(i);
if (!IsIntrinsic) {
Check(!ArgAttrs.hasAttribute(Attribute::ImmArg),
"immarg attribute only applies to intrinsics", V);
if (!IsInlineAsm)
Check(!ArgAttrs.hasAttribute(Attribute::ElementType),
"Attribute 'elementtype' can only be applied to intrinsics"
" and inline asm.",
V);
}
verifyParameterAttrs(ArgAttrs, Ty, V);
GetMaxParameterWidth(Ty);
if (ArgAttrs.hasAttribute(Attribute::Nest)) {
Check(!SawNest, "More than one parameter has attribute nest!", V);
SawNest = true;
}
if (ArgAttrs.hasAttribute(Attribute::Returned)) {
Check(!SawReturned, "More than one parameter has attribute returned!", V);
Check(Ty->canLosslesslyBitCastTo(FT->getReturnType()),
"Incompatible argument and return types for 'returned' attribute",
V);
SawReturned = true;
}
if (ArgAttrs.hasAttribute(Attribute::StructRet)) {
Check(!SawSRet, "Cannot have multiple 'sret' parameters!", V);
Check(i == 0 || i == 1,
"Attribute 'sret' is not on first or second parameter!", V);
SawSRet = true;
}
if (ArgAttrs.hasAttribute(Attribute::SwiftSelf)) {
Check(!SawSwiftSelf, "Cannot have multiple 'swiftself' parameters!", V);
SawSwiftSelf = true;
}
if (ArgAttrs.hasAttribute(Attribute::SwiftAsync)) {
Check(!SawSwiftAsync, "Cannot have multiple 'swiftasync' parameters!", V);
SawSwiftAsync = true;
}
if (ArgAttrs.hasAttribute(Attribute::SwiftError)) {
Check(!SawSwiftError, "Cannot have multiple 'swifterror' parameters!", V);
SawSwiftError = true;
}
if (ArgAttrs.hasAttribute(Attribute::InAlloca)) {
Check(i == FT->getNumParams() - 1,
"inalloca isn't on the last parameter!", V);
}
}
if (!Attrs.hasFnAttrs())
return;
verifyAttributeTypes(Attrs.getFnAttrs(), V);
for (Attribute FnAttr : Attrs.getFnAttrs())
Check(FnAttr.isStringAttribute() ||
Attribute::canUseAsFnAttr(FnAttr.getKindAsEnum()),
"Attribute '" + FnAttr.getAsString() +
"' does not apply to functions!",
V);
Check(!(Attrs.hasFnAttr(Attribute::NoInline) &&
Attrs.hasFnAttr(Attribute::AlwaysInline)),
"Attributes 'noinline and alwaysinline' are incompatible!", V);
if (Attrs.hasFnAttr(Attribute::OptimizeNone)) {
Check(Attrs.hasFnAttr(Attribute::NoInline),
"Attribute 'optnone' requires 'noinline'!", V);
Check(!Attrs.hasFnAttr(Attribute::OptimizeForSize),
"Attributes 'optsize and optnone' are incompatible!", V);
Check(!Attrs.hasFnAttr(Attribute::MinSize),
"Attributes 'minsize and optnone' are incompatible!", V);
Check(!Attrs.hasFnAttr(Attribute::OptimizeForDebugging),
"Attributes 'optdebug and optnone' are incompatible!", V);
}
if (Attrs.hasFnAttr(Attribute::OptimizeForDebugging)) {
Check(!Attrs.hasFnAttr(Attribute::OptimizeForSize),
"Attributes 'optsize and optdebug' are incompatible!", V);
Check(!Attrs.hasFnAttr(Attribute::MinSize),
"Attributes 'minsize and optdebug' are incompatible!", V);
}
Check(!Attrs.hasAttrSomewhere(Attribute::Writable) ||
isModSet(Attrs.getMemoryEffects().getModRef(IRMemLocation::ArgMem)),
"Attribute writable and memory without argmem: write are incompatible!",
V);
if (Attrs.hasFnAttr("aarch64_pstate_sm_enabled")) {
Check(!Attrs.hasFnAttr("aarch64_pstate_sm_compatible"),
"Attributes 'aarch64_pstate_sm_enabled and "
"aarch64_pstate_sm_compatible' are incompatible!",
V);
}
Check((Attrs.hasFnAttr("aarch64_new_za") + Attrs.hasFnAttr("aarch64_in_za") +
Attrs.hasFnAttr("aarch64_inout_za") +
Attrs.hasFnAttr("aarch64_out_za") +
Attrs.hasFnAttr("aarch64_preserves_za")) <= 1,
"Attributes 'aarch64_new_za', 'aarch64_in_za', 'aarch64_out_za', "
"'aarch64_inout_za' and 'aarch64_preserves_za' are mutually exclusive",
V);
Check(
(Attrs.hasFnAttr("aarch64_new_zt0") + Attrs.hasFnAttr("aarch64_in_zt0") +
Attrs.hasFnAttr("aarch64_inout_zt0") +
Attrs.hasFnAttr("aarch64_out_zt0") +
Attrs.hasFnAttr("aarch64_preserves_zt0")) <= 1,
"Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', "
"'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive",
V);
if (Attrs.hasFnAttr(Attribute::JumpTable)) {
const GlobalValue *GV = cast<GlobalValue>(V);
Check(GV->hasGlobalUnnamedAddr(),
"Attribute 'jumptable' requires 'unnamed_addr'", V);
}
if (auto Args = Attrs.getFnAttrs().getAllocSizeArgs()) {
auto CheckParam = [&](StringRef Name, unsigned ParamNo) {
if (ParamNo >= FT->getNumParams()) {
CheckFailed("'allocsize' " + Name + " argument is out of bounds", V);
return false;
}
if (!FT->getParamType(ParamNo)->isIntegerTy()) {
CheckFailed("'allocsize' " + Name +
" argument must refer to an integer parameter",
V);
return false;
}
return true;
};
if (!CheckParam("element size", Args->first))
return;
if (Args->second && !CheckParam("number of elements", *Args->second))
return;
}
if (Attrs.hasFnAttr(Attribute::AllocKind)) {
AllocFnKind K = Attrs.getAllocKind();
AllocFnKind Type =
K & (AllocFnKind::Alloc | AllocFnKind::Realloc | AllocFnKind::Free);
if (!is_contained(
{AllocFnKind::Alloc, AllocFnKind::Realloc, AllocFnKind::Free},
Type))
CheckFailed(
"'allockind()' requires exactly one of alloc, realloc, and free");
if ((Type == AllocFnKind::Free) &&
((K & (AllocFnKind::Uninitialized | AllocFnKind::Zeroed |
AllocFnKind::Aligned)) != AllocFnKind::Unknown))
CheckFailed("'allockind(\"free\")' doesn't allow uninitialized, zeroed, "
"or aligned modifiers.");
AllocFnKind ZeroedUninit = AllocFnKind::Uninitialized | AllocFnKind::Zeroed;
if ((K & ZeroedUninit) == ZeroedUninit)
CheckFailed("'allockind()' can't be both zeroed and uninitialized");
}
if (Attrs.hasFnAttr(Attribute::VScaleRange)) {
unsigned VScaleMin = Attrs.getFnAttrs().getVScaleRangeMin();
if (VScaleMin == 0)
CheckFailed("'vscale_range' minimum must be greater than 0", V);
else if (!isPowerOf2_32(VScaleMin))
CheckFailed("'vscale_range' minimum must be power-of-two value", V);
std::optional<unsigned> VScaleMax = Attrs.getFnAttrs().getVScaleRangeMax();
if (VScaleMax && VScaleMin > VScaleMax)
CheckFailed("'vscale_range' minimum cannot be greater than maximum", V);
else if (VScaleMax && !isPowerOf2_32(*VScaleMax))
CheckFailed("'vscale_range' maximum must be power-of-two value", V);
}
if (Attrs.hasFnAttr("frame-pointer")) {
StringRef FP = Attrs.getFnAttr("frame-pointer").getValueAsString();
if (FP != "all" && FP != "non-leaf" && FP != "none")
CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V);
}
// Check EVEX512 feature.
if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") &&
TT.isX86()) {
StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
"512-bit vector arguments require 'evex512' for AVX512", V);
}
checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V);
checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-entry", V);
checkUnsignedBaseTenFuncAttr(Attrs, "warn-stack-size", V);
if (auto A = Attrs.getFnAttr("sign-return-address"); A.isValid()) {
StringRef S = A.getValueAsString();
if (S != "none" && S != "all" && S != "non-leaf")
CheckFailed("invalid value for 'sign-return-address' attribute: " + S, V);
}
if (auto A = Attrs.getFnAttr("sign-return-address-key"); A.isValid()) {
StringRef S = A.getValueAsString();
if (S != "a_key" && S != "b_key")
CheckFailed("invalid value for 'sign-return-address-key' attribute: " + S,
V);
}
if (auto A = Attrs.getFnAttr("branch-target-enforcement"); A.isValid()) {
StringRef S = A.getValueAsString();
if (S != "true" && S != "false")
CheckFailed(
"invalid value for 'branch-target-enforcement' attribute: " + S, V);
}
if (auto A = Attrs.getFnAttr("vector-function-abi-variant"); A.isValid()) {
StringRef S = A.getValueAsString();
const std::optional<VFInfo> Info = VFABI::tryDemangleForVFABI(S, FT);
if (!Info)
CheckFailed("invalid name for a VFABI variant: " + S, V);
}
}
void Verifier::verifyFunctionMetadata(
ArrayRef<std::pair<unsigned, MDNode *>> MDs) {
for (const auto &Pair : MDs) {
if (Pair.first == LLVMContext::MD_prof) {
MDNode *MD = Pair.second;
Check(MD->getNumOperands() >= 2,
"!prof annotations should have no less than 2 operands", MD);
// Check first operand.
Check(MD->getOperand(0) != nullptr, "first operand should not be null",
MD);
Check(isa<MDString>(MD->getOperand(0)),
"expected string with name of the !prof annotation", MD);
MDString *MDS = cast<MDString>(MD->getOperand(0));
StringRef ProfName = MDS->getString();
Check(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.
Check(MD->getOperand(1) != nullptr, "second operand should not be null",
MD);
Check(isa<ConstantAsMetadata>(MD->getOperand(1)),
"expected integer argument to function_entry_count", MD);
} else if (Pair.first == LLVMContext::MD_kcfi_type) {
MDNode *MD = Pair.second;
Check(MD->getNumOperands() == 1,
"!kcfi_type must have exactly one operand", MD);
Check(MD->getOperand(0) != nullptr, "!kcfi_type operand must not be null",
MD);
Check(isa<ConstantAsMetadata>(MD->getOperand(0)),
"expected a constant operand for !kcfi_type", MD);
Constant *C = cast<ConstantAsMetadata>(MD->getOperand(0))->getValue();
Check(isa<ConstantInt>(C) && isa<IntegerType>(C->getType()),
"expected a constant integer operand for !kcfi_type", MD);
Check(cast<ConstantInt>(C)->getBitWidth() == 32,
"expected a 32-bit integer constant operand for !kcfi_type", MD);
}
}
}
void Verifier::visitConstantExprsRecursively(const Constant *EntryC) {
if (!ConstantExprVisited.insert(EntryC).second)
return;
SmallVector<const Constant *, 16> Stack;
Stack.push_back(EntryC);
while (!Stack.empty()) {
const Constant *C = Stack.pop_back_val();
// Check this constant expression.
if (const auto *CE = dyn_cast<ConstantExpr>(C))
visitConstantExpr(CE);
if (const auto *GV = dyn_cast<GlobalValue>(C)) {
// Global Values get visited separately, but we do need to make sure
// that the global value is in the correct module
Check(GV->getParent() == &M, "Referencing global in another module!",
EntryC, &M, GV, GV->getParent());
continue;
}
// Visit all sub-expressions.
for (const Use &U : C->operands()) {
const auto *OpC = dyn_cast<Constant>(U);
if (!OpC)
continue;
if (!ConstantExprVisited.insert(OpC).second)
continue;
Stack.push_back(OpC);
}
}
}
void Verifier::visitConstantExpr(const ConstantExpr *CE) {
if (CE->getOpcode() == Instruction::BitCast)
Check(CastInst::castIsValid(Instruction::BitCast, CE->getOperand(0),
CE->getType()),
"Invalid bitcast", CE);
}
bool Verifier::verifyAttributeCount(AttributeList Attrs, unsigned Params) {
// There shouldn't be more attribute sets than there are parameters plus the
// function and return value.
return Attrs.getNumAttrSets() <= Params + 2;
}
void Verifier::verifyInlineAsmCall(const CallBase &Call) {
const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
unsigned ArgNo = 0;
unsigned LabelNo = 0;
for (const InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) {
if (CI.Type == InlineAsm::isLabel) {
++LabelNo;
continue;
}
// Only deal with constraints that correspond to call arguments.
if (!CI.hasArg())
continue;
if (CI.isIndirect) {
const Value *Arg = Call.getArgOperand(ArgNo);
Check(Arg->getType()->isPointerTy(),
"Operand for indirect constraint must have pointer type", &Call);
Check(Call.getParamElementType(ArgNo),
"Operand for indirect constraint must have elementtype attribute",
&Call);
} else {
Check(!Call.paramHasAttr(ArgNo, Attribute::ElementType),
"Elementtype attribute can only be applied for indirect "
"constraints",
&Call);
}
ArgNo++;
}
if (auto *CallBr = dyn_cast<CallBrInst>(&Call)) {
Check(LabelNo == CallBr->getNumIndirectDests(),
"Number of label constraints does not match number of callbr dests",
&Call);
} else {
Check(LabelNo == 0, "Label constraints can only be used with callbr",
&Call);
}
}
/// Verify that statepoint intrinsic is well formed.
void Verifier::verifyStatepoint(const CallBase &Call) {
assert(Call.getCalledFunction() &&
Call.getCalledFunction()->getIntrinsicID() ==
Intrinsic::experimental_gc_statepoint);
Check(!Call.doesNotAccessMemory() && !Call.onlyReadsMemory() &&
!Call.onlyAccessesArgMemory(),
"gc.statepoint must read and write all memory to preserve "
"reordering restrictions required by safepoint semantics",
Call);
const int64_t NumPatchBytes =
cast<ConstantInt>(Call.getArgOperand(1))->getSExtValue();
assert(isInt<32>(NumPatchBytes) && "NumPatchBytesV is an i32!");
Check(NumPatchBytes >= 0,
"gc.statepoint number of patchable bytes must be "
"positive",
Call);
Type *TargetElemType = Call.getParamElementType(2);
Check(TargetElemType,
"gc.statepoint callee argument must have elementtype attribute", Call);
FunctionType *TargetFuncType = dyn_cast<FunctionType>(TargetElemType);
Check(TargetFuncType,
"gc.statepoint callee elementtype must be function type", Call);
const int NumCallArgs = cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue();
Check(NumCallArgs >= 0,
"gc.statepoint number of arguments to underlying call "
"must be positive",
Call);
const int NumParams = (int)TargetFuncType->getNumParams();
if (TargetFuncType->isVarArg()) {
Check(NumCallArgs >= NumParams,
"gc.statepoint mismatch in number of vararg call args", Call);
// TODO: Remove this limitation
Check(TargetFuncType->getReturnType()->isVoidTy(),
"gc.statepoint doesn't support wrapping non-void "
"vararg functions yet",
Call);
} else
Check(NumCallArgs == NumParams,
"gc.statepoint mismatch in number of call args", Call);
const uint64_t Flags
= cast<ConstantInt>(Call.getArgOperand(4))->getZExtValue();