https://github.com/BeMg updated https://github.com/llvm/llvm-project/pull/85786
>From 395ce72afbf9e4b12fcbfaf9cdbda8921c9ff72a Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Tue, 23 Jul 2024 19:59:06 -0700 Subject: [PATCH 01/14] [RISCV][FMV] Support target_clones --- .../clang/Basic/DiagnosticFrontendKinds.td | 4 + clang/include/clang/Basic/TargetInfo.h | 3 +- clang/include/clang/Sema/SemaRISCV.h | 1 + clang/lib/AST/ASTContext.cpp | 12 + clang/lib/CodeGen/CodeGenFunction.cpp | 106 ++++++++- clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/CodeGen/CodeGenModule.cpp | 5 +- clang/lib/CodeGen/Targets/RISCV.cpp | 35 +++ clang/lib/Sema/SemaDeclAttr.cpp | 30 +++ clang/lib/Sema/SemaRISCV.cpp | 10 + .../attr-target-clones-riscv-invalid.c | 8 + clang/test/CodeGen/attr-target-clones-riscv.c | 211 ++++++++++++++++++ .../CodeGenCXX/attr-target-clones-riscv.cpp | 210 +++++++++++++++++ .../test/SemaCXX/attr-target-clones-riscv.cpp | 35 +++ 14 files changed, 670 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/attr-target-clones-riscv-invalid.c create mode 100644 clang/test/CodeGen/attr-target-clones-riscv.c create mode 100644 clang/test/CodeGenCXX/attr-target-clones-riscv.cpp create mode 100644 clang/test/SemaCXX/attr-target-clones-riscv.cpp diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a1462c670d68f..0c870a1f3f1442 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -378,4 +378,8 @@ def warn_missing_symbol_graph_dir : Warning< def err_ast_action_on_llvm_ir : Error< "cannot apply AST actions to LLVM IR file '%0'">, DefaultFatal; + +def err_os_unsupport_riscv_target_clones : Error< + "target_clones is currently only supported on Linux">; + } diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index a58fb5f9792720..f31d88a354ea28 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1496,7 +1496,8 @@ class TargetInfo : public TransferrableTargetInfo, /// Identify whether this target supports multiversioning of functions, /// which requires support for cpu_supports and cpu_is functionality. bool supportsMultiVersioning() const { - return getTriple().isX86() || getTriple().isAArch64(); + return getTriple().isX86() || getTriple().isAArch64() || + getTriple().isRISCV(); } /// Identify whether this target supports IFuncs. diff --git a/clang/include/clang/Sema/SemaRISCV.h b/clang/include/clang/Sema/SemaRISCV.h index d62fca8128b2a3..d7f17797283b86 100644 --- a/clang/include/clang/Sema/SemaRISCV.h +++ b/clang/include/clang/Sema/SemaRISCV.h @@ -43,6 +43,7 @@ class SemaRISCV : public SemaBase { void handleInterruptAttr(Decl *D, const ParsedAttr &AL); bool isAliasValid(unsigned BuiltinID, llvm::StringRef AliasName); + bool isValidFMVExtension(StringRef Ext); /// Indicate RISC-V vector builtin functions enabled or not. bool DeclareRVVBuiltins = false; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b201d201e1ea6a..a4d123219770bb 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14181,6 +14181,18 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else if (Target->getTriple().isRISCV()) { + StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); + std::vector<std::string> Features; + if (VersionStr != "default") { + ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(VersionStr); + Features.insert(Features.begin(), ParsedAttr.Features.begin(), + ParsedAttr.Features.end()); + } + Features.insert(Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else { std::vector<std::string> Features; StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index eff8c9f5694084..d625dde684933b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2877,12 +2877,116 @@ void CodeGenFunction::EmitMultiVersionResolver( case llvm::Triple::aarch64: EmitAArch64MultiVersionResolver(Resolver, Options); return; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + EmitRISCVMultiVersionResolver(Resolver, Options); + return; default: - assert(false && "Only implemented for x86 and AArch64 targets"); + assert(false && "Only implemented for x86, AArch64 and RISC-V targets"); } } +void CodeGenFunction::EmitRISCVMultiVersionResolver( + llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) { + + if (getContext().getTargetInfo().getTriple().getOS() != + llvm::Triple::OSType::Linux) { + CGM.getDiags().Report(diag::err_os_unsupport_riscv_target_clones); + return; + } + + llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver); + Builder.SetInsertPoint(CurBlock); + EmitRISCVCpuInit(); + + bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); + bool HasDefault = false; + unsigned DefaultIndex = 0; + // Check the each candidate function. + for (unsigned Index = 0; Index < Options.size(); Index++) { + + if (Options[Index].Conditions.Features[0].starts_with("default")) { + HasDefault = true; + DefaultIndex = Index; + continue; + } + + Builder.SetInsertPoint(CurBlock); + + std::vector<std::string> TargetAttrFeats = + getContext() + .getTargetInfo() + .parseTargetAttr(Options[Index].Conditions.Features[0]) + .Features; + + if (TargetAttrFeats.empty()) + continue; + + // Only one conditions need to be checked for the current version: + // + // FeaturesCondition: The bitmask of the required extension has been + // enabled by the runtime object. + // (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) == + // REQUIRED_BITMASK + // + // When condition is met, return this version of the function. + // Otherwise, try the next version. + // + // if (FeaturesConditionVersion1) + // return Version1; + // else if (FeaturesConditionVersion2) + // return Version2; + // else if (FeaturesConditionVersion3) + // return Version3; + // ... + // else + // return DefaultVersion; + + // TODO: Add a condition to check the length due to runtime library version + // constraints. Without checking the length before access, it may result in + // accessing an incorrect memory address. Currently, the length must be 1. + llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats; + + for (auto &Feat : TargetAttrFeats) { + StringRef CurrFeat = Feat; + if (!CurrFeat.starts_with("+")) + continue; + CurrTargetAttrFeats.push_back(CurrFeat.substr(1)); + } + + Builder.SetInsertPoint(CurBlock); + llvm::Value *FeatsCondition = EmitRISCVCpuSupports(CurrTargetAttrFeats); + + llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver); + CGBuilderTy RetBuilder(*this, RetBlock); + CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, + Options[Index].Function, SupportsIFunc); + llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver); + + Builder.SetInsertPoint(CurBlock); + Builder.CreateCondBr(FeatsCondition, RetBlock, ElseBlock); + + CurBlock = ElseBlock; + } + + // Finally, emit the default one. + if (HasDefault) { + Builder.SetInsertPoint(CurBlock); + CreateMultiVersionResolverReturn( + CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc); + return; + } + + // If no generic/default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); +} + void CodeGenFunction::EmitAArch64MultiVersionResolver( llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) { assert(!Options.empty() && "No multiversion resolver options found"); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e1b9ada3c1e1fd..d317452e6cb3e5 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5326,6 +5326,9 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitAArch64MultiVersionResolver(llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options); + void + EmitRISCVMultiVersionResolver(llvm::Function *Resolver, + ArrayRef<MultiVersionResolverOption> Options); private: QualType getVarArgType(const Expr *Arg); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 42742ae83de47b..fbf0700897accf 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4281,7 +4281,10 @@ void CodeGenModule::emitMultiVersionFunctions() { Feats.clear(); if (getTarget().getTriple().isAArch64()) TC->getFeatures(Feats, I); - else { + else if (getTarget().getTriple().isRISCV()) { + StringRef Version = TC->getFeatureStr(I); + Feats.push_back(Version); + } else { StringRef Version = TC->getFeatureStr(I); if (Version.starts_with("arch=")) Architecture = Version.drop_front(sizeof("arch=") - 1); diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 826a1ec2c9d386..008f1043d31abf 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -63,9 +63,44 @@ class RISCVABIInfo : public DefaultABIInfo { CharUnits Field2Off) const; ABIArgInfo coerceVLSVector(QualType Ty) const; + + using ABIInfo::appendAttributeMangling; + void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, + raw_ostream &Out) const override; + void appendAttributeMangling(StringRef AttrStr, + raw_ostream &Out) const override; }; } // end anonymous namespace +void RISCVABIInfo::appendAttributeMangling(TargetClonesAttr *Attr, + unsigned Index, + raw_ostream &Out) const { + appendAttributeMangling(Attr->getFeatureStr(Index), Out); +} + +void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, + raw_ostream &Out) const { + if (AttrStr == "default") { + Out << ".default"; + return; + } + + Out << '.'; + + SmallVector<StringRef, 8> Features; + AttrStr.consume_front("arch="); + AttrStr.split(Features, ","); + + llvm::sort(Features, [](const StringRef LHS, const StringRef RHS) { + return LHS.compare(RHS) < 0; + }); + + for (auto Feat : Features) { + Feat.consume_front("+"); + Out << "_" << Feat; + } +} + void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 73d11ac972b020..221cba06576e7b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3138,6 +3138,36 @@ bool Sema::checkTargetClonesAttrString( HasNotDefault = true; } } + } else if (TInfo.getTriple().isRISCV()) { + // Suppress warn_target_clone_mixed_values + HasCommas = false; + + // Only support arch=+ext,... syntax. + if (Str.starts_with("arch=+")) { + // parseTargetAttr will parse full version string, + // the following split Cur string is no longer interesting. + if ((!Cur.starts_with("arch="))) + continue; + + ParsedTargetAttr TargetAttr = + Context.getTargetInfo().parseTargetAttr(Str); + + if (TargetAttr.Features.empty() || + llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { + return !RISCV().isValidFMVExtension(Ext); + })) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + } else if (Str == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else { + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + } + if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + StringsBuffer.push_back(Str); } else { // Other targets ( currently X86 ) if (Cur.starts_with("arch=")) { diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index abf8e4ac2f3e8a..54aecd96efa163 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/Sema.h" #include "clang/Support/RISCVVIntrinsicUtils.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include <optional> #include <string> @@ -1492,6 +1493,15 @@ bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) { BuiltinID <= RISCV::LastRVVBuiltin; } +bool SemaRISCV::isValidFMVExtension(StringRef Ext) { + if (Ext.empty()) + return false; + + Ext.consume_front("+"); + + return -1 != RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext).second; +} + SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {} } // namespace clang diff --git a/clang/test/CodeGen/attr-target-clones-riscv-invalid.c b/clang/test/CodeGen/attr-target-clones-riscv-invalid.c new file mode 100644 index 00000000000000..a84a0608044b5d --- /dev/null +++ b/clang/test/CodeGen/attr-target-clones-riscv-invalid.c @@ -0,0 +1,8 @@ +// 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: target_clones is currently only supported on Linux +__attribute__((target_clones("default", "arch=+c"))) int foo(void) { + return 2; +} + +int bar() { return foo(); } diff --git a/clang/test/CodeGen/attr-target-clones-riscv.c b/clang/test/CodeGen/attr-target-clones-riscv.c new file mode 100644 index 00000000000000..ceaf96bef19957 --- /dev/null +++ b/clang/test/CodeGen/attr-target-clones-riscv.c @@ -0,0 +1,211 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 4 +// RUN: %clang_cc1 -triple riscv64-linux-gnu -target-feature +i -emit-llvm -o - %s | FileCheck %s + +__attribute__((target_clones("default", "arch=+m"))) int foo1(void) { + return 1; +} +__attribute__((target_clones("default", "arch=+zbb", "arch=+m"))) int foo2(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb,+c"))) int foo3(void) { return 3; } +__attribute__((target_clones("default", "arch=+zbb,+v"))) int +foo4(void) { + return 4; +} +__attribute__((target_clones("default"))) int foo5(void) { return 5; } +__attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return 2; } + +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } + +//. +// CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } +// CHECK: @foo1.ifunc = weak_odr alias i32 (), ptr @foo1 +// CHECK: @foo2.ifunc = weak_odr alias i32 (), ptr @foo2 +// CHECK: @foo3.ifunc = weak_odr alias i32 (), ptr @foo3 +// CHECK: @foo4.ifunc = weak_odr alias i32 (), ptr @foo4 +// CHECK: @foo5.ifunc = weak_odr alias i32 (), ptr @foo5 +// CHECK: @foo6.ifunc = weak_odr alias i32 (), ptr @foo6 +// CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver +// CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver +// CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver +// CHECK: @foo4 = weak_odr ifunc i32 (), ptr @foo4.resolver +// CHECK: @foo5 = weak_odr ifunc i32 (), ptr @foo5.resolver +// CHECK: @foo6 = weak_odr ifunc i32 (), ptr @foo6.resolver +//. +// CHECK-LABEL: define dso_local signext i32 @foo1.default( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo1._m( +// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: define weak_odr ptr @foo1.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4096 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4096 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo1._m +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @foo1.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo2.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo2._zbb( +// CHECK-SAME: ) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo2._m( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo2.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435456 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo2._zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4096 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @foo2._m +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @foo2.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo3.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo3._c_zbb( +// CHECK-SAME: ) #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-LABEL: define weak_odr ptr @foo3.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435460 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435460 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo3._c_zbb +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @foo3.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo4.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo4._v_zbb( +// CHECK-SAME: ) #[[ATTR4:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK-LABEL: define weak_odr ptr @foo4.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 270532608 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 270532608 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo4._v_zbb +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @foo4.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo5.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 5 +// +// +// CHECK-LABEL: define weak_odr ptr @foo5.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: ret ptr @foo5.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo6.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo6._zvkt( +// CHECK-SAME: ) #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo6.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 576460752303423488 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 576460752303423488 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo6._zvkt +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @foo6.default +// +// +// CHECK-LABEL: define dso_local signext i32 @bar( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @foo1() +// CHECK-NEXT: [[CALL1:%.*]] = call signext i32 @foo2() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: [[CALL2:%.*]] = call signext i32 @foo3() +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NEXT: [[CALL4:%.*]] = call signext i32 @foo4() +// CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NEXT: [[CALL6:%.*]] = call signext i32 @foo5() +// CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]] +// CHECK-NEXT: ret i32 [[ADD7]] +// +//. +// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i" } +// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul" } +// CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zbb" } +// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+c,+i,+zbb" } +// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+d,+f,+i,+v,+zbb,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" } +// CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zvkt" } +//. +// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK: [[META1:![0-9]+]] = !{i32 1, !"target-abi", !"lp64"} +// CHECK: [[META2:![0-9]+]] = !{i32 6, !"riscv-isa", [[META3:![0-9]+]]} +// CHECK: [[META3]] = !{!"rv64i2p1"} +// CHECK: [[META4:![0-9]+]] = !{i32 8, !"SmallDataLimit", i32 0} +// CHECK: [[META5:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. diff --git a/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp new file mode 100644 index 00000000000000..344f6f59c4b3e1 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp @@ -0,0 +1,210 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 4 +// RUN: %clang_cc1 -std=c++11 -triple riscv64-linux-gnu -target-feature +i -target-feature +m -emit-llvm %s -o - | FileCheck %s + +__attribute__((target_clones("default", "arch=+m"))) int foo1(void) { + return 1; +} +__attribute__((target_clones("default", "arch=+zbb", "arch=+m"))) int foo2(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb,+c"))) int foo3(void) { return 3; } +__attribute__((target_clones("default", "arch=+zbb,+v"))) int +foo4(void) { + return 4; +} +__attribute__((target_clones("default"))) int foo5(void) { return 5; } +__attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return 2; } + +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } + +//. +// CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } +// CHECK: @_Z4foo1v.ifunc = weak_odr alias i32 (), ptr @_Z4foo1v +// CHECK: @_Z4foo2v.ifunc = weak_odr alias i32 (), ptr @_Z4foo2v +// CHECK: @_Z4foo3v.ifunc = weak_odr alias i32 (), ptr @_Z4foo3v +// CHECK: @_Z4foo4v.ifunc = weak_odr alias i32 (), ptr @_Z4foo4v +// CHECK: @_Z4foo5v.ifunc = weak_odr alias i32 (), ptr @_Z4foo5v +// CHECK: @_Z4foo6v.ifunc = weak_odr alias i32 (), ptr @_Z4foo6v +// CHECK: @_Z4foo1v = weak_odr ifunc i32 (), ptr @_Z4foo1v.resolver +// CHECK: @_Z4foo2v = weak_odr ifunc i32 (), ptr @_Z4foo2v.resolver +// CHECK: @_Z4foo3v = weak_odr ifunc i32 (), ptr @_Z4foo3v.resolver +// CHECK: @_Z4foo4v = weak_odr ifunc i32 (), ptr @_Z4foo4v.resolver +// CHECK: @_Z4foo5v = weak_odr ifunc i32 (), ptr @_Z4foo5v.resolver +// CHECK: @_Z4foo6v = weak_odr ifunc i32 (), ptr @_Z4foo6v.resolver +//. +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo1v.default( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo1v._m( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo1v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4096 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4096 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo1v._m +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z4foo1v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo2v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo2v._zbb( +// CHECK-SAME: ) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo2v._m( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo2v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435456 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo2v._zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4096 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_Z4foo2v._m +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @_Z4foo2v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo3v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo3v._c_zbb( +// CHECK-SAME: ) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo3v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435460 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435460 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo3v._c_zbb +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z4foo3v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo4v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo4v._v_zbb( +// CHECK-SAME: ) #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo4v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 270532608 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 270532608 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo4v._v_zbb +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z4foo4v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo5v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 5 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo5v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: ret ptr @_Z4foo5v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo6v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo6v._zvkt( +// CHECK-SAME: ) #[[ATTR4:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo6v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 576460752303423488 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 576460752303423488 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo6v._zvkt +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z4foo6v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z3barv( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call noundef signext i32 @_Z4foo1v() +// CHECK-NEXT: [[CALL1:%.*]] = call noundef signext i32 @_Z4foo2v() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: [[CALL2:%.*]] = call noundef signext i32 @_Z4foo3v() +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NEXT: [[CALL4:%.*]] = call noundef signext i32 @_Z4foo4v() +// CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NEXT: [[CALL6:%.*]] = call noundef signext i32 @_Z4foo5v() +// CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]] +// CHECK-NEXT: ret i32 [[ADD7]] +// +//. +// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul" } +// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zbb,+zmmul" } +// CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+c,+i,+m,+zbb,+zmmul" } +// CHECK: attributes #[[ATTR3]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+d,+f,+i,+m,+v,+zbb,+zicsr,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" } +// CHECK: attributes #[[ATTR4]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul,+zvkt" } +//. +// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK: [[META1:![0-9]+]] = !{i32 1, !"target-abi", !"lp64"} +// CHECK: [[META2:![0-9]+]] = !{i32 6, !"riscv-isa", [[META3:![0-9]+]]} +// CHECK: [[META3]] = !{!"rv64i2p1_m2p0_zmmul1p0"} +// CHECK: [[META4:![0-9]+]] = !{i32 8, !"SmallDataLimit", i32 0} +// CHECK: [[META5:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. diff --git a/clang/test/SemaCXX/attr-target-clones-riscv.cpp b/clang/test/SemaCXX/attr-target-clones-riscv.cpp new file mode 100644 index 00000000000000..e6122b7eed493b --- /dev/null +++ b/clang/test/SemaCXX/attr-target-clones-riscv.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple riscv64-linux-gnu -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14 + +// expected-warning@+1 {{unsupported 'mcpu=sifive-u74' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "mcpu=sifive-u74"))) mcpu() {} + +// expected-warning@+1 {{unsupported 'mtune=sifive-u74' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "mtune=sifive-u74"))) mtune() {} + +// expected-warning@+1 {{version list contains duplicate entries}} +void __attribute__((target_clones("default", "arch=+c", "arch=+c"))) dupVersion() {} + +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", ""))) emptyVersion() {} + +// expected-error@+1 {{'target_clones' multiversioning requires a default target}} +void __attribute__((target_clones("arch=+c"))) withoutDefault() {} + +// expected-warning@+1 {{unsupported '+c' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "+c"))) invaildVersion() {} + +// expected-warning@+1 {{unsupported 'arch=rv64g' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "arch=rv64g"))) fullArchString() {} + +// expected-warning@+1 {{unsupported 'arch=+zicsr' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "arch=+zicsr"))) UnsupportBitMaskExt() {} + + +void lambda() { + // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} + auto x = []() __attribute__((target_clones("default"))){}; + x(); + // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} + auto y = []() __attribute__((target_clones("arch=+v", "default"))){}; + y(); +} >From 83ef0726333e79205d4279d534374850cc12b183 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Mon, 5 Aug 2024 03:19:14 -0700 Subject: [PATCH 02/14] Support Priority syntax on target_clones for version order --- clang/lib/Basic/Targets/RISCV.cpp | 2 + clang/lib/CodeGen/CodeGenFunction.cpp | 46 ++++- clang/lib/CodeGen/Targets/RISCV.cpp | 17 +- clang/lib/Sema/SemaDeclAttr.cpp | 52 +++-- clang/test/CodeGen/attr-target-clones-riscv.c | 178 +++++++++++++++++- .../CodeGenCXX/attr-target-clones-riscv.cpp | 177 ++++++++++++++++- .../test/SemaCXX/attr-target-clones-riscv.cpp | 3 + 7 files changed, 441 insertions(+), 34 deletions(-) diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 1f8a8cd1462c9d..eae08996cc40c4 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -464,6 +464,8 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { Ret.Duplicate = "tune="; Ret.Tune = AttrString; + } else if (Feature.starts_with("priority")) { + // Skip because it only use for FMV. } } return Ret; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d625dde684933b..13b948d62de459 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2887,6 +2887,26 @@ void CodeGenFunction::EmitMultiVersionResolver( } } +static int getPrioiryFromAttrString(StringRef AttrStr) { + SmallVector<StringRef, 8> Attrs; + + AttrStr.split(Attrs, ";"); + + // Default Pri is zero. + int Pri = 0; + for (auto Attr : Attrs) { + if (Attr.starts_with("priority=")) { + Attr.consume_front("priority="); + int Result; + if (!Attr.getAsInteger(0, Result)) { + Pri = Result; + } + } + } + + return Pri; +} + void CodeGenFunction::EmitRISCVMultiVersionResolver( llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) { @@ -2904,9 +2924,20 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( bool HasDefault = false; unsigned DefaultIndex = 0; // Check the each candidate function. - for (unsigned Index = 0; Index < Options.size(); Index++) { - if (Options[Index].Conditions.Features[0].starts_with("default")) { + SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions( + Options); + + llvm::stable_sort( + CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS, + const CodeGenFunction::MultiVersionResolverOption &RHS) { + return getPrioiryFromAttrString(LHS.Conditions.Features[0]) > + getPrioiryFromAttrString(RHS.Conditions.Features[0]); + }); + + for (unsigned Index = 0; Index < CurrOptions.size(); Index++) { + + if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) { HasDefault = true; DefaultIndex = Index; continue; @@ -2917,7 +2948,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( std::vector<std::string> TargetAttrFeats = getContext() .getTargetInfo() - .parseTargetAttr(Options[Index].Conditions.Features[0]) + .parseTargetAttr(CurrOptions[Index].Conditions.Features[0]) .Features; if (TargetAttrFeats.empty()) @@ -2960,8 +2991,8 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver); CGBuilderTy RetBuilder(*this, RetBlock); - CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, - Options[Index].Function, SupportsIFunc); + CreateMultiVersionResolverReturn( + CGM, Resolver, RetBuilder, CurrOptions[Index].Function, SupportsIFunc); llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver); Builder.SetInsertPoint(CurBlock); @@ -2973,8 +3004,9 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( // Finally, emit the default one. if (HasDefault) { Builder.SetInsertPoint(CurBlock); - CreateMultiVersionResolverReturn( - CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc); + CreateMultiVersionResolverReturn(CGM, Resolver, Builder, + CurrOptions[DefaultIndex].Function, + SupportsIFunc); return; } diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 008f1043d31abf..5b222d512269f9 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -87,11 +87,22 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, Out << '.'; + SmallVector<StringRef, 8> Attrs; + AttrStr.split(Attrs, ";"); + + // Drop Priority syntax. + StringRef ArchStr; + for (auto &Attr : Attrs) { + if (Attr.starts_with("arch=")) + ArchStr = Attr; + } + + // Extract features string.s SmallVector<StringRef, 8> Features; - AttrStr.consume_front("arch="); - AttrStr.split(Features, ","); + ArchStr.consume_front("arch="); + ArchStr.split(Features, ","); - llvm::sort(Features, [](const StringRef LHS, const StringRef RHS) { + llvm::stable_sort(Features, [](const StringRef LHS, const StringRef RHS) { return LHS.compare(RHS) < 0; }); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 221cba06576e7b..cf94fdc280a707 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3142,29 +3142,41 @@ bool Sema::checkTargetClonesAttrString( // Suppress warn_target_clone_mixed_values HasCommas = false; - // Only support arch=+ext,... syntax. - if (Str.starts_with("arch=+")) { - // parseTargetAttr will parse full version string, - // the following split Cur string is no longer interesting. - if ((!Cur.starts_with("arch="))) - continue; - - ParsedTargetAttr TargetAttr = - Context.getTargetInfo().parseTargetAttr(Str); + // Cur is split's parts of Str. RISC-V uses Str directly, + // so skip when encountered more than once. + if (!Str.starts_with(Cur)) + continue; - if (TargetAttr.Features.empty() || - llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { - return !RISCV().isValidFMVExtension(Ext); - })) + llvm::SmallVector<StringRef, 8> AttrStrs; + Str.split(AttrStrs, ";"); + + for (auto &AttrStr : AttrStrs) { + // Only support arch=+ext,... syntax. + if (AttrStr.starts_with("arch=+")) { + ParsedTargetAttr TargetAttr = + Context.getTargetInfo().parseTargetAttr(AttrStr); + + if (TargetAttr.Features.empty() || + llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { + return !RISCV().isValidFMVExtension(Ext); + })) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + } else if (AttrStr.starts_with("default")) { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else if (AttrStr.starts_with("priority=")) { + AttrStr.consume_front("priority="); + int Digit; + if (AttrStr.getAsInteger(0, Digit)) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + } else { return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; - } else if (Str == "default") { - DefaultIsDupe = HasDefault; - HasDefault = true; - } else { - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; + << Unsupported << None << Str << TargetClones; + } } + if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe) Diag(CurLoc, diag::warn_target_clone_duplicate_options); StringsBuffer.push_back(Str); diff --git a/clang/test/CodeGen/attr-target-clones-riscv.c b/clang/test/CodeGen/attr-target-clones-riscv.c index ceaf96bef19957..2e8018c707d962 100644 --- a/clang/test/CodeGen/attr-target-clones-riscv.c +++ b/clang/test/CodeGen/attr-target-clones-riscv.c @@ -13,7 +13,12 @@ foo4(void) { __attribute__((target_clones("default"))) int foo5(void) { return 5; } __attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return 2; } -int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } +__attribute__((target_clones("default", "arch=+zbb", "arch=+zba", "arch=+zbb,+zba"))) int foo7(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=2", "arch=+zba;priority=1", "arch=+zbb,+zba;priority=3"))) int foo8(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=1", "priority=2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo9(void) { return 2; } + + +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() + foo8() + foo9(); } //. // CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } @@ -23,12 +28,18 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK: @foo4.ifunc = weak_odr alias i32 (), ptr @foo4 // CHECK: @foo5.ifunc = weak_odr alias i32 (), ptr @foo5 // CHECK: @foo6.ifunc = weak_odr alias i32 (), ptr @foo6 +// CHECK: @foo7.ifunc = weak_odr alias i32 (), ptr @foo7 +// CHECK: @foo8.ifunc = weak_odr alias i32 (), ptr @foo8 +// CHECK: @foo9.ifunc = weak_odr alias i32 (), ptr @foo9 // CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver // CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver // CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver // CHECK: @foo4 = weak_odr ifunc i32 (), ptr @foo4.resolver // CHECK: @foo5 = weak_odr ifunc i32 (), ptr @foo5.resolver // CHECK: @foo6 = weak_odr ifunc i32 (), ptr @foo6.resolver +// CHECK: @foo7 = weak_odr ifunc i32 (), ptr @foo7.resolver +// CHECK: @foo8 = weak_odr ifunc i32 (), ptr @foo8.resolver +// CHECK: @foo9 = weak_odr ifunc i32 (), ptr @foo9.resolver //. // CHECK-LABEL: define dso_local signext i32 @foo1.default( // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { @@ -180,6 +191,159 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK-NEXT: ret ptr @foo6.default // // +// CHECK-LABEL: define dso_local signext i32 @foo7.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo7._zbb( +// CHECK-SAME: ) #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo7._zba( +// CHECK-SAME: ) #[[ATTR6:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo7._zba_zbb( +// CHECK-SAME: ) #[[ATTR7:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo7.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435456 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo7._zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 134217728 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 134217728 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @foo7._zba +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 402653184 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 402653184 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @foo7._zba_zbb +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @foo7.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo8.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo8._zbb( +// CHECK-SAME: ) #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo8._zba( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo8._zba_zbb( +// CHECK-SAME: ) #[[ATTR7]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo8.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo8._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 268435456 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @foo8._zbb +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 134217728 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 134217728 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @foo8._zba +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @foo8.default +// +// +// CHECK-LABEL: define dso_local signext i32 @foo9.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo9._zbb( +// CHECK-SAME: ) #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo9._zba( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo9._zba_zbb( +// CHECK-SAME: ) #[[ATTR7]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo9.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo9._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 134217728 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 134217728 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @foo9._zba +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 268435456 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 268435456 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @foo9._zbb +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @foo9.default +// +// // CHECK-LABEL: define dso_local signext i32 @bar( // CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: entry: @@ -192,7 +356,15 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] // CHECK-NEXT: [[CALL6:%.*]] = call signext i32 @foo5() // CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]] -// CHECK-NEXT: ret i32 [[ADD7]] +// CHECK-NEXT: [[CALL8:%.*]] = call signext i32 @foo6() +// CHECK-NEXT: [[ADD9:%.*]] = add nsw i32 [[ADD7]], [[CALL8]] +// CHECK-NEXT: [[CALL10:%.*]] = call signext i32 @foo7() +// CHECK-NEXT: [[ADD11:%.*]] = add nsw i32 [[ADD9]], [[CALL10]] +// CHECK-NEXT: [[CALL12:%.*]] = call signext i32 @foo8() +// CHECK-NEXT: [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]] +// CHECK-NEXT: [[CALL14:%.*]] = call signext i32 @foo9() +// CHECK-NEXT: [[ADD15:%.*]] = add nsw i32 [[ADD13]], [[CALL14]] +// CHECK-NEXT: ret i32 [[ADD15]] // //. // CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i" } @@ -201,6 +373,8 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+c,+i,+zbb" } // CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+d,+f,+i,+v,+zbb,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" } // CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zvkt" } +// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zba" } +// CHECK: attributes #[[ATTR7]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zba,+zbb" } //. // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} // CHECK: [[META1:![0-9]+]] = !{i32 1, !"target-abi", !"lp64"} diff --git a/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp index 344f6f59c4b3e1..13a0226ce54152 100644 --- a/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp @@ -13,7 +13,11 @@ foo4(void) { __attribute__((target_clones("default"))) int foo5(void) { return 5; } __attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return 2; } -int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } +__attribute__((target_clones("default", "arch=+zbb", "arch=+zba", "arch=+zbb,+zba"))) int foo7(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=2", "arch=+zba;priority=1", "arch=+zbb,+zba;priority=3"))) int foo8(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=1", "priority=2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo9(void) { return 2; } + +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + foo8() + foo9(); } //. // CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } @@ -23,12 +27,18 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK: @_Z4foo4v.ifunc = weak_odr alias i32 (), ptr @_Z4foo4v // CHECK: @_Z4foo5v.ifunc = weak_odr alias i32 (), ptr @_Z4foo5v // CHECK: @_Z4foo6v.ifunc = weak_odr alias i32 (), ptr @_Z4foo6v +// CHECK: @_Z4foo7v.ifunc = weak_odr alias i32 (), ptr @_Z4foo7v +// CHECK: @_Z4foo8v.ifunc = weak_odr alias i32 (), ptr @_Z4foo8v +// CHECK: @_Z4foo9v.ifunc = weak_odr alias i32 (), ptr @_Z4foo9v // CHECK: @_Z4foo1v = weak_odr ifunc i32 (), ptr @_Z4foo1v.resolver // CHECK: @_Z4foo2v = weak_odr ifunc i32 (), ptr @_Z4foo2v.resolver // CHECK: @_Z4foo3v = weak_odr ifunc i32 (), ptr @_Z4foo3v.resolver // CHECK: @_Z4foo4v = weak_odr ifunc i32 (), ptr @_Z4foo4v.resolver // CHECK: @_Z4foo5v = weak_odr ifunc i32 (), ptr @_Z4foo5v.resolver // CHECK: @_Z4foo6v = weak_odr ifunc i32 (), ptr @_Z4foo6v.resolver +// CHECK: @_Z4foo7v = weak_odr ifunc i32 (), ptr @_Z4foo7v.resolver +// CHECK: @_Z4foo8v = weak_odr ifunc i32 (), ptr @_Z4foo8v.resolver +// CHECK: @_Z4foo9v = weak_odr ifunc i32 (), ptr @_Z4foo9v.resolver //. // CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo1v.default( // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { @@ -180,6 +190,159 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK-NEXT: ret ptr @_Z4foo6v.default // // +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo7v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo7v._zbb( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo7v._zba( +// CHECK-SAME: ) #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo7v._zba_zbb( +// CHECK-SAME: ) #[[ATTR6:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo7v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 268435456 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo7v._zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 134217728 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 134217728 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_Z4foo7v._zba +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 402653184 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 402653184 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @_Z4foo7v._zba_zbb +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @_Z4foo7v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo8v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo8v._zbb( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo8v._zba( +// CHECK-SAME: ) #[[ATTR5]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo8v._zba_zbb( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo8v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo8v._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 268435456 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_Z4foo8v._zbb +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 134217728 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 134217728 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @_Z4foo8v._zba +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @_Z4foo8v.default +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo9v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo9v._zbb( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo9v._zba( +// CHECK-SAME: ) #[[ATTR5]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo9v._zba_zbb( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z4foo9v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z4foo9v._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 134217728 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 134217728 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_Z4foo9v._zba +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 268435456 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 268435456 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @_Z4foo9v._zbb +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @_Z4foo9v.default +// +// // CHECK-LABEL: define dso_local noundef signext i32 @_Z3barv( // CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: entry: @@ -192,7 +355,15 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] // CHECK-NEXT: [[CALL6:%.*]] = call noundef signext i32 @_Z4foo5v() // CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]] -// CHECK-NEXT: ret i32 [[ADD7]] +// CHECK-NEXT: [[CALL8:%.*]] = call noundef signext i32 @_Z4foo6v() +// CHECK-NEXT: [[ADD9:%.*]] = add nsw i32 [[ADD7]], [[CALL8]] +// CHECK-NEXT: [[CALL10:%.*]] = call noundef signext i32 @_Z4foo7v() +// CHECK-NEXT: [[ADD11:%.*]] = add nsw i32 [[ADD9]], [[CALL10]] +// CHECK-NEXT: [[CALL12:%.*]] = call noundef signext i32 @_Z4foo8v() +// CHECK-NEXT: [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]] +// CHECK-NEXT: [[CALL14:%.*]] = call noundef signext i32 @_Z4foo9v() +// CHECK-NEXT: [[ADD15:%.*]] = add nsw i32 [[ADD13]], [[CALL14]] +// CHECK-NEXT: ret i32 [[ADD15]] // //. // CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul" } @@ -200,6 +371,8 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5(); } // CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+c,+i,+m,+zbb,+zmmul" } // CHECK: attributes #[[ATTR3]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+d,+f,+i,+m,+v,+zbb,+zicsr,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" } // CHECK: attributes #[[ATTR4]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul,+zvkt" } +// CHECK: attributes #[[ATTR5]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zba,+zmmul" } +// CHECK: attributes #[[ATTR6]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zba,+zbb,+zmmul" } //. // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} // CHECK: [[META1:![0-9]+]] = !{i32 1, !"target-abi", !"lp64"} diff --git a/clang/test/SemaCXX/attr-target-clones-riscv.cpp b/clang/test/SemaCXX/attr-target-clones-riscv.cpp index e6122b7eed493b..bc4a3ff628fa4d 100644 --- a/clang/test/SemaCXX/attr-target-clones-riscv.cpp +++ b/clang/test/SemaCXX/attr-target-clones-riscv.cpp @@ -24,6 +24,9 @@ void __attribute__((target_clones("default", "arch=rv64g"))) fullArchString() {} // expected-warning@+1 {{unsupported 'arch=+zicsr' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} void __attribute__((target_clones("default", "arch=+zicsr"))) UnsupportBitMaskExt() {} +// expected-warning@+1 {{unsupported 'arch=+c;priority=NotADigit' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "arch=+c;priority=NotADigit"))) UnsupportPriority() {} + void lambda() { // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} >From 56f8d710d8e2ec2e185cf3d78d528d0695bc7c41 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Wed, 21 Aug 2024 02:57:26 -0700 Subject: [PATCH 03/14] Move comment --- clang/lib/CodeGen/CodeGenFunction.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 13b948d62de459..e4131fe512295a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2923,7 +2923,6 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); bool HasDefault = false; unsigned DefaultIndex = 0; - // Check the each candidate function. SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions( Options); @@ -2935,6 +2934,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( getPrioiryFromAttrString(RHS.Conditions.Features[0]); }); + // Check the each candidate function. for (unsigned Index = 0; Index < CurrOptions.size(); Index++) { if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) { @@ -2954,8 +2954,6 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( if (TargetAttrFeats.empty()) continue; - // Only one conditions need to be checked for the current version: - // // FeaturesCondition: The bitmask of the required extension has been // enabled by the runtime object. // (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) == @@ -2974,9 +2972,9 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( // else // return DefaultVersion; - // TODO: Add a condition to check the length due to runtime library version - // constraints. Without checking the length before access, it may result in - // accessing an incorrect memory address. Currently, the length must be 1. + // TODO: Add a condition to check the length before accessing elements. + // Without checking the length first, we may access an incorrect memory + // address when using different versions. llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats; for (auto &Feat : TargetAttrFeats) { >From 45c0ac0e72fc3f381432acdede61ac117b79e5e4 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Wed, 21 Aug 2024 03:20:07 -0700 Subject: [PATCH 04/14] Add new testcase --- clang/test/CodeGen/attr-target-clones-riscv.c | 60 ++++++++++++++++++- .../CodeGenCXX/attr-target-clones-riscv.cpp | 60 ++++++++++++++++++- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGen/attr-target-clones-riscv.c b/clang/test/CodeGen/attr-target-clones-riscv.c index 2e8018c707d962..4a5dea91e22769 100644 --- a/clang/test/CodeGen/attr-target-clones-riscv.c +++ b/clang/test/CodeGen/attr-target-clones-riscv.c @@ -16,9 +16,10 @@ __attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return __attribute__((target_clones("default", "arch=+zbb", "arch=+zba", "arch=+zbb,+zba"))) int foo7(void) { return 2; } __attribute__((target_clones("default", "arch=+zbb;priority=2", "arch=+zba;priority=1", "arch=+zbb,+zba;priority=3"))) int foo8(void) { return 2; } __attribute__((target_clones("default", "arch=+zbb;priority=1", "priority=2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo9(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=-1", "priority=-2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo10(void) { return 2; } -int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() + foo8() + foo9(); } +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() + foo8() + foo9() + foo10(); } //. // CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } @@ -31,6 +32,7 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() // CHECK: @foo7.ifunc = weak_odr alias i32 (), ptr @foo7 // CHECK: @foo8.ifunc = weak_odr alias i32 (), ptr @foo8 // CHECK: @foo9.ifunc = weak_odr alias i32 (), ptr @foo9 +// CHECK: @foo10.ifunc = weak_odr alias i32 (), ptr @foo10 // CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver // CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver // CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver @@ -40,6 +42,7 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() // CHECK: @foo7 = weak_odr ifunc i32 (), ptr @foo7.resolver // CHECK: @foo8 = weak_odr ifunc i32 (), ptr @foo8.resolver // CHECK: @foo9 = weak_odr ifunc i32 (), ptr @foo9.resolver +// CHECK: @foo10 = weak_odr ifunc i32 (), ptr @foo10.resolver //. // CHECK-LABEL: define dso_local signext i32 @foo1.default( // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { @@ -344,6 +347,57 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() // CHECK-NEXT: ret ptr @foo9.default // // +// CHECK-LABEL: define dso_local signext i32 @foo10.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo10._zbb( +// CHECK-SAME: ) #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo10._zba( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local signext i32 @foo10._zba_zbb( +// CHECK-SAME: ) #[[ATTR7]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @foo10.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @foo10._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 268435456 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @foo10._zbb +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 134217728 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 134217728 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @foo10._zba +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @foo10.default +// +// // CHECK-LABEL: define dso_local signext i32 @bar( // CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: entry: @@ -364,7 +418,9 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() // CHECK-NEXT: [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]] // CHECK-NEXT: [[CALL14:%.*]] = call signext i32 @foo9() // CHECK-NEXT: [[ADD15:%.*]] = add nsw i32 [[ADD13]], [[CALL14]] -// CHECK-NEXT: ret i32 [[ADD15]] +// CHECK-NEXT: [[CALL16:%.*]] = call signext i32 @foo10() +// CHECK-NEXT: [[ADD17:%.*]] = add nsw i32 [[ADD15]], [[CALL16]] +// CHECK-NEXT: ret i32 [[ADD17]] // //. // CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i" } diff --git a/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp index 13a0226ce54152..d53e5c0520e6c7 100644 --- a/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp @@ -16,8 +16,9 @@ __attribute__((target_clones("default", "arch=+zvkt"))) int foo6(void) { return __attribute__((target_clones("default", "arch=+zbb", "arch=+zba", "arch=+zbb,+zba"))) int foo7(void) { return 2; } __attribute__((target_clones("default", "arch=+zbb;priority=2", "arch=+zba;priority=1", "arch=+zbb,+zba;priority=3"))) int foo8(void) { return 2; } __attribute__((target_clones("default", "arch=+zbb;priority=1", "priority=2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo9(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb;priority=-1", "priority=-2;arch=+zba", "priority=3;arch=+zbb,+zba"))) int foo10(void) { return 2; } -int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + foo8() + foo9(); } +int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + foo8() + foo9() + foo10(); } //. // CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] } @@ -30,6 +31,7 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + // CHECK: @_Z4foo7v.ifunc = weak_odr alias i32 (), ptr @_Z4foo7v // CHECK: @_Z4foo8v.ifunc = weak_odr alias i32 (), ptr @_Z4foo8v // CHECK: @_Z4foo9v.ifunc = weak_odr alias i32 (), ptr @_Z4foo9v +// CHECK: @_Z5foo10v.ifunc = weak_odr alias i32 (), ptr @_Z5foo10v // CHECK: @_Z4foo1v = weak_odr ifunc i32 (), ptr @_Z4foo1v.resolver // CHECK: @_Z4foo2v = weak_odr ifunc i32 (), ptr @_Z4foo2v.resolver // CHECK: @_Z4foo3v = weak_odr ifunc i32 (), ptr @_Z4foo3v.resolver @@ -39,6 +41,7 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + // CHECK: @_Z4foo7v = weak_odr ifunc i32 (), ptr @_Z4foo7v.resolver // CHECK: @_Z4foo8v = weak_odr ifunc i32 (), ptr @_Z4foo8v.resolver // CHECK: @_Z4foo9v = weak_odr ifunc i32 (), ptr @_Z4foo9v.resolver +// CHECK: @_Z5foo10v = weak_odr ifunc i32 (), ptr @_Z5foo10v.resolver //. // CHECK-LABEL: define dso_local noundef signext i32 @_Z4foo1v.default( // CHECK-SAME: ) #[[ATTR0:[0-9]+]] { @@ -343,6 +346,57 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + // CHECK-NEXT: ret ptr @_Z4foo9v.default // // +// CHECK-LABEL: define dso_local noundef signext i32 @_Z5foo10v.default( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z5foo10v._zbb( +// CHECK-SAME: ) #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z5foo10v._zba( +// CHECK-SAME: ) #[[ATTR5]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define dso_local noundef signext i32 @_Z5foo10v._zba_zbb( +// CHECK-SAME: ) #[[ATTR6]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define weak_odr ptr @_Z5foo10v.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_riscv_feature_bits(ptr null) +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 402653184 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 402653184 +// CHECK-NEXT: br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z5foo10v._zba_zbb +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 268435456 +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456 +// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_Z5foo10v._zbb +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 134217728 +// CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 134217728 +// CHECK-NEXT: br i1 [[TMP8]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @_Z5foo10v._zba +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @_Z5foo10v.default +// +// // CHECK-LABEL: define dso_local noundef signext i32 @_Z3barv( // CHECK-SAME: ) #[[ATTR0]] { // CHECK-NEXT: entry: @@ -363,7 +417,9 @@ int bar() { return foo1() + foo2() + foo3() + foo4() + foo5()+ foo6() + foo7() + // CHECK-NEXT: [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]] // CHECK-NEXT: [[CALL14:%.*]] = call noundef signext i32 @_Z4foo9v() // CHECK-NEXT: [[ADD15:%.*]] = add nsw i32 [[ADD13]], [[CALL14]] -// CHECK-NEXT: ret i32 [[ADD15]] +// CHECK-NEXT: [[CALL16:%.*]] = call noundef signext i32 @_Z5foo10v() +// CHECK-NEXT: [[ADD17:%.*]] = add nsw i32 [[ADD15]], [[CALL16]] +// CHECK-NEXT: ret i32 [[ADD17]] // //. // CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul" } >From 8569babdbef364b01564dee18fc3ce595b04a085 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 21:16:35 -0700 Subject: [PATCH 05/14] Pri -> Priority --- clang/lib/CodeGen/CodeGenFunction.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index e4131fe512295a..6d784cbe261e31 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2892,19 +2892,19 @@ static int getPrioiryFromAttrString(StringRef AttrStr) { AttrStr.split(Attrs, ";"); - // Default Pri is zero. - int Pri = 0; + // Default Priority is zero. + int Priority = 0; for (auto Attr : Attrs) { if (Attr.starts_with("priority=")) { Attr.consume_front("priority="); int Result; if (!Attr.getAsInteger(0, Result)) { - Pri = Result; + Priority = Result; } } } - return Pri; + return Priority; } void CodeGenFunction::EmitRISCVMultiVersionResolver( >From f67ce4bb0f4bf45c9cc1798b983b2c373b397359 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 21:20:26 -0700 Subject: [PATCH 06/14] getPrioiryFromAttrString -> getPriorityFromAttrString --- clang/lib/CodeGen/CodeGenFunction.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 6d784cbe261e31..990c389f896b51 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2887,7 +2887,7 @@ void CodeGenFunction::EmitMultiVersionResolver( } } -static int getPrioiryFromAttrString(StringRef AttrStr) { +static int getPriorityFromAttrString(StringRef AttrStr) { SmallVector<StringRef, 8> Attrs; AttrStr.split(Attrs, ";"); @@ -2930,8 +2930,8 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( llvm::stable_sort( CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS, const CodeGenFunction::MultiVersionResolverOption &RHS) { - return getPrioiryFromAttrString(LHS.Conditions.Features[0]) > - getPrioiryFromAttrString(RHS.Conditions.Features[0]); + return getPriorityFromAttrString(LHS.Conditions.Features[0]) > + getPriorityFromAttrString(RHS.Conditions.Features[0]); }); // Check the each candidate function. >From 478becbf14d694d0e2d2ada85254840319fac7a3 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 22:14:33 -0700 Subject: [PATCH 07/14] Replace starts_with with consume_front --- clang/lib/CodeGen/CodeGenFunction.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 990c389f896b51..f85675fc65a612 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2895,8 +2895,7 @@ static int getPriorityFromAttrString(StringRef AttrStr) { // Default Priority is zero. int Priority = 0; for (auto Attr : Attrs) { - if (Attr.starts_with("priority=")) { - Attr.consume_front("priority="); + if (Attr.consume_front("priority=")) { int Result; if (!Attr.getAsInteger(0, Result)) { Priority = Result; >From c39f500e5c3eacfd9d55ab6e0f1257be9c6c200e Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 22:15:42 -0700 Subject: [PATCH 08/14] Improve comment --- clang/lib/CodeGen/Targets/RISCV.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 5b222d512269f9..d7f06565990506 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -90,14 +90,14 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, SmallVector<StringRef, 8> Attrs; AttrStr.split(Attrs, ";"); - // Drop Priority syntax. + // Only consider the arch string. StringRef ArchStr; for (auto &Attr : Attrs) { if (Attr.starts_with("arch=")) ArchStr = Attr; } - // Extract features string.s + // Extract features string. SmallVector<StringRef, 8> Features; ArchStr.consume_front("arch="); ArchStr.split(Features, ","); >From b891fdd1bff80b934808cd7b9e0d0c7b3002d78f Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 22:21:56 -0700 Subject: [PATCH 09/14] Drop stable_sort lambda --- clang/lib/CodeGen/Targets/RISCV.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index d7f06565990506..6ec9063e0f6db4 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -102,9 +102,7 @@ void RISCVABIInfo::appendAttributeMangling(StringRef AttrStr, ArchStr.consume_front("arch="); ArchStr.split(Features, ","); - llvm::stable_sort(Features, [](const StringRef LHS, const StringRef RHS) { - return LHS.compare(RHS) < 0; - }); + llvm::stable_sort(Features); for (auto Feat : Features) { Feat.consume_front("+"); >From a8006d2bb9fa1b7bbe2412a1d1575e533b2313ca Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 22:39:47 -0700 Subject: [PATCH 10/14] Replace starts_with with consume_front --- clang/lib/Sema/SemaDeclAttr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index cf94fdc280a707..5c9aad4495bc04 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3165,8 +3165,7 @@ bool Sema::checkTargetClonesAttrString( } else if (AttrStr.starts_with("default")) { DefaultIsDupe = HasDefault; HasDefault = true; - } else if (AttrStr.starts_with("priority=")) { - AttrStr.consume_front("priority="); + } else if (AttrStr.consume_front("priority=")) { int Digit; if (AttrStr.getAsInteger(0, Digit)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) >From 9d2d7944cfe885e74d2e8da8930d9ec85b182ca8 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Thu, 22 Aug 2024 22:51:11 -0700 Subject: [PATCH 11/14] Add Sema check for priority in default --- clang/lib/Sema/SemaDeclAttr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5c9aad4495bc04..04ba9bfe2d9c5a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3150,6 +3150,8 @@ bool Sema::checkTargetClonesAttrString( llvm::SmallVector<StringRef, 8> AttrStrs; Str.split(AttrStrs, ";"); + bool IsPriority = false; + bool IsDefault = false; for (auto &AttrStr : AttrStrs) { // Only support arch=+ext,... syntax. if (AttrStr.starts_with("arch=+")) { @@ -3163,9 +3165,11 @@ bool Sema::checkTargetClonesAttrString( return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << Str << TargetClones; } else if (AttrStr.starts_with("default")) { + IsDefault = true; DefaultIsDupe = HasDefault; HasDefault = true; } else if (AttrStr.consume_front("priority=")) { + IsPriority = true; int Digit; if (AttrStr.getAsInteger(0, Digit)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) @@ -3176,6 +3180,10 @@ bool Sema::checkTargetClonesAttrString( } } + if (IsPriority && IsDefault) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe) Diag(CurLoc, diag::warn_target_clone_duplicate_options); StringsBuffer.push_back(Str); >From 61147fcf98f431d7ee61554ab26d0e9e2a299621 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Fri, 23 Aug 2024 00:07:21 -0700 Subject: [PATCH 12/14] Add testcase for default and priority --- clang/test/SemaCXX/attr-target-clones-riscv.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clang/test/SemaCXX/attr-target-clones-riscv.cpp b/clang/test/SemaCXX/attr-target-clones-riscv.cpp index bc4a3ff628fa4d..b893a062900222 100644 --- a/clang/test/SemaCXX/attr-target-clones-riscv.cpp +++ b/clang/test/SemaCXX/attr-target-clones-riscv.cpp @@ -27,6 +27,12 @@ void __attribute__((target_clones("default", "arch=+zicsr"))) UnsupportBitMaskEx // expected-warning@+1 {{unsupported 'arch=+c;priority=NotADigit' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} void __attribute__((target_clones("default", "arch=+c;priority=NotADigit"))) UnsupportPriority() {} +// expected-warning@+1 {{unsupported 'default;priority=2' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default;priority=2", "arch=+c"))) UnsupportDefaultPriority() {} + +// expected-warning@+1 {{unsupported 'priority=2;default' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("priority=2;default", "arch=+c"))) UnsupportDefaultPriority2() {} + void lambda() { // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} >From f7feb0ebee570983229dffcbe0ea125a1fd00c7e Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Sat, 24 Aug 2024 02:59:18 -0700 Subject: [PATCH 13/14] Update format --- clang/lib/CodeGen/CodeGenFunction.cpp | 2 +- clang/lib/Sema/SemaDeclAttr.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index f85675fc65a612..c4d5adfa3a5afb 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2972,7 +2972,7 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( // return DefaultVersion; // TODO: Add a condition to check the length before accessing elements. - // Without checking the length first, we may access an incorrect memory + // Without checking the length first, we may access an incorrect memory // address when using different versions. llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 04ba9bfe2d9c5a..c8760330414a88 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3163,7 +3163,7 @@ bool Sema::checkTargetClonesAttrString( return !RISCV().isValidFMVExtension(Ext); })) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; + << Unsupported << None << Str << TargetClones; } else if (AttrStr.starts_with("default")) { IsDefault = true; DefaultIsDupe = HasDefault; @@ -3173,10 +3173,10 @@ bool Sema::checkTargetClonesAttrString( int Digit; if (AttrStr.getAsInteger(0, Digit)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; + << Unsupported << None << Str << TargetClones; } else { return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; + << Unsupported << None << Str << TargetClones; } } >From 90ede114f0a1b1c8dac1496228d5ebf064862c90 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Mon, 26 Aug 2024 23:35:15 -0700 Subject: [PATCH 14/14] Address kito's comment --- clang/lib/CodeGen/CodeGenFunction.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index c4d5adfa3a5afb..513337b52a09e0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2978,9 +2978,8 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver( for (auto &Feat : TargetAttrFeats) { StringRef CurrFeat = Feat; - if (!CurrFeat.starts_with("+")) - continue; - CurrTargetAttrFeats.push_back(CurrFeat.substr(1)); + if (CurrFeat.starts_with("+")) + CurrTargetAttrFeats.push_back(CurrFeat.substr(1)); } Builder.SetInsertPoint(CurBlock); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits