diff options
Diffstat (limited to 'llvm/lib/IR/Verifier.cpp')
| -rw-r--r-- | llvm/lib/IR/Verifier.cpp | 803 |
1 files changed, 460 insertions, 343 deletions
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 100e881c8fa8..758205a39eb3 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -199,6 +199,27 @@ private: 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); + } + template <typename T> void Write(ArrayRef<T> Vs) { for (const T &V : Vs) Write(V); @@ -307,6 +328,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// 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 @@ -513,11 +537,13 @@ private: void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal); void verifySwiftErrorValue(const Value *SwiftErrorVal); + void verifyTailCCMustTailAttrs(AttrBuilder Attrs, StringRef Context); void verifyMustTailCall(CallInst &CI); bool verifyAttributeCount(AttributeList Attrs, unsigned Params); - void verifyAttributeTypes(AttributeSet Attrs, bool IsFunction, - const Value *V); + 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); void verifyFunctionMetadata(ArrayRef<std::pair<unsigned, MDNode *>> MDs); @@ -672,8 +698,9 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) { "the third field of the element type is mandatory, " "specify i8* null to migrate from the obsoleted 2-field form"); Type *ETy = STy->getTypeAtIndex(2); + Type *Int8Ty = Type::getInt8Ty(ETy->getContext()); Assert(ETy->isPointerTy() && - cast<PointerType>(ETy)->getElementType()->isIntegerTy(8), + cast<PointerType>(ETy)->isOpaqueOrPointeeTypeMatches(Int8Ty), "wrong type for intrinsic global variable", &GV); } } @@ -813,6 +840,9 @@ void Verifier::visitMDNode(const MDNode &MD, AreDebugLocsAllowed AllowLocs) { if (!MDNodes.insert(&MD).second) return; + Assert(&MD.getContext() == &Context, + "MDNode context does not match Module context!", &MD); + switch (MD.getMetadataID()) { default: llvm_unreachable("Invalid MDNode subclass"); @@ -919,8 +949,10 @@ void Verifier::visitDISubrange(const DISubrange &N) { "Subrange must contain count or upperBound", &N); AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(), "Subrange can have any one of count or upperBound", &N); - AssertDI(!N.getRawCountNode() || N.getCount(), - "Count must either be a signed constant or a DIVariable", &N); + auto *CBound = N.getRawCountNode(); + AssertDI(!CBound || isa<ConstantAsMetadata>(CBound) || + isa<DIVariable>(CBound) || isa<DIExpression>(CBound), + "Count must be signed constant or DIVariable or DIExpression", &N); auto Count = N.getCount(); AssertDI(!Count || !Count.is<ConstantInt *>() || Count.get<ConstantInt *>()->getSExtValue() >= -1, @@ -997,13 +1029,29 @@ void Verifier::visitDIDerivedType(const DIDerivedType &N) { N.getTag() == dwarf::DW_TAG_atomic_type || N.getTag() == dwarf::DW_TAG_member || N.getTag() == dwarf::DW_TAG_inheritance || - N.getTag() == dwarf::DW_TAG_friend, + 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) { AssertDI(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); + AssertDI( + (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); + } + } + AssertDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope()); AssertDI(isType(N.getRawBaseType()), "invalid base type", &N, N.getRawBaseType()); @@ -1070,12 +1118,6 @@ void Verifier::visitDICompositeType(const DICompositeType &N) { if (auto *Params = N.getRawTemplateParams()) visitTemplateParams(N, *Params); - if (N.getTag() == dwarf::DW_TAG_class_type || - N.getTag() == dwarf::DW_TAG_union_type) { - 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"); @@ -1307,6 +1349,13 @@ void Verifier::visitDIMacroFile(const DIMacroFile &N) { } } +void Verifier::visitDIArgList(const DIArgList &N) { + AssertDI(!N.getNumOperands(), + "DIArgList should have no operands other than a list of " + "ValueAsMetadata", + &N); +} + void Verifier::visitDIModule(const DIModule &N) { AssertDI(N.getTag() == dwarf::DW_TAG_module, "invalid tag", &N); AssertDI(!N.getName().empty(), "anonymous module", &N); @@ -1604,96 +1653,26 @@ void Verifier::visitModuleFlagCGProfileEntry(const MDOperand &MDO) { "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::NoMerge: - case Attribute::NoReturn: - case Attribute::NoSync: - case Attribute::WillReturn: - case Attribute::NoCallback: - case Attribute::NoCfCheck: - case Attribute::NoUnwind: - case Attribute::NoInline: - case Attribute::AlwaysInline: - case Attribute::OptimizeForSize: - case Attribute::StackProtect: - case Attribute::StackProtectReq: - case Attribute::StackProtectStrong: - case Attribute::SafeStack: - case Attribute::ShadowCallStack: - case Attribute::NoRedZone: - case Attribute::NoImplicitFloat: - case Attribute::Naked: - case Attribute::InlineHint: - case Attribute::StackAlignment: - case Attribute::UWTable: - case Attribute::NonLazyBind: - case Attribute::ReturnsTwice: - case Attribute::SanitizeAddress: - case Attribute::SanitizeHWAddress: - case Attribute::SanitizeMemTag: - case Attribute::SanitizeThread: - case Attribute::SanitizeMemory: - case Attribute::MinSize: - case Attribute::NoDuplicate: - case Attribute::Builtin: - case Attribute::NoBuiltin: - case Attribute::Cold: - case Attribute::Hot: - case Attribute::OptForFuzzing: - case Attribute::OptimizeNone: - case Attribute::JumpTable: - case Attribute::Convergent: - case Attribute::ArgMemOnly: - case Attribute::NoRecurse: - case Attribute::InaccessibleMemOnly: - case Attribute::InaccessibleMemOrArgMemOnly: - case Attribute::AllocSize: - case Attribute::SpeculativeLoadHardening: - case Attribute::Speculatable: - case Attribute::StrictFP: - case Attribute::NullPointerIsValid: - case Attribute::MustProgress: - case Attribute::NoProfile: - return true; - default: - break; - } - return false; -} +void Verifier::verifyAttributeTypes(AttributeSet Attrs, const Value *V) { + for (Attribute A : Attrs) { -/// Return true if this is a function attribute that can also appear on -/// arguments. -static bool isFuncOrArgAttr(Attribute::AttrKind Kind) { - return Kind == Attribute::ReadOnly || Kind == Attribute::WriteOnly || - Kind == Attribute::ReadNone || Kind == Attribute::NoFree || - Kind == Attribute::Preallocated; -} + 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 + \ + ""); \ + } -void Verifier::verifyAttributeTypes(AttributeSet Attrs, bool IsFunction, - const Value *V) { - for (Attribute A : Attrs) { - if (A.isStringAttribute()) +#include "llvm/IR/Attributes.inc" continue; - - if (A.isIntAttribute() != - Attribute::doesAttrKindHaveArgument(A.getKindAsEnum())) { - CheckFailed("Attribute '" + A.getAsString() + "' should have an Argument", - V); - return; } - if (isFuncOnlyAttr(A.getKindAsEnum())) { - if (!IsFunction) { - CheckFailed("Attribute '" + A.getAsString() + - "' only applies to functions!", - V); - return; - } - } else if (IsFunction && !isFuncOrArgAttr(A.getKindAsEnum())) { - CheckFailed("Attribute '" + A.getAsString() + - "' does not apply to functions!", + if (A.isIntAttribute() != Attribute::isIntAttrKind(A.getKindAsEnum())) { + CheckFailed("Attribute '" + A.getAsString() + "' should have an Argument", V); return; } @@ -1707,7 +1686,14 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, if (!Attrs.hasAttributes()) return; - verifyAttributeTypes(Attrs, /*IsFunction=*/false, V); + verifyAttributeTypes(Attrs, V); + + for (Attribute Attr : Attrs) + Assert(Attr.isStringAttribute() || + Attribute::canUseAsParamAttr(Attr.getKindAsEnum()), + "Attribute '" + Attr.getAsString() + + "' does not apply to parameters", + V); if (Attrs.hasAttribute(Attribute::ImmArg)) { Assert(Attrs.getNumAttributes() == 1, @@ -1772,53 +1758,78 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty, V); AttrBuilder IncompatibleAttrs = AttributeFuncs::typeIncompatible(Ty); - Assert(!AttrBuilder(Attrs).overlaps(IncompatibleAttrs), - "Wrong types for attribute: " + - AttributeSet::get(Context, IncompatibleAttrs).getAsString(), - V); + for (Attribute Attr : Attrs) { + if (!Attr.isStringAttribute() && + IncompatibleAttrs.contains(Attr.getKindAsEnum())) { + CheckFailed("Attribute '" + Attr.getAsString() + + "' applied to incompatible type!", V); + return; + } + } if (PointerType *PTy = dyn_cast<PointerType>(Ty)) { - SmallPtrSet<Type*, 4> Visited; - if (!PTy->getElementType()->isSized(&Visited)) { - Assert(!Attrs.hasAttribute(Attribute::ByVal) && - !Attrs.hasAttribute(Attribute::ByRef) && - !Attrs.hasAttribute(Attribute::InAlloca) && - !Attrs.hasAttribute(Attribute::Preallocated), - "Attributes 'byval', 'byref', 'inalloca', and 'preallocated' do not " - "support unsized types!", - V); + if (Attrs.hasAttribute(Attribute::ByVal)) { + SmallPtrSet<Type *, 4> Visited; + Assert(Attrs.getByValType()->isSized(&Visited), + "Attribute 'byval' does not support unsized types!", V); } - if (!isa<PointerType>(PTy->getElementType())) - Assert(!Attrs.hasAttribute(Attribute::SwiftError), - "Attribute 'swifterror' only applies to parameters " - "with pointer to pointer type!", - V); - if (Attrs.hasAttribute(Attribute::ByRef)) { - Assert(Attrs.getByRefType() == PTy->getElementType(), - "Attribute 'byref' type does not match parameter!", V); + SmallPtrSet<Type *, 4> Visited; + Assert(Attrs.getByRefType()->isSized(&Visited), + "Attribute 'byref' does not support unsized types!", V); } - - if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) { - Assert(Attrs.getByValType() == PTy->getElementType(), - "Attribute 'byval' type does not match parameter!", V); + if (Attrs.hasAttribute(Attribute::InAlloca)) { + SmallPtrSet<Type *, 4> Visited; + Assert(Attrs.getInAllocaType()->isSized(&Visited), + "Attribute 'inalloca' does not support unsized types!", V); } - if (Attrs.hasAttribute(Attribute::Preallocated)) { - Assert(Attrs.getPreallocatedType() == PTy->getElementType(), - "Attribute 'preallocated' type does not match parameter!", V); + SmallPtrSet<Type *, 4> Visited; + Assert(Attrs.getPreallocatedType()->isSized(&Visited), + "Attribute 'preallocated' does not support unsized types!", V); } - } else { - Assert(!Attrs.hasAttribute(Attribute::ByVal), - "Attribute 'byval' only applies to parameters with pointer type!", - V); - Assert(!Attrs.hasAttribute(Attribute::ByRef), - "Attribute 'byref' only applies to parameters with pointer type!", - V); - Assert(!Attrs.hasAttribute(Attribute::SwiftError), - "Attribute 'swifterror' only applies to parameters " - "with pointer type!", - V); + if (!PTy->isOpaque()) { + if (!isa<PointerType>(PTy->getElementType())) + Assert(!Attrs.hasAttribute(Attribute::SwiftError), + "Attribute 'swifterror' only applies to parameters " + "with pointer to pointer type!", + V); + if (Attrs.hasAttribute(Attribute::ByRef)) { + Assert(Attrs.getByRefType() == PTy->getElementType(), + "Attribute 'byref' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::ByVal) && Attrs.getByValType()) { + Assert(Attrs.getByValType() == PTy->getElementType(), + "Attribute 'byval' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::Preallocated)) { + Assert(Attrs.getPreallocatedType() == PTy->getElementType(), + "Attribute 'preallocated' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::InAlloca)) { + Assert(Attrs.getInAllocaType() == PTy->getElementType(), + "Attribute 'inalloca' type does not match parameter!", V); + } + + if (Attrs.hasAttribute(Attribute::ElementType)) { + Assert(Attrs.getElementType() == PTy->getElementType(), + "Attribute 'elementtype' type does not match parameter!", V); + } + } + } +} + +void Verifier::checkUnsignedBaseTenFuncAttr(AttributeList Attrs, StringRef Attr, + const Value *V) { + if (Attrs.hasFnAttribute(Attr)) { + StringRef S = Attrs.getAttribute(AttributeList::FunctionIndex, Attr) + .getValueAsString(); + unsigned N; + if (S.getAsInteger(10, N)) + CheckFailed("\"" + Attr + "\" takes an unsigned integer: " + S, V); } } @@ -1829,36 +1840,35 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, if (Attrs.isEmpty()) return; + if (AttributeListsVisited.insert(Attrs.getRawPointer()).second) { + Assert(Attrs.hasParentContext(Context), + "Attribute list does not match Module context!", &Attrs, V); + for (const auto &AttrSet : Attrs) { + Assert(!AttrSet.hasAttributes() || AttrSet.hasParentContext(Context), + "Attribute set does not match Module context!", &AttrSet, V); + for (const auto &A : AttrSet) { + Assert(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.getRetAttributes(); - Assert((!RetAttrs.hasAttribute(Attribute::ByVal) && - !RetAttrs.hasAttribute(Attribute::Nest) && - !RetAttrs.hasAttribute(Attribute::StructRet) && - !RetAttrs.hasAttribute(Attribute::NoCapture) && - !RetAttrs.hasAttribute(Attribute::NoFree) && - !RetAttrs.hasAttribute(Attribute::Returned) && - !RetAttrs.hasAttribute(Attribute::InAlloca) && - !RetAttrs.hasAttribute(Attribute::Preallocated) && - !RetAttrs.hasAttribute(Attribute::ByRef) && - !RetAttrs.hasAttribute(Attribute::SwiftSelf) && - !RetAttrs.hasAttribute(Attribute::SwiftError)), - "Attributes 'byval', 'inalloca', 'preallocated', 'byref', " - "'nest', 'sret', 'nocapture', 'nofree', " - "'returned', 'swiftself', and 'swifterror' do not apply to return " - "values!", - V); - Assert((!RetAttrs.hasAttribute(Attribute::ReadOnly) && - !RetAttrs.hasAttribute(Attribute::WriteOnly) && - !RetAttrs.hasAttribute(Attribute::ReadNone)), - "Attribute '" + RetAttrs.getAsString() + - "' does not apply to function returns", - V); + for (Attribute RetAttr : RetAttrs) + Assert(RetAttr.isStringAttribute() || + Attribute::canUseAsRetAttr(RetAttr.getKindAsEnum()), + "Attribute '" + RetAttr.getAsString() + + "' does not apply to function return values", + V); + verifyParameterAttrs(RetAttrs, FT->getReturnType(), V); // Verify parameter attributes. @@ -1869,6 +1879,8 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, if (!IsIntrinsic) { Assert(!ArgAttrs.hasAttribute(Attribute::ImmArg), "immarg attribute only applies to intrinsics",V); + Assert(!ArgAttrs.hasAttribute(Attribute::ElementType), + "Attribute 'elementtype' can only be applied to intrinsics.", V); } verifyParameterAttrs(ArgAttrs, Ty, V); @@ -1899,6 +1911,11 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, SawSwiftSelf = true; } + if (ArgAttrs.hasAttribute(Attribute::SwiftAsync)) { + Assert(!SawSwiftAsync, "Cannot have multiple 'swiftasync' parameters!", V); + SawSwiftAsync = true; + } + if (ArgAttrs.hasAttribute(Attribute::SwiftError)) { Assert(!SawSwiftError, "Cannot have multiple 'swifterror' parameters!", V); @@ -1914,7 +1931,13 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, if (!Attrs.hasAttributes(AttributeList::FunctionIndex)) return; - verifyAttributeTypes(Attrs.getFnAttributes(), /*IsFunction=*/true, V); + verifyAttributeTypes(Attrs.getFnAttributes(), V); + for (Attribute FnAttr : Attrs.getFnAttributes()) + Assert(FnAttr.isStringAttribute() || + Attribute::canUseAsFnAttr(FnAttr.getKindAsEnum()), + "Attribute '" + FnAttr.getAsString() + + "' does not apply to functions!", + V); Assert(!(Attrs.hasFnAttribute(Attribute::ReadNone) && Attrs.hasFnAttribute(Attribute::ReadOnly)), @@ -1986,6 +2009,14 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, return; } + if (Attrs.hasFnAttribute(Attribute::VScaleRange)) { + std::pair<unsigned, unsigned> Args = + Attrs.getVScaleRangeArgs(AttributeList::FunctionIndex); + + if (Args.first > Args.second && Args.second != 0) + CheckFailed("'vscale_range' minimum cannot be greater than maximum", V); + } + if (Attrs.hasFnAttribute("frame-pointer")) { StringRef FP = Attrs.getAttribute(AttributeList::FunctionIndex, "frame-pointer").getValueAsString(); @@ -1993,26 +2024,9 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V); } - if (Attrs.hasFnAttribute("patchable-function-prefix")) { - StringRef S = Attrs - .getAttribute(AttributeList::FunctionIndex, - "patchable-function-prefix") - .getValueAsString(); - unsigned N; - if (S.getAsInteger(10, N)) - CheckFailed( - "\"patchable-function-prefix\" takes an unsigned integer: " + S, V); - } - if (Attrs.hasFnAttribute("patchable-function-entry")) { - StringRef S = Attrs - .getAttribute(AttributeList::FunctionIndex, - "patchable-function-entry") - .getValueAsString(); - unsigned N; - if (S.getAsInteger(10, N)) - CheckFailed( - "\"patchable-function-entry\" takes an unsigned integer: " + S, V); - } + checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V); + checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-entry", V); + checkUnsignedBaseTenFuncAttr(Attrs, "warn-stack-size", V); } void Verifier::verifyFunctionMetadata( @@ -2084,19 +2098,6 @@ void Verifier::visitConstantExpr(const ConstantExpr *CE) { Assert(CastInst::castIsValid(Instruction::BitCast, CE->getOperand(0), CE->getType()), "Invalid bitcast", CE); - - if (CE->getOpcode() == Instruction::IntToPtr || - CE->getOpcode() == Instruction::PtrToInt) { - auto *PtrTy = CE->getOpcode() == Instruction::IntToPtr - ? CE->getType() - : CE->getOperand(0)->getType(); - StringRef Msg = CE->getOpcode() == Instruction::IntToPtr - ? "inttoptr not supported for non-integral pointers" - : "ptrtoint not supported for non-integral pointers"; - Assert( - !DL.isNonIntegralPointerType(cast<PointerType>(PtrTy->getScalarType())), - Msg); - } } bool Verifier::verifyAttributeCount(AttributeList Attrs, unsigned Params) { @@ -2325,11 +2326,10 @@ void Verifier::visitFunction(const Function &F) { Assert(verifyAttributeCount(Attrs, FT->getNumParams()), "Attribute after last parameter!", &F); - bool isLLVMdotName = F.getName().size() >= 5 && - F.getName().substr(0, 5) == "llvm."; + bool IsIntrinsic = F.isIntrinsic(); // Check function attributes. - verifyFunctionAttrs(FT, Attrs, &F, isLLVMdotName); + verifyFunctionAttrs(FT, Attrs, &F, IsIntrinsic); // On function declarations/definitions, we do not support the builtin // attribute. We do not check this in VerifyFunctionAttrs since that is @@ -2337,6 +2337,9 @@ void Verifier::visitFunction(const Function &F) { Assert(!Attrs.hasFnAttribute(Attribute::Builtin), "Attribute 'builtin' can only be applied to a callsite.", &F); + Assert(!Attrs.hasAttrSomewhere(Attribute::ElementType), + "Attribute 'elementtype' can only be applied to a callsite.", &F); + // Check that this function meets the restrictions on this calling convention. // Sometimes varargs is used for perfectly forwarding thunks, so some of these // restrictions can be lifted. @@ -2403,11 +2406,13 @@ void Verifier::visitFunction(const Function &F) { FT->getParamType(i)); Assert(Arg.getType()->isFirstClassType(), "Function arguments must have first-class types!", &Arg); - if (!isLLVMdotName) { + if (!IsIntrinsic) { Assert(!Arg.getType()->isMetadataTy(), "Function takes metadata but isn't an intrinsic", &Arg, &F); Assert(!Arg.getType()->isTokenTy(), "Function takes token but isn't an intrinsic", &Arg, &F); + Assert(!Arg.getType()->isX86_AMXTy(), + "Function takes x86_amx but isn't an intrinsic", &Arg, &F); } // Check that swifterror argument is only used by loads and stores. @@ -2417,9 +2422,12 @@ void Verifier::visitFunction(const Function &F) { ++i; } - if (!isLLVMdotName) + if (!IsIntrinsic) { Assert(!F.getReturnType()->isTokenTy(), - "Functions returns a token but isn't an intrinsic", &F); + "Function returns a token but isn't an intrinsic", &F); + Assert(!F.getReturnType()->isX86_AMXTy(), + "Function returns a x86_amx but isn't an intrinsic", &F); + } // Get the function metadata attachments. SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; @@ -2458,7 +2466,7 @@ void Verifier::visitFunction(const Function &F) { } else { // Verify that this function (which has a body) is not named "llvm.*". It // is not legal to define intrinsics. - Assert(!isLLVMdotName, "llvm intrinsics cannot be defined!", &F); + Assert(!IsIntrinsic, "llvm intrinsics cannot be defined!", &F); // Check the entry node const BasicBlock *Entry = &F.getEntryBlock(); @@ -2513,12 +2521,35 @@ void Verifier::visitFunction(const Function &F) { // direct call/invokes, never having its "address taken". // Only do this if the module is materialized, otherwise we don't have all the // uses. - if (F.getIntrinsicID() && F.getParent()->isMaterialized()) { + if (F.isIntrinsic() && F.getParent()->isMaterialized()) { const User *U; if (F.hasAddressTaken(&U)) Assert(false, "Invalid user of intrinsic instruction!", U); } + // Check intrinsics' signatures. + switch (F.getIntrinsicID()) { + case Intrinsic::experimental_gc_get_pointer_base: { + FunctionType *FT = F.getFunctionType(); + Assert(FT->getNumParams() == 1, "wrong number of parameters", F); + Assert(isa<PointerType>(F.getReturnType()), + "gc.get.pointer.base must return a pointer", F); + Assert(FT->getParamType(0) == F.getReturnType(), + "gc.get.pointer.base operand and result must be of the same type", + F); + break; + } + case Intrinsic::experimental_gc_get_pointer_offset: { + FunctionType *FT = F.getFunctionType(); + Assert(FT->getNumParams() == 1, "wrong number of parameters", F); + Assert(isa<PointerType>(FT->getParamType(0)), + "gc.get.pointer.offset operand must be a pointer", F); + Assert(F.getReturnType()->isIntegerTy(), + "gc.get.pointer.offset must return integer", F); + break; + } + } + auto *N = F.getSubprogram(); HasDebugInfo = (N != nullptr); if (!HasDebugInfo) @@ -2689,6 +2720,8 @@ void Verifier::visitIndirectBrInst(IndirectBrInst &BI) { void Verifier::visitCallBrInst(CallBrInst &CBI) { Assert(CBI.isInlineAsm(), "Callbr is currently only used for asm-goto!", &CBI); + const InlineAsm *IA = cast<InlineAsm>(CBI.getCalledOperand()); + Assert(!IA->canThrow(), "Unwinding from Callbr is not allowed"); for (unsigned i = 0, e = CBI.getNumSuccessors(); i != e; ++i) Assert(CBI.getSuccessor(i)->getType()->isLabelTy(), "Callbr successors must all have pointer type!", &CBI); @@ -2917,10 +2950,6 @@ void Verifier::visitPtrToIntInst(PtrToIntInst &I) { Assert(SrcTy->isPtrOrPtrVectorTy(), "PtrToInt source must be pointer", &I); - if (auto *PTy = dyn_cast<PointerType>(SrcTy->getScalarType())) - Assert(!DL.isNonIntegralPointerType(PTy), - "ptrtoint not supported for non-integral pointers"); - Assert(DestTy->isIntOrIntVectorTy(), "PtrToInt result must be integral", &I); Assert(SrcTy->isVectorTy() == DestTy->isVectorTy(), "PtrToInt type mismatch", &I); @@ -2944,10 +2973,6 @@ void Verifier::visitIntToPtrInst(IntToPtrInst &I) { "IntToPtr source must be an integral", &I); Assert(DestTy->isPtrOrPtrVectorTy(), "IntToPtr result must be a pointer", &I); - if (auto *PTy = dyn_cast<PointerType>(DestTy->getScalarType())) - Assert(!DL.isNonIntegralPointerType(PTy), - "inttoptr not supported for non-integral pointers"); - Assert(SrcTy->isVectorTy() == DestTy->isVectorTy(), "IntToPtr type mismatch", &I); if (SrcTy->isVectorTy()) { @@ -3014,10 +3039,7 @@ void Verifier::visitCallBase(CallBase &Call) { "Called function must be a pointer!", Call); PointerType *FPTy = cast<PointerType>(Call.getCalledOperand()->getType()); - Assert(FPTy->getElementType()->isFunctionTy(), - "Called function is not pointer to function type!", Call); - - Assert(FPTy->getElementType() == Call.getFunctionType(), + Assert(FPTy->isOpaqueOrPointeeTypeMatches(Call.getFunctionType()), "Called function is not the same type as the call!", Call); FunctionType *FTy = Call.getFunctionType(); @@ -3042,11 +3064,12 @@ void Verifier::visitCallBase(CallBase &Call) { Assert(verifyAttributeCount(Attrs, Call.arg_size()), "Attribute after last parameter!", Call); - bool IsIntrinsic = Call.getCalledFunction() && - Call.getCalledFunction()->getName().startswith("llvm."); - Function *Callee = dyn_cast<Function>(Call.getCalledOperand()->stripPointerCasts()); + bool IsIntrinsic = Callee && Callee->isIntrinsic(); + if (IsIntrinsic) + Assert(Callee->getValueType() == FTy, + "Intrinsic called with incompatible signature", Call); if (Attrs.hasFnAttribute(Attribute::Speculatable)) { // Don't allow speculatable on call sites, unless the underlying function @@ -3180,9 +3203,12 @@ void Verifier::visitCallBase(CallBase &Call) { } // Verify that indirect calls don't return tokens. - if (!Call.getCalledFunction()) + if (!Call.getCalledFunction()) { Assert(!FTy->getReturnType()->isTokenTy(), "Return type cannot be token for indirect call!"); + Assert(!FTy->getReturnType()->isX86_AMXTy(), + "Return type cannot be x86_amx for indirect call!"); + } if (Function *F = Call.getCalledFunction()) if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) @@ -3193,7 +3219,8 @@ void Verifier::visitCallBase(CallBase &Call) { // and at most one "preallocated" operand bundle. bool FoundDeoptBundle = false, FoundFuncletBundle = false, FoundGCTransitionBundle = false, FoundCFGuardTargetBundle = false, - FoundPreallocatedBundle = false, FoundGCLiveBundle = false;; + FoundPreallocatedBundle = false, FoundGCLiveBundle = false, + FoundAttachedCallBundle = false; for (unsigned i = 0, e = Call.getNumOperandBundles(); i < e; ++i) { OperandBundleUse BU = Call.getOperandBundleAt(i); uint32_t Tag = BU.getTagID(); @@ -3234,9 +3261,21 @@ void Verifier::visitCallBase(CallBase &Call) { Assert(!FoundGCLiveBundle, "Multiple gc-live operand bundles", Call); FoundGCLiveBundle = true; + } else if (Tag == LLVMContext::OB_clang_arc_attachedcall) { + Assert(!FoundAttachedCallBundle, + "Multiple \"clang.arc.attachedcall\" operand bundles", Call); + FoundAttachedCallBundle = true; } } + if (FoundAttachedCallBundle) + Assert((FTy->getReturnType()->isPointerTy() || + (Call.doesNotReturn() && FTy->getReturnType()->isVoidTy())), + "a call with operand bundle \"clang.arc.attachedcall\" must call a " + "function returning a pointer or a non-returning function that has " + "a void return type", + Call); + // Verify that each inlinable callsite of a debug-info-bearing function in a // debug-info-bearing function has a debug location attached to it. Failure to // do so causes assertion failures when the inliner sets up inline scope info. @@ -3250,6 +3289,20 @@ void Verifier::visitCallBase(CallBase &Call) { visitInstruction(Call); } +void Verifier::verifyTailCCMustTailAttrs(AttrBuilder Attrs, + StringRef Context) { + Assert(!Attrs.contains(Attribute::InAlloca), + Twine("inalloca attribute not allowed in ") + Context); + Assert(!Attrs.contains(Attribute::InReg), + Twine("inreg attribute not allowed in ") + Context); + Assert(!Attrs.contains(Attribute::SwiftError), + Twine("swifterror attribute not allowed in ") + Context); + Assert(!Attrs.contains(Attribute::Preallocated), + Twine("preallocated attribute not allowed in ") + Context); + Assert(!Attrs.contains(Attribute::ByRef), + Twine("byref attribute not allowed in ") + Context); +} + /// Two types are "congruent" if they are identical, or if they are both pointer /// types with different pointee types and the same address space. static bool isTypeCongruent(Type *L, Type *R) { @@ -3264,13 +3317,15 @@ static bool isTypeCongruent(Type *L, Type *R) { static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { static const Attribute::AttrKind ABIAttrs[] = { - Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, - Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftError, - Attribute::Preallocated, Attribute::ByRef}; + Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca, + Attribute::InReg, Attribute::StackAlignment, Attribute::SwiftSelf, + Attribute::SwiftAsync, Attribute::SwiftError, Attribute::Preallocated, + Attribute::ByRef}; AttrBuilder Copy; for (auto AK : ABIAttrs) { - if (Attrs.hasParamAttribute(I, AK)) - Copy.addAttribute(AK); + Attribute Attr = Attrs.getParamAttributes(I).getAttribute(AK); + if (Attr.isValid()) + Copy.addAttribute(Attr); } // `align` is ABI-affecting only in combination with `byval` or `byref`. @@ -3284,22 +3339,9 @@ static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { void Verifier::verifyMustTailCall(CallInst &CI) { Assert(!CI.isInlineAsm(), "cannot use musttail call with inline asm", &CI); - // - The caller and callee prototypes must match. Pointer types of - // parameters or return types may differ in pointee type, but not - // address space. Function *F = CI.getParent()->getParent(); FunctionType *CallerTy = F->getFunctionType(); FunctionType *CalleeTy = CI.getFunctionType(); - 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()), @@ -3309,19 +3351,6 @@ void Verifier::verifyMustTailCall(CallInst &CI) { Assert(F->getCallingConv() == CI.getCallingConv(), "cannot guarantee tail call due to mismatched calling conv", &CI); - // - All ABI-impacting function attributes, such as sret, byval, inreg, - // returned, preallocated, and inalloca, must match. - AttributeList CallerAttrs = F->getAttributes(); - AttributeList CalleeAttrs = CI.getAttributes(); - for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) { - AttrBuilder CallerABIAttrs = getParameterABIAttributes(I, CallerAttrs); - AttrBuilder CalleeABIAttrs = getParameterABIAttributes(I, CalleeAttrs); - Assert(CallerABIAttrs == CalleeABIAttrs, - "cannot guarantee tail call due to mismatched ABI impacting " - "function attributes", - &CI, CI.getOperand(I)); - } - // - The call must immediately precede a :ref:`ret <i_ret>` instruction, // or a pointer bitcast followed by a ret instruction. // - The ret instruction must return the (possibly bitcasted) value @@ -3341,8 +3370,59 @@ void Verifier::verifyMustTailCall(CallInst &CI) { ReturnInst *Ret = dyn_cast_or_null<ReturnInst>(Next); Assert(Ret, "musttail call must precede a ret with an optional bitcast", &CI); - Assert(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal, + Assert(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal || + isa<UndefValue>(Ret->getReturnValue()), "musttail call result must be returned", Ret); + + AttributeList CallerAttrs = F->getAttributes(); + AttributeList CalleeAttrs = CI.getAttributes(); + if (CI.getCallingConv() == CallingConv::SwiftTail || + CI.getCallingConv() == CallingConv::Tail) { + StringRef CCName = + CI.getCallingConv() == CallingConv::Tail ? "tailcc" : "swifttailcc"; + + // - Only sret, byval, swiftself, and swiftasync ABI-impacting attributes + // are allowed in swifttailcc call + for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) { + AttrBuilder ABIAttrs = getParameterABIAttributes(I, CallerAttrs); + SmallString<32> Context{CCName, StringRef(" musttail caller")}; + verifyTailCCMustTailAttrs(ABIAttrs, Context); + } + for (int I = 0, E = CalleeTy->getNumParams(); I != E; ++I) { + AttrBuilder ABIAttrs = getParameterABIAttributes(I, CalleeAttrs); + SmallString<32> Context{CCName, StringRef(" musttail callee")}; + verifyTailCCMustTailAttrs(ABIAttrs, Context); + } + // - Varargs functions are not allowed + Assert(!CallerTy->isVarArg(), Twine("cannot guarantee ") + CCName + + " tail call for varargs function"); + return; + } + + // - The caller and callee prototypes must match. Pointer types of + // parameters or return types may differ in pointee type, but not + // address space. + 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); + } + } + + // - All ABI-impacting function attributes, such as sret, byval, inreg, + // returned, preallocated, and inalloca, must match. + for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) { + AttrBuilder CallerABIAttrs = getParameterABIAttributes(I, CallerAttrs); + AttrBuilder CalleeABIAttrs = getParameterABIAttributes(I, CalleeAttrs); + Assert(CallerABIAttrs == CalleeABIAttrs, + "cannot guarantee tail call due to mismatched ABI impacting " + "function attributes", + &CI, CI.getOperand(I)); + } } void Verifier::visitCallInst(CallInst &CI) { @@ -3639,8 +3719,8 @@ void Verifier::visitLoadInst(LoadInst &LI) { void Verifier::visitStoreInst(StoreInst &SI) { PointerType *PTy = dyn_cast<PointerType>(SI.getOperand(1)->getType()); Assert(PTy, "Store operand must be a pointer.", &SI); - Type *ElTy = PTy->getElementType(); - Assert(ElTy == SI.getOperand(0)->getType(), + Type *ElTy = SI.getOperand(0)->getType(); + Assert(PTy->isOpaqueOrPointeeTypeMatches(ElTy), "Stored value type does not match pointer operand type!", &SI, ElTy); Assert(SI.getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", &SI); @@ -3666,10 +3746,9 @@ void Verifier::visitStoreInst(StoreInst &SI) { /// Check that SwiftErrorVal is used as a swifterror argument in CS. void Verifier::verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal) { - unsigned Idx = 0; - for (auto I = Call.arg_begin(), E = Call.arg_end(); I != E; ++I, ++Idx) { - if (*I == SwiftErrorVal) { - Assert(Call.paramHasAttr(Idx, Attribute::SwiftError), + for (const auto &I : llvm::enumerate(Call.args())) { + if (I.value() == SwiftErrorVal) { + Assert(Call.paramHasAttr(I.index(), Attribute::SwiftError), "swifterror value when used in a callsite should be marked " "with swifterror attribute", SwiftErrorVal, Call); @@ -3698,11 +3777,6 @@ void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) { void Verifier::visitAllocaInst(AllocaInst &AI) { SmallPtrSet<Type*, 4> Visited; - PointerType *PTy = AI.getType(); - // TODO: Relax this restriction? - Assert(PTy->getAddressSpace() == DL.getAllocaAddrSpace(), - "Allocation instruction pointer not in the stack address space!", - &AI); Assert(AI.getAllocatedType()->isSized(&Visited), "Cannot allocate unsized type", &AI); Assert(AI.getArraySize()->getType()->isIntegerTy(), @@ -3718,47 +3792,18 @@ void Verifier::visitAllocaInst(AllocaInst &AI) { } void Verifier::visitAtomicCmpXchgInst(AtomicCmpXchgInst &CXI) { - - // FIXME: more conditions??? - Assert(CXI.getSuccessOrdering() != AtomicOrdering::NotAtomic, - "cmpxchg instructions must be atomic.", &CXI); - Assert(CXI.getFailureOrdering() != AtomicOrdering::NotAtomic, - "cmpxchg instructions must be atomic.", &CXI); - Assert(CXI.getSuccessOrdering() != AtomicOrdering::Unordered, - "cmpxchg instructions cannot be unordered.", &CXI); - Assert(CXI.getFailureOrdering() != AtomicOrdering::Unordered, - "cmpxchg instructions cannot be unordered.", &CXI); - Assert(!isStrongerThan(CXI.getFailureOrdering(), CXI.getSuccessOrdering()), - "cmpxchg instructions failure argument shall be no stronger than the " - "success argument", - &CXI); - Assert(CXI.getFailureOrdering() != AtomicOrdering::Release && - CXI.getFailureOrdering() != AtomicOrdering::AcquireRelease, - "cmpxchg failure ordering cannot include release semantics", &CXI); - - PointerType *PTy = dyn_cast<PointerType>(CXI.getOperand(0)->getType()); - Assert(PTy, "First cmpxchg operand must be a pointer.", &CXI); - Type *ElTy = PTy->getElementType(); + Type *ElTy = CXI.getOperand(1)->getType(); 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, - ElTy); - Assert(ElTy == CXI.getOperand(2)->getType(), - "Stored value type does not match pointer operand type!", &CXI, ElTy); visitInstruction(CXI); } void Verifier::visitAtomicRMWInst(AtomicRMWInst &RMWI) { - Assert(RMWI.getOrdering() != AtomicOrdering::NotAtomic, - "atomicrmw instructions must be atomic.", &RMWI); Assert(RMWI.getOrdering() != AtomicOrdering::Unordered, "atomicrmw instructions cannot be unordered.", &RMWI); auto Op = RMWI.getOperation(); - PointerType *PTy = dyn_cast<PointerType>(RMWI.getOperand(0)->getType()); - Assert(PTy, "First atomicrmw operand must be a pointer.", &RMWI); - Type *ElTy = PTy->getElementType(); + Type *ElTy = RMWI.getOperand(1)->getType(); if (Op == AtomicRMWInst::Xchg) { Assert(ElTy->isIntegerTy() || ElTy->isFloatingPointTy(), "atomicrmw " + AtomicRMWInst::getOperationName(Op) + @@ -3776,9 +3821,6 @@ void Verifier::visitAtomicRMWInst(AtomicRMWInst &RMWI) { &RMWI, ElTy); } checkAtomicMemAccessSize(ElTy, &RMWI); - Assert(ElTy == RMWI.getOperand(1)->getType(), - "Argument value type does not match pointer operand type!", &RMWI, - ElTy); Assert(AtomicRMWInst::FIRST_BINOP <= Op && Op <= AtomicRMWInst::LAST_BINOP, "Invalid binary operation!", &RMWI); visitInstruction(RMWI); @@ -4369,6 +4411,10 @@ void Verifier::visitInstruction(Instruction &I) { Assert( !F->isIntrinsic() || isa<CallInst>(I) || F->getIntrinsicID() == Intrinsic::donothing || + F->getIntrinsicID() == Intrinsic::seh_try_begin || + F->getIntrinsicID() == Intrinsic::seh_try_end || + F->getIntrinsicID() == Intrinsic::seh_scope_begin || + F->getIntrinsicID() == Intrinsic::seh_scope_end || F->getIntrinsicID() == Intrinsic::coro_resume || F->getIntrinsicID() == Intrinsic::coro_destroy || F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void || @@ -4395,12 +4441,9 @@ void Verifier::visitInstruction(Instruction &I) { Assert(CBI && &CBI->getCalledOperandUse() == &I.getOperandUse(i), "Cannot take the address of an inline asm!", &I); } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(I.getOperand(i))) { - if (CE->getType()->isPtrOrPtrVectorTy() || - !DL.getNonIntegralAddressSpaces().empty()) { + if (CE->getType()->isPtrOrPtrVectorTy()) { // If we have a ConstantExpr pointer, we need to see if it came from an - // illegal bitcast. If the datalayout string specifies non-integral - // address spaces then we also need to check for illegal ptrtoint and - // inttoptr expressions. + // illegal bitcast. visitConstantExprsRecursively(CE); } } @@ -4531,7 +4574,8 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { // know they are legal for the intrinsic!) get the intrinsic name through the // usual means. This allows us to verify the mangling of argument types into // the name. - const std::string ExpectedName = Intrinsic::getName(ID, ArgTys); + const std::string ExpectedName = + Intrinsic::getName(ID, ArgTys, IF->getParent(), IFTy); Assert(ExpectedName == IF->getName(), "Intrinsic name not mangled correctly for type arguments! " "Should be: " + @@ -4540,9 +4584,13 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { // If the intrinsic takes MDNode arguments, verify that they are either global // or are local to *this* function. - for (Value *V : Call.args()) + for (Value *V : Call.args()) { if (auto *MD = dyn_cast<MetadataAsValue>(V)) visitMetadataAsValue(*MD, Call.getCaller()); + if (auto *Const = dyn_cast<Constant>(V)) + Assert(!Const->getType()->isX86_AMXTy(), + "const x86_amx is not allowed in argument!"); + } switch (ID) { default: @@ -4570,14 +4618,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { Assert(ArgCount <= 2, "to many arguments"); if (Kind == Attribute::None) break; - if (Attribute::doesAttrKindHaveArgument(Kind)) { + if (Attribute::isIntAttrKind(Kind)) { Assert(ArgCount == 2, "this attribute should have 2 arguments"); Assert(isa<ConstantInt>(Call.getOperand(Elem.Begin + 1)), "the second argument should be a constant integral value"); - } else if (isFuncOnlyAttr(Kind)) { - Assert((ArgCount) == 0, "this attribute has no argument"); - } else if (!isFuncOrArgAttr(Kind)) { + } else if (Attribute::canUseAsParamAttr(Kind)) { Assert((ArgCount) == 1, "this attribute should have one argument"); + } else if (Attribute::canUseAsFnAttr(Kind)) { + Assert((ArgCount) == 0, "this attribute has no argument"); } } break; @@ -4588,12 +4636,12 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { break; auto *GV = dyn_cast<GlobalVariable>(InfoArg); Assert(GV && GV->isConstant() && GV->hasDefinitiveInitializer(), - "info argument of llvm.coro.begin must refer to an initialized " - "constant"); + "info argument of llvm.coro.id must refer to an initialized " + "constant"); Constant *Init = GV->getInitializer(); Assert(isa<ConstantStruct>(Init) || isa<ConstantArray>(Init), - "info argument of llvm.coro.begin must refer to either a struct or " - "an array"); + "info argument of llvm.coro.id must refer to either a struct or " + "an array"); break; } #define INSTRUCTION(NAME, NARGS, ROUND_MODE, INTRINSIC) \ @@ -4937,15 +4985,14 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { Assert(Alignment->getValue().isPowerOf2(), "masked_load: alignment must be a power of 2", Call); - // DataTy is the overloaded type - Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType(); - Assert(DataTy == Call.getType(), + PointerType *PtrTy = cast<PointerType>(Ptr->getType()); + Assert(PtrTy->isOpaqueOrPointeeTypeMatches(Call.getType()), "masked_load: return must match pointer type", Call); - Assert(PassThru->getType() == DataTy, - "masked_load: pass through and data type must match", Call); + Assert(PassThru->getType() == Call.getType(), + "masked_load: pass through and return type must match", Call); Assert(cast<VectorType>(Mask->getType())->getElementCount() == - cast<VectorType>(DataTy)->getElementCount(), - "masked_load: vector mask must be same length as data", Call); + cast<VectorType>(Call.getType())->getElementCount(), + "masked_load: vector mask must be same length as return", Call); break; } case Intrinsic::masked_store: { @@ -4958,13 +5005,12 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { Assert(Alignment->getValue().isPowerOf2(), "masked_store: alignment must be a power of 2", Call); - // DataTy is the overloaded type - Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType(); - Assert(DataTy == Val->getType(), + PointerType *PtrTy = cast<PointerType>(Ptr->getType()); + Assert(PtrTy->isOpaqueOrPointeeTypeMatches(Val->getType()), "masked_store: storee must match pointer type", Call); Assert(cast<VectorType>(Mask->getType())->getElementCount() == - cast<VectorType>(DataTy)->getElementCount(), - "masked_store: vector mask must be same length as data", Call); + cast<VectorType>(Val->getType())->getElementCount(), + "masked_store: vector mask must be same length as value", Call); break; } @@ -5013,20 +5059,34 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { break; } - case Intrinsic::sadd_sat: - case Intrinsic::uadd_sat: - case Intrinsic::ssub_sat: - case Intrinsic::usub_sat: - case Intrinsic::sshl_sat: - case Intrinsic::ushl_sat: { - Value *Op1 = Call.getArgOperand(0); - Value *Op2 = Call.getArgOperand(1); - Assert(Op1->getType()->isIntOrIntVectorTy(), - "first operand of [us][add|sub|shl]_sat must be an int type or " - "vector of ints"); - Assert(Op2->getType()->isIntOrIntVectorTy(), - "second operand of [us][add|sub|shl]_sat must be an int type or " - "vector of ints"); + case Intrinsic::vector_reduce_and: + case Intrinsic::vector_reduce_or: + case Intrinsic::vector_reduce_xor: + case Intrinsic::vector_reduce_add: + case Intrinsic::vector_reduce_mul: + case Intrinsic::vector_reduce_smax: + case Intrinsic::vector_reduce_smin: + case Intrinsic::vector_reduce_umax: + case Intrinsic::vector_reduce_umin: { + Type *ArgTy = Call.getArgOperand(0)->getType(); + Assert(ArgTy->isIntOrIntVectorTy() && ArgTy->isVectorTy(), + "Intrinsic has incorrect argument type!"); + break; + } + case Intrinsic::vector_reduce_fmax: + case Intrinsic::vector_reduce_fmin: { + Type *ArgTy = Call.getArgOperand(0)->getType(); + Assert(ArgTy->isFPOrFPVectorTy() && ArgTy->isVectorTy(), + "Intrinsic has incorrect argument type!"); + break; + } + case Intrinsic::vector_reduce_fadd: + case Intrinsic::vector_reduce_fmul: { + // Unlike the other reductions, the first argument is a start value. The + // second argument is the vector to be reduced. + Type *ArgTy = Call.getArgOperand(1)->getType(); + Assert(ArgTy->isFPOrFPVectorTy() && ArgTy->isVectorTy(), + "Intrinsic has incorrect argument type!"); break; } case Intrinsic::smul_fix: @@ -5160,30 +5220,87 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { break; } + case Intrinsic::experimental_stepvector: { + VectorType *VecTy = dyn_cast<VectorType>(Call.getType()); + Assert(VecTy && VecTy->getScalarType()->isIntegerTy() && + VecTy->getScalarSizeInBits() >= 8, + "experimental_stepvector only supported for vectors of integers " + "with a bitwidth of at least 8.", + &Call); + break; + } case Intrinsic::experimental_vector_insert: { - VectorType *VecTy = cast<VectorType>(Call.getArgOperand(0)->getType()); - VectorType *SubVecTy = cast<VectorType>(Call.getArgOperand(1)->getType()); + Value *Vec = Call.getArgOperand(0); + Value *SubVec = Call.getArgOperand(1); + Value *Idx = Call.getArgOperand(2); + unsigned IdxN = cast<ConstantInt>(Idx)->getZExtValue(); + + VectorType *VecTy = cast<VectorType>(Vec->getType()); + VectorType *SubVecTy = cast<VectorType>(SubVec->getType()); + ElementCount VecEC = VecTy->getElementCount(); + ElementCount SubVecEC = SubVecTy->getElementCount(); Assert(VecTy->getElementType() == SubVecTy->getElementType(), "experimental_vector_insert parameters must have the same element " "type.", &Call); + Assert(IdxN % SubVecEC.getKnownMinValue() == 0, + "experimental_vector_insert index must be a constant multiple of " + "the subvector's known minimum vector length."); + + // If this insertion is not the 'mixed' case where a fixed vector is + // inserted into a scalable vector, ensure that the insertion of the + // subvector does not overrun the parent vector. + if (VecEC.isScalable() == SubVecEC.isScalable()) { + Assert( + IdxN < VecEC.getKnownMinValue() && + IdxN + SubVecEC.getKnownMinValue() <= VecEC.getKnownMinValue(), + "subvector operand of experimental_vector_insert would overrun the " + "vector being inserted into."); + } break; } case Intrinsic::experimental_vector_extract: { + Value *Vec = Call.getArgOperand(0); + Value *Idx = Call.getArgOperand(1); + unsigned IdxN = cast<ConstantInt>(Idx)->getZExtValue(); + VectorType *ResultTy = cast<VectorType>(Call.getType()); - VectorType *VecTy = cast<VectorType>(Call.getArgOperand(0)->getType()); + VectorType *VecTy = cast<VectorType>(Vec->getType()); + + ElementCount VecEC = VecTy->getElementCount(); + ElementCount ResultEC = ResultTy->getElementCount(); Assert(ResultTy->getElementType() == VecTy->getElementType(), "experimental_vector_extract result must have the same element " "type as the input vector.", &Call); + Assert(IdxN % ResultEC.getKnownMinValue() == 0, + "experimental_vector_extract index must be a constant multiple of " + "the result type's known minimum vector length."); + + // If this extraction is not the 'mixed' case where a fixed vector is is + // extracted from a scalable vector, ensure that the extraction does not + // overrun the parent vector. + if (VecEC.isScalable() == ResultEC.isScalable()) { + Assert(IdxN < VecEC.getKnownMinValue() && + IdxN + ResultEC.getKnownMinValue() <= VecEC.getKnownMinValue(), + "experimental_vector_extract would overrun."); + } break; } case Intrinsic::experimental_noalias_scope_decl: { NoAliasScopeDecls.push_back(cast<IntrinsicInst>(&Call)); break; } + case Intrinsic::preserve_array_access_index: + case Intrinsic::preserve_struct_access_index: { + Type *ElemTy = Call.getAttributes().getParamElementType(0); + Assert(ElemTy, + "Intrinsic requires elementtype attribute on first argument.", + &Call); + break; + } }; } @@ -5346,10 +5463,10 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { } void Verifier::visitDbgIntrinsic(StringRef Kind, DbgVariableIntrinsic &DII) { - auto *MD = cast<MetadataAsValue>(DII.getArgOperand(0))->getMetadata(); - AssertDI(isa<ValueAsMetadata>(MD) || - (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()), - "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD); + auto *MD = DII.getRawLocation(); + AssertDI(isa<ValueAsMetadata>(MD) || isa<DIArgList>(MD) || + (isa<MDNode>(MD) && !cast<MDNode>(MD)->getNumOperands()), + "invalid llvm.dbg." + Kind + " intrinsic address/value", &DII, MD); AssertDI(isa<DILocalVariable>(DII.getRawVariable()), "invalid llvm.dbg." + Kind + " intrinsic variable", &DII, DII.getRawVariable()); |
