Skip to content

Commit

Permalink
[RISCV][FMV] Support target_version (#99040)
Browse files Browse the repository at this point in the history
This patch enable `target_version` attribute for RISC-V target.

The proposal of `target_version` syntax can be found at the
riscv-non-isa/riscv-c-api-doc#48 (which has
landed), as modified by the proposed
riscv-non-isa/riscv-c-api-doc#85 (which adds the
priority syntax).

`target_version` attribute will trigger the function multi-versioning
feature and act like `target_clones` attribute. See
#85786 for the implementation
of `target_clones`.
  • Loading branch information
BeMg authored Oct 4, 2024
1 parent eaff3a7 commit 7ab488e
Show file tree
Hide file tree
Showing 8 changed files with 1,081 additions and 8 deletions.
14 changes: 11 additions & 3 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14325,9 +14325,17 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
}
} else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
llvm::SmallVector<StringRef, 8> Feats;
TV->getFeatures(Feats);
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
std::vector<std::string> Features;
if (Target->getTriple().isRISCV()) {
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TV->getName());
Features.insert(Features.begin(), ParsedAttr.Features.begin(),
ParsedAttr.Features.end());
} else {
assert(Target->getTriple().isAArch64());
llvm::SmallVector<StringRef, 8> Feats;
TV->getFeatures(Feats);
Features = getFMVBackendFeaturesFor(Feats);
}
Features.insert(Features.begin(),
Target->getTargetOpts().FeaturesAsWritten.begin(),
Target->getTargetOpts().FeaturesAsWritten.end());
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4287,8 +4287,13 @@ void CodeGenModule::emitMultiVersionFunctions() {
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
if (TVA->isDefaultVersion() && IsDefined)
ShouldEmitResolver = true;
TVA->getFeatures(Feats);
llvm::Function *Func = createFunction(CurFD);
if (getTarget().getTriple().isRISCV()) {
Feats.push_back(TVA->getName());
} else {
assert(getTarget().getTriple().isAArch64());
TVA->getFeatures(Feats);
}
Options.emplace_back(Func, /*Architecture*/ "", Feats);
} else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
if (IsDefined)
Expand Down
19 changes: 15 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10329,7 +10329,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
if (NewTVA && !NewTVA->isDefaultVersion() &&
if (Context.getTargetInfo().getTriple().isAArch64() && NewTVA &&
!NewTVA->isDefaultVersion() &&
!Context.getTargetInfo().hasFeature("fmv")) {
// Don't add to scope fmv functions declarations if fmv disabled
AddToScope = false;
Expand Down Expand Up @@ -11038,7 +11039,15 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {

if (TVA) {
llvm::SmallVector<StringRef, 8> Feats;
TVA->getFeatures(Feats);
if (S.getASTContext().getTargetInfo().getTriple().isRISCV()) {
ParsedTargetAttr ParseInfo =
S.getASTContext().getTargetInfo().parseTargetAttr(TVA->getName());
for (auto &Feat : ParseInfo.Features)
Feats.push_back(StringRef{Feat}.substr(1));
} else {
assert(S.getASTContext().getTargetInfo().getTriple().isAArch64());
TVA->getFeatures(Feats);
}
for (const auto &Feat : Feats) {
if (!TargetInfo.validateCpuSupports(Feat)) {
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
Expand Down Expand Up @@ -11324,7 +11333,8 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
}

static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {
if (!From->getASTContext().getTargetInfo().getTriple().isAArch64())
if (!From->getASTContext().getTargetInfo().getTriple().isAArch64() &&
!From->getASTContext().getTargetInfo().getTriple().isRISCV())
return;

MultiVersionKind MVKindFrom = From->getMultiVersionKind();
Expand Down Expand Up @@ -15511,7 +15521,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
FD->setInvalidDecl();
}
if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
if (!Context.getTargetInfo().hasFeature("fmv") &&
if (Context.getTargetInfo().getTriple().isAArch64() &&
!Context.getTargetInfo().hasFeature("fmv") &&
!Attr->isDefaultVersion()) {
// If function multi versioning disabled skip parsing function body
// defined with non-default target_version attribute
Expand Down
48 changes: 48 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3040,6 +3040,54 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
enum SecondParam { None };
enum ThirdParam { Target, TargetClones, TargetVersion };
llvm::SmallVector<StringRef, 8> Features;
if (Context.getTargetInfo().getTriple().isRISCV()) {
llvm::SmallVector<StringRef, 8> AttrStrs;
AttrStr.split(AttrStrs, ';');

bool HasArch = false;
bool HasPriority = false;
bool HasDefault = false;
bool DuplicateAttr = false;
for (auto &AttrStr : AttrStrs) {
// Only support arch=+ext,... syntax.
if (AttrStr.starts_with("arch=+")) {
if (HasArch)
DuplicateAttr = true;
HasArch = true;
ParsedTargetAttr TargetAttr =
Context.getTargetInfo().parseTargetAttr(AttrStr);

if (TargetAttr.Features.empty() ||
llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) {
return !RISCV().isValidFMVExtension(Ext);
}))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << AttrStr << TargetVersion;
} else if (AttrStr.starts_with("default")) {
if (HasDefault)
DuplicateAttr = true;
HasDefault = true;
} else if (AttrStr.consume_front("priority=")) {
if (HasPriority)
DuplicateAttr = true;
HasPriority = true;
int Digit;
if (AttrStr.getAsInteger(0, Digit))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << AttrStr << TargetVersion;
} else {
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << AttrStr << TargetVersion;
}
}

if (((HasPriority || HasArch) && HasDefault) || DuplicateAttr ||
(HasPriority && !HasArch))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << AttrStr << TargetVersion;

return false;
}
AttrStr.split(Features, "+");
for (auto &CurFeature : Features) {
CurFeature = CurFeature.trim();
Expand Down
13 changes: 13 additions & 0 deletions clang/test/CodeGen/attr-target-version-riscv-invalid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: not %clang_cc1 -triple riscv64 -target-feature +i -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORT-OS

// CHECK-UNSUPPORT-OS: error: function multiversioning is currently only supported on Linux
__attribute__((target_version("default"))) int foo(void) {
return 2;
}

__attribute__((target_version("arch=+c"))) int foo(void) {
return 2;
}


int bar() { return foo(); }
Loading

0 comments on commit 7ab488e

Please sign in to comment.