Skip to content

Commit

Permalink
[NFC][clang][FMV][TargetInfo] Refactor API for FMV feature priority.
Browse files Browse the repository at this point in the history
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:
llvm#87939
  • Loading branch information
labrinea committed Nov 14, 2024
1 parent b96c24b commit eb6fea7
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 85 deletions.
6 changes: 1 addition & 5 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1514,14 +1514,10 @@ class TargetInfo : public TransferrableTargetInfo,

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

// Return the target-specific cost for feature
// that taken into account in priority sorting.
virtual unsigned multiVersionFeatureCost() const { return 0; }

// Validate the contents of the __builtin_cpu_is(const char*)
// argument.
virtual bool validateCpuIs(StringRef Name) const { return false; }
Expand Down
14 changes: 2 additions & 12 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,18 +705,8 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
return std::nullopt;
}

unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
if (Name == "default")
return 0;
if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
return Ext->Priority;
return 0;
}

unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
// Take the maximum priority as per feature cost, so more features win.
constexpr unsigned MaxFMVPriority = 1000;
return MaxFMVPriority;
unsigned AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return llvm::AArch64::getFMVPriority(Features);
}

bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;

unsigned multiVersionSortPriority(StringRef Name) const override;
unsigned multiVersionFeatureCost() const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

bool useFP16ConversionIntrinsics() const override {
return false;
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,21 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
return Ret;
}

unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
SmallVector<StringRef, 8> Attrs;
Features[0].split(Attrs, ';');
// Default Priority is zero.
unsigned Priority = 0;
for (auto Attr : Attrs) {
if (Attr.consume_front("priority=")) {
unsigned Result;
if (!Attr.getAsInteger(0, Result))
Priority = Result;
}
}
return Priority;
}

TargetInfo::CallingConvCheckResult
RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class RISCVTargetInfo : public TargetInfo {
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
Expand Down
35 changes: 22 additions & 13 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1363,19 +1363,28 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
// correct, so it asserts if the value is out of range.
}

unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const {
// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
CPUKind Kind = parseArchX86(Name);
if (Kind != CK_None) {
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
return (getFeaturePriority(KeyFeature) << 1) + 1;
}

// Now we know we have a feature, so get its priority and shift it a few so
// that we have sufficient room for the CPUs (above).
return getFeaturePriority(getFeature(Name)) << 1;
unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
auto getPriority = [this](StringRef Feature) -> unsigned {
if (Feature.empty())
return 0;

// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
CPUKind Kind = parseArchX86(Feature);
if (Kind != CK_None) {
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
return (getFeaturePriority(KeyFeature) << 1) + 1;
}
// Now we know we have a feature, so get its priority and shift it a few so
// that we have sufficient room for the CPUs (above).
return getFeaturePriority(getFeature(Feature)) << 1;
};

unsigned Priority = 0;
for (StringRef Feature : Features)
Priority = std::max(Priority, getPriority(Feature));
return Priority;
}

bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
return CPU != llvm::X86::CK_None;
}

unsigned multiVersionSortPriority(StringRef Name) const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

bool setFPMath(StringRef Name) override;

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/ABIInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ void ABIInfo::appendAttributeMangling(StringRef AttrStr,
// only have "+" prefixes here.
assert(LHS.starts_with("+") && RHS.starts_with("+") &&
"Features should always have a prefix.");
return TI.multiVersionSortPriority(LHS.substr(1)) >
TI.multiVersionSortPriority(RHS.substr(1));
return TI.getFMVPriority({LHS.substr(1)}) >
TI.getFMVPriority({RHS.substr(1)});
});

bool IsFirst = true;
Expand Down
38 changes: 5 additions & 33 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2904,24 +2904,6 @@ void CodeGenFunction::EmitMultiVersionResolver(
}
}

static unsigned getPriorityFromAttrString(StringRef AttrStr) {
SmallVector<StringRef, 8> Attrs;

AttrStr.split(Attrs, ';');

// Default Priority is zero.
unsigned Priority = 0;
for (auto Attr : Attrs) {
if (Attr.consume_front("priority=")) {
unsigned Result;
if (!Attr.getAsInteger(0, Result))
Priority = Result;
}
}

return Priority;
}

void CodeGenFunction::EmitRISCVMultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {

Expand All @@ -2939,20 +2921,10 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
bool HasDefault = false;
unsigned DefaultIndex = 0;

SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions(
Options);

llvm::stable_sort(
CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
const CodeGenFunction::MultiVersionResolverOption &RHS) {
return getPriorityFromAttrString(LHS.Conditions.Features[0]) >
getPriorityFromAttrString(RHS.Conditions.Features[0]);
});

// Check the each candidate function.
for (unsigned Index = 0; Index < CurrOptions.size(); Index++) {
for (unsigned Index = 0; Index < Options.size(); Index++) {

if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) {
if (Options[Index].Conditions.Features[0].starts_with("default")) {
HasDefault = true;
DefaultIndex = Index;
continue;
Expand All @@ -2963,7 +2935,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
std::vector<std::string> TargetAttrFeats =
getContext()
.getTargetInfo()
.parseTargetAttr(CurrOptions[Index].Conditions.Features[0])
.parseTargetAttr(Options[Index].Conditions.Features[0])
.Features;

if (TargetAttrFeats.empty())
Expand Down Expand Up @@ -3004,7 +2976,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
CGBuilderTy RetBuilder(*this, RetBlock);
CreateMultiVersionResolverReturn(
CGM, Resolver, RetBuilder, CurrOptions[Index].Function, SupportsIFunc);
CGM, Resolver, RetBuilder, Options[Index].Function, SupportsIFunc);
llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);

Builder.SetInsertPoint(CurBlock);
Expand All @@ -3017,7 +2989,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
if (HasDefault) {
Builder.SetInsertPoint(CurBlock);
CreateMultiVersionResolverReturn(CGM, Resolver, Builder,
CurrOptions[DefaultIndex].Function,
Options[DefaultIndex].Function,
SupportsIFunc);
return;
}
Expand Down
23 changes: 6 additions & 17 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4216,22 +4216,11 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *NewFn);

static unsigned
TargetMVPriority(const TargetInfo &TI,
const CodeGenFunction::MultiVersionResolverOption &RO) {
unsigned Priority = 0;
unsigned NumFeatures = 0;
for (StringRef Feat : RO.Conditions.Features) {
Priority = std::max(Priority, TI.multiVersionSortPriority(Feat));
NumFeatures++;
}

if (!RO.Conditions.Architecture.empty())
Priority = std::max(
Priority, TI.multiVersionSortPriority(RO.Conditions.Architecture));

Priority += TI.multiVersionFeatureCost() * NumFeatures;

return Priority;
getFMVPriority(const TargetInfo &TI,
const CodeGenFunction::MultiVersionResolverOption &RO) {
llvm::SmallVector<StringRef, 8> Features{RO.Conditions.Features};
Features.push_back(RO.Conditions.Architecture);
return TI.getFMVPriority(Features);
}

// Multiversion functions should be at most 'WeakODRLinkage' so that a different
Expand Down Expand Up @@ -4362,7 +4351,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
llvm::stable_sort(
Options, [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
const CodeGenFunction::MultiVersionResolverOption &RHS) {
return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
return getFMVPriority(TI, LHS) > getFMVPriority(TI, RHS);
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/TargetParser/AArch64TargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values);

bool isX18ReservedByDefault(const Triple &TT);

// Return the priority for a given set of FMV features.
unsigned getFMVPriority(ArrayRef<StringRef> Features);

// For given feature names, return a bitmask corresponding to the entries of
// AArch64::CPUFeatures. The values in CPUFeatures are not bitmasks
// themselves, they are sequential (0, 1, 2, 3, ...).
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/TargetParser/AArch64TargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubA
return {};
}

unsigned AArch64::getFMVPriority(ArrayRef<StringRef> Features) {
constexpr unsigned MaxFMVPriority = 1000;
unsigned Priority = 0;
unsigned NumFeatures = 0;
for (StringRef Feature : Features) {
if (auto Ext = parseFMVExtension(Feature)) {
Priority = std::max(Priority, Ext->Priority);
NumFeatures++;
}
}
return Priority + MaxFMVPriority * NumFeatures;
}

uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
uint64_t FeaturesMask = 0;
for (const StringRef &FeatureStr : FeatureStrs) {
Expand Down

0 comments on commit eb6fea7

Please sign in to comment.