https://github.com/BeMg updated https://github.com/llvm/llvm-project/pull/85786
>From 708c81609c603c5ea820493e92d8c82cf4620d64 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 1/3] [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/CGBuiltin.cpp | 64 ++++-- clang/lib/CodeGen/CodeGenFunction.cpp | 106 ++++++++- clang/lib/CodeGen/CodeGenFunction.h | 4 + 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 +++ .../llvm/TargetParser/RISCVTargetParser.h | 2 + 16 files changed, 717 insertions(+), 23 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 12a4617c64d87..b2b63674ecc07 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -375,4 +375,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 a58fb5f979272..f31d88a354ea2 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 48d15c411bddd..9798328361f8e 100644 --- a/clang/include/clang/Sema/SemaRISCV.h +++ b/clang/include/clang/Sema/SemaRISCV.h @@ -40,6 +40,7 @@ class SemaRISCV : public SemaBase { void handleInterruptAttr(Decl *D, const ParsedAttr &AL); bool isAliasValid(unsigned BuiltinID, 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 7af9ea7105bb0..d7147ff02906a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14129,6 +14129,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/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a0d03b87ccdc9..6bdaeb655a09a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -63,6 +63,7 @@ #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/AArch64TargetParser.h" #include "llvm/TargetParser/RISCVISAInfo.h" +#include "llvm/TargetParser/RISCVTargetParser.h" #include "llvm/TargetParser/X86TargetParser.h" #include <optional> #include <sstream> @@ -14371,6 +14372,27 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) { return Result; } +static Value *LoadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder, + CodeGenModule &CGM, + llvm::LLVMContext &Context) { + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Context); + llvm::Type *Int64Ty = llvm::Type::getInt64Ty(Context); + llvm::ArrayType *ArrayOfInt64Ty = + llvm::ArrayType::get(Int64Ty, llvm::RISCV::RISCVFeatureBitSize); + llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty); + llvm::Constant *RISCVFeaturesBits = + CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits"); + cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true); + Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index); + llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1), + IndexVal}; + Value *Ptr = + Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices); + Value *FeaturesBit = + Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8)); + return FeaturesBit; +} + Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) { const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts(); @@ -14381,32 +14403,34 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) { // Note: We are making an unchecked assumption that the size of the // feature array is >= 1. This holds for any version of compiler-rt // which defines this interface. - llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1); - llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty); - llvm::Constant *RISCVFeaturesBits = - CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits"); - auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits); - GV->setDSOLocal(true); - - auto LoadFeatureBit = [&](unsigned Index) { - // Create GEP then load. - Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index); - llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1), - IndexVal}; - Value *Ptr = - Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices); - Value *FeaturesBit = - Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8)); - return FeaturesBit; - }; - int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr); assert(BitPos != -1 && "validation should have rejected this feature"); Value *MaskV = Builder.getInt64(1ULL << BitPos); - Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV); + Value *Bitset = Builder.CreateAnd( + LoadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), MaskV); return Builder.CreateICmpEQ(Bitset, MaskV); } +Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) { + uint64_t RequireBitMaskForGroup0 = 0; + + // Note: We are making an unchecked assumption that the size of the + // feature array is >= 1. This holds for any version of compiler-rt + // which defines this interface. + for (auto Feat : FeaturesStrs) { + int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(Feat); + if (BitPos == -1) + return Builder.getFalse(); + + RequireBitMaskForGroup0 |= (1ULL << BitPos); + } + + Value *Mask = Builder.getInt64(RequireBitMaskForGroup0); + Value *Bitset = Builder.CreateAnd( + LoadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), Mask); + return Builder.CreateICmpEQ(Bitset, Mask); +} + Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == Builtin::BI__builtin_cpu_is) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d6078696a7d91..3ff170fb0dba5 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2865,12 +2865,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 67e3019565cd0..f56e549f40111 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5318,6 +5318,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); @@ -5342,6 +5345,7 @@ class CodeGenFunction : public CodeGenTypeCache { FormAArch64ResolverCondition(const MultiVersionResolverOption &RO); llvm::Value *EmitAArch64CpuSupports(const CallExpr *E); llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs); + llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeatureStrs); }; inline DominatingLLVMValue::saved_type diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 63ed5b4dd0c31..0a9a1bc363684 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4251,7 +4251,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 f2add9351c03c..22171c1bbf563 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 5fd8622c90dd8..59eac42bfc591 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3127,6 +3127,36 @@ bool Sema::checkTargetClonesAttrString( /*IncludeLocallyStreaming=*/false)) return Diag(LiteralLoc, diag::err_sme_streaming_cannot_be_multiversioned); + } 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 f1c7c0516e671..6c64b9eccf317 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> @@ -1486,6 +1487,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::getRISCVFeaturesBitPosition(Ext); +} + 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 0000000000000..a84a0608044b5 --- /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 0000000000000..4598ab7fe4f52 --- /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, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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 0000000000000..39dec41353c7c --- /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, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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() +// 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() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 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 0000000000000..e6122b7eed493 --- /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(); +} diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h index c75778952e0f5..b64b523a0c539 100644 --- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h +++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h @@ -32,6 +32,8 @@ struct RISCVExtensionBitmask { }; } // namespace RISCVExtensionBitmaskTable +static constexpr unsigned RISCVFeatureBitSize = 1; + // We use 64 bits as the known part in the scalable vector types. static constexpr unsigned RVVBitsPerBlock = 64; >From f1accba7a05fb43507f0399685d59f7b550474d1 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Wed, 24 Jul 2024 21:08:56 -0700 Subject: [PATCH 2/3] LoadRISCVFeatureBits -> loadRISCVFeatureBits --- clang/lib/CodeGen/CGBuiltin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6bdaeb655a09a..28641ee501b0c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -14372,7 +14372,7 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) { return Result; } -static Value *LoadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder, +static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder, CodeGenModule &CGM, llvm::LLVMContext &Context) { llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Context); @@ -14407,7 +14407,7 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) { assert(BitPos != -1 && "validation should have rejected this feature"); Value *MaskV = Builder.getInt64(1ULL << BitPos); Value *Bitset = Builder.CreateAnd( - LoadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), MaskV); + loadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), MaskV); return Builder.CreateICmpEQ(Bitset, MaskV); } @@ -14427,7 +14427,7 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) { Value *Mask = Builder.getInt64(RequireBitMaskForGroup0); Value *Bitset = Builder.CreateAnd( - LoadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), Mask); + loadRISCVFeatureBits(0, Builder, CGM, getLLVMContext()), Mask); return Builder.CreateICmpEQ(Bitset, Mask); } >From 6c49718fae644cfb7086dbe4d234a41a7c73ee24 Mon Sep 17 00:00:00 2001 From: Piyou Chen <piyou.c...@sifive.com> Date: Wed, 24 Jul 2024 22:07:04 -0700 Subject: [PATCH 3/3] Add comment --- clang/lib/CodeGen/CGBuiltin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 28641ee501b0c..0256dbd44d14f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -14419,6 +14419,9 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) { // which defines this interface. for (auto Feat : FeaturesStrs) { int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(Feat); + + // If there isn't BitPos for this feature, skip this version. + // It also report the warning to user during compilation. if (BitPos == -1) return Builder.getFalse(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits