Skip to content

Commit 88c2af8

Browse files
authored
[NFC][clang][FMV][TargetInfo] Refactor API for FMV feature priority. (#116257)
Currently we have code with target hooks in CodeGenModule shared between X86 and AArch64 for sorting MultiVersionResolverOptions. Those are used when generating IFunc resolvers for FMV. The RISCV target has different criteria for sorting, therefore it repeats sorting after calling CodeGenFunction::EmitMultiVersionResolver. I am moving the FMV priority logic in TargetInfo, so that it can be implemented by the TargetParser which then makes it possible to query it from llvm. Here is an example why this is handy: #87939
1 parent 2c242b9 commit 88c2af8

File tree

14 files changed

+216
-227
lines changed

14 files changed

+216
-227
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,33 +3263,28 @@ def Target : InheritableAttr {
32633263
let Subjects = SubjectList<[Function], ErrorDiag>;
32643264
let Documentation = [TargetDocs];
32653265
let AdditionalMembers = [{
3266-
StringRef getArchitecture() const {
3266+
std::optional<StringRef> getX86Architecture() const {
32673267
StringRef Features = getFeaturesStr();
3268-
if (Features == "default") return {};
3269-
3270-
SmallVector<StringRef, 1> AttrFeatures;
3271-
Features.split(AttrFeatures, ",");
3272-
3273-
for (auto &Feature : AttrFeatures) {
3268+
SmallVector<StringRef, 4> AttrFeatures;
3269+
Features.split(AttrFeatures, ',');
3270+
for (StringRef Feature : AttrFeatures) {
32743271
Feature = Feature.trim();
32753272
if (Feature.starts_with("arch="))
32763273
return Feature.drop_front(sizeof("arch=") - 1);
32773274
}
3278-
return "";
3275+
return std::nullopt;
32793276
}
32803277

32813278
// Gets the list of features as simple string-refs with no +/- or 'no-'.
32823279
// Only adds the items to 'Out' that are additions.
3283-
void getAddedFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
3280+
void getX86AddedFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
3281+
if (isDefaultVersion())
3282+
return;
32843283
StringRef Features = getFeaturesStr();
3285-
if (Features == "default") return;
3286-
3287-
SmallVector<StringRef, 1> AttrFeatures;
3288-
Features.split(AttrFeatures, ",");
3289-
3284+
SmallVector<StringRef, 4> AttrFeatures;
3285+
Features.split(AttrFeatures, ',');
32903286
for (auto &Feature : AttrFeatures) {
32913287
Feature = Feature.trim();
3292-
32933288
if (!Feature.starts_with("no-") && !Feature.starts_with("arch=") &&
32943289
!Feature.starts_with("fpmath=") && !Feature.starts_with("tune="))
32953290
Out.push_back(Feature);
@@ -3307,17 +3302,17 @@ def TargetVersion : InheritableAttr, TargetSpecificAttr<TargetArch<!listconcat(T
33073302
let Documentation = [TargetVersionDocs];
33083303
let AdditionalMembers = [{
33093304
StringRef getName() const { return getNamesStr().trim(); }
3310-
bool isDefaultVersion() const {
3311-
return getName() == "default";
3312-
}
3313-
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
3314-
if (isDefaultVersion()) return;
3315-
StringRef Features = getName();
33163305

3317-
SmallVector<StringRef, 8> AttrFeatures;
3318-
Features.split(AttrFeatures, "+");
3306+
bool isDefaultVersion() const { return getName() == "default"; }
33193307

3320-
for (auto &Feature : AttrFeatures) {
3308+
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out,
3309+
char Delim = '+') const {
3310+
if (isDefaultVersion())
3311+
return;
3312+
StringRef Features = getName();
3313+
SmallVector<StringRef, 4> AttrFeatures;
3314+
Features.split(AttrFeatures, Delim);
3315+
for (StringRef Feature : AttrFeatures) {
33213316
Feature = Feature.trim();
33223317
Out.push_back(Feature);
33233318
}
@@ -3334,20 +3329,40 @@ def TargetClones : InheritableAttr {
33343329
StringRef getFeatureStr(unsigned Index) const {
33353330
return *(featuresStrs_begin() + Index);
33363331
}
3332+
33373333
bool isDefaultVersion(unsigned Index) const {
33383334
return getFeatureStr(Index) == "default";
33393335
}
3336+
33403337
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out,
3341-
unsigned Index) const {
3342-
if (isDefaultVersion(Index)) return;
3338+
unsigned Index, char Delim = '+') const {
3339+
if (isDefaultVersion(Index))
3340+
return;
33433341
StringRef Features = getFeatureStr(Index);
3344-
SmallVector<StringRef, 8> AttrFeatures;
3345-
Features.split(AttrFeatures, "+");
3346-
for (auto &Feature : AttrFeatures) {
3342+
SmallVector<StringRef, 4> AttrFeatures;
3343+
Features.split(AttrFeatures, Delim);
3344+
for (StringRef Feature : AttrFeatures) {
33473345
Feature = Feature.trim();
33483346
Out.push_back(Feature);
33493347
}
33503348
}
3349+
3350+
std::optional<StringRef> getX86Architecture(unsigned Index) const {
3351+
StringRef Feature = getFeatureStr(Index);
3352+
if (Feature.starts_with("arch="))
3353+
return Feature.drop_front(sizeof("arch=") - 1);
3354+
return std::nullopt;
3355+
}
3356+
3357+
void getX86Feature(llvm::SmallVectorImpl<StringRef> &Out,
3358+
unsigned Index) const {
3359+
if (isDefaultVersion(Index))
3360+
return;
3361+
if (getX86Architecture(Index))
3362+
return;
3363+
Out.push_back(getFeatureStr(Index));
3364+
}
3365+
33513366
// Given an index into the 'featuresStrs' sequence, compute a unique
33523367
// ID to be used with function name mangling for the associated variant.
33533368
// This mapping is necessary due to a requirement that the mangling ID

clang/include/clang/Basic/TargetInfo.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,14 +1525,10 @@ class TargetInfo : public TransferrableTargetInfo,
15251525

15261526
// Return the target-specific priority for features/cpus/vendors so
15271527
// that they can be properly sorted for checking.
1528-
virtual unsigned multiVersionSortPriority(StringRef Name) const {
1528+
virtual unsigned getFMVPriority(ArrayRef<StringRef> Features) const {
15291529
return 0;
15301530
}
15311531

1532-
// Return the target-specific cost for feature
1533-
// that taken into account in priority sorting.
1534-
virtual unsigned multiVersionFeatureCost() const { return 0; }
1535-
15361532
// Validate the contents of the __builtin_cpu_is(const char*)
15371533
// argument.
15381534
virtual bool validateCpuIs(StringRef Name) const { return false; }

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -705,18 +705,8 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
705705
return std::nullopt;
706706
}
707707

708-
unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
709-
if (Name == "default")
710-
return 0;
711-
if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
712-
return Ext->Priority;
713-
return 0;
714-
}
715-
716-
unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
717-
// Take the maximum priority as per feature cost, so more features win.
718-
constexpr unsigned MaxFMVPriority = 1000;
719-
return MaxFMVPriority;
708+
unsigned AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
709+
return llvm::AArch64::getFMVPriority(Features);
720710
}
721711

722712
bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {

clang/lib/Basic/Targets/AArch64.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
137137
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
138138
bool setCPU(const std::string &Name) override;
139139

140-
unsigned multiVersionSortPriority(StringRef Name) const override;
141-
unsigned multiVersionFeatureCost() const override;
140+
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
142141

143142
bool useFP16ConversionIntrinsics() const override {
144143
return false;

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,24 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
423423
Features.split(AttrFeatures, ";");
424424
bool FoundArch = false;
425425

426+
auto handleArchExtension = [](StringRef AttrString,
427+
std::vector<std::string> &Features) {
428+
SmallVector<StringRef, 1> Exts;
429+
AttrString.split(Exts, ",");
430+
for (auto Ext : Exts) {
431+
if (Ext.empty())
432+
continue;
433+
434+
StringRef ExtName = Ext.substr(1);
435+
std::string TargetFeature =
436+
llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
437+
if (!TargetFeature.empty())
438+
Features.push_back(Ext.front() + TargetFeature);
439+
else
440+
Features.push_back(Ext.str());
441+
}
442+
};
443+
426444
for (auto &Feature : AttrFeatures) {
427445
Feature = Feature.trim();
428446
StringRef AttrString = Feature.split("=").second.trim();
@@ -436,20 +454,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
436454

437455
if (AttrString.starts_with("+")) {
438456
// EXTENSION like arch=+v,+zbb
439-
SmallVector<StringRef, 1> Exts;
440-
AttrString.split(Exts, ",");
441-
for (auto Ext : Exts) {
442-
if (Ext.empty())
443-
continue;
444-
445-
StringRef ExtName = Ext.substr(1);
446-
std::string TargetFeature =
447-
llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
448-
if (!TargetFeature.empty())
449-
Ret.Features.push_back(Ext.front() + TargetFeature);
450-
else
451-
Ret.Features.push_back(Ext.str());
452-
}
457+
handleArchExtension(AttrString, Ret.Features);
453458
} else {
454459
// full-arch-string like arch=rv64gcv
455460
handleFullArchString(AttrString, Ret.Features);
@@ -475,11 +480,35 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
475480
Ret.Tune = AttrString;
476481
} else if (Feature.starts_with("priority")) {
477482
// Skip because it only use for FMV.
483+
} else if (Feature.starts_with("+")) {
484+
// Handle target_version/target_clones attribute strings
485+
// that are already delimited by ','
486+
handleArchExtension(Feature, Ret.Features);
478487
}
479488
}
480489
return Ret;
481490
}
482491

492+
unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
493+
// Priority is explicitly specified on RISC-V unlike on other targets, where
494+
// it is derived by all the features of a specific version. Therefore if a
495+
// feature contains the priority string, then return it immediately.
496+
for (StringRef Feature : Features) {
497+
auto [LHS, RHS] = Feature.rsplit(';');
498+
if (LHS.consume_front("priority="))
499+
Feature = LHS;
500+
else if (RHS.consume_front("priority="))
501+
Feature = RHS;
502+
else
503+
continue;
504+
unsigned Priority;
505+
if (!Feature.getAsInteger(0, Priority))
506+
return Priority;
507+
}
508+
// Default Priority is zero.
509+
return 0;
510+
}
511+
483512
TargetInfo::CallingConvCheckResult
484513
RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
485514
switch (CC) {

clang/lib/Basic/Targets/RISCV.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ class RISCVTargetInfo : public TargetInfo {
122122
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
123123
bool supportsTargetAttributeTune() const override { return true; }
124124
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
125+
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
125126

126127
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
127128
return std::make_pair(32, 32);

clang/lib/Basic/Targets/X86.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,19 +1364,26 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
13641364
// correct, so it asserts if the value is out of range.
13651365
}
13661366

1367-
unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const {
1368-
// Valid CPUs have a 'key feature' that compares just better than its key
1369-
// feature.
1370-
using namespace llvm::X86;
1371-
CPUKind Kind = parseArchX86(Name);
1372-
if (Kind != CK_None) {
1373-
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
1374-
return (getFeaturePriority(KeyFeature) << 1) + 1;
1375-
}
1376-
1377-
// Now we know we have a feature, so get its priority and shift it a few so
1378-
// that we have sufficient room for the CPUs (above).
1379-
return getFeaturePriority(getFeature(Name)) << 1;
1367+
unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
1368+
auto getPriority = [this](StringRef Feature) -> unsigned {
1369+
// Valid CPUs have a 'key feature' that compares just better than its key
1370+
// feature.
1371+
using namespace llvm::X86;
1372+
CPUKind Kind = parseArchX86(Feature);
1373+
if (Kind != CK_None) {
1374+
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
1375+
return (getFeaturePriority(KeyFeature) << 1) + 1;
1376+
}
1377+
// Now we know we have a feature, so get its priority and shift it a few so
1378+
// that we have sufficient room for the CPUs (above).
1379+
return getFeaturePriority(getFeature(Feature)) << 1;
1380+
};
1381+
1382+
unsigned Priority = 0;
1383+
for (StringRef Feature : Features)
1384+
if (!Feature.empty())
1385+
Priority = std::max(Priority, getPriority(Feature));
1386+
return Priority;
13801387
}
13811388

13821389
bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const {

clang/lib/Basic/Targets/X86.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
384384
return CPU != llvm::X86::CK_None;
385385
}
386386

387-
unsigned multiVersionSortPriority(StringRef Name) const override;
387+
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;
388388

389389
bool setFPMath(StringRef Name) override;
390390

clang/lib/CodeGen/ABIInfo.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ void ABIInfo::appendAttributeMangling(StringRef AttrStr,
218218
// only have "+" prefixes here.
219219
assert(LHS.starts_with("+") && RHS.starts_with("+") &&
220220
"Features should always have a prefix.");
221-
return TI.multiVersionSortPriority(LHS.substr(1)) >
222-
TI.multiVersionSortPriority(RHS.substr(1));
221+
return TI.getFMVPriority({LHS.substr(1)}) >
222+
TI.getFMVPriority({RHS.substr(1)});
223223
});
224224

225225
bool IsFirst = true;

0 commit comments

Comments
 (0)