Skip to content

Conversation

@BeMg
Copy link
Contributor

@BeMg BeMg commented Sep 11, 2023

The spec of RISC-V target feature is riscv-non-isa/riscv-c-api-doc#35.


This patch implements target attribute for RISC-V.

This patch implements target attribute for RISC-V.
@BeMg BeMg requested a review from a team as a code owner September 11, 2023 11:31
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 11, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 11, 2023

@llvm/pr-subscribers-clang

Changes

The spec of RISC-V target feature is riscv-non-isa/riscv-c-api-doc#35.


This patch implements target attribute for RISC-V.

Full diff: https://github.com/llvm/llvm-project/pull/65948.diff

3 Files Affected:

  • (modified) clang/lib/Basic/Targets/RISCV.cpp (+95-2)
  • (modified) clang/lib/Basic/Targets/RISCV.h (+2)
  • (added) clang/test/CodeGen/RISCV/riscv-func-attr-target.c (+55)
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index d55ab76395c8271..e132e3bfc9f5b75 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -224,6 +224,21 @@ ArrayRef RISCVTargetInfo::getTargetBuiltins() const { clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); } +static std::vector +resolveTargetAttrOverride(const std::vector &FeaturesVec) { + if (!llvm::is_contained(FeaturesVec, "__RISCV_TargetAttrNeedOverride")) + return FeaturesVec; + + auto VecPtr = FeaturesVec.begin(); + + while (*VecPtr != "__RISCV_TargetAttrNeedOverride") + VecPtr++; + + VecPtr++; + + return std::vector(VecPtr, FeaturesVec.end()); +} + bool RISCVTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { @@ -237,7 +252,10 @@ bool RISCVTargetInfo::initFeatureMap( Features["32bit"] = true; } - auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); + std::vector NewFeaturesVec = + resolveTargetAttrOverride(FeaturesVec); + + auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, NewFeaturesVec); if (!ParseResult) { std::string Buffer; llvm::raw_string_ostream OutputErrMsg(Buffer); @@ -251,7 +269,7 @@ bool RISCVTargetInfo::initFeatureMap( // RISCVISAInfo makes implications for ISA features std::vector ImpliedFeatures = (*ParseResult)->toFeatureVector(); // Add non-ISA features like `relax` and `save-restore` back - for (const std::string &Feature : FeaturesVec) + for (const std::string &Feature : NewFeaturesVec) if (!llvm::is_contained(ImpliedFeatures, Feature)) ImpliedFeatures.push_back(Feature); @@ -346,3 +364,78 @@ void RISCVTargetInfo::fillValidTuneCPUList( bool Is64Bit = getTriple().isArch64Bit(); llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); } + +static void handleFullArchString(StringRef FullArchStr, + std::vector &Features) { + Features.push_back("__RISCV_TargetAttrNeedOverride"); + auto RII = llvm::RISCVISAInfo::parseArchString( + FullArchStr, /* EnableExperimentalExtension */ true); + if (!RII) { + consumeError(RII.takeError()); + // Forward the invalid FullArchStr. + Features.push_back("+" + FullArchStr.str()); + } else { + std::vector FeatStrings = (*RII)->toFeatureVector(); + for (auto FeatString : FeatStrings) + Features.push_back(FeatString); + } +} + +ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { + ParsedTargetAttr Ret; + if (Features == "default") + return Ret; + SmallVector AttrFeatures; + Features.split(AttrFeatures, ";"); + bool FoundArch = false; + + for (auto &Feature : AttrFeatures) { + Feature = Feature.trim(); + StringRef AttrString = Feature.split("=").second.trim(); + + if (Feature.startswith("arch=")) { + // Override last features + Ret.Features.clear(); + FoundArch = true; + + if (AttrString.startswith("+")) { + // EXTENSION like arch=+v,+zbb + SmallVector Exts; + AttrString.split(Exts, ","); + for (auto Ext : Exts) { + if (Ext.empty()) + continue; + + StringRef ExtName = Ext.substr(1); + std::string TargetFeature = + llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); + if (!TargetFeature.empty()) + Ret.Features.push_back(Ext.front() + TargetFeature); + else + Ret.Features.push_back(Ext.str()); + } + } else { + // full-arch-string like arch=rv64gcv + handleFullArchString(AttrString, Ret.Features); + } + continue; + } else if (Feature.startswith("cpu=")) { + Ret.CPU = AttrString; + + if (!FoundArch) { + // Update Features with CPU's features + StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); + if (MarchFromCPU != "") { + Ret.Features.clear(); + handleFullArchString(MarchFromCPU, Ret.Features); + } + } + + continue; + } else if (Feature.startswith("tune=")) { + Ret.Tune = AttrString; + continue; + } + } + return Ret; +} diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 6be0e49ca2f5525..c1892870de24c40 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -114,6 +114,8 @@ class RISCVTargetInfo : public TargetInfo { void fillValidCPUList(SmallVectorImpl &Values) const override; bool isValidTuneCPUName(StringRef Name) const override; void fillValidTuneCPUList(SmallVectorImpl &Values) const override; + bool supportsTargetAttributeTune() const override { return true; } + ParsedTargetAttr parseTargetAttr(StringRef Str) const override; }; class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo { public: diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c new file mode 100644 index 000000000000000..e75cd3d64ad91ad --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c @@ -0,0 +1,55 @@ +// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -triple riscv64 -target-feature +zifencei -target-feature +m -target-feature +a \ +// RUN: -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: define dso_local void @testDefault +// CHECK-SAME: () #0 { +void testDefault() {} +// CHECK-LABEL: define dso_local void @testMultiAttrStr +// CHECK-SAME: () #1 { +__attribute__((target("cpu=rocket-rv64;tune=generic-rv64;arch=+v"))) void +testMultiAttrStr() {} +// CHECK-LABEL: define dso_local void @testSingleExtension +// CHECK-SAME: () #2 { +__attribute__((target("arch=+zbb"))) void testSingleExtension() {} +// CHECK-LABEL: define dso_local void @testMultiExtension +// CHECK-SAME: () #3 { +__attribute__((target("arch=+zbb,+v,+zicond"))) void testMultiExtension() {} +// CHECK-LABEL: define dso_local void @testFullArch +// CHECK-SAME: () #4 { +__attribute__((target("arch=rv64gc_zbb"))) void testFullArch() {} +// CHECK-LABEL: define dso_local void @testFullArchButSmallThanCmdArch +// CHECK-SAME: () #5 { +__attribute__((target("arch=rv64im"))) void testFullArchButSmallThanCmdArch() {} +// CHECK-LABEL: define dso_local void @testAttrArchAndAttrCpu +// CHECK-SAME: () #6 { +__attribute__((target("cpu=sifive-u54;arch=+zbb"))) void +testAttrArchAndAttrCpu() {} +// CHECK-LABEL: define dso_local void @testAttrFullArchAndAttrCpu +// CHECK-SAME: () #7 { +__attribute__((target("cpu=sifive-u54;arch=rv64im"))) void +testAttrFullArchAndAttrCpu() {} +// CHECK-LABEL: define dso_local void @testAttrCpuOnly +// CHECK-SAME: () #8 { +__attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} +// CHECK-LABEL: define dso_local void @testMultiArchSelectLast +// CHECK-SAME: () #4 { +__attribute__((target("arch=rv64gc;arch=rv64gc_zbb"))) void testMultiArchSelectLast() {} +// CHECK-LABEL: define dso_local void @testMultiCpuSelectLast +// CHECK-SAME: () #8 { +__attribute__((target("cpu=sifive-u74;cpu=sifive-u54"))) void testMultiCpuSelectLast() {} +// CHECK-LABEL: define dso_local void @testMultiTuneSelectLast +// CHECK-SAME: () #9 { +__attribute__((target("tune=sifive-u74;tune=sifive-u54"))) void testMultiTuneSelectLast() {} + +//. +// CHECK: attributes #0 = { {{.*}}"target-features"="+64bit,+a,+m,+zifencei" } +// CHECK: attributes #1 = { {{.*}}"target-cpu"="rocket-rv64" "target-features"="+64bit,+a,+d,+f,+m,+v,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" "tune-cpu"="generic-rv64" } +// CHECK: attributes #2 = { {{.*}}"target-features"="+64bit,+a,+m,+zbb,+zifencei" } +// CHECK: attributes #3 = { {{.*}}"target-features"="+64bit,+a,+d,+experimental-zicond,+f,+m,+v,+zbb,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" } +// CHECK: attributes #4 = { {{.*}}"target-features"="+64bit,+a,+c,+d,+f,+m,+zbb,+zicsr,+zifencei" } +// CHECK: attributes #5 = { {{.*}}"target-features"="+64bit,+m" } +// CHECK: attributes #6 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+m,+zbb,+zifencei" } +// CHECK: attributes #7 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+m" } +// CHECK: attributes #8 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+c,+d,+f,+m,+zicsr,+zifencei" } +// CHECK: attributes #9 = { {{.*}}"target-features"="+64bit,+a,+m,+zifencei" "tune-cpu"="sifive-u54" } 
@BeMg
Copy link
Contributor Author

BeMg commented Sep 11, 2023

This pull request move from https://reviews.llvm.org/D151730.

And update with lastest spec.

  1. When it exist the duplicate target attribute, select the lastest one.
  2. arch's features will override cpu's features
  3. enhence the testcase
@jrtc27
Copy link
Collaborator

jrtc27 commented Sep 11, 2023

Please do not move from Phabricator to GitHub for existing changes, it loses all the context that was built up from previous reviews. New changes should be proposed on GitHub but existing ones should stay put.

@BeMg
Copy link
Contributor Author

BeMg commented Sep 12, 2023

Sorry for disrupting the review process. I will update the change into Phabricator existing patch.

@BeMg BeMg closed this Sep 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

3 participants