diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2768,7 +2768,7 @@ HelpText<"Provide information about a particular module file">; def mthumb : Flag<["-"], "mthumb">, Group; def mtune_EQ : Joined<["-"], "mtune=">, Group, - HelpText<"Only supported on X86. Otherwise accepted for compatibility with GCC.">; + HelpText<"Only supported on X86 and RISC-V. Otherwise accepted for compatibility with GCC.">; def multi__module : Flag<["-"], "multi_module">; def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">; def multiply__defined : Separate<["-"], "multiply_defined">; diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -106,6 +106,8 @@ bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl &Values) const override; + bool isValidTuneCPUName(StringRef Name) const override; + void fillValidTuneCPUList(SmallVectorImpl &Values) const override; void setMaxAtomicWidth() override { MaxAtomicPromoteWidth = 128; @@ -133,6 +135,8 @@ bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl &Values) const override; + bool isValidTuneCPUName(StringRef Name) const override; + void fillValidTuneCPUList(SmallVectorImpl &Values) const override; void setMaxAtomicWidth() override { MaxAtomicPromoteWidth = 128; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -178,6 +178,17 @@ llvm::RISCV::fillValidCPUArchList(Values, false); } +bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const { + return llvm::RISCV::checkTuneCPUKind( + llvm::RISCV::parseTuneCPUKind(Name, false), + /*Is64Bit=*/false); +} + +void RISCV32TargetInfo::fillValidTuneCPUList( + SmallVectorImpl &Values) const { + llvm::RISCV::fillValidTuneCPUArchList(Values, false); +} + bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const { return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name), /*Is64Bit=*/true); @@ -187,3 +198,14 @@ SmallVectorImpl &Values) const { llvm::RISCV::fillValidCPUArchList(Values, true); } + +bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const { + return llvm::RISCV::checkTuneCPUKind( + llvm::RISCV::parseTuneCPUKind(Name, true), + /*Is64Bit=*/true); +} + +void RISCV64TargetInfo::fillValidTuneCPUList( + SmallVectorImpl &Values) const { + llvm::RISCV::fillValidTuneCPUArchList(Values, true); +} diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2012,6 +2012,20 @@ CmdArgs.push_back(ABIName.data()); SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); + + std::string TuneCPU; + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + StringRef Name = A->getValue(); + + Name = llvm::RISCV::resolveTuneCPUAlias(Name, Triple.isArch64Bit()); + TuneCPU = std::string(Name); + } + + if (!TuneCPU.empty()) { + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } } void Clang::AddSparcTargetArgs(const ArgList &Args, diff --git a/clang/test/Driver/riscv-cpus.c b/clang/test/Driver/riscv-cpus.c --- a/clang/test/Driver/riscv-cpus.c +++ b/clang/test/Driver/riscv-cpus.c @@ -14,6 +14,37 @@ // MCPU-SIFIVE7-64: "-nostdsysteminc" "-target-cpu" "sifive-7-rv64" // MCPU-SIFIVE7-64: "-target-feature" "+64bit" +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mtune=rocket-rv32 | FileCheck -check-prefix=MTUNE-ROCKET32 %s +// MTUNE-ROCKET32: "-tune-cpu" "rocket-rv32" + +// RUN: %clang -target riscv64 -### -c %s 2>&1 -mtune=rocket-rv64 | FileCheck -check-prefix=MTUNE-ROCKET64 %s +// MTUNE-ROCKET64: "-tune-cpu" "rocket-rv64" + +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mtune=sifive-7-rv32 | FileCheck -check-prefix=MTUNE-SIFIVE7-32 %s +// MTUNE-SIFIVE7-32: "-tune-cpu" "sifive-7-rv32" + +// RUN: %clang -target riscv64 -### -c %s 2>&1 -mtune=sifive-7-rv64 | FileCheck -check-prefix=MTUNE-SIFIVE7-64 %s +// MTUNE-SIFIVE7-64: "-tune-cpu" "sifive-7-rv64" + +// Check mtune alias CPU has resolved to the right CPU according XLEN. +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mtune=generic | FileCheck -check-prefix=MTUNE-GENERIC-32 %s +// MTUNE-GENERIC-32: "-tune-cpu" "generic-rv32" + +// RUN: %clang -target riscv64 -### -c %s 2>&1 -mtune=generic | FileCheck -check-prefix=MTUNE-GENERIC-64 %s +// MTUNE-GENERIC-64: "-tune-cpu" "generic-rv64" + +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mtune=rocket | FileCheck -check-prefix=MTUNE-ROCKET-32 %s +// MTUNE-ROCKET-32: "-tune-cpu" "rocket-rv32" + +// RUN: %clang -target riscv64 -### -c %s 2>&1 -mtune=rocket | FileCheck -check-prefix=MTUNE-ROCKET-64 %s +// MTUNE-ROCKET-64: "-tune-cpu" "rocket-rv64" + +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mtune=sifive-7-series | FileCheck -check-prefix=MTUNE-SIFIVE7-SERIES-32 %s +// MTUNE-SIFIVE7-SERIES-32: "-tune-cpu" "sifive-7-rv32" + +// RUN: %clang -target riscv64 -### -c %s 2>&1 -mtune=sifive-7-series | FileCheck -check-prefix=MTUNE-SIFIVE7-SERIES-64 %s +// MTUNE-SIFIVE7-SERIES-64: "-tune-cpu" "sifive-7-rv64" + // mcpu with default march // RUN: %clang -target riscv64 -### -c %s 2>&1 -mcpu=sifive-u54 | FileCheck -check-prefix=MCPU-SIFIVE-U54 %s // MCPU-SIFIVE-U54: "-nostdsysteminc" "-target-cpu" "sifive-u54" @@ -47,6 +78,20 @@ // MCPU-MARCH: "-nostdsysteminc" "-target-cpu" "sifive-e31" "-target-feature" "+m" "-target-feature" "+c" // MCPU-MARCH: "-target-abi" "ilp32" +// Check interaction between mcpu and mtune, mtune won't affect arch related +// target feature, but mcpu will. +// +// In this case, sifive-e31 is rv32imac, sifive-e76 is rv32imafc, so M-extension +// should not enabled. +// +// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=sifive-e31 -mtune=sifive-e76 | FileCheck -check-prefix=MTUNE-E31-MCPU-E76 %s +// MTUNE-E31-MCPU-E76: "-target-cpu" "sifive-e31" +// MTUNE-E31-MCPU-E76-NOT: "-target-feature" "+f" +// MTUNE-E31-MCPU-E76-SAME: "-target-feature" "+m" +// MTUNE-E31-MCPU-E76-SAME: "-target-feature" "+a" +// MTUNE-E31-MCPU-E76-SAME: "-target-feature" "+c" +// MTUNE-E31-MCPU-E76-SAME: "-tune-cpu" "sifive-e76" + // Check failed cases // RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=generic-rv321 | FileCheck -check-prefix=FAIL-MCPU-NAME %s diff --git a/clang/test/Misc/target-invalid-cpu-note.c b/clang/test/Misc/target-invalid-cpu-note.c --- a/clang/test/Misc/target-invalid-cpu-note.c +++ b/clang/test/Misc/target-invalid-cpu-note.c @@ -197,3 +197,11 @@ // RUN: not %clang_cc1 -triple riscv64 -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix RISCV64 // RISCV64: error: unknown target CPU 'not-a-cpu' // RISCV64: note: valid target CPU values are: generic-rv64, rocket-rv64, sifive-7-rv64, sifive-u54, sifive-u74 + +// RUN: not %clang_cc1 -triple riscv32 -tune-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix TUNE-RISCV32 +// TUNE-RISCV32: error: unknown target CPU 'not-a-cpu' +// TUNE-RISCV32: note: valid target CPU values are: generic-rv32, rocket-rv32, sifive-7-rv32, sifive-e31, sifive-e76, generic, rocket, sifive-7-series + +// RUN: not %clang_cc1 -triple riscv64 -tune-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix TUNE-RISCV64 +// TUNE-RISCV64: error: unknown target CPU 'not-a-cpu' +// TUNE-RISCV64: note: valid target CPU values are: generic-rv64, rocket-rv64, sifive-7-rv64, sifive-u54, sifive-u74, generic, rocket, sifive-7-series diff --git a/llvm/include/llvm/Support/RISCVTargetParser.def b/llvm/include/llvm/Support/RISCVTargetParser.def --- a/llvm/include/llvm/Support/RISCVTargetParser.def +++ b/llvm/include/llvm/Support/RISCVTargetParser.def @@ -1,3 +1,13 @@ +#ifndef PROC_ALIAS +#define PROC_ALIAS(NAME, RV32, RV64) +#endif + +PROC_ALIAS({"generic"}, {"generic-rv32"}, {"generic-rv64"}) +PROC_ALIAS({"rocket"}, {"rocket-rv32"}, {"rocket-rv64"}) +PROC_ALIAS({"sifive-7-series"}, {"sifive-7-rv32"}, {"sifive-7-rv64"}) + +#undef PROC_ALIAS + #ifndef PROC #define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) #endif diff --git a/llvm/include/llvm/Support/TargetParser.h b/llvm/include/llvm/Support/TargetParser.h --- a/llvm/include/llvm/Support/TargetParser.h +++ b/llvm/include/llvm/Support/TargetParser.h @@ -160,10 +160,14 @@ }; bool checkCPUKind(CPUKind Kind, bool IsRV64); +bool checkTuneCPUKind(CPUKind Kind, bool IsRV64); CPUKind parseCPUKind(StringRef CPU); +CPUKind parseTuneCPUKind(StringRef CPU, bool IsRV64); StringRef getMArchFromMcpu(StringRef CPU); void fillValidCPUArchList(SmallVectorImpl &Values, bool IsRV64); +void fillValidTuneCPUArchList(SmallVectorImpl &Values, bool IsRV64); bool getCPUFeaturesExceptStdExt(CPUKind Kind, std::vector &Features); +StringRef resolveTuneCPUAlias(StringRef TuneCPU, bool IsRV64); } // namespace RISCV diff --git a/llvm/lib/Support/TargetParser.cpp b/llvm/lib/Support/TargetParser.cpp --- a/llvm/lib/Support/TargetParser.cpp +++ b/llvm/lib/Support/TargetParser.cpp @@ -253,6 +253,12 @@ return RISCVCPUInfo[static_cast(Kind)].is64Bit() == IsRV64; } +bool checkTuneCPUKind(CPUKind Kind, bool IsRV64) { + if (Kind == CK_INVALID) + return false; + return RISCVCPUInfo[static_cast(Kind)].is64Bit() == IsRV64; +} + CPUKind parseCPUKind(StringRef CPU) { return llvm::StringSwitch(CPU) #define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) @@ -260,6 +266,22 @@ .Default(CK_INVALID); } +StringRef resolveTuneCPUAlias(StringRef TuneCPU, bool IsRV64) { + return llvm::StringSwitch(TuneCPU) +#define PROC_ALIAS(NAME, RV32, RV64) .Case(NAME, IsRV64 ? StringRef(RV64) : StringRef(RV32)) +#include "llvm/Support/RISCVTargetParser.def" + .Default(TuneCPU); +} + +CPUKind parseTuneCPUKind(StringRef TuneCPU, bool IsRV64) { + TuneCPU = resolveTuneCPUAlias(TuneCPU, IsRV64); + + return llvm::StringSwitch(TuneCPU) +#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) .Case(NAME, CK_##ENUM) +#include "llvm/Support/RISCVTargetParser.def" + .Default(CK_INVALID); +} + StringRef getMArchFromMcpu(StringRef CPU) { CPUKind Kind = parseCPUKind(CPU); return RISCVCPUInfo[static_cast(Kind)].DefaultMarch; @@ -272,6 +294,15 @@ } } +void fillValidTuneCPUArchList(SmallVectorImpl &Values, bool IsRV64) { + for (const auto &C : RISCVCPUInfo) { + if (C.Kind != CK_INVALID && IsRV64 == C.is64Bit()) + Values.emplace_back(C.Name); + } +#define PROC_ALIAS(NAME, RV32, RV64) Values.emplace_back(StringRef(NAME)); +#include "llvm/Support/RISCVTargetParser.def" +} + // Get all features except standard extension feature bool getCPUFeaturesExceptStdExt(CPUKind Kind, std::vector &Features) { diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -198,7 +198,9 @@ StringRef CPU = TM.getTargetCPU(); StringRef FS = TM.getTargetFeatureString(); const RISCVTargetMachine &RTM = static_cast(TM); - const RISCVSubtarget STI(TT, CPU, FS, /*ABIName=*/"", RTM); + /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only + care about arch related features, so we can set TuneCPU as CPU. */ + const RISCVSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, /*ABIName=*/"", RTM); RTS.emitTargetAttributes(STI); } diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -71,13 +71,15 @@ /// Initializes using the passed in CPU and feature strings so that we can /// use initializer lists for subtarget initialization. RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, - StringRef CPU, StringRef FS, + StringRef CPU, + StringRef TuneCPU, + StringRef FS, StringRef ABIName); public: // Initializes the data members to match that of the specified triple. - RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef FS, - StringRef ABIName, const TargetMachine &TM); + RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, + StringRef FS, StringRef ABIName, const TargetMachine &TM); // Parses features string setting specified subtarget options. The // definition of this function is auto-generated by tblgen. diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -30,13 +30,16 @@ void RISCVSubtarget::anchor() {} RISCVSubtarget &RISCVSubtarget::initializeSubtargetDependencies( - const Triple &TT, StringRef CPU, StringRef FS, StringRef ABIName) { + const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS, StringRef ABIName) { // Determine default and user-specified characteristics bool Is64Bit = TT.isArch64Bit(); std::string CPUName = std::string(CPU); + std::string TuneCPUName = std::string(TuneCPU); if (CPUName.empty()) CPUName = Is64Bit ? "generic-rv64" : "generic-rv32"; - ParseSubtargetFeatures(CPUName, /*TuneCPU*/ CPUName, FS); + if (TuneCPUName.empty()) + TuneCPUName = CPUName; + ParseSubtargetFeatures(CPUName, TuneCPUName, FS); if (Is64Bit) { XLenVT = MVT::i64; XLen = 64; @@ -47,11 +50,12 @@ return *this; } -RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef FS, +RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU, + StringRef TuneCPU, StringRef FS, StringRef ABIName, const TargetMachine &TM) - : RISCVGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), + : RISCVGenSubtargetInfo(TT, CPU, TuneCPU, FS), UserReservedRegister(RISCV::NUM_TARGET_REGS), - FrameLowering(initializeSubtargetDependencies(TT, CPU, FS, ABIName)), + FrameLowering(initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)), InstrInfo(*this), RegInfo(getHwMode()), TLInfo(TM, *this) { CallLoweringInfo.reset(new RISCVCallLowering(*getTargetLowering())); Legalizer.reset(new RISCVLegalizerInfo(*this)); diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -75,13 +75,16 @@ const RISCVSubtarget * RISCVTargetMachine::getSubtargetImpl(const Function &F) const { Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute TuneAttr = F.getFnAttribute("tune-cpu"); Attribute FSAttr = F.getFnAttribute("target-features"); std::string CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; + std::string TuneCPU = + TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU; std::string FS = FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; - std::string Key = CPU + FS; + std::string Key = CPU + TuneCPU + FS; auto &I = SubtargetMap[Key]; if (!I) { // This needs to be done before we create a new subtarget since any @@ -98,7 +101,7 @@ } ABIName = ModuleTargetABI->getString(); } - I = std::make_unique(TargetTriple, CPU, FS, ABIName, *this); + I = std::make_unique(TargetTriple, CPU, TuneCPU, FS, ABIName, *this); } return I.get(); }