Skip to content

Commit fc134b2

Browse files
committed
[RISCV][FMV] Support target_clones
1 parent 126b56a commit fc134b2

15 files changed

+1200
-3
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,4 +378,8 @@ def warn_missing_symbol_graph_dir : Warning<
378378
def err_ast_action_on_llvm_ir : Error<
379379
"cannot apply AST actions to LLVM IR file '%0'">,
380380
DefaultFatal;
381+
382+
def err_os_unsupport_riscv_target_clones : Error<
383+
"target_clones is currently only supported on Linux">;
384+
381385
}

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,8 @@ class TargetInfo : public TransferrableTargetInfo,
14961496
/// Identify whether this target supports multiversioning of functions,
14971497
/// which requires support for cpu_supports and cpu_is functionality.
14981498
bool supportsMultiVersioning() const {
1499-
return getTriple().isX86() || getTriple().isAArch64();
1499+
return getTriple().isX86() || getTriple().isAArch64() ||
1500+
getTriple().isRISCV();
15001501
}
15011502

15021503
/// Identify whether this target supports IFuncs.

clang/include/clang/Sema/SemaRISCV.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class SemaRISCV : public SemaBase {
4343

4444
void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
4545
bool isAliasValid(unsigned BuiltinID, llvm::StringRef AliasName);
46+
bool isValidFMVExtension(StringRef Ext);
4647

4748
/// Indicate RISC-V vector builtin functions enabled or not.
4849
bool DeclareRVVBuiltins = false;

clang/lib/AST/ASTContext.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14181,6 +14181,18 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1418114181
Target->getTargetOpts().FeaturesAsWritten.begin(),
1418214182
Target->getTargetOpts().FeaturesAsWritten.end());
1418314183
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
14184+
} else if (Target->getTriple().isRISCV()) {
14185+
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
14186+
std::vector<std::string> Features;
14187+
if (VersionStr != "default") {
14188+
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr);
14189+
Features.insert(Features.begin(), ParsedAttr.Features.begin(),
14190+
ParsedAttr.Features.end());
14191+
}
14192+
Features.insert(Features.begin(),
14193+
Target->getTargetOpts().FeaturesAsWritten.begin(),
14194+
Target->getTargetOpts().FeaturesAsWritten.end());
14195+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1418414196
} else {
1418514197
std::vector<std::string> Features;
1418614198
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
464464
Ret.Duplicate = "tune=";
465465

466466
Ret.Tune = AttrString;
467+
} else if (Feature.starts_with("priority")) {
468+
// Skip because it only use for FMV.
467469
}
468470
}
469471
return Ret;

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2877,10 +2877,142 @@ void CodeGenFunction::EmitMultiVersionResolver(
28772877
case llvm::Triple::aarch64:
28782878
EmitAArch64MultiVersionResolver(Resolver, Options);
28792879
return;
2880+
case llvm::Triple::riscv32:
2881+
case llvm::Triple::riscv64:
2882+
EmitRISCVMultiVersionResolver(Resolver, Options);
2883+
return;
28802884

28812885
default:
2882-
assert(false && "Only implemented for x86 and AArch64 targets");
2886+
assert(false && "Only implemented for x86, AArch64 and RISC-V targets");
2887+
}
2888+
}
2889+
2890+
static int getPriorityFromAttrString(StringRef AttrStr) {
2891+
SmallVector<StringRef, 8> Attrs;
2892+
2893+
AttrStr.split(Attrs, ";");
2894+
2895+
// Default Priority is zero.
2896+
int Priority = 0;
2897+
for (auto Attr : Attrs) {
2898+
if (Attr.consume_front("priority=")) {
2899+
int Result;
2900+
if (!Attr.getAsInteger(0, Result)) {
2901+
Priority = Result;
2902+
}
2903+
}
2904+
}
2905+
2906+
return Priority;
2907+
}
2908+
2909+
void CodeGenFunction::EmitRISCVMultiVersionResolver(
2910+
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
2911+
2912+
if (getContext().getTargetInfo().getTriple().getOS() !=
2913+
llvm::Triple::OSType::Linux) {
2914+
CGM.getDiags().Report(diag::err_os_unsupport_riscv_target_clones);
2915+
return;
28832916
}
2917+
2918+
llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
2919+
Builder.SetInsertPoint(CurBlock);
2920+
EmitRISCVCpuInit();
2921+
2922+
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
2923+
bool HasDefault = false;
2924+
unsigned DefaultIndex = 0;
2925+
2926+
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions(
2927+
Options);
2928+
2929+
llvm::stable_sort(
2930+
CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
2931+
const CodeGenFunction::MultiVersionResolverOption &RHS) {
2932+
return getPriorityFromAttrString(LHS.Conditions.Features[0]) >
2933+
getPriorityFromAttrString(RHS.Conditions.Features[0]);
2934+
});
2935+
2936+
// Check the each candidate function.
2937+
for (unsigned Index = 0; Index < CurrOptions.size(); Index++) {
2938+
2939+
if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) {
2940+
HasDefault = true;
2941+
DefaultIndex = Index;
2942+
continue;
2943+
}
2944+
2945+
Builder.SetInsertPoint(CurBlock);
2946+
2947+
std::vector<std::string> TargetAttrFeats =
2948+
getContext()
2949+
.getTargetInfo()
2950+
.parseTargetAttr(CurrOptions[Index].Conditions.Features[0])
2951+
.Features;
2952+
2953+
if (TargetAttrFeats.empty())
2954+
continue;
2955+
2956+
// FeaturesCondition: The bitmask of the required extension has been
2957+
// enabled by the runtime object.
2958+
// (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) ==
2959+
// REQUIRED_BITMASK
2960+
//
2961+
// When condition is met, return this version of the function.
2962+
// Otherwise, try the next version.
2963+
//
2964+
// if (FeaturesConditionVersion1)
2965+
// return Version1;
2966+
// else if (FeaturesConditionVersion2)
2967+
// return Version2;
2968+
// else if (FeaturesConditionVersion3)
2969+
// return Version3;
2970+
// ...
2971+
// else
2972+
// return DefaultVersion;
2973+
2974+
// TODO: Add a condition to check the length before accessing elements.
2975+
// Without checking the length first, we may access an incorrect memory
2976+
// address when using different versions.
2977+
llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats;
2978+
2979+
for (auto &Feat : TargetAttrFeats) {
2980+
StringRef CurrFeat = Feat;
2981+
if (CurrFeat.starts_with("+"))
2982+
CurrTargetAttrFeats.push_back(CurrFeat.substr(1));
2983+
}
2984+
2985+
Builder.SetInsertPoint(CurBlock);
2986+
llvm::Value *FeatsCondition = EmitRISCVCpuSupports(CurrTargetAttrFeats);
2987+
2988+
llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
2989+
CGBuilderTy RetBuilder(*this, RetBlock);
2990+
CreateMultiVersionResolverReturn(
2991+
CGM, Resolver, RetBuilder, CurrOptions[Index].Function, SupportsIFunc);
2992+
llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);
2993+
2994+
Builder.SetInsertPoint(CurBlock);
2995+
Builder.CreateCondBr(FeatsCondition, RetBlock, ElseBlock);
2996+
2997+
CurBlock = ElseBlock;
2998+
}
2999+
3000+
// Finally, emit the default one.
3001+
if (HasDefault) {
3002+
Builder.SetInsertPoint(CurBlock);
3003+
CreateMultiVersionResolverReturn(CGM, Resolver, Builder,
3004+
CurrOptions[DefaultIndex].Function,
3005+
SupportsIFunc);
3006+
return;
3007+
}
3008+
3009+
// If no generic/default, emit an unreachable.
3010+
Builder.SetInsertPoint(CurBlock);
3011+
llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
3012+
TrapCall->setDoesNotReturn();
3013+
TrapCall->setDoesNotThrow();
3014+
Builder.CreateUnreachable();
3015+
Builder.ClearInsertionPoint();
28843016
}
28853017

28863018
void CodeGenFunction::EmitAArch64MultiVersionResolver(

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5326,6 +5326,9 @@ class CodeGenFunction : public CodeGenTypeCache {
53265326
void
53275327
EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
53285328
ArrayRef<MultiVersionResolverOption> Options);
5329+
void
5330+
EmitRISCVMultiVersionResolver(llvm::Function *Resolver,
5331+
ArrayRef<MultiVersionResolverOption> Options);
53295332

53305333
private:
53315334
QualType getVarArgType(const Expr *Arg);

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4281,7 +4281,10 @@ void CodeGenModule::emitMultiVersionFunctions() {
42814281
Feats.clear();
42824282
if (getTarget().getTriple().isAArch64())
42834283
TC->getFeatures(Feats, I);
4284-
else {
4284+
else if (getTarget().getTriple().isRISCV()) {
4285+
StringRef Version = TC->getFeatureStr(I);
4286+
Feats.push_back(Version);
4287+
} else {
42854288
StringRef Version = TC->getFeatureStr(I);
42864289
if (Version.starts_with("arch="))
42874290
Architecture = Version.drop_front(sizeof("arch=") - 1);

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,53 @@ class RISCVABIInfo : public DefaultABIInfo {
6363
CharUnits Field2Off) const;
6464

6565
ABIArgInfo coerceVLSVector(QualType Ty) const;
66+
67+
using ABIInfo::appendAttributeMangling;
68+
void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index,
69+
raw_ostream &Out) const override;
70+
void appendAttributeMangling(StringRef AttrStr,
71+
raw_ostream &Out) const override;
6672
};
6773
} // end anonymous namespace
6874

75+
void RISCVABIInfo::appendAttributeMangling(TargetClonesAttr *Attr,
76+
unsigned Index,
77+
raw_ostream &Out) const {
78+
appendAttributeMangling(Attr->getFeatureStr(Index), Out);
79+
}
80+
81+
void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr,
82+
raw_ostream &Out) const {
83+
if (AttrStr == "default") {
84+
Out << ".default";
85+
return;
86+
}
87+
88+
Out << '.';
89+
90+
SmallVector<StringRef, 8> Attrs;
91+
AttrStr.split(Attrs, ";");
92+
93+
// Only consider the arch string.
94+
StringRef ArchStr;
95+
for (auto &Attr : Attrs) {
96+
if (Attr.starts_with("arch="))
97+
ArchStr = Attr;
98+
}
99+
100+
// Extract features string.
101+
SmallVector<StringRef, 8> Features;
102+
ArchStr.consume_front("arch=");
103+
ArchStr.split(Features, ",");
104+
105+
llvm::stable_sort(Features);
106+
107+
for (auto Feat : Features) {
108+
Feat.consume_front("+");
109+
Out << "_" << Feat;
110+
}
111+
}
112+
69113
void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
70114
QualType RetTy = FI.getReturnType();
71115
if (!getCXXABI().classifyReturnType(FI))

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3138,6 +3138,55 @@ bool Sema::checkTargetClonesAttrString(
31383138
HasNotDefault = true;
31393139
}
31403140
}
3141+
} else if (TInfo.getTriple().isRISCV()) {
3142+
// Suppress warn_target_clone_mixed_values
3143+
HasCommas = false;
3144+
3145+
// Cur is split's parts of Str. RISC-V uses Str directly,
3146+
// so skip when encountered more than once.
3147+
if (!Str.starts_with(Cur))
3148+
continue;
3149+
3150+
llvm::SmallVector<StringRef, 8> AttrStrs;
3151+
Str.split(AttrStrs, ";");
3152+
3153+
bool IsPriority = false;
3154+
bool IsDefault = false;
3155+
for (auto &AttrStr : AttrStrs) {
3156+
// Only support arch=+ext,... syntax.
3157+
if (AttrStr.starts_with("arch=+")) {
3158+
ParsedTargetAttr TargetAttr =
3159+
Context.getTargetInfo().parseTargetAttr(AttrStr);
3160+
3161+
if (TargetAttr.Features.empty() ||
3162+
llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) {
3163+
return !RISCV().isValidFMVExtension(Ext);
3164+
}))
3165+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3166+
<< Unsupported << None << Str << TargetClones;
3167+
} else if (AttrStr.starts_with("default")) {
3168+
IsDefault = true;
3169+
DefaultIsDupe = HasDefault;
3170+
HasDefault = true;
3171+
} else if (AttrStr.consume_front("priority=")) {
3172+
IsPriority = true;
3173+
int Digit;
3174+
if (AttrStr.getAsInteger(0, Digit))
3175+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3176+
<< Unsupported << None << Str << TargetClones;
3177+
} else {
3178+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3179+
<< Unsupported << None << Str << TargetClones;
3180+
}
3181+
}
3182+
3183+
if (IsPriority && IsDefault)
3184+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3185+
<< Unsupported << None << Str << TargetClones;
3186+
3187+
if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe)
3188+
Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3189+
StringsBuffer.push_back(Str);
31413190
} else {
31423191
// Other targets ( currently X86 )
31433192
if (Cur.starts_with("arch=")) {

clang/lib/Sema/SemaRISCV.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "clang/Sema/Sema.h"
2626
#include "clang/Support/RISCVVIntrinsicUtils.h"
2727
#include "llvm/ADT/SmallVector.h"
28+
#include "llvm/TargetParser/RISCVISAInfo.h"
2829
#include "llvm/TargetParser/RISCVTargetParser.h"
2930
#include <optional>
3031
#include <string>
@@ -1492,6 +1493,16 @@ bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) {
14921493
BuiltinID <= RISCV::LastRVVBuiltin;
14931494
}
14941495

1496+
bool SemaRISCV::isValidFMVExtension(StringRef Ext) {
1497+
if (Ext.empty())
1498+
return false;
1499+
1500+
if (!Ext.consume_front("+"))
1501+
return false;
1502+
1503+
return -1 != RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext).second;
1504+
}
1505+
14951506
SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {}
14961507

14971508
} // namespace clang
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: not %clang_cc1 -triple riscv64 -target-feature +i -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORT-OS
2+
3+
// CHECK-UNSUPPORT-OS: error: target_clones is currently only supported on Linux
4+
__attribute__((target_clones("default", "arch=+c"))) int foo(void) {
5+
return 2;
6+
}
7+
8+
int bar() { return foo(); }

0 commit comments

Comments
 (0)