Skip to content

Commit e43924a

Browse files
committed
[AArch64] FMV support and necessary target features dependencies.
This is Function Multi Versioning (FMV) implementation for AArch64 target in accordance with Beta Arm C Language Extensions specification https://github.com/ARM-software/acle/blob/main/main/acle.md#function-multi-versioning It supports new "target_version" function attribute and extends existing "target_clones" one. Also missing dependencies for target features were added. Differential Revision: https://reviews.llvm.org/D127812
1 parent daa022c commit e43924a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3297
-277
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
31163116
/// valid feature names.
31173117
ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const;
31183118

3119+
std::vector<std::string>
3120+
filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const;
3121+
31193122
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
31203123
const FunctionDecl *) const;
31213124
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,

clang/include/clang/AST/Decl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,8 @@ enum class MultiVersionKind {
18911891
Target,
18921892
CPUSpecific,
18931893
CPUDispatch,
1894-
TargetClones
1894+
TargetClones,
1895+
TargetVersion
18951896
};
18961897

18971898
/// Represents a function declaration or definition.

clang/include/clang/Basic/Attr.td

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2740,6 +2740,31 @@ def Target : InheritableAttr {
27402740
}];
27412741
}
27422742

2743+
def TargetVersion : InheritableAttr {
2744+
let Spellings = [GCC<"target_version">];
2745+
let Args = [StringArgument<"NamesStr">];
2746+
let Subjects = SubjectList<[Function], ErrorDiag>;
2747+
let Documentation = [TargetVersionDocs];
2748+
let AdditionalMembers = [{
2749+
StringRef getName() const { return getNamesStr().trim(); }
2750+
bool isDefaultVersion() const {
2751+
return getName() == "default";
2752+
}
2753+
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
2754+
if (isDefaultVersion()) return;
2755+
StringRef Features = getName();
2756+
2757+
SmallVector<StringRef, 8> AttrFeatures;
2758+
Features.split(AttrFeatures, "+");
2759+
2760+
for (auto &Feature : AttrFeatures) {
2761+
Feature = Feature.trim();
2762+
Out.push_back(Feature);
2763+
}
2764+
}
2765+
}];
2766+
}
2767+
27432768
def TargetClones : InheritableAttr {
27442769
let Spellings = [GCC<"target_clones">];
27452770
let Args = [VariadicStringArgument<"featuresStrs">];
@@ -2773,11 +2798,12 @@ def TargetClones : InheritableAttr {
27732798
return 0 == std::count_if(
27742799
featuresStrs_begin(), featuresStrs_begin() + Index,
27752800
[FeatureStr](StringRef S) { return S == FeatureStr; });
2801+
27762802
}
27772803
}];
27782804
}
27792805

2780-
def : MutualExclusions<[TargetClones, Target, CPUDispatch, CPUSpecific]>;
2806+
def : MutualExclusions<[TargetClones, TargetVersion, Target, CPUDispatch, CPUSpecific]>;
27812807

27822808
def MinVectorWidth : InheritableAttr {
27832809
let Spellings = [Clang<"min_vector_width">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,6 +2377,19 @@ Additionally, a function may not become multiversioned after its first use.
23772377
}];
23782378
}
23792379

2380+
def TargetVersionDocs : Documentation {
2381+
let Category = DocCatFunction;
2382+
let Content = [{
2383+
For AArch64 target clang supports function multiversioning by
2384+
``__attribute__((target_version("OPTIONS")))`` attribute. When applied to a
2385+
function it instructs compiler to emit multiple function versions based on
2386+
``target_version`` attribute strings, which resolved at runtime depend on their
2387+
priority and target features availability. One of the versions is always
2388+
( implicitly or explicitly ) the ``default`` (fallback). Attribute strings can
2389+
contain dependent features names joined by the "+" sign.
2390+
}];
2391+
}
2392+
23802393
def TargetClonesDocs : Documentation {
23812394
let Category = DocCatFunction;
23822395
let Content = [{
@@ -2387,6 +2400,19 @@ generation options. Additionally, these versions will be resolved at runtime
23872400
based on the priority of their attribute options. All ``target_clone`` functions
23882401
are considered multiversioned functions.
23892402

2403+
For AArch64 target:
2404+
The attribute contains comma-separated strings of target features joined by "+"
2405+
sign. For example:
2406+
2407+
.. code-block:: c++
2408+
2409+
__attribute__((target_clones("sha2+memtag2", "fcma+sve2-pmull128")))
2410+
void foo() {}
2411+
2412+
For every multiversioned function a ``default`` (fallback) implementation
2413+
always generated if not specified directly.
2414+
2415+
For x86/x86-64 targets:
23902416
All multiversioned functions must contain a ``default`` (fallback)
23912417
implementation, otherwise usages of the function are considered invalid.
23922418
Additionally, a function may not become multiversioned after its first use.

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3056,8 +3056,8 @@ def warn_unsupported_branch_protection_spec : Warning<
30563056

30573057
def warn_unsupported_target_attribute
30583058
: Warning<"%select{unsupported|duplicate|unknown}0%select{| CPU|"
3059-
" tune CPU}1 '%2' in the '%select{target|target_clones}3' "
3060-
"attribute string; '%select{target|target_clones}3' "
3059+
" tune CPU}1 '%2' in the '%select{target|target_clones|target_version}3' "
3060+
"attribute string; '%select{target|target_clones|target_version}3' "
30613061
"attribute ignored">,
30623062
InGroup<IgnoredAttributes>;
30633063
def err_attribute_unsupported
@@ -11511,7 +11511,7 @@ def note_shadow_field : Note<"declared here">;
1151111511

1151211512
def err_multiversion_required_in_redecl : Error<
1151311513
"function declaration is missing %select{'target'|'cpu_specific' or "
11514-
"'cpu_dispatch'}0 attribute in a multiversioned function">;
11514+
"'cpu_dispatch'|'target_version'}0 attribute in a multiversioned function">;
1151511515
def note_multiversioning_caused_here : Note<
1151611516
"function multiversioning caused by this declaration">;
1151711517
def err_multiversion_after_used : Error<
@@ -11526,7 +11526,7 @@ def err_multiversion_noproto : Error<
1152611526
"multiversioned function must have a prototype">;
1152711527
def err_multiversion_disallowed_other_attr
1152811528
: Error<"attribute "
11529-
"'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
11529+
"'%select{|target|cpu_specific|cpu_dispatch|target_clones|target_version}0' "
1153011530
"multiversioning cannot be combined"
1153111531
" with attribute %1">;
1153211532
def err_multiversion_diff : Error<
@@ -11535,7 +11535,7 @@ def err_multiversion_diff : Error<
1153511535
"language linkage}0">;
1153611536
def err_multiversion_doesnt_support
1153711537
: Error<"attribute "
11538-
"'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
11538+
"'%select{|target|cpu_specific|cpu_dispatch|target_clones|target_version}0' "
1153911539
"multiversioned functions do not "
1154011540
"yet support %select{function templates|virtual functions|"
1154111541
"deduced return types|constructors|destructors|deleted functions|"
@@ -11570,6 +11570,9 @@ def warn_target_clone_mixed_values
1157011570
def warn_target_clone_duplicate_options
1157111571
: Warning<"version list contains duplicate entries">,
1157211572
InGroup<FunctionMultiVersioning>;
11573+
def warn_target_clone_no_impact_options
11574+
: Warning<"version list contains entries that don't impact code generation">,
11575+
InGroup<FunctionMultiVersioning>;
1157311576

1157411577
// three-way comparison operator diagnostics
1157511578
def err_implied_comparison_category_type_not_found : Error<

clang/include/clang/Basic/TargetInfo.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,13 @@ class TargetInfo : public virtual TransferrableTargetInfo,
13401340
return true;
13411341
}
13421342

1343+
/// Returns true if feature has an impact on target code
1344+
/// generation and get its dependent options in second argument.
1345+
virtual bool getFeatureDepOptions(StringRef Feature,
1346+
std::string &Options) const {
1347+
return true;
1348+
}
1349+
13431350
struct BranchProtectionInfo {
13441351
LangOptions::SignReturnAddressScopeKind SignReturnAddr =
13451352
LangOptions::SignReturnAddressScopeKind::None;
@@ -1386,7 +1393,9 @@ class TargetInfo : public virtual TransferrableTargetInfo,
13861393

13871394
/// Identify whether this target supports multiversioning of functions,
13881395
/// which requires support for cpu_supports and cpu_is functionality.
1389-
bool supportsMultiVersioning() const { return getTriple().isX86(); }
1396+
bool supportsMultiVersioning() const {
1397+
return getTriple().isX86() || getTriple().isAArch64();
1398+
}
13901399

13911400
/// Identify whether this target supports IFuncs.
13921401
bool supportsIFunc() const {
@@ -1403,6 +1412,10 @@ class TargetInfo : public virtual TransferrableTargetInfo,
14031412
return 0;
14041413
}
14051414

1415+
// Return the target-specific cost for feature
1416+
// that taken into account in priority sorting.
1417+
virtual unsigned multiVersionFeatureCost() const { return 0; }
1418+
14061419
// Validate the contents of the __builtin_cpu_is(const char*)
14071420
// argument.
14081421
virtual bool validateCpuIs(StringRef Name) const { return false; }

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3858,6 +3858,8 @@ def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">,
38583858
def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>,
38593859
HelpText<"Use software floating point">,
38603860
MarshallingInfoFlag<CodeGenOpts<"SoftFloat">>;
3861+
def mno_fmv : Flag<["-"], "mno-fmv">, Group<f_clang_Group>, Flags<[CC1Option]>,
3862+
HelpText<"Disable function multiversioning">;
38613863
def moutline_atomics : Flag<["-"], "moutline-atomics">, Group<f_clang_Group>, Flags<[CC1Option]>,
38623864
HelpText<"Generate local calls to out-of-line atomic operations">;
38633865
def mno_outline_atomics : Flag<["-"], "mno-outline-atomics">, Group<f_clang_Group>, Flags<[CC1Option]>,

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4657,10 +4657,14 @@ class Sema final {
46574657
llvm::Error isValidSectionSpecifier(StringRef Str);
46584658
bool checkSectionName(SourceLocation LiteralLoc, StringRef Str);
46594659
bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
4660-
bool checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
4661-
const StringLiteral *Literal,
4662-
bool &HasDefault, bool &HasCommas,
4663-
SmallVectorImpl<StringRef> &Strings);
4660+
bool checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &Str,
4661+
bool &isDefault);
4662+
bool
4663+
checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
4664+
const StringLiteral *Literal, bool &HasDefault,
4665+
bool &HasCommas, bool &HasNotDefault,
4666+
SmallVectorImpl<StringRef> &Strings,
4667+
SmallVectorImpl<SmallString<64>> &StringsBuffer);
46644668
bool checkMSInheritanceAttrOnDefinition(
46654669
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
46664670
MSInheritanceModel SemanticSpelling);

clang/lib/AST/ASTContext.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13291,6 +13291,18 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
1329113291
}
1329213292
}
1329313293

13294+
std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs(
13295+
const TargetVersionAttr *TV) const {
13296+
assert(TV != nullptr);
13297+
llvm::SmallVector<StringRef, 8> Feats;
13298+
std::vector<std::string> ResFeats;
13299+
TV->getFeatures(Feats);
13300+
for (auto &Feature : Feats)
13301+
if (Target->validateCpuSupports(Feature.str()))
13302+
ResFeats.push_back("?" + Feature.str());
13303+
return ResFeats;
13304+
}
13305+
1329413306
ParsedTargetAttr
1329513307
ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
1329613308
assert(TD != nullptr);
@@ -13349,12 +13361,32 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1334913361
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
1335013362
std::vector<std::string> Features;
1335113363
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
13352-
if (VersionStr.startswith("arch="))
13353-
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
13354-
else if (VersionStr != "default")
13355-
Features.push_back((StringRef{"+"} + VersionStr).str());
13356-
13364+
if (Target->getTriple().isAArch64()) {
13365+
// TargetClones for AArch64
13366+
if (VersionStr != "default") {
13367+
SmallVector<StringRef, 1> VersionFeatures;
13368+
VersionStr.split(VersionFeatures, "+");
13369+
for (auto &VFeature : VersionFeatures) {
13370+
VFeature = VFeature.trim();
13371+
Features.push_back((StringRef{"?"} + VFeature).str());
13372+
}
13373+
}
13374+
Features.insert(Features.begin(),
13375+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13376+
Target->getTargetOpts().FeaturesAsWritten.end());
13377+
} else {
13378+
if (VersionStr.startswith("arch="))
13379+
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
13380+
else if (VersionStr != "default")
13381+
Features.push_back((StringRef{"+"} + VersionStr).str());
13382+
}
1335713383
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
13384+
} else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
13385+
std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV);
13386+
Feats.insert(Feats.begin(),
13387+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13388+
Target->getTargetOpts().FeaturesAsWritten.end());
13389+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats);
1335813390
} else {
1335913391
FeatureMap = Target->getTargetOpts().FeatureMap;
1336013392
}

clang/lib/AST/Decl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3347,6 +3347,8 @@ bool FunctionDecl::isNoReturn() const {
33473347
MultiVersionKind FunctionDecl::getMultiVersionKind() const {
33483348
if (hasAttr<TargetAttr>())
33493349
return MultiVersionKind::Target;
3350+
if (hasAttr<TargetVersionAttr>())
3351+
return MultiVersionKind::TargetVersion;
33503352
if (hasAttr<CPUDispatchAttr>())
33513353
return MultiVersionKind::CPUDispatch;
33523354
if (hasAttr<CPUSpecificAttr>())
@@ -3365,7 +3367,8 @@ bool FunctionDecl::isCPUSpecificMultiVersion() const {
33653367
}
33663368

33673369
bool FunctionDecl::isTargetMultiVersion() const {
3368-
return isMultiVersion() && hasAttr<TargetAttr>();
3370+
return isMultiVersion() &&
3371+
(hasAttr<TargetAttr>() || hasAttr<TargetVersionAttr>());
33693372
}
33703373

33713374
bool FunctionDecl::isTargetClonesMultiVersion() const {

0 commit comments

Comments
 (0)