forked from OSchip/llvm-project
[Clang][AArch64] Support AArch64 target(..) attribute formats.
This adds support under AArch64 for the target("..") attributes. The current parsing is very X86-shaped, this patch attempts to bring it line with the GCC implementation from https://gcc.gnu.org/onlinedocs/gcc/AArch64-Function-Attributes.html#AArch64-Function-Attributes. The supported formats are: - "arch=<arch>" strings, that specify the architecture features for a function as per the -march=arch+feature option. - "cpu=<cpu>" strings, that specify the target-cpu and any implied atributes as per the -mcpu=cpu+feature option. - "tune=<cpu>" strings, that specify the tune-cpu cpu for a function as per -mtune. - "+<feature>", "+no<feature>" enables/disables the specific feature, for compatibility with GCC target attributes. - "<feature>", "no-<feature>" enabled/disables the specific feature, for backward compatibility with previous releases. To do this, the parsing of target attributes has been moved into TargetInfo to give the target the opportunity to override the existing parsing. The only non-aarch64 change should be a minor alteration to the error message, specifying using "CPU" to describe the cpu, not "architecture", and the DuplicateArch/Tune from ParsedTargetAttr have been combined into a single option. Differential Revision: https://reviews.llvm.org/D133848
This commit is contained in:
parent
4a549be9c3
commit
781b491bba
|
@ -450,6 +450,14 @@ DWARF Support in Clang
|
|||
|
||||
Arm and AArch64 Support in Clang
|
||||
--------------------------------
|
||||
|
||||
- The target(..) function attributes for AArch64 now accept:
|
||||
|
||||
* ``"arch=<arch>"`` strings, that specify the architecture for a function as per the ``-march`` option.
|
||||
* ``"cpu=<cpu>"`` strings, that specify the cpu for a function as per the ``-mcpu`` option.
|
||||
* ``"tune=<cpu>"`` strings, that specify the tune cpu for a function as per ``-mtune``.
|
||||
* ``"+<feature>"``, ``"+no<feature>"`` enables/disables the specific feature, for compatibility with GCC target attributes.
|
||||
* ``"<feature>"``, ``"no-<feature>"`` enabled/disables the specific feature, for backward compatibility with previous releases.
|
||||
- ``-march`` values for targeting armv2, armv2A, armv3 and armv3M have been removed.
|
||||
Their presence gave the impression that Clang can correctly generate code for
|
||||
them, which it cannot.
|
||||
|
|
|
@ -365,17 +365,13 @@ static_assert(sizeof(ParamIdx) == sizeof(ParamIdx::SerialType),
|
|||
/// Contains information gathered from parsing the contents of TargetAttr.
|
||||
struct ParsedTargetAttr {
|
||||
std::vector<std::string> Features;
|
||||
StringRef Architecture;
|
||||
StringRef CPU;
|
||||
StringRef Tune;
|
||||
StringRef BranchProtection;
|
||||
bool DuplicateArchitecture = false;
|
||||
bool DuplicateTune = false;
|
||||
StringRef Duplicate;
|
||||
bool operator ==(const ParsedTargetAttr &Other) const {
|
||||
return DuplicateArchitecture == Other.DuplicateArchitecture &&
|
||||
DuplicateTune == Other.DuplicateTune &&
|
||||
Architecture == Other.Architecture &&
|
||||
Tune == Other.Tune &&
|
||||
BranchProtection == Other.BranchProtection &&
|
||||
return Duplicate == Other.Duplicate && CPU == Other.CPU &&
|
||||
Tune == Other.Tune && BranchProtection == Other.BranchProtection &&
|
||||
Features == Other.Features;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2697,10 +2697,6 @@ def Target : InheritableAttr {
|
|||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [TargetDocs];
|
||||
let AdditionalMembers = [{
|
||||
ParsedTargetAttr parse() const {
|
||||
return parse(getFeaturesStr());
|
||||
}
|
||||
|
||||
StringRef getArchitecture() const {
|
||||
StringRef Features = getFeaturesStr();
|
||||
if (Features == "default") return {};
|
||||
|
@ -2734,57 +2730,7 @@ def Target : InheritableAttr {
|
|||
}
|
||||
}
|
||||
|
||||
template<class Compare>
|
||||
ParsedTargetAttr parse(Compare cmp) const {
|
||||
ParsedTargetAttr Attrs = parse();
|
||||
llvm::sort(Attrs.Features, cmp);
|
||||
return Attrs;
|
||||
}
|
||||
|
||||
bool isDefaultVersion() const { return getFeaturesStr() == "default"; }
|
||||
|
||||
static ParsedTargetAttr parse(StringRef Features) {
|
||||
ParsedTargetAttr Ret;
|
||||
if (Features == "default") return Ret;
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
Features.split(AttrFeatures, ",");
|
||||
|
||||
// Grab the various features and prepend a "+" to turn on the feature to
|
||||
// the backend and add them to our existing set of features.
|
||||
for (auto &Feature : AttrFeatures) {
|
||||
// Go ahead and trim whitespace rather than either erroring or
|
||||
// accepting it weirdly.
|
||||
Feature = Feature.trim();
|
||||
|
||||
// TODO: Support the fpmath option. It will require checking
|
||||
// overall feature validity for the function with the rest of the
|
||||
// attributes on the function.
|
||||
if (Feature.startswith("fpmath="))
|
||||
continue;
|
||||
|
||||
if (Feature.startswith("branch-protection=")) {
|
||||
Ret.BranchProtection = Feature.split('=').second.trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we're here iterating check for a different target cpu.
|
||||
if (Feature.startswith("arch=")) {
|
||||
if (!Ret.Architecture.empty())
|
||||
Ret.DuplicateArchitecture = true;
|
||||
else
|
||||
Ret.Architecture = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("tune=")) {
|
||||
if (!Ret.Tune.empty())
|
||||
Ret.DuplicateTune = true;
|
||||
else
|
||||
Ret.Tune = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("no-"))
|
||||
Ret.Features.push_back("-" + Feature.split("-").second.str());
|
||||
else
|
||||
Ret.Features.push_back("+" + Feature.str());
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -2345,9 +2345,12 @@ for the function.
|
|||
For X86, the attribute also allows ``tune="CPU"`` to optimize the generated
|
||||
code for the given CPU without changing the available instructions.
|
||||
|
||||
For AArch64, the attribute also allows the "branch-protection=<args>" option,
|
||||
where the permissible arguments and their effect on code generation are the same
|
||||
as for the command-line option ``-mbranch-protection``.
|
||||
For AArch64, ``arch="Arch"`` will set the architecture, similar to the -march
|
||||
command line options. ``cpu="CPU"`` can be used to select a specific cpu,
|
||||
as per the ``-mcpu`` option, similarly for ``tune=``. The attribute also allows the
|
||||
"branch-protection=<args>" option, where the permissible arguments and their
|
||||
effect on code generation are the same as for the command-line option
|
||||
``-mbranch-protection``.
|
||||
|
||||
Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2",
|
||||
"avx", "xop" and largely correspond to the machine specific options handled by
|
||||
|
|
|
@ -3050,7 +3050,7 @@ def warn_unsupported_branch_protection_spec : Warning<
|
|||
"unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
|
||||
|
||||
def warn_unsupported_target_attribute
|
||||
: Warning<"%select{unsupported|duplicate|unknown}0%select{| architecture|"
|
||||
: Warning<"%select{unsupported|duplicate|unknown}0%select{| CPU|"
|
||||
" tune CPU}1 '%2' in the '%select{target|target_clones}3' "
|
||||
"attribute string; '%select{target|target_clones}3' "
|
||||
"attribute ignored">,
|
||||
|
|
|
@ -49,6 +49,7 @@ class DiagnosticsEngine;
|
|||
class LangOptions;
|
||||
class CodeGenOptions;
|
||||
class MacroBuilder;
|
||||
class ParsedTargetAttr;
|
||||
|
||||
namespace Builtin { struct Info; }
|
||||
|
||||
|
@ -1281,6 +1282,8 @@ public:
|
|||
return isValidCPUName(Name);
|
||||
}
|
||||
|
||||
virtual ParsedTargetAttr parseTargetAttr(StringRef Str) const;
|
||||
|
||||
/// brief Determine whether this TargetInfo supports tune in target attribute.
|
||||
virtual bool supportsTargetAttributeTune() const {
|
||||
return false;
|
||||
|
|
|
@ -13255,7 +13255,7 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
|
|||
ParsedTargetAttr
|
||||
ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
|
||||
assert(TD != nullptr);
|
||||
ParsedTargetAttr ParsedAttr = TD->parse();
|
||||
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TD->getFeaturesStr());
|
||||
|
||||
llvm::erase_if(ParsedAttr.Features, [&](const std::string &Feat) {
|
||||
return !Target->isValidFeatureName(StringRef{Feat}.substr(1));
|
||||
|
@ -13289,9 +13289,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
|
|||
Target->getTargetOpts().FeaturesAsWritten.begin(),
|
||||
Target->getTargetOpts().FeaturesAsWritten.end());
|
||||
|
||||
if (ParsedAttr.Architecture != "" &&
|
||||
Target->isValidCPUName(ParsedAttr.Architecture))
|
||||
TargetCPU = ParsedAttr.Architecture;
|
||||
if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU))
|
||||
TargetCPU = ParsedAttr.CPU;
|
||||
|
||||
// Now populate the feature map, first with the TargetCPU which is either
|
||||
// the default or a new one from the target attribute string. Then we'll use
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/Basic/AddressSpaces.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
@ -507,6 +508,50 @@ bool TargetInfo::initFeatureMap(
|
|||
return true;
|
||||
}
|
||||
|
||||
ParsedTargetAttr TargetInfo::parseTargetAttr(StringRef Features) const {
|
||||
ParsedTargetAttr Ret;
|
||||
if (Features == "default")
|
||||
return Ret;
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
Features.split(AttrFeatures, ",");
|
||||
|
||||
// Grab the various features and prepend a "+" to turn on the feature to
|
||||
// the backend and add them to our existing set of features.
|
||||
for (auto &Feature : AttrFeatures) {
|
||||
// Go ahead and trim whitespace rather than either erroring or
|
||||
// accepting it weirdly.
|
||||
Feature = Feature.trim();
|
||||
|
||||
// TODO: Support the fpmath option. It will require checking
|
||||
// overall feature validity for the function with the rest of the
|
||||
// attributes on the function.
|
||||
if (Feature.startswith("fpmath="))
|
||||
continue;
|
||||
|
||||
if (Feature.startswith("branch-protection=")) {
|
||||
Ret.BranchProtection = Feature.split('=').second.trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
// While we're here iterating check for a different target cpu.
|
||||
if (Feature.startswith("arch=")) {
|
||||
if (!Ret.CPU.empty())
|
||||
Ret.Duplicate = "arch=";
|
||||
else
|
||||
Ret.CPU = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("tune=")) {
|
||||
if (!Ret.Tune.empty())
|
||||
Ret.Duplicate = "tune=";
|
||||
else
|
||||
Ret.Tune = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("no-"))
|
||||
Ret.Features.push_back("-" + Feature.split("-").second.str());
|
||||
else
|
||||
Ret.Features.push_back("+" + Feature.str());
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
TargetInfo::CallingConvKind
|
||||
TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
|
||||
if (getCXXABI() != TargetCXXABI::Microsoft &&
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AArch64.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
|
@ -699,6 +700,108 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::initFeatureMap(
|
||||
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
|
||||
const std::vector<std::string> &FeaturesVec) const {
|
||||
// Parse the CPU and add any implied features.
|
||||
llvm::AArch64::ArchKind Arch = llvm::AArch64::parseCPUArch(CPU);
|
||||
if (Arch != llvm::AArch64::ArchKind::INVALID) {
|
||||
uint64_t Exts = llvm::AArch64::getDefaultExtensions(CPU, Arch);
|
||||
std::vector<StringRef> CPUFeats;
|
||||
llvm::AArch64::getExtensionFeatures(Exts, CPUFeats);
|
||||
for (auto F : CPUFeats) {
|
||||
assert((F[0] == '+' || F[0] == '-') && "Expected +/- in target feature!");
|
||||
setFeatureEnabled(Features, F.drop_front(), F[0] == '+');
|
||||
}
|
||||
}
|
||||
|
||||
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
|
||||
}
|
||||
|
||||
// Parse AArch64 Target attributes, which are a comma separated list of:
|
||||
// "arch=<arch>" - parsed to features as per -march=..
|
||||
// "cpu=<cpu>" - parsed to features as per -mcpu=.., with CPU set to <cpu>
|
||||
// "tune=<cpu>" - TuneCPU set to <cpu>
|
||||
// "feature", "no-feature" - Add (or remove) feature.
|
||||
// "+feature", "+nofeature" - Add (or remove) feature.
|
||||
ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
|
||||
ParsedTargetAttr Ret;
|
||||
if (Features == "default")
|
||||
return Ret;
|
||||
SmallVector<StringRef, 1> AttrFeatures;
|
||||
Features.split(AttrFeatures, ",");
|
||||
bool FoundArch = false;
|
||||
|
||||
auto SplitAndAddFeatures = [](StringRef FeatString,
|
||||
std::vector<std::string> &Features) {
|
||||
SmallVector<StringRef, 8> SplitFeatures;
|
||||
FeatString.split(SplitFeatures, StringRef("+"), -1, false);
|
||||
for (StringRef Feature : SplitFeatures) {
|
||||
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
|
||||
if (!FeatureName.empty())
|
||||
Features.push_back(FeatureName.str());
|
||||
else
|
||||
// Pushing the original feature string to give a sema error later on
|
||||
// when they get checked.
|
||||
Features.push_back(Feature.str());
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &Feature : AttrFeatures) {
|
||||
Feature = Feature.trim();
|
||||
if (Feature.startswith("fpmath="))
|
||||
continue;
|
||||
|
||||
if (Feature.startswith("branch-protection=")) {
|
||||
Ret.BranchProtection = Feature.split('=').second.trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Feature.startswith("arch=")) {
|
||||
if (FoundArch)
|
||||
Ret.Duplicate = "arch=";
|
||||
FoundArch = true;
|
||||
std::pair<StringRef, StringRef> Split =
|
||||
Feature.split("=").second.trim().split("+");
|
||||
llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
|
||||
|
||||
// Parse the architecture version, adding the required features to
|
||||
// Ret.Features.
|
||||
std::vector<StringRef> FeatureStrs;
|
||||
if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
|
||||
!llvm::AArch64::getArchFeatures(ArchKind, FeatureStrs))
|
||||
continue;
|
||||
for (auto R : FeatureStrs)
|
||||
Ret.Features.push_back(R.str());
|
||||
// Add any extra features, after the +
|
||||
SplitAndAddFeatures(Split.second, Ret.Features);
|
||||
} else if (Feature.startswith("cpu=")) {
|
||||
if (!Ret.CPU.empty())
|
||||
Ret.Duplicate = "cpu=";
|
||||
else {
|
||||
// Split the cpu string into "cpu=", "cortex-a710" and any remaining
|
||||
// "+feat" features.
|
||||
std::pair<StringRef, StringRef> Split =
|
||||
Feature.split("=").second.trim().split("+");
|
||||
Ret.CPU = Split.first;
|
||||
SplitAndAddFeatures(Split.second, Ret.Features);
|
||||
}
|
||||
} else if (Feature.startswith("tune=")) {
|
||||
if (!Ret.Tune.empty())
|
||||
Ret.Duplicate = "tune=";
|
||||
else
|
||||
Ret.Tune = Feature.split("=").second.trim();
|
||||
} else if (Feature.startswith("no-"))
|
||||
Ret.Features.push_back("-" + Feature.split("-").second.str());
|
||||
else if (Feature.startswith("+")) {
|
||||
SplitAndAddFeatures(Feature, Ret.Features);
|
||||
}
|
||||
else
|
||||
Ret.Features.push_back("+" + Feature.str());
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::hasBFloat16Type() const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -118,6 +118,12 @@ public:
|
|||
bool Enabled) const override;
|
||||
bool handleTargetFeatures(std::vector<std::string> &Features,
|
||||
DiagnosticsEngine &Diags) override;
|
||||
bool
|
||||
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
|
||||
StringRef CPU,
|
||||
const std::vector<std::string> &FeaturesVec) const override;
|
||||
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
|
||||
bool supportsTargetAttributeTune() const override { return true; }
|
||||
|
||||
bool hasBFloat16Type() const override;
|
||||
|
||||
|
|
|
@ -1333,21 +1333,21 @@ static void AppendTargetMangling(const CodeGenModule &CGM,
|
|||
|
||||
Out << '.';
|
||||
const TargetInfo &Target = CGM.getTarget();
|
||||
ParsedTargetAttr Info =
|
||||
Attr->parse([&Target](StringRef LHS, StringRef RHS) {
|
||||
// Multiversioning doesn't allow "no-${feature}", so we can
|
||||
// only have "+" prefixes here.
|
||||
assert(LHS.startswith("+") && RHS.startswith("+") &&
|
||||
"Features should always have a prefix.");
|
||||
return Target.multiVersionSortPriority(LHS.substr(1)) >
|
||||
Target.multiVersionSortPriority(RHS.substr(1));
|
||||
});
|
||||
ParsedTargetAttr Info = Target.parseTargetAttr(Attr->getFeaturesStr());
|
||||
llvm::sort(Info.Features, [&Target](StringRef LHS, StringRef RHS) {
|
||||
// Multiversioning doesn't allow "no-${feature}", so we can
|
||||
// only have "+" prefixes here.
|
||||
assert(LHS.startswith("+") && RHS.startswith("+") &&
|
||||
"Features should always have a prefix.");
|
||||
return Target.multiVersionSortPriority(LHS.substr(1)) >
|
||||
Target.multiVersionSortPriority(RHS.substr(1));
|
||||
});
|
||||
|
||||
bool IsFirst = true;
|
||||
|
||||
if (!Info.Architecture.empty()) {
|
||||
if (!Info.CPU.empty()) {
|
||||
IsFirst = false;
|
||||
Out << "arch_" << Info.Architecture;
|
||||
Out << "arch_" << Info.CPU;
|
||||
}
|
||||
|
||||
for (StringRef Feat : Info.Features) {
|
||||
|
@ -2171,10 +2171,11 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
|
|||
// get and parse the target attribute so we can get the cpu for
|
||||
// the function.
|
||||
if (TD) {
|
||||
ParsedTargetAttr ParsedAttr = TD->parse();
|
||||
if (!ParsedAttr.Architecture.empty() &&
|
||||
getTarget().isValidCPUName(ParsedAttr.Architecture)) {
|
||||
TargetCPU = ParsedAttr.Architecture;
|
||||
ParsedTargetAttr ParsedAttr =
|
||||
Target.parseTargetAttr(TD->getFeaturesStr());
|
||||
if (!ParsedAttr.CPU.empty() &&
|
||||
getTarget().isValidCPUName(ParsedAttr.CPU)) {
|
||||
TargetCPU = ParsedAttr.CPU;
|
||||
TuneCPU = ""; // Clear the tune CPU.
|
||||
}
|
||||
if (!ParsedAttr.Tune.empty() &&
|
||||
|
|
|
@ -5577,14 +5577,15 @@ public:
|
|||
if (TA == nullptr)
|
||||
return;
|
||||
|
||||
ParsedTargetAttr Attr = TA->parse();
|
||||
ParsedTargetAttr Attr =
|
||||
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
|
||||
if (Attr.BranchProtection.empty())
|
||||
return;
|
||||
|
||||
TargetInfo::BranchProtectionInfo BPI;
|
||||
StringRef Error;
|
||||
(void)CGM.getTarget().validateBranchProtection(
|
||||
Attr.BranchProtection, Attr.Architecture, BPI, Error);
|
||||
(void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
|
||||
Attr.CPU, BPI, Error);
|
||||
assert(Error.empty());
|
||||
|
||||
auto *Fn = cast<llvm::Function>(GV);
|
||||
|
@ -6405,13 +6406,13 @@ public:
|
|||
auto *Fn = cast<llvm::Function>(GV);
|
||||
|
||||
if (const auto *TA = FD->getAttr<TargetAttr>()) {
|
||||
ParsedTargetAttr Attr = TA->parse();
|
||||
ParsedTargetAttr Attr =
|
||||
CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
|
||||
if (!Attr.BranchProtection.empty()) {
|
||||
TargetInfo::BranchProtectionInfo BPI;
|
||||
StringRef DiagMsg;
|
||||
StringRef Arch = Attr.Architecture.empty()
|
||||
? CGM.getTarget().getTargetOpts().CPU
|
||||
: Attr.Architecture;
|
||||
StringRef Arch =
|
||||
Attr.CPU.empty() ? CGM.getTarget().getTargetOpts().CPU : Attr.CPU;
|
||||
if (!CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
|
||||
Arch, BPI, DiagMsg)) {
|
||||
CGM.getDiags().Report(
|
||||
|
@ -6434,11 +6435,11 @@ public:
|
|||
// If the Branch Protection attribute is missing, validate the target
|
||||
// Architecture attribute against Branch Protection command line
|
||||
// settings.
|
||||
if (!CGM.getTarget().isBranchProtectionSupportedArch(Attr.Architecture))
|
||||
if (!CGM.getTarget().isBranchProtectionSupportedArch(Attr.CPU))
|
||||
CGM.getDiags().Report(
|
||||
D->getLocation(),
|
||||
diag::warn_target_unsupported_branch_protection_attribute)
|
||||
<< Attr.Architecture;
|
||||
<< Attr.CPU;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10717,14 +10717,14 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
|
|||
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
|
||||
const auto *TA = FD->getAttr<TargetAttr>();
|
||||
assert(TA && "MultiVersion Candidate requires a target attribute");
|
||||
ParsedTargetAttr ParseInfo = TA->parse();
|
||||
ParsedTargetAttr ParseInfo =
|
||||
S.getASTContext().getTargetInfo().parseTargetAttr(TA->getFeaturesStr());
|
||||
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
|
||||
enum ErrType { Feature = 0, Architecture = 1 };
|
||||
|
||||
if (!ParseInfo.Architecture.empty() &&
|
||||
!TargetInfo.validateCpuIs(ParseInfo.Architecture)) {
|
||||
if (!ParseInfo.CPU.empty() && !TargetInfo.validateCpuIs(ParseInfo.CPU)) {
|
||||
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
|
||||
<< Architecture << ParseInfo.Architecture;
|
||||
<< Architecture << ParseInfo.CPU;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10997,7 +10997,9 @@ static bool CheckTargetCausesMultiVersioning(
|
|||
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA,
|
||||
bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
|
||||
const auto *OldTA = OldFD->getAttr<TargetAttr>();
|
||||
ParsedTargetAttr NewParsed = NewTA->parse();
|
||||
ParsedTargetAttr NewParsed =
|
||||
S.getASTContext().getTargetInfo().parseTargetAttr(
|
||||
NewTA->getFeaturesStr());
|
||||
// Sort order doesn't matter, it just needs to be consistent.
|
||||
llvm::sort(NewParsed.Features);
|
||||
|
||||
|
@ -11034,7 +11036,10 @@ static bool CheckTargetCausesMultiVersioning(
|
|||
return true;
|
||||
}
|
||||
|
||||
ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>());
|
||||
ParsedTargetAttr OldParsed =
|
||||
S.getASTContext().getTargetInfo().parseTargetAttr(
|
||||
OldTA->getFeaturesStr());
|
||||
llvm::sort(OldParsed.Features);
|
||||
|
||||
if (OldParsed == NewParsed) {
|
||||
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
|
||||
|
@ -11097,7 +11102,8 @@ static bool CheckMultiVersionAdditionalDecl(
|
|||
|
||||
ParsedTargetAttr NewParsed;
|
||||
if (NewTA) {
|
||||
NewParsed = NewTA->parse();
|
||||
NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr(
|
||||
NewTA->getFeaturesStr());
|
||||
llvm::sort(NewParsed.Features);
|
||||
}
|
||||
|
||||
|
@ -11131,7 +11137,10 @@ static bool CheckMultiVersionAdditionalDecl(
|
|||
return false;
|
||||
}
|
||||
|
||||
ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>());
|
||||
ParsedTargetAttr CurParsed =
|
||||
S.getASTContext().getTargetInfo().parseTargetAttr(
|
||||
CurTA->getFeaturesStr());
|
||||
llvm::sort(CurParsed.Features);
|
||||
if (CurParsed == NewParsed) {
|
||||
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
|
||||
S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
|
||||
|
|
|
@ -3394,7 +3394,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
// handled later in the process, once we know how many exist.
|
||||
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
|
||||
enum FirstParam { Unsupported, Duplicate, Unknown };
|
||||
enum SecondParam { None, Architecture, Tune };
|
||||
enum SecondParam { None, CPU, Tune };
|
||||
enum ThirdParam { Target, TargetClones };
|
||||
if (AttrStr.contains("fpmath="))
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
|
@ -3406,24 +3406,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
|
|||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Unsupported << None << "tune=" << Target;
|
||||
|
||||
ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
|
||||
ParsedTargetAttr ParsedAttrs =
|
||||
Context.getTargetInfo().parseTargetAttr(AttrStr);
|
||||
|
||||
if (!ParsedAttrs.Architecture.empty() &&
|
||||
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
|
||||
if (!ParsedAttrs.CPU.empty() &&
|
||||
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU))
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Unknown << Architecture << ParsedAttrs.Architecture << Target;
|
||||
<< Unknown << CPU << ParsedAttrs.CPU << Target;
|
||||
|
||||
if (!ParsedAttrs.Tune.empty() &&
|
||||
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune))
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Unknown << Tune << ParsedAttrs.Tune << Target;
|
||||
|
||||
if (ParsedAttrs.DuplicateArchitecture)
|
||||
if (ParsedAttrs.Duplicate != "")
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Duplicate << None << "arch=" << Target;
|
||||
if (ParsedAttrs.DuplicateTune)
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Duplicate << None << "tune=" << Target;
|
||||
<< Duplicate << None << ParsedAttrs.Duplicate << Target;
|
||||
|
||||
for (const auto &Feature : ParsedAttrs.Features) {
|
||||
auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
|
||||
|
@ -3437,8 +3435,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
|
|||
if (ParsedAttrs.BranchProtection.empty())
|
||||
return false;
|
||||
if (!Context.getTargetInfo().validateBranchProtection(
|
||||
ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI,
|
||||
DiagMsg)) {
|
||||
ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) {
|
||||
if (DiagMsg.empty())
|
||||
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Unsupported << None << "branch-protection" << Target;
|
||||
|
@ -3467,7 +3464,7 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
|
|||
bool &HasDefault, bool &HasCommas,
|
||||
SmallVectorImpl<StringRef> &Strings) {
|
||||
enum FirstParam { Unsupported, Duplicate, Unknown };
|
||||
enum SecondParam { None, Architecture, Tune };
|
||||
enum SecondParam { None, CPU, Tune };
|
||||
enum ThirdParam { Target, TargetClones };
|
||||
HasCommas = HasCommas || Str.contains(',');
|
||||
// Warn on empty at the beginning of a string.
|
||||
|
@ -3492,8 +3489,8 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
|
|||
if (!Context.getTargetInfo().isValidCPUName(
|
||||
Cur.drop_front(sizeof("arch=") - 1)))
|
||||
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
|
||||
<< Unsupported << Architecture
|
||||
<< Cur.drop_front(sizeof("arch=") - 1) << TargetClones;
|
||||
<< Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1)
|
||||
<< TargetClones;
|
||||
} else if (Cur == "default") {
|
||||
DefaultIsDupe = HasDefault;
|
||||
HasDefault = true;
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
|
||||
// RUN: %clang_cc1 -triple aarch64-eabi -S -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: @v82() #0
|
||||
__attribute__((target("arch=armv8.2-a")))
|
||||
void v82() {}
|
||||
// CHECK-LABEL: @v82sve() #1
|
||||
__attribute__((target("arch=armv8.2-a+sve")))
|
||||
void v82sve() {}
|
||||
// CHECK-LABEL: @v82sve2() #2
|
||||
__attribute__((target("arch=armv8.2-a+sve2")))
|
||||
void v82sve2() {}
|
||||
// CHECK-LABEL: @v82svesve2() #3
|
||||
__attribute__((target("arch=armv8.2-a+sve+sve2")))
|
||||
void v82svesve2() {}
|
||||
// CHECK-LABEL: @v86sve2() #4
|
||||
__attribute__((target("arch=armv8.6-a+sve2")))
|
||||
void v86sve2() {}
|
||||
|
||||
// CHECK-LABEL: @a710() #5
|
||||
__attribute__((target("cpu=cortex-a710")))
|
||||
void a710() {}
|
||||
// CHECK-LABEL: @tunea710() #6
|
||||
__attribute__((target("tune=cortex-a710")))
|
||||
void tunea710() {}
|
||||
// CHECK-LABEL: @generic() #7
|
||||
__attribute__((target("cpu=generic")))
|
||||
void generic() {}
|
||||
// CHECK-LABEL: @tune() #8
|
||||
__attribute__((target("tune=generic")))
|
||||
void tune() {}
|
||||
|
||||
// CHECK-LABEL: @n1tunea710() #9
|
||||
__attribute__((target("cpu=neoverse-n1,tune=cortex-a710")))
|
||||
void n1tunea710() {}
|
||||
// CHECK-LABEL: @svetunea710() #10
|
||||
__attribute__((target("sve,tune=cortex-a710")))
|
||||
void svetunea710() {}
|
||||
// CHECK-LABEL: @plussvetunea710() #10
|
||||
__attribute__((target("+sve,tune=cortex-a710")))
|
||||
void plussvetunea710() {}
|
||||
// CHECK-LABEL: @v1plussve2() #11
|
||||
__attribute__((target("cpu=neoverse-v1,+sve2")))
|
||||
void v1plussve2() {}
|
||||
// CHECK-LABEL: @v1sve2() #11
|
||||
__attribute__((target("cpu=neoverse-v1+sve2")))
|
||||
void v1sve2() {}
|
||||
// CHECK-LABEL: @v1minussve() #12
|
||||
__attribute__((target("cpu=neoverse-v1,+nosve")))
|
||||
void v1minussve() {}
|
||||
// CHECK-LABEL: @v1nosve() #12
|
||||
__attribute__((target("cpu=neoverse-v1,no-sve")))
|
||||
void v1nosve() {}
|
||||
// CHECK-LABEL: @v1msve() #12
|
||||
__attribute__((target("cpu=neoverse-v1+nosve")))
|
||||
void v1msve() {}
|
||||
|
||||
// CHECK-LABEL: @plussve() #13
|
||||
__attribute__((target("+sve")))
|
||||
void plussve() {}
|
||||
// CHECK-LABEL: @plussveplussve2() #14
|
||||
__attribute__((target("+sve+nosve2")))
|
||||
void plussveplussve2() {}
|
||||
// CHECK-LABEL: @plussveminusnosve2() #14
|
||||
__attribute__((target("sve,no-sve2")))
|
||||
void plussveminusnosve2() {}
|
||||
// CHECK-LABEL: @plusfp16() #15
|
||||
__attribute__((target("+fp16")))
|
||||
void plusfp16() {}
|
||||
|
||||
// CHECK-LABEL: @all() #16
|
||||
__attribute__((target("cpu=neoverse-n1,tune=cortex-a710,arch=armv8.6-a+sve2")))
|
||||
void all() {}
|
||||
// CHECK-LABEL: @allplusbranchprotection() #17
|
||||
__attribute__((target("cpu=neoverse-n1,tune=cortex-a710,arch=armv8.6-a+sve2,branch-protection=standard")))
|
||||
void allplusbranchprotection() {}
|
||||
|
||||
// CHECK: attributes #0 = { {{.*}} "target-features"="+v8.1a,+v8.2a,+v8a" }
|
||||
// CHECK: attributes #1 = { {{.*}} "target-features"="+sve,+v8.1a,+v8.2a,+v8a" }
|
||||
// CHECK: attributes #2 = { {{.*}} "target-features"="+sve2,+v8.1a,+v8.2a,+v8a" }
|
||||
// CHECK: attributes #4 = { {{.*}} "target-features"="+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" }
|
||||
// CHECK: attributes #5 = { {{.*}} "target-cpu"="cortex-a710" "target-features"="+bf16,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+i8mm,+lse,+mte,+neon,+pauth,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm" }
|
||||
// CHECK: attributes #6 = { {{.*}} "tune-cpu"="cortex-a710" }
|
||||
// CHECK: attributes #7 = { {{.*}} "target-cpu"="generic" }
|
||||
// CHECK: attributes #8 = { {{.*}} "tune-cpu"="generic" }
|
||||
// CHECK: attributes #9 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs" "tune-cpu"="cortex-a710" }
|
||||
// CHECK: attributes #10 = { {{.*}} "target-features"="+sve" "tune-cpu"="cortex-a710" }
|
||||
// CHECK: attributes #11 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,+sve,+sve2" }
|
||||
// CHECK: attributes #12 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,-sve" }
|
||||
// CHECK: attributes #13 = { {{.*}} "target-features"="+sve" }
|
||||
// CHECK: attributes #14 = { {{.*}} "target-features"="+sve,-sve2" }
|
||||
// CHECK: attributes #15 = { {{.*}} "target-features"="+fullfp16" }
|
||||
// CHECK: attributes #16 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
|
||||
// CHECK: attributes #17 = { {{.*}} "branch-target-enforcement"="true" {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
|
|
@ -1,5 +1,6 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -std=c2x %s
|
||||
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -std=c2x %s
|
||||
// RUN: %clang_cc1 -triple arm-linux-gnu -fsyntax-only -verify -std=c2x %s
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
|
@ -10,13 +11,13 @@ int __attribute__((target())) bar(void) { return 4; }
|
|||
int __attribute__((target("tune=sandybridge"))) baz(void) { return 4; }
|
||||
//expected-warning@+1 {{unsupported 'fpmath=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("fpmath=387"))) walrus(void) { return 4; }
|
||||
//expected-warning@+1 {{unknown architecture 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
//expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("avx,sse4.2,arch=hiss"))) meow(void) { return 4; }
|
||||
//expected-warning@+1 {{unsupported 'woof' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("woof"))) bark(void) { return 4; }
|
||||
// no warning, same as saying 'nothing'.
|
||||
int __attribute__((target("arch="))) turtle(void) { return 4; }
|
||||
//expected-warning@+1 {{unknown architecture 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
//expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("arch=hiss,arch=woof"))) pine_tree(void) { return 4; }
|
||||
//expected-warning@+1 {{duplicate 'arch=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("arch=ivybridge,arch=haswell"))) oak_tree(void) { return 4; }
|
||||
|
@ -25,6 +26,36 @@ int __attribute__((target("branch-protection=none"))) birch_tree(void) { return
|
|||
//expected-warning@+1 {{unknown tune CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("tune=hiss,tune=woof"))) apple_tree(void) { return 4; }
|
||||
|
||||
#elifdef __aarch64__
|
||||
|
||||
int __attribute__((target("sve,arch=armv8-a"))) foo(void) { return 4; }
|
||||
//expected-error@+1 {{'target' attribute takes one argument}}
|
||||
int __attribute__((target())) bar(void) { return 4; }
|
||||
// no warning, tune is supported for aarch64
|
||||
int __attribute__((target("tune=cortex-a710"))) baz(void) { return 4; }
|
||||
//expected-warning@+1 {{unsupported 'fpmath=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("fpmath=387"))) walrus(void) { return 4; }
|
||||
//expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("sve,cpu=hiss"))) meow(void) { return 4; }
|
||||
// FIXME: We currently have no implementation of isValidFeatureName, so this is not noticed as an error.
|
||||
int __attribute__((target("woof"))) bark(void) { return 4; }
|
||||
// FIXME: Same
|
||||
int __attribute__((target("arch=armv8-a+woof"))) buff(void) { return 4; }
|
||||
// FIXME: Same
|
||||
int __attribute__((target("+noway"))) noway(void) { return 4; }
|
||||
// no warning, same as saying 'nothing'.
|
||||
int __attribute__((target("arch="))) turtle(void) { return 4; }
|
||||
//expected-warning@+1 {{unknown CPU 'hiss' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("cpu=hiss,cpu=woof"))) pine_tree(void) { return 4; }
|
||||
//expected-warning@+1 {{duplicate 'arch=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("arch=armv8.1-a,arch=armv8-a"))) oak_tree(void) { return 4; }
|
||||
//expected-warning@+1 {{duplicate 'cpu=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("cpu=cortex-a710,cpu=neoverse-n2"))) apple_tree(void) { return 4; }
|
||||
//expected-warning@+1 {{duplicate 'tune=' in the 'target' attribute string; 'target' attribute ignored}}
|
||||
int __attribute__((target("tune=cortex-a710,tune=neoverse-n2"))) pear_tree(void) { return 4; }
|
||||
// no warning - branch-protection should work on aarch64
|
||||
int __attribute__((target("branch-protection=none"))) birch_tree(void) { return 5; }
|
||||
|
||||
#else
|
||||
|
||||
// tune is not supported by other targets.
|
||||
|
|
Loading…
Reference in New Issue