Author: Piyou Chen Date: 2024-09-13T18:04:53+08:00 New Revision: 9cd93774098c861c260090a690f428b7ae031c65
URL: https://github.com/llvm/llvm-project/commit/9cd93774098c861c260090a690f428b7ae031c65 DIFF: https://github.com/llvm/llvm-project/commit/9cd93774098c861c260090a690f428b7ae031c65.diff LOG: [RISCV][FMV] Support target_clones (#85786) This patch enable the function multiversion(FMV) and `target_clones` attribute for RISC-V target. The proposal of `target_clones` syntax can be found at the https://github.com/riscv-non-isa/riscv-c-api-doc/pull/48 (which has landed), as modified by the proposed https://github.com/riscv-non-isa/riscv-c-api-doc/pull/85 (which adds the priority syntax). It supports the `target_clones` function attribute and function multiversioning feature for RISC-V target. It will generate the ifunc resolver function for the function that declared with target_clones attribute. The resolver function will check the version support by runtime object `__riscv_feature_bits`. For example: ``` __attribute__((target_clones("default", "arch=+ver1", "arch=+ver2"))) int bar() { return 1; } ``` the corresponding resolver will be like: ``` bar.resolver() { __init_riscv_feature_bits(); // Check arch=+ver1 if ((__riscv_feature_bits.features[0] & BITMASK_OF_VERSION1) == BITMASK_OF_VERSION1) { return bar.arch=+ver1; } else { // Check arch=+ver2 if ((__riscv_feature_bits.features[0] & BITMASK_OF_VERSION2) == BITMASK_OF_VERSION2) { return bar.arch=+ver2; } else { // Default return bar.default; } } } ``` Added: clang/test/CodeGen/attr-target-clones-riscv-invalid.c clang/test/CodeGen/attr-target-clones-riscv.c clang/test/CodeGenCXX/attr-target-clones-riscv.cpp clang/test/SemaCXX/attr-target-clones-riscv.cpp Modified: clang/include/clang/Basic/DiagnosticFrontendKinds.td clang/include/clang/Basic/TargetInfo.h clang/include/clang/Sema/SemaRISCV.h clang/lib/AST/ASTContext.cpp clang/lib/Basic/Targets/RISCV.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/Targets/RISCV.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaRISCV.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8a1462c670d68f..a85b72a3981578 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_fmv : Error< + "function multiversioning 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 8ece39a3830468..7cc69ca4a8a814 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14248,6 +14248,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/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 223ac66b5f219d..a4925e84784af9 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -459,6 +459,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 fae26d11feca24..eda96f3e352ce3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2889,10 +2889,142 @@ 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"); + } +} + +static int getPriorityFromAttrString(StringRef AttrStr) { + SmallVector<StringRef, 8> Attrs; + + AttrStr.split(Attrs, ';'); + + // Default Priority is zero. + int Priority = 0; + for (auto Attr : Attrs) { + if (Attr.consume_front("priority=")) { + int Result; + if (!Attr.getAsInteger(0, Result)) { + Priority = Result; + } + } + } + + return Priority; +} + +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_fmv); + return; } + + llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver); + Builder.SetInsertPoint(CurBlock); + EmitRISCVCpuInit(); + + bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); + bool HasDefault = false; + unsigned DefaultIndex = 0; + + SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions( + Options); + + llvm::stable_sort( + CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS, + const CodeGenFunction::MultiVersionResolverOption &RHS) { + return getPriorityFromAttrString(LHS.Conditions.Features[0]) > + getPriorityFromAttrString(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")) { + HasDefault = true; + DefaultIndex = Index; + continue; + } + + Builder.SetInsertPoint(CurBlock); + + std::vector<std::string> TargetAttrFeats = + getContext() + .getTargetInfo() + .parseTargetAttr(CurrOptions[Index].Conditions.Features[0]) + .Features; + + if (TargetAttrFeats.empty()) + continue; + + // 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 before accessing elements. + // Without checking the length first, we may access an incorrect memory + // address when using diff erent versions. + llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats; + + for (auto &Feat : TargetAttrFeats) { + StringRef CurrFeat = Feat; + if (CurrFeat.starts_with('+')) + 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, CurrOptions[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, + CurrOptions[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( diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 4eca770ca35d85..9f868c98458996 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5339,6 +5339,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 50fa48656009ff..ba2d6588900a11 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4283,7 +4283,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 57b09f1a3d7632..fd72fe673b9b14 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -63,9 +63,53 @@ 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> Attrs; + AttrStr.split(Attrs, ';'); + + // Only consider the arch string. + StringRef ArchStr; + for (auto &Attr : Attrs) { + if (Attr.starts_with("arch=")) + ArchStr = Attr; + } + + // Extract features string. + SmallVector<StringRef, 8> Features; + ArchStr.consume_front("arch="); + ArchStr.split(Features, ','); + + llvm::stable_sort(Features); + + 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 fb2c2fba0e4628..14cc51cf89665a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3161,6 +3161,55 @@ bool Sema::checkTargetClonesAttrString( HasNotDefault = true; } } + } else if (TInfo.getTriple().isRISCV()) { + // Suppress warn_target_clone_mixed_values + HasCommas = false; + + // 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; + + 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=+")) { + 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")) { + 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) + << Unsupported << None << Str << TargetClones; + } else { + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Str << TargetClones; + } + } + + 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); } 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 56d6f12fbc6e4a..3da4b515b1b114 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,16 @@ bool SemaRISCV::isAliasValid(unsigned BuiltinID, StringRef AliasName) { BuiltinID <= RISCV::LastRVVBuiltin; } +bool SemaRISCV::isValidFMVExtension(StringRef Ext) { + if (Ext.empty()) + return false; + + if (!Ext.consume_front("+")) + return false; + + 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..4086eec31cc6a2 --- /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: function multiversioning 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..4a5dea91e22769 --- /dev/null +++ b/clang/test/CodeGen/attr-target-clones-riscv.c @@ -0,0 +1,441 @@ +// 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; } + +__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() + foo10(); } + +//. +// 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: @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 +// 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: @foo10 = weak_odr ifunc i32 (), ptr @foo10.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 @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 @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: +// 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: [[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: [[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" } +// 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: 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"} +// 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..d53e5c0520e6c7 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-target-clones-riscv.cpp @@ -0,0 +1,439 @@ +// 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; } + +__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() + foo10(); } + +//. +// 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: @_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 +// 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: @_Z5foo10v = weak_odr ifunc i32 (), ptr @_Z5foo10v.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 @_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 @_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: +// 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: [[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: [[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" } +// 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: 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"} +// 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..4425dd2108a6e0 --- /dev/null +++ b/clang/test/SemaCXX/attr-target-clones-riscv.cpp @@ -0,0 +1,47 @@ +// 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() {} + +// 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() {} + +// expected-warning@+1 {{unsupported 'arch=+c,zbb' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default", "arch=+c,zbb"))) WithoutAddSign() {} + + +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(); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits