Skip to content

Commit ad2c9f3

Browse files
committed
[RISCV][FMV] Support target_clones
1 parent 48eea6e commit ad2c9f3

File tree

17 files changed

+674
-5
lines changed

17 files changed

+674
-5
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: 55 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,50 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
1422614237
return Result;
1422714238
}
1422814239

14240+
llvm::Value *
14241+
CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) {
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+
llvm::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+
llvm::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<llvm::Value *> FeatureBits;
14265+
FeatureBits.push_back(LoadFeatureBit(0));
14266+
FeatureBits.push_back(LoadFeatureBit(1));
14267+
14268+
SmallVector<unsigned long long> RequireFeatureBits =
14269+
llvm::RISCV::getRequireFeatureBitMask(FeaturesStrs);
14270+
14271+
Value *Result = Builder.getTrue();
14272+
for (unsigned i = 0; i < FeatureBits.size(); i++) {
14273+
if (!RequireFeatureBits[i])
14274+
continue;
14275+
Value *Mask = Builder.getInt64(RequireFeatureBits[i]);
14276+
Value *Bitset = Builder.CreateAnd(FeatureBits[i], Mask);
14277+
Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
14278+
Result = Builder.CreateAnd(Result, Cmp);
14279+
}
14280+
14281+
return Result;
14282+
}
14283+
1422914284
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
1423014285
const CallExpr *E) {
1423114286
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
@@ -2850,10 +2850,121 @@ 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 *EntryBlock = createBasicBlock("resolver_entry", Resolver);
2873+
Builder.SetInsertPoint(EntryBlock);
2874+
EmitRISCVCpuInit();
2875+
2876+
llvm::BasicBlock *CurBlock = createBasicBlock("resolver_cond", Resolver);
2877+
llvm::BasicBlock *FirstCond = CurBlock;
2878+
2879+
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
2880+
bool HasDefault = false;
2881+
int DefaultIndex = 0;
2882+
// Check the each candidate function.
2883+
for (unsigned Index = 0; Index < Options.size(); Index++) {
2884+
2885+
if (Options[Index].Conditions.Features[0].starts_with("default")) {
2886+
HasDefault = true;
2887+
DefaultIndex = Index;
2888+
continue;
2889+
}
2890+
2891+
Builder.SetInsertPoint(CurBlock);
2892+
2893+
std::vector<std::string> TargetAttrFeats =
2894+
getContext()
2895+
.getTargetInfo()
2896+
.parseTargetAttr(Options[Index].Conditions.Features[0])
2897+
.Features;
2898+
2899+
if (!TargetAttrFeats.empty()) {
2900+
// If this function doens't need override, then merge with module level
2901+
// target features. Otherwise, remain the current target features.
2902+
auto I = llvm::find(TargetAttrFeats, "+__RISCV_TargetAttrNeedOverride");
2903+
if (I == TargetAttrFeats.end())
2904+
TargetAttrFeats.insert(TargetAttrFeats.begin(),
2905+
Target.getTargetOpts().FeaturesAsWritten.begin(),
2906+
Target.getTargetOpts().FeaturesAsWritten.end());
2907+
else
2908+
TargetAttrFeats.erase(I);
2909+
2910+
// Only consider +<extension-feature>.
2911+
llvm::SmallVector<StringRef, 8> PlusTargetAttrFeats;
2912+
for (StringRef Feat : TargetAttrFeats) {
2913+
if (!getContext().getTargetInfo().isValidFeatureName(
2914+
Feat.substr(1).str()))
2915+
continue;
2916+
if (Feat.starts_with("+"))
2917+
PlusTargetAttrFeats.push_back(Feat.substr(1));
2918+
}
2919+
2920+
llvm::Value *Condition = EmitRISCVCpuSupports(PlusTargetAttrFeats);
2921+
llvm::BasicBlock *RetBlock =
2922+
createBasicBlock("resolver_return", Resolver);
2923+
CGBuilderTy RetBuilder(*this, RetBlock);
2924+
CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder,
2925+
Options[Index].Function, SupportsIFunc);
2926+
CurBlock = createBasicBlock("resolver_else", Resolver);
2927+
Builder.CreateCondBr(Condition, RetBlock, CurBlock);
2928+
}
2929+
}
2930+
2931+
// Finally, emit the default one.
2932+
if (HasDefault) {
2933+
Builder.SetInsertPoint(CurBlock);
2934+
CreateMultiVersionResolverReturn(
2935+
CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc);
2936+
2937+
Builder.SetInsertPoint(EntryBlock);
2938+
const unsigned FeatureBitSize = 2;
2939+
llvm::ArrayType *ArrayOfInt64Ty =
2940+
llvm::ArrayType::get(Int64Ty, FeatureBitSize);
2941+
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
2942+
llvm::Constant *RISCVFeaturesBits =
2943+
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
2944+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
2945+
std::vector<llvm::Value *> GEPIndices = {
2946+
llvm::ConstantInt::get(Int32Ty, 0), llvm::ConstantInt::get(Int32Ty, 0)};
2947+
llvm::Value *Ptr =
2948+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
2949+
llvm::Value *Length =
2950+
Builder.CreateAlignedLoad(Int32Ty, Ptr, CharUnits::fromQuantity(8));
2951+
2952+
llvm::Value *FeatureBitSizeVal =
2953+
llvm::ConstantInt::get(Int32Ty, FeatureBitSize);
2954+
llvm::Value *Result = Builder.CreateICmpULE(Length, FeatureBitSizeVal);
2955+
2956+
Builder.CreateCondBr(Result, FirstCond, CurBlock);
2957+
2958+
return;
28562959
}
2960+
2961+
// If no generic/default, emit an unreachable.
2962+
Builder.SetInsertPoint(CurBlock);
2963+
llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
2964+
TrapCall->setDoesNotReturn();
2965+
TrapCall->setDoesNotThrow();
2966+
Builder.CreateUnreachable();
2967+
Builder.ClearInsertionPoint();
28572968
}
28582969

28592970
void CodeGenFunction::EmitAArch64MultiVersionResolver(

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 5 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,8 @@ 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);
52815286
};
52825287

52835288
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))

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3152,6 +3152,31 @@ bool Sema::checkTargetClonesAttrString(
31523152
/*IncludeLocallyStreaming=*/false))
31533153
return Diag(LiteralLoc,
31543154
diag::err_sme_streaming_cannot_be_multiversioned);
3155+
} else if (TInfo.getTriple().isRISCV()) {
3156+
// Suppress warn_target_clone_mixed_values
3157+
HasCommas = false;
3158+
3159+
if (Str.starts_with("arch=")) {
3160+
// parseTargetAttr will parse full version string,
3161+
// the following split Cur string is no longer interesting.
3162+
if ((!Cur.starts_with("arch=")))
3163+
continue;
3164+
3165+
ParsedTargetAttr TargetAttr =
3166+
Context.getTargetInfo().parseTargetAttr(Str);
3167+
if (TargetAttr.Features.empty())
3168+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3169+
<< Unsupported << None << Str << TargetClones;
3170+
} else if (Str == "default") {
3171+
DefaultIsDupe = HasDefault;
3172+
HasDefault = true;
3173+
} else {
3174+
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
3175+
<< Unsupported << None << Str << TargetClones;
3176+
}
3177+
if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe)
3178+
Diag(CurLoc, diag::warn_target_clone_duplicate_options);
3179+
StringsBuffer.push_back(Str);
31553180
} else {
31563181
// Other targets ( currently X86 )
31573182
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)