[NFC][Clang][FMV] Make FMV priority data type future proof. (#150079)

FMV priority is the returned value of a polymorphic function. On RISC-V
and X86 targets a 32-bit value is enough. On AArch64 we currently need
64 bits and we will soon exceed that. APInt seems to be a suitable
replacement for uint64_t, presumably with minimal compile time overhead.
It allows bit manipulation, comparison and variable bit width.
This commit is contained in:
Alexandros Lamprineas 2025-07-23 10:37:29 +01:00 committed by GitHub
parent 36c37b019b
commit 3ab64c5b29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 45 additions and 40 deletions

View File

@ -1551,8 +1551,8 @@ public:
// Return the target-specific priority for features/cpus/vendors so
// that they can be properly sorted for checking.
virtual uint64_t getFMVPriority(ArrayRef<StringRef> Features) const {
return 0;
virtual llvm::APInt getFMVPriority(ArrayRef<StringRef> Features) const {
return llvm::APInt::getZero(32);
}
// Validate the contents of the __builtin_cpu_is(const char*)

View File

@ -786,7 +786,8 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts,
return std::nullopt;
}
uint64_t AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
llvm::APInt
AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return llvm::AArch64::getFMVPriority(Features);
}

View File

@ -152,7 +152,7 @@ public:
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;
uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
llvm::APInt getFMVPriority(ArrayRef<StringRef> Features) const override;
bool useFP16ConversionIntrinsics() const override {
return false;

View File

@ -568,7 +568,8 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
return Ret;
}
uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
llvm::APInt
RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
// Priority is explicitly specified on RISC-V unlike on other targets, where
// it is derived by all the features of a specific version. Therefore if a
// feature contains the priority string, then return it immediately.
@ -580,12 +581,12 @@ uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
Feature = RHS;
else
continue;
uint64_t Priority;
unsigned Priority;
if (!Feature.getAsInteger(0, Priority))
return Priority;
return llvm::APInt(32, Priority);
}
// Default Priority is zero.
return 0;
return llvm::APInt::getZero(32);
}
TargetInfo::CallingConvCheckResult

View File

@ -123,7 +123,7 @@ public:
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
llvm::APInt getFMVPriority(ArrayRef<StringRef> Features) const override;
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);

View File

@ -1390,8 +1390,8 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
// correct, so it asserts if the value is out of range.
}
uint64_t X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
auto getPriority = [](StringRef Feature) -> uint64_t {
llvm::APInt X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
auto getPriority = [](StringRef Feature) -> unsigned {
// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
@ -1405,11 +1405,11 @@ uint64_t X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return getFeaturePriority(getFeature(Feature)) << 1;
};
uint64_t Priority = 0;
unsigned Priority = 0;
for (StringRef Feature : Features)
if (!Feature.empty())
Priority = std::max(Priority, getPriority(Feature));
return Priority;
return llvm::APInt(32, Priority);
}
bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const {

View File

@ -388,7 +388,7 @@ public:
return CPU != llvm::X86::CK_None;
}
uint64_t getFMVPriority(ArrayRef<StringRef> Features) const override;
llvm::APInt getFMVPriority(ArrayRef<StringRef> Features) const override;
bool setFPMath(StringRef Name) override;

View File

@ -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.getFMVPriority({LHS.substr(1)}) >
TI.getFMVPriority({RHS.substr(1)});
return TI.getFMVPriority({LHS.substr(1)})
.ugt(TI.getFMVPriority({RHS.substr(1)}));
});
bool IsFirst = true;

View File

@ -4418,8 +4418,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *NewFn);
static uint64_t getFMVPriority(const TargetInfo &TI,
const CodeGenFunction::FMVResolverOption &RO) {
static llvm::APInt
getFMVPriority(const TargetInfo &TI,
const CodeGenFunction::FMVResolverOption &RO) {
llvm::SmallVector<StringRef, 8> Features{RO.Features};
if (RO.Architecture)
Features.push_back(*RO.Architecture);
@ -4544,7 +4545,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
llvm::stable_sort(
Options, [&TI](const CodeGenFunction::FMVResolverOption &LHS,
const CodeGenFunction::FMVResolverOption &RHS) {
return getFMVPriority(TI, LHS) > getFMVPriority(TI, RHS);
return getFMVPriority(TI, LHS).ugt(getFMVPriority(TI, RHS));
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);

View File

@ -8112,7 +8112,7 @@ Value *CodeGenFunction::EmitAArch64CpuSupports(const CallExpr *E) {
llvm::Value *
CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
uint64_t FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs);
llvm::APInt FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs);
Value *Result = Builder.getTrue();
if (FeaturesMask != 0) {
// Get features from structure in runtime library
@ -8128,7 +8128,7 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
{ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 0)});
Value *Features = Builder.CreateAlignedLoad(Int64Ty, CpuFeatures,
CharUnits::fromQuantity(8));
Value *Mask = Builder.getInt64(FeaturesMask);
Value *Mask = Builder.getInt(FeaturesMask.trunc(64));
Value *Bitset = Builder.CreateAnd(Features, Mask);
Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
Result = Builder.CreateAnd(Result, Cmp);

View File

@ -1930,7 +1930,7 @@ public:
/// Returns a bitmask constructed from the target-features or fmv-features
/// metadata of a function.
LLVM_ABI uint64_t getFeatureMask(const Function &F) const;
LLVM_ABI APInt getFeatureMask(const Function &F) const;
/// Returns true if this is an instance of a function with multiple versions.
LLVM_ABI bool isMultiversionedFunction(const Function &F) const;

View File

@ -1126,7 +1126,9 @@ public:
virtual bool hasArmWideBranch(bool) const { return false; }
virtual uint64_t getFeatureMask(const Function &F) const { return 0; }
virtual APInt getFeatureMask(const Function &F) const {
return APInt::getZero(32);
}
virtual bool isMultiversionedFunction(const Function &F) const {
return false;

View File

@ -276,14 +276,14 @@ LLVM_ABI bool isX18ReservedByDefault(const Triple &TT);
// For a given set of feature names, which can be either target-features, or
// fmv-features metadata, expand their dependencies and then return a bitmask
// corresponding to the entries of AArch64::FeatPriorities.
LLVM_ABI uint64_t getFMVPriority(ArrayRef<StringRef> Features);
LLVM_ABI APInt getFMVPriority(ArrayRef<StringRef> Features);
// For a given set of FMV feature names, expand their dependencies and then
// 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, ...). The resulting bitmask is used at runtime to test whether
// a certain FMV feature is available on the host.
LLVM_ABI uint64_t getCpuSupportsMask(ArrayRef<StringRef> Features);
LLVM_ABI APInt getCpuSupportsMask(ArrayRef<StringRef> Features);
LLVM_ABI void PrintSupportedExtensions();

View File

@ -1423,7 +1423,7 @@ bool TargetTransformInfo::hasArmWideBranch(bool Thumb) const {
return TTIImpl->hasArmWideBranch(Thumb);
}
uint64_t TargetTransformInfo::getFeatureMask(const Function &F) const {
APInt TargetTransformInfo::getFeatureMask(const Function &F) const {
return TTIImpl->getFeatureMask(F);
}

View File

@ -249,7 +249,7 @@ static bool hasPossibleIncompatibleOps(const Function *F) {
return false;
}
uint64_t AArch64TTIImpl::getFeatureMask(const Function &F) const {
APInt AArch64TTIImpl::getFeatureMask(const Function &F) const {
StringRef AttributeStr =
isMultiversionedFunction(F) ? "fmv-features" : "target-features";
StringRef FeatureStr = F.getFnAttribute(AttributeStr).getValueAsString();

View File

@ -89,7 +89,7 @@ public:
unsigned getInlineCallPenalty(const Function *F, const CallBase &Call,
unsigned DefaultCallPenalty) const override;
uint64_t getFeatureMask(const Function &F) const override;
APInt getFeatureMask(const Function &F) const override;
bool isMultiversionedFunction(const Function &F) const override;

View File

@ -55,7 +55,7 @@ std::optional<AArch64::FMVInfo> lookupFMVByID(AArch64::ArchExtKind ExtID) {
return {};
}
uint64_t AArch64::getFMVPriority(ArrayRef<StringRef> Features) {
APInt AArch64::getFMVPriority(ArrayRef<StringRef> Features) {
// Transitively enable the Arch Extensions which correspond to each feature.
ExtensionSet FeatureBits;
for (const StringRef Feature : Features) {
@ -69,15 +69,15 @@ uint64_t AArch64::getFMVPriority(ArrayRef<StringRef> Features) {
}
// Construct a bitmask for all the transitively enabled Arch Extensions.
uint64_t PriorityMask = 0;
APInt PriorityMask = APInt::getZero(128);
for (const FMVInfo &Info : getFMVInfo())
if (Info.ID && FeatureBits.Enabled.test(*Info.ID))
PriorityMask |= (1ULL << Info.PriorityBit);
PriorityMask.setBit(Info.PriorityBit);
return PriorityMask;
}
uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> Features) {
APInt AArch64::getCpuSupportsMask(ArrayRef<StringRef> Features) {
// Transitively enable the Arch Extensions which correspond to each feature.
ExtensionSet FeatureBits;
for (const StringRef Feature : Features)
@ -86,10 +86,10 @@ uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> Features) {
FeatureBits.enable(*Info->ID);
// Construct a bitmask for all the transitively enabled Arch Extensions.
uint64_t FeaturesMask = 0;
APInt FeaturesMask = APInt::getZero(128);
for (const FMVInfo &Info : getFMVInfo())
if (Info.ID && FeatureBits.Enabled.test(*Info.ID))
FeaturesMask |= (1ULL << Info.FeatureBit);
FeaturesMask.setBit(Info.FeatureBit);
return FeaturesMask;
}

View File

@ -2529,7 +2529,7 @@ static bool OptimizeNonTrivialIFuncs(
bool Changed = false;
// Cache containing the mask constructed from a function's target features.
DenseMap<Function *, uint64_t> FeatureMask;
DenseMap<Function *, APInt> FeatureMask;
for (GlobalIFunc &IF : M.ifuncs()) {
if (IF.isInterposable())
@ -2568,7 +2568,7 @@ static bool OptimizeNonTrivialIFuncs(
// Sort the callee versions in decreasing priority order.
sort(Callees, [&](auto *LHS, auto *RHS) {
return FeatureMask[LHS] > FeatureMask[RHS];
return FeatureMask[LHS].ugt(FeatureMask[RHS]);
});
// Find the callsites and cache the feature mask for each caller.
@ -2591,10 +2591,10 @@ static bool OptimizeNonTrivialIFuncs(
// Sort the caller versions in decreasing priority order.
sort(Callers, [&](auto *LHS, auto *RHS) {
return FeatureMask[LHS] > FeatureMask[RHS];
return FeatureMask[LHS].ugt(FeatureMask[RHS]);
});
auto implies = [](uint64_t A, uint64_t B) { return (A & B) == B; };
auto implies = [](APInt A, APInt B) { return B.isSubsetOf(A); };
// Index to the highest priority candidate.
unsigned I = 0;
@ -2603,8 +2603,8 @@ static bool OptimizeNonTrivialIFuncs(
assert(I < Callees.size() && "Found callers of equal priority");
Function *Callee = Callees[I];
uint64_t CallerBits = FeatureMask[Caller];
uint64_t CalleeBits = FeatureMask[Callee];
APInt CallerBits = FeatureMask[Caller];
APInt CalleeBits = FeatureMask[Callee];
// In the case of FMV callers, we know that all higher priority callers
// than the current one did not get selected at runtime, which helps