Skip to content

Commit aaa7017

Browse files
committed
[RISCV][FMV] Support target_clones
1 parent 937fecd commit aaa7017

File tree

17 files changed

+741
-7
lines changed

17 files changed

+741
-7
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

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

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,8 @@ class TargetInfo : public TransferrableTargetInfo,
14811481
/// Identify whether this target supports multiversioning of functions,
14821482
/// which requires support for cpu_supports and cpu_is functionality.
14831483
bool supportsMultiVersioning() const {
1484-
return getTriple().isX86() || getTriple().isAArch64();
1484+
return getTriple().isX86() || getTriple().isAArch64() ||
1485+
getTriple().isRISCV();
14851486
}
14861487

14871488
/// Identify whether this target supports IFuncs.

clang/lib/AST/ASTContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13744,6 +13744,16 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1374413744
Features.insert(Features.begin(),
1374513745
Target->getTargetOpts().FeaturesAsWritten.begin(),
1374613746
Target->getTargetOpts().FeaturesAsWritten.end());
13747+
} else if (Target->getTriple().isRISCV()) {
13748+
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
13749+
if (VersionStr != "default") {
13750+
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr);
13751+
Features.insert(Features.begin(), ParsedAttr.Features.begin(),
13752+
ParsedAttr.Features.end());
13753+
}
13754+
Features.insert(Features.begin(),
13755+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13756+
Target->getTargetOpts().FeaturesAsWritten.end());
1374713757
} else {
1374813758
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
1374913759
if (VersionStr.starts_with("arch="))

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ bool RISCVTargetInfo::initFeatureMap(
257257

258258
// If a target attribute specified a full arch string, override all the ISA
259259
// extension target features.
260-
const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
260+
const auto I = llvm::find(FeaturesVec, "+__RISCV_TargetAttrNeedOverride");
261261
if (I != FeaturesVec.end()) {
262262
std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());
263263

@@ -367,6 +367,12 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
367367
return true;
368368
}
369369

370+
bool RISCVTargetInfo::isValidFeatureName(StringRef Feature) const {
371+
if (Feature.starts_with("__RISCV_TargetAttrNeedOverride"))
372+
return true;
373+
return llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature);
374+
}
375+
370376
bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
371377
bool Is64Bit = getTriple().isArch64Bit();
372378
return llvm::RISCV::parseCPU(Name, Is64Bit);
@@ -391,7 +397,7 @@ void RISCVTargetInfo::fillValidTuneCPUList(
391397

392398
static void handleFullArchString(StringRef FullArchStr,
393399
std::vector<std::string> &Features) {
394-
Features.push_back("__RISCV_TargetAttrNeedOverride");
400+
Features.push_back("+__RISCV_TargetAttrNeedOverride");
395401
auto RII = llvm::RISCVISAInfo::parseArchString(
396402
FullArchStr, /* EnableExperimentalExtension */ true);
397403
if (llvm::errorToBool(RII.takeError())) {

clang/lib/Basic/Targets/RISCV.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ class RISCVTargetInfo : public TargetInfo {
106106
bool handleTargetFeatures(std::vector<std::string> &Features,
107107
DiagnosticsEngine &Diags) override;
108108

109+
bool isValidFeatureName(StringRef Feature) const override;
110+
109111
bool hasBitIntType() const override { return true; }
110112

111113
bool hasBFloat16Type() const override { return true; }

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 78 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>
@@ -14174,6 +14175,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
1417414175
return Builder.CreateCall(Func);
1417514176
}
1417614177

14178+
Value *CodeGenFunction::EmitRISCVCpuInit() {
14179+
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
14180+
llvm::FunctionCallee Func =
14181+
CGM.CreateRuntimeFunction(FTy, "__init_riscv_features_bit");
14182+
cast<llvm::GlobalValue>(Func.getCallee())->setDSOLocal(true);
14183+
cast<llvm::GlobalValue>(Func.getCallee())
14184+
->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
14185+
return Builder.CreateCall(Func);
14186+
}
14187+
1417714188
Value *CodeGenFunction::EmitX86CpuInit() {
1417814189
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
1417914190
/*Variadic*/ false);
@@ -14226,6 +14237,73 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1422614237
return Result;
1422714238
}
1422814239

14240+
Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs,
14241+
unsigned &MaxGroupIDUsed) {
14242+
14243+
const unsigned FeatureBitSize = 2;
14244+
llvm::ArrayType *ArrayOfInt64Ty =
14245+
llvm::ArrayType::get(Int64Ty, FeatureBitSize);
14246+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
14247+
llvm::Constant *RISCVFeaturesBits =
14248+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14249+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
14250+
14251+
auto LoadFeatureBit = [&](unsigned Index) {
14252+
// Create GEP then load.
14253+
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
14254+
std::vector<llvm::Value *> GEPIndices = {llvm::ConstantInt::get(Int32Ty, 0),
14255+
llvm::ConstantInt::get(Int32Ty, 1),
14256+
IndexVal};
14257+
Value *Ptr =
14258+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14259+
Value *FeaturesBit =
14260+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14261+
return FeaturesBit;
14262+
};
14263+
14264+
SmallVector<unsigned long long> RequireFeatureBits =
14265+
llvm::RISCV::getRequireFeatureBitMask(FeaturesStrs);
14266+
Value *Result = Builder.getTrue();
14267+
for (unsigned i = 0; i < RequireFeatureBits.size(); i++) {
14268+
if (!RequireFeatureBits[i])
14269+
continue;
14270+
MaxGroupIDUsed = i;
14271+
Value *Mask = Builder.getInt64(RequireFeatureBits[i]);
14272+
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(i), Mask);
14273+
Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
14274+
Result = Builder.CreateAnd(Result, Cmp);
14275+
}
14276+
14277+
return Result;
14278+
}
14279+
14280+
Value *CodeGenFunction::EmitRISCVFeatureBitsLength(unsigned MaxGroupIDUsed) {
14281+
14282+
const unsigned FeatureBitSize = 2;
14283+
llvm::ArrayType *ArrayOfInt64Ty =
14284+
llvm::ArrayType::get(Int64Ty, FeatureBitSize);
14285+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
14286+
llvm::Constant *RISCVFeaturesBits =
14287+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14288+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
14289+
14290+
auto LoadMaxGroupID = [&]() {
14291+
std::vector<llvm::Value *> GEPIndices = {
14292+
llvm::ConstantInt::get(Int32Ty, 0), llvm::ConstantInt::get(Int32Ty, 0)};
14293+
llvm::Value *Ptr =
14294+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14295+
Value *Length =
14296+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14297+
return Length;
14298+
};
14299+
14300+
Value *UsedMaxGroupID = Builder.getInt64(MaxGroupIDUsed);
14301+
Value *GroupIDResult =
14302+
Builder.CreateICmpULT(UsedMaxGroupID, LoadMaxGroupID());
14303+
14304+
return GroupIDResult;
14305+
}
14306+
1422914307
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
1423014308
const CallExpr *E) {
1423114309
if (BuiltinID == Builtin::BI__builtin_cpu_is)

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2850,10 +2850,113 @@ void CodeGenFunction::EmitMultiVersionResolver(
28502850
case llvm::Triple::aarch64:
28512851
EmitAArch64MultiVersionResolver(Resolver, Options);
28522852
return;
2853+
case llvm::Triple::riscv32:
2854+
case llvm::Triple::riscv64:
2855+
EmitRISCVMultiVersionResolver(Resolver, Options);
2856+
return;
28532857

28542858
default:
2855-
assert(false && "Only implemented for x86 and AArch64 targets");
2859+
assert(false && "Only implemented for x86, AArch64 and RISC-V targets");
2860+
}
2861+
}
2862+
2863+
void CodeGenFunction::EmitRISCVMultiVersionResolver(
2864+
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
2865+
2866+
if (getContext().getTargetInfo().getTriple().getOS() !=
2867+
llvm::Triple::OSType::Linux) {
2868+
CGM.getDiags().Report(diag::err_os_unsupport_riscv_target_clones);
2869+
return;
2870+
}
2871+
2872+
llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
2873+
Builder.SetInsertPoint(CurBlock);
2874+
EmitRISCVCpuInit();
2875+
2876+
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
2877+
bool HasDefault = false;
2878+
int DefaultIndex = 0;
2879+
// Check the each candidate function.
2880+
for (unsigned Index = 0; Index < Options.size(); Index++) {
2881+
2882+
if (Options[Index].Conditions.Features[0].starts_with("default")) {
2883+
HasDefault = true;
2884+
DefaultIndex = Index;
2885+
continue;
2886+
}
2887+
2888+
Builder.SetInsertPoint(CurBlock);
2889+
2890+
std::vector<std::string> TargetAttrFeats =
2891+
getContext()
2892+
.getTargetInfo()
2893+
.parseTargetAttr(Options[Index].Conditions.Features[0])
2894+
.Features;
2895+
2896+
if (!TargetAttrFeats.empty()) {
2897+
// If this function doens't need override, then merge with module level
2898+
// target features. Otherwise, remain the current target features.
2899+
auto I = llvm::find(TargetAttrFeats, "+__RISCV_TargetAttrNeedOverride");
2900+
if (I == TargetAttrFeats.end())
2901+
TargetAttrFeats.insert(TargetAttrFeats.begin(),
2902+
Target.getTargetOpts().FeaturesAsWritten.begin(),
2903+
Target.getTargetOpts().FeaturesAsWritten.end());
2904+
else
2905+
TargetAttrFeats.erase(I);
2906+
2907+
// Only consider +<extension-feature>.
2908+
llvm::SmallVector<StringRef, 8> PlusTargetAttrFeats;
2909+
for (StringRef Feat : TargetAttrFeats) {
2910+
if (!getContext().getTargetInfo().isValidFeatureName(
2911+
Feat.substr(1).str()))
2912+
continue;
2913+
if (Feat.starts_with("+"))
2914+
PlusTargetAttrFeats.push_back(Feat.substr(1));
2915+
}
2916+
2917+
llvm::BasicBlock *SecondCond =
2918+
createBasicBlock("resovler_cond", Resolver);
2919+
2920+
Builder.SetInsertPoint(SecondCond);
2921+
unsigned MaxGroupIDUsed = 0;
2922+
llvm::Value *SecondCondition =
2923+
EmitRISCVCpuSupports(PlusTargetAttrFeats, MaxGroupIDUsed);
2924+
2925+
Builder.SetInsertPoint(CurBlock);
2926+
llvm::Value *FirstCondition = EmitRISCVFeatureBitsLength(MaxGroupIDUsed);
2927+
2928+
llvm::BasicBlock *RetBlock =
2929+
createBasicBlock("resolver_return", Resolver);
2930+
CGBuilderTy RetBuilder(*this, RetBlock);
2931+
CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder,
2932+
Options[Index].Function, SupportsIFunc);
2933+
llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);
2934+
2935+
Builder.SetInsertPoint(CurBlock);
2936+
Builder.CreateCondBr(FirstCondition, SecondCond, ElseBlock);
2937+
2938+
Builder.SetInsertPoint(SecondCond);
2939+
Builder.CreateCondBr(SecondCondition, RetBlock, ElseBlock);
2940+
2941+
CurBlock = ElseBlock;
2942+
}
28562943
}
2944+
2945+
// Finally, emit the default one.
2946+
if (HasDefault) {
2947+
Builder.SetInsertPoint(CurBlock);
2948+
CreateMultiVersionResolverReturn(
2949+
CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc);
2950+
return;
2951+
}
2952+
2953+
// If no generic/default, emit an unreachable.
2954+
Builder.SetInsertPoint(CurBlock);
2955+
llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
2956+
TrapCall->setDoesNotReturn();
2957+
TrapCall->setDoesNotThrow();
2958+
Builder.CreateUnreachable();
2959+
Builder.ClearInsertionPoint();
28572960
}
28582961

28592962
void CodeGenFunction::EmitAArch64MultiVersionResolver(

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5254,6 +5254,9 @@ class CodeGenFunction : public CodeGenTypeCache {
52545254
void
52555255
EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
52565256
ArrayRef<MultiVersionResolverOption> Options);
5257+
void
5258+
EmitRISCVMultiVersionResolver(llvm::Function *Resolver,
5259+
ArrayRef<MultiVersionResolverOption> Options);
52575260

52585261
private:
52595262
QualType getVarArgType(const Expr *Arg);
@@ -5278,6 +5281,10 @@ class CodeGenFunction : public CodeGenTypeCache {
52785281
FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
52795282
llvm::Value *EmitAArch64CpuSupports(const CallExpr *E);
52805283
llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
5284+
llvm::Value *EmitRISCVCpuInit();
5285+
llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeatureStrs,
5286+
unsigned &MaxGroupIDUsed);
5287+
llvm::Value *EmitRISCVFeatureBitsLength(unsigned MaxGroupIDUsed);
52815288
};
52825289

52835290
inline DominatingLLVMValue::saved_type

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4233,7 +4233,10 @@ void CodeGenModule::emitMultiVersionFunctions() {
42334233
Feats.clear();
42344234
if (getTarget().getTriple().isAArch64())
42354235
TC->getFeatures(Feats, I);
4236-
else {
4236+
else if (getTarget().getTriple().isRISCV()) {
4237+
StringRef Version = TC->getFeatureStr(I);
4238+
Feats.push_back(Version);
4239+
} else {
42374240
StringRef Version = TC->getFeatureStr(I);
42384241
if (Version.starts_with("arch="))
42394242
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))

0 commit comments

Comments
 (0)