llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-risc-v Author: Piyou Chen (BeMg) <details> <summary>Changes</summary> This patch enable the function multiversion(FMV) and `target_clones` attribute for RISC-V target. It will emit the IFUNC resolver function to select appropriate function during runtime. --- Patch is 31.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85786.diff 12 Files Affected: - (modified) clang/include/clang/Basic/TargetInfo.h (+2-1) - (modified) clang/lib/AST/ASTContext.cpp (+9) - (modified) clang/lib/Basic/Targets/RISCV.cpp (+8-2) - (modified) clang/lib/Basic/Targets/RISCV.h (+2) - (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+101-1) - (modified) clang/lib/CodeGen/CodeGenFunction.h (+3) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+2) - (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+23) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+22) - (added) clang/test/CodeGen/attr-target-clones-riscv.c (+135) - (added) clang/test/CodeGenCXX/attr-target-clones-riscv.cpp (+136) - (added) clang/test/SemaCXX/attr-target-clones-riscv.cpp (+28) ``````````diff diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 374595edd2ce4a..aa48596fbce07d 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1445,7 +1445,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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 5a8fae76a43a4d..0fd75e0b36b123 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13636,6 +13636,15 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, Features.insert(Features.begin(), Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); + } else if (Target->getTriple().isRISCV()) { + 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()); } else { if (VersionStr.starts_with("arch=")) TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index a6d4af2b88111a..8e9132c9191a3c 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -257,7 +257,7 @@ bool RISCVTargetInfo::initFeatureMap( // If a target attribute specified a full arch string, override all the ISA // extension target features. - const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride"); + const auto I = llvm::find(FeaturesVec, "+__RISCV_TargetAttrNeedOverride"); if (I != FeaturesVec.end()) { std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end()); @@ -366,6 +366,12 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, return true; } +bool RISCVTargetInfo::isValidFeatureName(StringRef Feature) const { + if (Feature.starts_with("__RISCV_TargetAttrNeedOverride")) + return true; + return llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature); +} + bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { bool Is64Bit = getTriple().isArch64Bit(); return llvm::RISCV::parseCPU(Name, Is64Bit); @@ -390,7 +396,7 @@ void RISCVTargetInfo::fillValidTuneCPUList( static void handleFullArchString(StringRef FullArchStr, std::vector<std::string> &Features) { - Features.push_back("__RISCV_TargetAttrNeedOverride"); + Features.push_back("+__RISCV_TargetAttrNeedOverride"); auto RII = llvm::RISCVISAInfo::parseArchString( FullArchStr, /* EnableExperimentalExtension */ true); if (llvm::errorToBool(RII.takeError())) { diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index bfbdafb682c851..ef8f59185d753c 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -106,6 +106,8 @@ class RISCVTargetInfo : public TargetInfo { bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; + bool isValidFeatureName(StringRef Feature) const override; + bool hasBitIntType() const override { return true; } bool hasBFloat16Type() const override { return true; } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 4a3ff49b0007a3..544c696376cd89 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2803,12 +2803,112 @@ 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) { + + auto EmitIFUNCFeatureCheckFunc = + [&](std::string CurrFeatStr) -> llvm::Value * { + llvm::Constant *FeatStr = Builder.CreateGlobalString(CurrFeatStr); + llvm::Type *Args[] = {Int8PtrTy}; + llvm::FunctionType *FTy = + llvm::FunctionType::get(Builder.getInt1Ty(), Args, /*Variadic*/ false); + llvm::FunctionCallee Func = + CGM.CreateRuntimeFunction(FTy, "__riscv_ifunc_select"); + cast<llvm::GlobalValue>(Func.getCallee())->setDSOLocal(true); + cast<llvm::GlobalValue>(Func.getCallee()) + ->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); + return Builder.CreateCall(Func, FeatStr); + }; + + llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver); + Builder.SetInsertPoint(CurBlock); + + bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); + bool HasDefault = false; + int 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()) { + // If this function doens't need override, then merge with module level + // target features. Otherwise, remain the current target features. + auto I = llvm::find(TargetAttrFeats, "+__RISCV_TargetAttrNeedOverride"); + if (I == TargetAttrFeats.end()) + TargetAttrFeats.insert(TargetAttrFeats.begin(), + Target.getTargetOpts().FeaturesAsWritten.begin(), + Target.getTargetOpts().FeaturesAsWritten.end()); + else + TargetAttrFeats.erase(I); + + // Only consider +<extension-feature>. + std::vector<std::string> PlusTargetAttrFeats; + for (StringRef Feat : TargetAttrFeats) { + if (!getContext().getTargetInfo().isValidFeatureName( + Feat.substr(1).str())) + continue; + if (Feat.starts_with("+")) + PlusTargetAttrFeats.push_back(Feat.substr(1).str()); + } + + // Join with ';' delimiter + std::string CurrFeatStr = std::accumulate( + std::begin(PlusTargetAttrFeats), std::end(PlusTargetAttrFeats), + std::string(), [](const std::string &a, const std::string &b) { + return a.empty() ? b : a + ";" + b; + }); + + llvm::Value *Condition = EmitIFUNCFeatureCheckFunc(CurrFeatStr); + llvm::BasicBlock *RetBlock = + createBasicBlock("resolver_return", Resolver); + CGBuilderTy RetBuilder(*this, RetBlock); + CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, + Options[Index].Function, SupportsIFunc); + CurBlock = createBasicBlock("resolver_else", Resolver); + Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + } + + // 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 e8f8aa601ed017..e62657de7b7323 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5013,6 +5013,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 8ceecff28cbc63..e571dbb384b78d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4161,6 +4161,8 @@ void CodeGenModule::emitMultiVersionFunctions() { for (auto &CurFeat : VerFeats) Feature.push_back(CurFeat.trim()); } + } else if (getTarget().getTriple().isRISCV()) { + Feature.push_back(Version); } else { 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 9a79424c4612ce..30c10c35133161 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -63,9 +63,32 @@ 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 << '.'; + Out << AttrStr; +} + 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 ec00fdf3f88d9e..9e44e6a3b70734 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3626,6 +3626,28 @@ bool Sema::checkTargetClonesAttrString( if (hasArmStreamingInterface(cast<FunctionDecl>(D))) return Diag(LiteralLoc, diag::err_sme_streaming_cannot_be_multiversioned); + } else if (TInfo.getTriple().isRISCV()) { + 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()) + 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/test/CodeGen/attr-target-clones-riscv.c b/clang/test/CodeGen/attr-target-clones-riscv.c new file mode 100644 index 00000000000000..70b74befb54ffb --- /dev/null +++ b/clang/test/CodeGen/attr-target-clones-riscv.c @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -triple riscv64-linux-gnu -target-feature +i -S -emit-llvm -o - %s | FileCheck %s + +__attribute__((target_clones("default", "arch=rv64gc"))) int foo1(void) { return 1; } +__attribute__((target_clones("default", "arch=+zbb"))) int foo2(void) { return 2; } +__attribute__((target_clones("default", "arch=+zbb,+c"))) int foo3(void) { return 3; } +__attribute__((target_clones("default", "arch=rv64gc", "arch=+zbb,+v"))) int foo4(void) { return 4; } +__attribute__((target_clones("default"))) int foo5(void) { return 5; } + +int bar() { + return foo1() + foo2() + foo3() + foo4(); +} + +//. +// CHECK: @[[GLOB0:[0-9]+]] = private unnamed_addr constant [25 x i8] c"m;a;f;d;c;zicsr;zifencei\00", align 1 +// CHECK: @[[GLOB1:[0-9]+]] = private unnamed_addr constant [6 x i8] c"i;zbb\00", align 1 +// CHECK: @[[GLOB2:[0-9]+]] = private unnamed_addr constant [8 x i8] c"i;zbb;c\00", align 1 +// CHECK: @[[GLOB3:[0-9]+]] = private unnamed_addr constant [25 x i8] c"m;a;f;d;c;zicsr;zifencei\00", align 1 +// CHECK: @[[GLOB4:[0-9]+]] = private unnamed_addr constant [8 x i8] c"i;zbb;v\00", align 1 +// 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: @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-LABEL: define dso_local signext i32 @foo1.default( +// CHECK-SAME: ) #[[ATTR0:[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: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @[[GLOB0]]) +// CHECK-NEXT: br i1 [[TMP0]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @"foo1.arch=rv64gc" +// 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 weak_odr ptr @foo2.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @[[GLOB1]]) +// CHECK-NEXT: br i1 [[TMP0]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @"foo2.arch=+zbb" +// CHECK: resolver_else: +// 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 weak_odr ptr @foo3.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @[[GLOB2]]) +// CHECK-NEXT: br i1 [[TMP0]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @"foo3.arch=+zbb,+c" +// 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 weak_odr ptr @foo4.resolver() comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: [[TMP0:%.*]] = call i1 @__riscv_ifunc_select(ptr @[[GLOB3]]) +// CHECK-NEXT: br i1 [[TMP0]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @"foo4.arch=rv64gc" +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP1:%.*]] = call i1 @__riscv_ifunc_select(ptr @[[GLOB4]]) +// CHECK-NEXT: br i1 [[TMP1]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @"foo4.arch=+zbb,+v" +// CHECK: resolver_else2: +// 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: ret ptr @foo5.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: ret i32 [[ADD5]] +// +//. +// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i" } +// CHECK: attributes #[[ATTR1:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+a,+c,+d,+f,+m,+zicsr,+zifencei,-e,-experimental-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zaamo,-experimental-zabha,-experimental-zalasr,-experimental-zalrsc,-experimental-zcmop,-experimental-zfbfmin,-experimental-zicfilp,-experimental-zicfiss,-experimental-zimop,-experimental-ztso,-experimental-zvfbfmin,-experimental-zvfbfwma,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smepmp,-ssaia,-ssccptr,-sscofpmf,-sscounterenw,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-za128rs,-za64rs,-zacas,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmp,-zcmt,-zdinx,-zfa,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } +// CHECK: attributes #[[ATTR2:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zbb" } +// CHECK: attributes #[[ATTR3:[0-9]+]] = { noinline nounwind optnone "n... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/85786 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits