This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG781b491bba9d: [Clang][AArch64] Support AArch64 target(..)
attribute formats. (authored by dmgreen).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Changed prior to commit:
https://reviews.llvm.org/D133848?vs=460017&id=464501#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D133848/new/
https://reviews.llvm.org/D133848
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Attr.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/TargetInfo.h
clang/lib/AST/ASTContext.cpp
clang/lib/Basic/TargetInfo.cpp
clang/lib/Basic/Targets/AArch64.cpp
clang/lib/Basic/Targets/AArch64.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/TargetInfo.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/aarch64-targetattr.c
clang/test/Sema/attr-target.c
Index: clang/test/Sema/attr-target.c
===================================================================
--- clang/test/Sema/attr-target.c
+++ clang/test/Sema/attr-target.c
@@ -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("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 @@
//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.
Index: clang/test/CodeGen/aarch64-targetattr.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-targetattr.c
@@ -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" }
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -3394,7 +3394,7 @@
// 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 @@
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 @@
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 &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 @@
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;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -10717,14 +10717,14 @@
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 @@
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 @@
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 @@
ParsedTargetAttr NewParsed;
if (NewTA) {
- NewParsed = NewTA->parse();
+ NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr(
+ NewTA->getFeaturesStr());
llvm::sort(NewParsed.Features);
}
@@ -11131,7 +11137,10 @@
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);
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -5577,14 +5577,15 @@
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 @@
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 @@
// 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;
}
}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -1333,21 +1333,21 @@
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 @@
// 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() &&
Index: clang/lib/Basic/Targets/AArch64.h
===================================================================
--- clang/lib/Basic/Targets/AArch64.h
+++ clang/lib/Basic/Targets/AArch64.h
@@ -118,6 +118,12 @@
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;
Index: clang/lib/Basic/Targets/AArch64.cpp
===================================================================
--- clang/lib/Basic/Targets/AArch64.cpp
+++ clang/lib/Basic/Targets/AArch64.cpp
@@ -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 @@
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;
}
Index: clang/lib/Basic/TargetInfo.cpp
===================================================================
--- clang/lib/Basic/TargetInfo.cpp
+++ clang/lib/Basic/TargetInfo.cpp
@@ -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 @@
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 &&
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -13255,7 +13255,7 @@
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 @@
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
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -49,6 +49,7 @@
class LangOptions;
class CodeGenOptions;
class MacroBuilder;
+class ParsedTargetAttr;
namespace Builtin { struct Info; }
@@ -1281,6 +1282,8 @@
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;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3050,7 +3050,7 @@
"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">,
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -2345,9 +2345,12 @@
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
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2697,10 +2697,6 @@
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 @@
}
}
- 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;
- }
}];
}
Index: clang/include/clang/AST/Attr.h
===================================================================
--- clang/include/clang/AST/Attr.h
+++ clang/include/clang/AST/Attr.h
@@ -365,17 +365,13 @@
/// 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;
}
};
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -450,6 +450,14 @@
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.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits