aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/Verifier.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR/Verifier.cpp')
-rw-r--r--llvm/lib/IR/Verifier.cpp803
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());