Skip to content

Commit 0216578

Browse files
committed
[RISCV][FMV] Support target_clones
1 parent 4260683 commit 0216578

File tree

15 files changed

+733
-5
lines changed

15 files changed

+733
-5
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,8 @@ def warn_missing_symbol_graph_dir : Warning<
375375
def err_ast_action_on_llvm_ir : Error<
376376
"cannot apply AST actions to LLVM IR file '%0'">,
377377
DefaultFatal;
378+
379+
def err_os_unsupport_riscv_target_clones : Error<
380+
"target_clones is currently only supported on Linux">;
381+
378382
}

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,8 @@ class TargetInfo : public TransferrableTargetInfo,
15191519
/// Identify whether this target supports multiversioning of functions,
15201520
/// which requires support for cpu_supports and cpu_is functionality.
15211521
bool supportsMultiVersioning() const {
1522-
return getTriple().isX86() || getTriple().isAArch64();
1522+
return getTriple().isX86() || getTriple().isAArch64() ||
1523+
getTriple().isRISCV();
15231524
}
15241525

15251526
/// Identify whether this target supports IFuncs.

clang/lib/AST/ASTContext.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13839,6 +13839,18 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1383913839
Target->getTargetOpts().FeaturesAsWritten.begin(),
1384013840
Target->getTargetOpts().FeaturesAsWritten.end());
1384113841
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
13842+
} else if (Target->getTriple().isRISCV()) {
13843+
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
13844+
std::vector<std::string> Features;
13845+
if (VersionStr != "default") {
13846+
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr);
13847+
Features.insert(Features.begin(), ParsedAttr.Features.begin(),
13848+
ParsedAttr.Features.end());
13849+
}
13850+
Features.insert(Features.begin(),
13851+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13852+
Target->getTargetOpts().FeaturesAsWritten.end());
13853+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1384213854
} else {
1384313855
std::vector<std::string> Features;
1384413856
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "llvm/Support/MathExtras.h"
6363
#include "llvm/Support/ScopedPrinter.h"
6464
#include "llvm/TargetParser/AArch64TargetParser.h"
65+
#include "llvm/TargetParser/RISCVTargetParser.h"
6566
#include "llvm/TargetParser/X86TargetParser.h"
6667
#include <optional>
6768
#include <sstream>
@@ -14214,6 +14215,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
1421414215
return Builder.CreateCall(Func);
1421514216
}
1421614217

14218+
Value *CodeGenFunction::EmitRISCVCpuInit() {
14219+
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
14220+
llvm::FunctionCallee Func =
14221+
CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
14222+
cast<llvm::GlobalValue>(Func.getCallee())->setDSOLocal(true);
14223+
cast<llvm::GlobalValue>(Func.getCallee())
14224+
->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
14225+
return Builder.CreateCall(Func);
14226+
}
14227+
1421714228
Value *CodeGenFunction::EmitX86CpuInit() {
1421814229
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
1421914230
/*Variadic*/ false);
@@ -14266,6 +14277,71 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1426614277
return Result;
1426714278
}
1426814279

14280+
Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs,
14281+
unsigned &MaxGroupIDUsed) {
14282+
14283+
const unsigned FeatureBitSize = llvm::RISCV::RISCVFeatureBitSize;
14284+
llvm::ArrayType *ArrayOfInt64Ty =
14285+
llvm::ArrayType::get(Int64Ty, FeatureBitSize);
14286+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
14287+
llvm::Constant *RISCVFeaturesBits =
14288+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14289+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
14290+
14291+
auto LoadFeatureBit = [&](unsigned Index) {
14292+
// Create GEP then load.
14293+
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
14294+
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
14295+
IndexVal};
14296+
Value *Ptr =
14297+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14298+
Value *FeaturesBit =
14299+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14300+
return FeaturesBit;
14301+
};
14302+
14303+
SmallVector<uint64_t> RequireFeatureBits =
14304+
llvm::RISCV::getRequireFeatureBitMask(FeaturesStrs);
14305+
Value *Result = Builder.getTrue();
14306+
for (unsigned i = 0; i < RequireFeatureBits.size(); i++) {
14307+
if (!RequireFeatureBits[i])
14308+
continue;
14309+
MaxGroupIDUsed = i;
14310+
Value *Mask = Builder.getInt64(RequireFeatureBits[i]);
14311+
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(i), Mask);
14312+
Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
14313+
Result = Builder.CreateAnd(Result, Cmp);
14314+
}
14315+
14316+
return Result;
14317+
}
14318+
14319+
Value *CodeGenFunction::EmitRISCVFeatureBitsLength(unsigned MaxGroupIDUsed) {
14320+
14321+
const unsigned FeatureBitSize = llvm::RISCV::RISCVFeatureBitSize;
14322+
llvm::ArrayType *ArrayOfInt64Ty =
14323+
llvm::ArrayType::get(Int64Ty, FeatureBitSize);
14324+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
14325+
llvm::Constant *RISCVFeaturesBits =
14326+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14327+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
14328+
14329+
auto LoadMaxGroupID = [&]() {
14330+
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(0)};
14331+
llvm::Value *Ptr =
14332+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14333+
Value *Length =
14334+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14335+
return Length;
14336+
};
14337+
14338+
Value *UsedMaxGroupID = Builder.getInt64(MaxGroupIDUsed);
14339+
Value *GroupIDResult =
14340+
Builder.CreateICmpUGT(LoadMaxGroupID(), UsedMaxGroupID);
14341+
14342+
return GroupIDResult;
14343+
}
14344+
1426914345
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
1427014346
const CallExpr *E) {
1427114347
if (BuiltinID == Builtin::BI__builtin_cpu_is)

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2854,10 +2854,121 @@ void CodeGenFunction::EmitMultiVersionResolver(
28542854
case llvm::Triple::aarch64:
28552855
EmitAArch64MultiVersionResolver(Resolver, Options);
28562856
return;
2857+
case llvm::Triple::riscv32:
2858+
case llvm::Triple::riscv64:
2859+
EmitRISCVMultiVersionResolver(Resolver, Options);
2860+
return;
28572861

28582862
default:
2859-
assert(false && "Only implemented for x86 and AArch64 targets");
2863+
assert(false && "Only implemented for x86, AArch64 and RISC-V targets");
2864+
}
2865+
}
2866+
2867+
void CodeGenFunction::EmitRISCVMultiVersionResolver(
2868+
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
2869+
2870+
if (getContext().getTargetInfo().getTriple().getOS() !=
2871+
llvm::Triple::OSType::Linux) {
2872+
CGM.getDiags().Report(diag::err_os_unsupport_riscv_target_clones);
2873+
return;
2874+
}
2875+
2876+
llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
2877+
Builder.SetInsertPoint(CurBlock);
2878+
EmitRISCVCpuInit();
2879+
2880+
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
2881+
bool HasDefault = false;
2882+
int DefaultIndex = 0;
2883+
// Check the each candidate function.
2884+
for (unsigned Index = 0; Index < Options.size(); Index++) {
2885+
2886+
if (Options[Index].Conditions.Features[0].starts_with("default")) {
2887+
HasDefault = true;
2888+
DefaultIndex = Index;
2889+
continue;
2890+
}
2891+
2892+
Builder.SetInsertPoint(CurBlock);
2893+
2894+
std::vector<std::string> TargetAttrFeats =
2895+
getContext()
2896+
.getTargetInfo()
2897+
.parseTargetAttr(Options[Index].Conditions.Features[0])
2898+
.Features;
2899+
2900+
if (TargetAttrFeats.empty())
2901+
continue;
2902+
2903+
// Two conditions need to be checked for the current version:
2904+
//
2905+
// 1. LengthCondition: The maximum group ID of the required extension
2906+
// does not exceed the runtime object's length.
2907+
// __riscv_feature_bits.length > MAX_USED_GROUPID
2908+
//
2909+
// 2. FeaturesCondition: The bitmask of the required extension has been
2910+
// enabled by the runtime object.
2911+
// (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) ==
2912+
// REQUIRED_BITMASK
2913+
//
2914+
// When both conditions are met, return this version of the function.
2915+
// Otherwise, try the next version.
2916+
//
2917+
// if (LengthConditionVersion1 && FeaturesConditionVersion1)
2918+
// return Version1;
2919+
// else if (LengthConditionVersion2 && FeaturesConditionVersion2)
2920+
// return Version2;
2921+
// else if (LengthConditionVersion3 && FeaturesConditionVersion3)
2922+
// return Version3;
2923+
// ...
2924+
// else
2925+
// return DefaultVersion;
2926+
llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats;
2927+
2928+
for (auto Feat : TargetAttrFeats)
2929+
CurrTargetAttrFeats.push_back(StringRef(Feat).substr(1));
2930+
2931+
llvm::BasicBlock *FeatsCondBB = createBasicBlock("resolver_cond", Resolver);
2932+
2933+
Builder.SetInsertPoint(FeatsCondBB);
2934+
unsigned MaxGroupIDUsed = 0;
2935+
llvm::Value *FeatsCondition =
2936+
EmitRISCVCpuSupports(CurrTargetAttrFeats, MaxGroupIDUsed);
2937+
2938+
Builder.SetInsertPoint(CurBlock);
2939+
llvm::Value *MaxGroupLengthCondition =
2940+
EmitRISCVFeatureBitsLength(MaxGroupIDUsed);
2941+
2942+
llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
2943+
CGBuilderTy RetBuilder(*this, RetBlock);
2944+
CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder,
2945+
Options[Index].Function, SupportsIFunc);
2946+
llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);
2947+
2948+
Builder.SetInsertPoint(CurBlock);
2949+
Builder.CreateCondBr(MaxGroupLengthCondition, FeatsCondBB, ElseBlock);
2950+
2951+
Builder.SetInsertPoint(FeatsCondBB);
2952+
Builder.CreateCondBr(FeatsCondition, RetBlock, ElseBlock);
2953+
2954+
CurBlock = ElseBlock;
28602955
}
2956+
2957+
// Finally, emit the default one.
2958+
if (HasDefault) {
2959+
Builder.SetInsertPoint(CurBlock);
2960+
CreateMultiVersionResolverReturn(
2961+
CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc);
2962+
return;
2963+
}
2964+
2965+
// If no generic/default, emit an unreachable.
2966+
Builder.SetInsertPoint(CurBlock);
2967+
llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
2968+
TrapCall->setDoesNotReturn();
2969+
TrapCall->setDoesNotThrow();
2970+
Builder.CreateUnreachable();
2971+
Builder.ClearInsertionPoint();
28612972
}
28622973

28632974
void CodeGenFunction::EmitAArch64MultiVersionResolver(

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5291,6 +5291,9 @@ class CodeGenFunction : public CodeGenTypeCache {
52915291
void
52925292
EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
52935293
ArrayRef<MultiVersionResolverOption> Options);
5294+
void
5295+
EmitRISCVMultiVersionResolver(llvm::Function *Resolver,
5296+
ArrayRef<MultiVersionResolverOption> Options);
52945297

52955298
private:
52965299
QualType getVarArgType(const Expr *Arg);
@@ -5315,6 +5318,10 @@ class CodeGenFunction : public CodeGenTypeCache {
53155318
FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
53165319
llvm::Value *EmitAArch64CpuSupports(const CallExpr *E);
53175320
llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
5321+
llvm::Value *EmitRISCVCpuInit();
5322+
llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeatureStrs,
5323+
unsigned &MaxGroupIDUsed);
5324+
llvm::Value *EmitRISCVFeatureBitsLength(unsigned MaxGroupIDUsed);
53185325
};
53195326

53205327
inline DominatingLLVMValue::saved_type

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4257,7 +4257,10 @@ void CodeGenModule::emitMultiVersionFunctions() {
42574257
Feats.clear();
42584258
if (getTarget().getTriple().isAArch64())
42594259
TC->getFeatures(Feats, I);
4260-
else {
4260+
else if (getTarget().getTriple().isRISCV()) {
4261+
StringRef Version = TC->getFeatureStr(I);
4262+
Feats.push_back(Version);
4263+
} else {
42614264
StringRef Version = TC->getFeatureStr(I);
42624265
if (Version.starts_with("arch="))
42634266
Architecture = Version.drop_front(sizeof("arch=") - 1);

clang/lib/CodeGen/Targets/RISCV.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,32 @@ 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+
Out << AttrStr;
90+
}
91+
6992
void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
7093
QualType RetTy = FI.getReturnType();
7194
if (!getCXXABI().classifyReturnType(FI))

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,32 @@ bool Sema::checkTargetClonesAttrString(
31273127
/*IncludeLocallyStreaming=*/false))
31283128
return Diag(LiteralLoc,
31293129
diag::err_sme_streaming_cannot_be_multiversioned);
3130+
} else if (TInfo.getTriple().isRISCV()) {
3131+
// Suppress warn_target_clone_mixed_values
3132+
HasCommas = false;
3133+
3134+
// Only support arch=+ext,... syntax.
3135+
if (Str.starts_with("arch=+")) {
3136+
// parseTargetAttr will parse full version string,
3137+
// the following split Cur string is no longer interesting.
3138+
if ((!Cur.starts_with("arch=")))
3139+
continue;
3140+
3141+
ParsedTargetAttr TargetAttr =
3142+
Context.getTargetInfo().parseTargetAttr(Str);
3143+
if (TargetAttr.Features.empty())
3144+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3145+
<< Unsupported << None << Str << TargetClones;
3146+
} else if (Str == "default") {
3147+
DefaultIsDupe = HasDefault;
3148+
HasDefault = true;
3149+
} else {
3150+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3151+
<< Unsupported << None << Str << TargetClones;
3152+
}
3153+
if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe)
3154+
Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3155+
StringsBuffer.push_back(Str);
31303156
} else {
31313157
// Other targets ( currently X86 )
31323158
if (Cur.starts_with("arch=")) {
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 foo2(void) {
5+
return 2;
6+
}
7+
8+
int bar() { return foo1()+foo2(); }

0 commit comments

Comments
 (0)