diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -496,6 +496,13 @@ if (LargestVectorWidth) CurFn->addFnAttr("min-legal-vector-width", llvm::utostr(LargestVectorWidth)); + // Add vscale attribute if appropriate. + if (getLangOpts().ArmSveVectorBits) { + unsigned VScale = getLangOpts().ArmSveVectorBits / 128; + CurFn->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(getLLVMContext(), + VScale, VScale)); + } + // If we generated an unreachable return block, delete it now. if (ReturnBlock.isValid() && ReturnBlock.getBlock()->use_empty()) { Builder.ClearInsertionPoint(); diff --git a/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm-sve-vector-bits-vscale-range.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=128 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-128 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=256 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-256 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=512 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-512 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=1024 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-1024 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=2048 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-2048 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -msve-vector-bits=scalable -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE + +// CHECK-LABEL: @func() #0 +// CHECK-128: attributes #0 = { {{.*}} vscale_range(1,1) {{.*}} } +// CHECK-256: attributes #0 = { {{.*}} vscale_range(2,2) {{.*}} } +// CHECK-512: attributes #0 = { {{.*}} vscale_range(4,4) {{.*}} } +// CHECK-1024: attributes #0 = { {{.*}} vscale_range(8,8) {{.*}} } +// CHECK-2048: attributes #0 = { {{.*}} vscale_range(16,16) {{.*}} } +// CHECK-NONE-NOT: vscale_range +void func() {} diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst --- a/llvm/docs/BitCodeFormat.rst +++ b/llvm/docs/BitCodeFormat.rst @@ -1070,6 +1070,7 @@ * code 68: ``noundef`` * code 69: ``byref`` * code 70: ``mustprogress`` +* code 74: ``vscale_range([, ])`` .. note:: The ``allocsize`` attribute has a special encoding for its arguments. Its two @@ -1077,6 +1078,12 @@ (i.e. ``(EltSizeParam << 32) | NumEltsParam``), with ``NumEltsParam`` taking on the sentinel value -1 if it is not specified. +.. note:: + The ``vscale_range`` attribute has a special encoding for its arguments. Its two + arguments, which are 32-bit integers, are packed into one 64-bit integer value + (i.e. ``(Min << 32) | Max``), with ``Max`` taking on the value of ``Min`` if + it is not specified. + .. _TYPE_BLOCK: TYPE_BLOCK Contents diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1992,6 +1992,11 @@ function does not satisfy this contract, the behavior is undefined. This attribute does not apply transitively to callees, but does apply to call sites within the function. Note that `willreturn` implies `mustprogress`. +``vscale_range([, ])`` + This attribute indicates the minimum and maximum vscale value for the given + function. A value of 0 means unbounded. If the optional max value is omitted + then max is set to the value of min. If the attribute is not present, no + assumptions are made about the range of vscale. Call Site Attributes ---------------------- diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -659,6 +659,7 @@ ATTR_KIND_NO_CALLBACK = 71, ATTR_KIND_HOT = 72, ATTR_KIND_NO_PROFILE = 73, + ATTR_KIND_VSCALE_RANGE = 74, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -107,6 +107,8 @@ static Attribute getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, const Optional &NumElemsArg); + static Attribute getWithVScaleRangeArgs(LLVMContext &Context, + unsigned MinValue, unsigned MaxValue); static Attribute getWithByValType(LLVMContext &Context, Type *Ty); static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty); static Attribute getWithByRefType(LLVMContext &Context, Type *Ty); @@ -196,6 +198,10 @@ /// if not known). std::pair> getAllocSizeArgs() const; + /// Returns the argument numbers for the vscale_range attribute (or pair(0, 0) + /// if not known). + std::pair getVScaleRangeArgs() const; + /// The Attribute is converted to a string of equivalent mnemonic. This /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString(bool InAttrGrp = false) const; @@ -319,6 +325,7 @@ Type *getByRefType() const; Type *getPreallocatedType() const; std::pair> getAllocSizeArgs() const; + std::pair getVScaleRangeArgs() const; std::string getAsString(bool InAttrGrp = false) const; using iterator = const Attribute *; @@ -571,6 +578,13 @@ return addAllocSizeAttr(C, ArgNo + FirstArgIndex, ElemSizeArg, NumElemsArg); } + /// Add the vscale_range attribute to the attribute set at the given index. + /// Returns a new list because attribute lists are immutable. + LLVM_NODISCARD AttributeList addVScaleRangeAttr(LLVMContext &C, + unsigned Index, + unsigned MinValue, + unsigned MaxValue); + //===--------------------------------------------------------------------===// // AttributeList Accessors //===--------------------------------------------------------------------===// @@ -689,6 +703,9 @@ std::pair> getAllocSizeArgs(unsigned Index) const; + /// Get the vscale_range argument numbers (or pair(0, 0) if unknown). + std::pair getVScaleRangeArgs(unsigned Index) const; + /// Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; @@ -762,6 +779,7 @@ uint64_t DerefBytes = 0; uint64_t DerefOrNullBytes = 0; uint64_t AllocSizeArgs = 0; + uint64_t VScaleRangeArgs = 0; Type *ByValType = nullptr; Type *StructRetType = nullptr; Type *ByRefType = nullptr; @@ -864,6 +882,10 @@ /// doesn't exist, pair(0, 0) is returned. std::pair> getAllocSizeArgs() const; + /// Retrieve the vscale_range args, if the vscale_range attribute exists. If + /// it doesn't exist, pair(0, 0) is returned. + std::pair getVScaleRangeArgs() const; + /// This turns an alignment into the form used internally in Attribute. /// This call has no effect if Align is not set. AttrBuilder &addAlignmentAttr(MaybeAlign Align); @@ -900,6 +922,9 @@ AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg, const Optional &NumElemsArg); + /// This turns two ints into the form used internally in Attribute. + AttrBuilder &addVScaleRangeAttr(unsigned MinValue, unsigned MaxValue); + /// This turns a byval type into the form used internally in Attribute. AttrBuilder &addByValAttr(Type *Ty); @@ -916,6 +941,10 @@ /// Attribute.getIntValue(). AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr); + /// Add an vscale_range attribute, using the representation returned by + /// Attribute.getIntValue(). + AttrBuilder &addVScaleRangeAttrFromRawRepr(uint64_t RawVScaleRangeRepr); + /// Return true if the builder contains no target-independent /// attributes. bool empty() const { return Attrs.none(); } diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -247,6 +247,9 @@ /// Function must be in a unwind table. def UWTable : EnumAttr<"uwtable">; +/// Minimum/Maximum vscale value for function. +def VScaleRange : IntAttr<"vscale_range">; + /// Function always comes back to callsite. def WillReturn : EnumAttr<"willreturn">; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -697,6 +697,7 @@ KEYWORD(swifterror); KEYWORD(swiftself); KEYWORD(uwtable); + KEYWORD(vscale_range); KEYWORD(willreturn); KEYWORD(writeonly); KEYWORD(zeroext); diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -281,6 +281,7 @@ bool parseOptionalCommaInAlloca(bool &IsInAlloca); bool parseAllocSizeArguments(unsigned &BaseSizeArg, Optional &HowManyArg); + bool parseVScaleRangeArguments(unsigned &MinValue, unsigned &MaxValue); bool parseIndexList(SmallVectorImpl &Indices, bool &AteExtraComma); bool parseIndexList(SmallVectorImpl &Indices) { diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1341,6 +1341,14 @@ B.addAllocSizeAttr(ElemSizeArg, NumElemsArg); continue; } + case lltok::kw_vscale_range: { + unsigned MinValue, MaxValue; + // inAttrGrp doesn't matter; we only support vscale_range(a[, b]) + if (parseVScaleRangeArguments(MinValue, MaxValue)) + return true; + B.addVScaleRangeAttr(MinValue, MaxValue); + continue; + } case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break; case lltok::kw_argmemonly: B.addAttribute(Attribute::ArgMemOnly); break; case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break; @@ -1806,6 +1814,7 @@ case lltok::kw_shadowcallstack: case lltok::kw_strictfp: case lltok::kw_uwtable: + case lltok::kw_vscale_range: HaveError |= error(Lex.getLoc(), "invalid use of function-only attribute"); break; @@ -1915,6 +1924,7 @@ case lltok::kw_shadowcallstack: case lltok::kw_strictfp: case lltok::kw_uwtable: + case lltok::kw_vscale_range: HaveError |= error(Lex.getLoc(), "invalid use of function-only attribute"); break; @@ -2355,6 +2365,29 @@ return false; } +bool LLParser::parseVScaleRangeArguments(unsigned &MinValue, + unsigned &MaxValue) { + Lex.Lex(); + + auto StartParen = Lex.getLoc(); + if (!EatIfPresent(lltok::lparen)) + return error(StartParen, "expected '('"); + + if (parseUInt32(MinValue)) + return true; + + if (EatIfPresent(lltok::comma)) { + if (parseUInt32(MaxValue)) + return true; + } else + MaxValue = MinValue; + + auto EndParen = Lex.getLoc(); + if (!EatIfPresent(lltok::rparen)) + return error(EndParen, "expected ')'"); + return false; +} + /// parseScopeAndOrdering /// if isAtomic: ::= SyncScope? AtomicOrdering /// else: ::= diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -240,6 +240,7 @@ kw_swifterror, kw_swiftself, kw_uwtable, + kw_vscale_range, kw_willreturn, kw_writeonly, kw_zeroext, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1526,6 +1526,8 @@ return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; + case bitc::ATTR_KIND_VSCALE_RANGE: + return Attribute::VScaleRange; case bitc::ATTR_KIND_WILLRETURN: return Attribute::WillReturn; case bitc::ATTR_KIND_WRITEONLY: @@ -1638,6 +1640,8 @@ B.addDereferenceableOrNullAttr(Record[++i]); else if (Kind == Attribute::AllocSize) B.addAllocSizeAttrFromRawRepr(Record[++i]); + else if (Kind == Attribute::VScaleRange) + B.addVScaleRangeAttrFromRawRepr(Record[++i]); } else if (Record[i] == 3 || Record[i] == 4) { // String attribute bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -738,6 +738,8 @@ return bitc::ATTR_KIND_SWIFT_SELF; case Attribute::UWTable: return bitc::ATTR_KIND_UW_TABLE; + case Attribute::VScaleRange: + return bitc::ATTR_KIND_VSCALE_RANGE; case Attribute::WillReturn: return bitc::ATTR_KIND_WILLRETURN; case Attribute::WriteOnly: diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h --- a/llvm/lib/IR/AttributeImpl.h +++ b/llvm/lib/IR/AttributeImpl.h @@ -252,6 +252,7 @@ uint64_t getDereferenceableBytes() const; uint64_t getDereferenceableOrNullBytes() const; std::pair> getAllocSizeArgs() const; + std::pair getVScaleRangeArgs() const; std::string getAsString(bool InAttrGrp) const; Type *getByValType() const; Type *getStructRetType() const; diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -78,6 +78,17 @@ return std::make_pair(ElemSizeArg, NumElemsArg); } +static uint64_t packVScaleRangeArgs(unsigned MinValue, unsigned MaxValue) { + return uint64_t(MinValue) << 32 | MaxValue; +} + +static std::pair unpackVScaleRangeArgs(uint64_t Value) { + unsigned MaxValue = Value & std::numeric_limits::max(); + unsigned MinValue = Value >> 32; + + return std::make_pair(MinValue, MaxValue); +} + Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, uint64_t Val) { LLVMContextImpl *pImpl = Context.pImpl; @@ -192,6 +203,12 @@ return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg)); } +Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context, + unsigned MinValue, + unsigned MaxValue) { + return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue)); +} + Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) { return StringSwitch(AttrName) #define GET_ATTR_NAMES @@ -220,7 +237,8 @@ AttrKind == Attribute::StackAlignment || AttrKind == Attribute::Dereferenceable || AttrKind == Attribute::AllocSize || - AttrKind == Attribute::DereferenceableOrNull; + AttrKind == Attribute::DereferenceableOrNull || + AttrKind == Attribute::VScaleRange; } bool Attribute::isExistingAttribute(StringRef Name) { @@ -328,6 +346,12 @@ return unpackAllocSizeArgs(pImpl->getValueAsInt()); } +std::pair Attribute::getVScaleRangeArgs() const { + assert(hasAttribute(Attribute::VScaleRange) && + "Trying to get vscale args from non-vscale attribute"); + return unpackVScaleRangeArgs(pImpl->getValueAsInt()); +} + std::string Attribute::getAsString(bool InAttrGrp) const { if (!pImpl) return {}; @@ -536,6 +560,18 @@ return Result; } + if (hasAttribute(Attribute::VScaleRange)) { + unsigned MinValue, MaxValue; + std::tie(MinValue, MaxValue) = getVScaleRangeArgs(); + + std::string Result = "vscale_range("; + Result += utostr(MinValue); + Result += ','; + Result += utostr(MaxValue); + Result += ')'; + return Result; + } + // Convert target-dependent attributes to strings of the form: // // "kind" @@ -778,6 +814,11 @@ : std::pair>(0, 0); } +std::pair AttributeSet::getVScaleRangeArgs() const { + return SetNode ? SetNode->getVScaleRangeArgs() + : std::pair(0, 0); +} + std::string AttributeSet::getAsString(bool InAttrGrp) const { return SetNode ? SetNode->getAsString(InAttrGrp) : ""; } @@ -895,6 +936,11 @@ Attr = Attribute::getWithAllocSizeArgs(C, A.first, A.second); break; } + case Attribute::VScaleRange: { + auto A = B.getVScaleRangeArgs(); + Attr = Attribute::getWithVScaleRangeArgs(C, A.first, A.second); + break; + } default: Attr = Attribute::get(C, Kind); } @@ -994,6 +1040,12 @@ return std::make_pair(0, 0); } +std::pair AttributeSetNode::getVScaleRangeArgs() const { + if (auto A = findEnumAttribute(Attribute::VScaleRange)) + return A->getVScaleRangeArgs(); + return std::make_pair(0, 0); +} + std::string AttributeSetNode::getAsString(bool InAttrGrp) const { std::string Str; for (iterator I = begin(), E = end(); I != E; ++I) { @@ -1427,6 +1479,14 @@ return addAttributes(C, Index, B); } +AttributeList AttributeList::addVScaleRangeAttr(LLVMContext &C, unsigned Index, + unsigned MinValue, + unsigned MaxValue) { + AttrBuilder B; + B.addVScaleRangeAttr(MinValue, MaxValue); + return addAttributes(C, Index, B); +} + //===----------------------------------------------------------------------===// // AttributeList Accessor Methods //===----------------------------------------------------------------------===// @@ -1524,6 +1584,11 @@ return getAttributes(Index).getAllocSizeArgs(); } +std::pair +AttributeList::getVScaleRangeArgs(unsigned Index) const { + return getAttributes(Index).getVScaleRangeArgs(); +} + std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const { return getAttributes(Index).getAsString(InAttrGrp); } @@ -1587,6 +1652,7 @@ StackAlignment.reset(); DerefBytes = DerefOrNullBytes = 0; AllocSizeArgs = 0; + VScaleRangeArgs = 0; ByValType = nullptr; StructRetType = nullptr; ByRefType = nullptr; @@ -1620,6 +1686,8 @@ DerefOrNullBytes = Attr.getDereferenceableOrNullBytes(); else if (Kind == Attribute::AllocSize) AllocSizeArgs = Attr.getValueAsInt(); + else if (Kind == Attribute::VScaleRange) + VScaleRangeArgs = Attr.getValueAsInt(); return *this; } @@ -1650,6 +1718,8 @@ DerefOrNullBytes = 0; else if (Val == Attribute::AllocSize) AllocSizeArgs = 0; + else if (Val == Attribute::VScaleRange) + VScaleRangeArgs = 0; return *this; } @@ -1670,6 +1740,10 @@ return unpackAllocSizeArgs(AllocSizeArgs); } +std::pair AttrBuilder::getVScaleRangeArgs() const { + return unpackVScaleRangeArgs(VScaleRangeArgs); +} + AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) { if (!Align) return *this; @@ -1726,6 +1800,22 @@ return *this; } +AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue, + unsigned MaxValue) { + return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue)); +} + +AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) { + // (0, 0) is our "not present" value, so we need to check for it here. + assert(RawArgs && "Invalid vscale arguments -- given vscale(0, 0)"); + + Attrs[Attribute::VScaleRange] = true; + // Reuse existing machinery to store this as a single 64-bit integer so we can + // save a few bytes over using a pair. + VScaleRangeArgs = RawArgs; + return *this; +} + AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { Attrs[Attribute::ByVal] = true; ByValType = Ty; @@ -1779,6 +1869,9 @@ if (!PreallocatedType) PreallocatedType = B.PreallocatedType; + if (!VScaleRangeArgs) + VScaleRangeArgs = B.VScaleRangeArgs; + Attrs |= B.Attrs; for (const auto &I : B.td_attrs()) @@ -1816,6 +1909,9 @@ if (B.PreallocatedType) PreallocatedType = nullptr; + if (B.VScaleRangeArgs) + VScaleRangeArgs = 0; + Attrs &= ~B.Attrs; for (const auto &I : B.td_attrs()) @@ -1876,7 +1972,8 @@ return Alignment == B.Alignment && StackAlignment == B.StackAlignment && DerefBytes == B.DerefBytes && ByValType == B.ByValType && StructRetType == B.StructRetType && ByRefType == B.ByRefType && - PreallocatedType == B.PreallocatedType; + PreallocatedType == B.PreallocatedType && + VScaleRangeArgs == B.VScaleRangeArgs; } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1629,6 +1629,7 @@ case Attribute::InlineHint: case Attribute::StackAlignment: case Attribute::UWTable: + case Attribute::VScaleRange: case Attribute::NonLazyBind: case Attribute::ReturnsTwice: case Attribute::SanitizeAddress: @@ -1987,6 +1988,14 @@ return; } + if (Attrs.hasFnAttribute(Attribute::VScaleRange)) { + std::pair 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(); diff --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp --- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -73,6 +73,7 @@ .Case("sspstrong", Attribute::StackProtectStrong) .Case("strictfp", Attribute::StrictFP) .Case("uwtable", Attribute::UWTable) + .Case("vscale_range", Attribute::VScaleRange) .Default(Attribute::None); } diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -970,6 +970,7 @@ case Attribute::StackProtectStrong: case Attribute::StrictFP: case Attribute::UWTable: + case Attribute::VScaleRange: case Attribute::NoCfCheck: case Attribute::MustProgress: case Attribute::NoProfile: diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -422,6 +422,18 @@ ret void } +; CHECK: define void @f72() #45 +define void @f72() vscale_range(8) +{ + ret void +} + +; CHECK: define void @f73() #46 +define void @f73() vscale_range(1,8) +{ + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -467,4 +479,6 @@ ; CHECK: attributes #42 = { nocallback } ; CHECK: attributes #43 = { cold } ; CHECK: attributes #44 = { hot } +; CHECK: attributes #45 = { vscale_range(8,8) } +; CHECK: attributes #46 = { vscale_range(1,8) } ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin } diff --git a/llvm/test/Verifier/vscale_range.ll b/llvm/test/Verifier/vscale_range.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/vscale_range.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK-NOT: 'vscale_range' minimum cannot be greater than maximum +declare i8* @a(i32) vscale_range(1, 0) + +; CHECK: 'vscale_range' minimum cannot be greater than maximum +declare i8* @b(i32*) vscale_range(8, 1)