Skip to content

Commit

Permalink
Recommit "[RISCV][FMV] Support target_version" (#111096)" (#111333)
Browse files Browse the repository at this point in the history
Fix the buildbot failure caused by heap use-after-free error.

Origin message:

    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 8, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 634c57d commit f658c1b
Showing 8 changed files with 1,082 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
@@ -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());
7 changes: 6 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
@@ -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)
20 changes: 16 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
@@ -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;
@@ -11038,7 +11039,16 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {

if (TVA) {
llvm::SmallVector<StringRef, 8> Feats;
TVA->getFeatures(Feats);
ParsedTargetAttr ParseInfo;
if (S.getASTContext().getTargetInfo().getTriple().isRISCV()) {
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)
@@ -11324,7 +11334,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();
@@ -15511,7 +15522,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
48 changes: 48 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
@@ -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();
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(); }
443 changes: 443 additions & 0 deletions clang/test/CodeGen/attr-target-version-riscv.c

Large diffs are not rendered by default.

432 changes: 432 additions & 0 deletions clang/test/CodeGenCXX/attr-target-version-riscv.cpp

Large diffs are not rendered by default.

113 changes: 113 additions & 0 deletions clang/test/SemaCXX/attr-target-version-riscv.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// RUN: %clang_cc1 -triple riscv64-linux-gnu -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14

// expected-warning@+2 {{unsupported 'arch=rv64gcv' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=rv64gcv"))) int fullArchString(void) { return 2; }
// expected-error@+2 {{redefinition of 'fullArchString'}}
// expected-warning@+1 {{unsupported 'arch=default' in the 'target_version' attribute string; 'target_version' attribute ignored}}
__attribute__((target_version("arch=default"))) int fullArchString(void) { return 2; }

// expected-warning@+2 {{unsupported 'mcpu=sifive-u74' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("mcpu=sifive-u74"))) int mcpu(void) { return 2; }
// expected-error@+1 {{redefinition of 'mcpu'}}
__attribute__((target_version("default"))) int mcpu(void) { return 2; }

// expected-warning@+2 {{unsupported 'mtune=sifive-u74' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("mtune=sifive-u74"))) int mtune(void) { return 2; }
// expected-error@+1 {{redefinition of 'mtune'}}
__attribute__((target_version("default"))) int mtune(void) { return 2; }

// expected-warning@+2 {{unsupported '' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version(""))) int emptyVersion(void) { return 2; }
// expected-error@+1 {{redefinition of 'emptyVersion'}}
__attribute__((target_version("default"))) int emptyVersion(void) { return 2; }

// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c"))) int dupVersion(void) { return 2; }
// expected-error@+1 {{redefinition of 'dupVersion'}}
__attribute__((target_version("arch=+c"))) int dupVersion(void) { return 2; }
__attribute__((target_version("default"))) int dupVersion(void) { return 2; }

// expected-warning@+2 {{unsupported 'arch=+zicsr' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+zicsr"))) int UnsupportBitMaskExt(void) { return 2; }
// expected-error@+1 {{redefinition of 'UnsupportBitMaskExt'}}
__attribute__((target_version("default"))) int UnsupportBitMaskExt(void) { return 2; }

// expected-warning@+2 {{unsupported 'NotADigit' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c;priority=NotADigit"))) int UnsupportPriority(void) { return 2; }
// expected-error@+1 {{redefinition of 'UnsupportPriority'}}
__attribute__((target_version("default"))) int UnsupportPriority(void) { return 2;}

// expected-warning@+1 {{unsupported 'default;priority=2' in the 'target_version' attribute string; 'target_version' attribute ignored}}
__attribute__((target_version("default;priority=2"))) int UnsupportDefaultPriority(void) { return 2; }

// expected-warning@+2 {{unsupported 'arch=+c,zbb' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c,zbb"))) int WithoutAddSign(void) { return 2;}
// expected-error@+1 {{redefinition of 'WithoutAddSign'}}
__attribute__((target_version("default"))) int WithoutAddSign(void) { return 2; }

// expected-warning@+2 {{unsupported 'arch=+c;default' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c;default"))) int DefaultInVersion(void) { return 2;}
// expected-error@+1 {{redefinition of 'DefaultInVersion'}}
__attribute__((target_version("default"))) int DefaultInVersion(void) { return 2; }

// expected-warning@+2 {{unsupported '' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c;"))) int EmptyVersionAfterSemiColon(void) { return 2;}
// expected-error@+1 {{redefinition of 'EmptyVersionAfterSemiColon'}}
__attribute__((target_version("default"))) int EmptyVersionAfterSemiColon(void) { return 2; }

// expected-warning@+2 {{unsupported 'arch=+c;arch=+f' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("arch=+c;arch=+f"))) int dupArch(void) { return 2; }
// expected-error@+1 {{redefinition of 'dupArch'}}
__attribute__((target_version("default"))) int dupArch(void) { return 2; }

// expected-warning@+2 {{unsupported 'default;default' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("default;default"))) int dupDefault(void) { return 2;}
// expected-error@+1 {{redefinition of 'dupDefault'}}
__attribute__((target_version("default"))) int dupDefault(void) { return 2; }

// expected-warning@+2 {{unsupported 'priority=1;priority=2' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("priority=1;priority=2"))) int dupPriority(void) { return 2; }
// expected-error@+1 {{redefinition of 'dupPriority'}}
__attribute__((target_version("default"))) int dupPriority(void) { return 2; }

// expected-warning@+2 {{unsupported '=1' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("=1"))) int invalidVerson1(void) { return 2; }
// expected-error@+1 {{redefinition of 'invalidVerson1'}}
__attribute__((target_version("default"))) int invalidVerson1(void) { return 2; }

// expected-warning@+2 {{unsupported '=+v' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("=+v"))) int invalidVerson2(void) { return 2; }
// expected-error@+1 {{redefinition of 'invalidVerson2'}}
__attribute__((target_version("default"))) int invalidVerson2(void) { return 2; }

// expected-warning@+2 {{unsupported 'v' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("v"))) int invalidVerson3(void) { return 2; }
// expected-error@+1 {{redefinition of 'invalidVerson3'}}
__attribute__((target_version("default"))) int invalidVerson3(void) { return 2; }

// expected-warning@+2 {{unsupported '' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version(";"))) int invalidVerson4(void) { return 2; }
// expected-error@+1 {{redefinition of 'invalidVerson4'}}
__attribute__((target_version("default"))) int invalidVerson4(void) { return 2; }

// expected-warning@+2 {{unsupported 'priority=1' in the 'target_version' attribute string; 'target_version' attribute ignored}}
// expected-note@+1 {{previous definition is here}}
__attribute__((target_version("priority=1"))) int prioriyWithoutArch(void) { return 2; }
// expected-error@+1 {{redefinition of 'prioriyWithoutArch'}}
__attribute__((target_version("default"))) int prioriyWithoutArch(void) { return 2; }

0 comments on commit f658c1b

Please sign in to comment.