Skip to content

Commit 294d1ea

Browse files
committed
[RISCV] Add support for -mcpu option.
Summary: 1. gcc uses `-march` and `-mtune` flag to chose arch and pipeline model, but clang does not have `-mtune` flag, we uses `-mcpu` to chose both infos. 2. Add SiFive e31 and u54 cpu which have default march and pipeline model. 3. Specific `-mcpu` with rocket-rv[32|64] would select pipeline model only, and use the driver's arch choosing logic to get default arch. Reviewers: lenary, asb, evandro, HsiangKai Reviewed By: lenary, asb, evandro Tags: #llvm, #clang Differential Revision: https://reviews.llvm.org/D71124
1 parent a394aa1 commit 294d1ea

File tree

11 files changed

+262
-34
lines changed

11 files changed

+262
-34
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "RISCV.h"
1414
#include "clang/Basic/MacroBuilder.h"
1515
#include "llvm/ADT/StringSwitch.h"
16+
#include "llvm/Support/TargetParser.h"
1617

1718
using namespace clang;
1819
using namespace clang::targets;
@@ -166,3 +167,23 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
166167

167168
return true;
168169
}
170+
171+
bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
172+
return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
173+
/*Is64Bit=*/false);
174+
}
175+
176+
void RISCV32TargetInfo::fillValidCPUList(
177+
SmallVectorImpl<StringRef> &Values) const {
178+
llvm::RISCV::fillValidCPUArchList(Values, false);
179+
}
180+
181+
bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
182+
return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
183+
/*Is64Bit=*/true);
184+
}
185+
186+
void RISCV64TargetInfo::fillValidCPUList(
187+
SmallVectorImpl<StringRef> &Values) const {
188+
llvm::RISCV::fillValidCPUArchList(Values, true);
189+
}

clang/lib/Basic/Targets/RISCV.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace targets {
2424
// RISC-V Target
2525
class RISCVTargetInfo : public TargetInfo {
2626
protected:
27-
std::string ABI;
27+
std::string ABI, CPU;
2828
bool HasM;
2929
bool HasA;
3030
bool HasF;
@@ -44,6 +44,13 @@ class RISCVTargetInfo : public TargetInfo {
4444
WIntType = UnsignedInt;
4545
}
4646

47+
bool setCPU(const std::string &Name) override {
48+
if (!isValidCPUName(Name))
49+
return false;
50+
CPU = Name;
51+
return true;
52+
}
53+
4754
StringRef getABI() const override { return ABI; }
4855
void getTargetDefines(const LangOptions &Opts,
4956
MacroBuilder &Builder) const override;
@@ -97,6 +104,9 @@ class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
97104
return false;
98105
}
99106

107+
bool isValidCPUName(StringRef Name) const override;
108+
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
109+
100110
void setMaxAtomicWidth() override {
101111
MaxAtomicPromoteWidth = 128;
102112

@@ -121,6 +131,9 @@ class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo {
121131
return false;
122132
}
123133

134+
bool isValidCPUName(StringRef Name) const override;
135+
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
136+
124137
void setMaxAtomicWidth() override {
125138
MaxAtomicPromoteWidth = 128;
126139

clang/lib/Driver/ToolChains/Arch/RISCV.cpp

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,19 @@ static bool getArchFeatures(const Driver &D, StringRef MArch,
446446
return true;
447447
}
448448

449+
// Get features except standard extension feature
450+
void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple,
451+
const llvm::opt::ArgList &Args,
452+
const llvm::opt::Arg *A, StringRef Mcpu,
453+
std::vector<StringRef> &Features) {
454+
bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64);
455+
llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
456+
if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) ||
457+
!llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) {
458+
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
459+
}
460+
}
461+
449462
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
450463
const ArgList &Args,
451464
std::vector<StringRef> &Features) {
@@ -454,6 +467,11 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
454467
if (!getArchFeatures(D, MArch, Features, Args))
455468
return;
456469

470+
// If users give march and mcpu, get std extension feature from MArch
471+
// and other features (ex. mirco architecture feature) from mcpu
472+
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
473+
getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
474+
457475
// Handle features corresponding to "-ffixed-X" options
458476
if (Args.hasArg(options::OPT_ffixed_x1))
459477
Features.push_back("+reserve-x1");
@@ -543,11 +561,9 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
543561

544562
// GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
545563
// configured using `--with-abi=`, then the logic for the default choice is
546-
// defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
547-
// deviate from GCC's default only on baremetal targets (UnknownOS) where
548-
// neither `-march` nor `-mabi` is specified.
564+
// defined in config.gcc. This function is based on the logic in GCC 9.2.0.
549565
//
550-
// The logic uses the following, in order:
566+
// The logic used in GCC 9.2.0 is the following, in order:
551567
// 1. Explicit choices using `--with-abi=`
552568
// 2. A default based on `--with-arch=`, if provided
553569
// 3. A default based on the target triple's arch
@@ -556,38 +572,40 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
556572
//
557573
// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
558574
// and `-mabi=` respectively instead.
575+
//
576+
// In order to make chosing logic more clear, Clang uses the following logic,
577+
// in order:
578+
// 1. Explicit choices using `-mabi=`
579+
// 2. A default based on the architecture as determined by getRISCVArch
580+
// 3. Choose a default based on the triple
559581

560582
// 1. If `-mabi=` is specified, use it.
561583
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
562584
return A->getValue();
563585

564-
// 2. Choose a default based on `-march=`
586+
// 2. Choose a default based on the target architecture.
565587
//
566588
// rv32g | rv32*d -> ilp32d
567589
// rv32e -> ilp32e
568590
// rv32* -> ilp32
569591
// rv64g | rv64*d -> lp64d
570592
// rv64* -> lp64
571-
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
572-
StringRef MArch = A->getValue();
573-
574-
if (MArch.startswith_lower("rv32")) {
575-
// FIXME: parse `March` to find `D` extension properly
576-
if (MArch.substr(4).contains_lower("d") ||
577-
MArch.startswith_lower("rv32g"))
578-
return "ilp32d";
579-
else if (MArch.startswith_lower("rv32e"))
580-
return "ilp32e";
581-
else
582-
return "ilp32";
583-
} else if (MArch.startswith_lower("rv64")) {
584-
// FIXME: parse `March` to find `D` extension properly
585-
if (MArch.substr(4).contains_lower("d") ||
586-
MArch.startswith_lower("rv64g"))
587-
return "lp64d";
588-
else
589-
return "lp64";
590-
}
593+
StringRef MArch = getRISCVArch(Args, Triple);
594+
595+
if (MArch.startswith_lower("rv32")) {
596+
// FIXME: parse `March` to find `D` extension properly
597+
if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv32g"))
598+
return "ilp32d";
599+
else if (MArch.startswith_lower("rv32e"))
600+
return "ilp32e";
601+
else
602+
return "ilp32";
603+
} else if (MArch.startswith_lower("rv64")) {
604+
// FIXME: parse `March` to find `D` extension properly
605+
if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv64g"))
606+
return "lp64d";
607+
else
608+
return "lp64";
591609
}
592610

593611
// 3. Choose a default based on the triple
@@ -617,10 +635,11 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
617635
// GCC's logic around choosing a default `-march=` is complex. If GCC is not
618636
// configured using `--with-arch=`, then the logic for the default choice is
619637
// defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
620-
// deviate from GCC's default only on baremetal targets (UnknownOS) where
621-
// neither `-march` nor `-mabi` is specified.
638+
// deviate from GCC's default on additional `-mcpu` option (GCC does not
639+
// support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
640+
// nor `-mabi` is specified.
622641
//
623-
// The logic uses the following, in order:
642+
// The logic used in GCC 9.2.0 is the following, in order:
624643
// 1. Explicit choices using `--with-arch=`
625644
// 2. A default based on `--with-abi=`, if provided
626645
// 3. A default based on the target triple's arch
@@ -630,14 +649,28 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
630649
// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
631650
// and `-mabi=` respectively instead.
632651
//
652+
// Clang uses the following logic, in order:
653+
// 1. Explicit choices using `-march=`
654+
// 2. Based on `-mcpu` if the target CPU has a default ISA string
655+
// 3. A default based on `-mabi`, if provided
656+
// 4. A default based on the target triple's arch
657+
//
633658
// Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
634659
// instead of `rv{XLEN}gc` though they are (currently) equivalent.
635660

636661
// 1. If `-march=` is specified, use it.
637662
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
638663
return A->getValue();
639664

640-
// 2. Choose a default based on `-mabi=`
665+
// 2. Get march (isa string) based on `-mcpu=`
666+
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
667+
StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue());
668+
// Bypass if target cpu's default march is empty.
669+
if (MArch != "")
670+
return MArch;
671+
}
672+
673+
// 3. Choose a default based on `-mabi=`
641674
//
642675
// ilp32e -> rv32e
643676
// ilp32 | ilp32f | ilp32d -> rv32imafdc
@@ -653,7 +686,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
653686
return "rv64imafdc";
654687
}
655688

656-
// 3. Choose a default based on the triple
689+
// 4. Choose a default based on the triple
657690
//
658691
// We deviate from GCC's defaults here:
659692
// - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
333333

334334
return TargetCPUName;
335335
}
336+
case llvm::Triple::riscv32:
337+
case llvm::Triple::riscv64:
338+
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
339+
return A->getValue();
340+
return "";
336341

337342
case llvm::Triple::bpfel:
338343
case llvm::Triple::bpfeb:

clang/test/Driver/riscv-arch.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,9 @@
156156
// RV32-LOWER: error: invalid arch name 'rv32imC',
157157
// RV32-LOWER: string must be lowercase
158158

159-
// RUN: %clang -target riscv32-unknown-elf -march=rv32 -### %s \
159+
// RUN: %clang -target riscv32-unknown-elf -march=unknown -### %s \
160160
// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-STR %s
161-
// RV32-STR: error: invalid arch name 'rv32',
161+
// RV32-STR: error: invalid arch name 'unknown',
162162
// RV32-STR: string must begin with rv32{i,e,g} or rv64{i,g}
163163

164164
// RUN: %clang -target riscv32-unknown-elf -march=rv32q -### %s \

clang/test/Driver/riscv-cpus.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Check target CPUs are correctly passed.
2+
3+
// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=rocket-rv32 | FileCheck -check-prefix=MCPU-ROCKETCHIP32 %s
4+
// MCPU-ROCKETCHIP32: "-nostdsysteminc" "-target-cpu" "rocket-rv32"
5+
6+
// RUN: %clang -target riscv64 -### -c %s 2>&1 -mcpu=rocket-rv64 | FileCheck -check-prefix=MCPU-ROCKETCHIP64 %s
7+
// MCPU-ROCKETCHIP64: "-nostdsysteminc" "-target-cpu" "rocket-rv64"
8+
// MCPU-ROCKETCHIP64: "-target-feature" "+64bit"
9+
10+
// mcpu with default march
11+
// RUN: %clang -target riscv64 -### -c %s 2>&1 -mcpu=sifive-u54 | FileCheck -check-prefix=MCPU-SIFIVE-U54 %s
12+
// MCPU-SIFIVE-U54: "-nostdsysteminc" "-target-cpu" "sifive-u54"
13+
// MCPU-SIFIVE-U54: "-target-feature" "+m" "-target-feature" "+a" "-target-feature" "+f" "-target-feature" "+d"
14+
// MCPU-SIFIVE-U54: "-target-feature" "+c" "-target-feature" "+64bit"
15+
// MCPU-SIFIVE-U54: "-target-abi" "lp64d"
16+
17+
// mcpu with mabi option
18+
// RUN: %clang -target riscv64 -### -c %s 2>&1 -mcpu=sifive-u54 -mabi=lp64 | FileCheck -check-prefix=MCPU-ABI-SIFIVE-U54 %s
19+
// MCPU-ABI-SIFIVE-U54: "-nostdsysteminc" "-target-cpu" "sifive-u54"
20+
// MCPU-ABI-SIFIVE-U54: "-target-feature" "+m" "-target-feature" "+a" "-target-feature" "+f" "-target-feature" "+d"
21+
// MCPU-ABI-SIFIVE-U54: "-target-feature" "+c" "-target-feature" "+64bit"
22+
// MCPU-ABI-SIFIVE-U54: "-target-abi" "lp64"
23+
24+
// march overwirte mcpu's default march
25+
// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=sifive-e31 -march=rv32imc | FileCheck -check-prefix=MCPU-MARCH %s
26+
// MCPU-MARCH: "-nostdsysteminc" "-target-cpu" "sifive-e31" "-target-feature" "+m" "-target-feature" "+c"
27+
// MCPU-MARCH: "-target-abi" "ilp32"
28+
29+
// Check failed cases
30+
31+
// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=generic-rv321 | FileCheck -check-prefix=FAIL-MCPU-NAME %s
32+
// FAIL-MCPU-NAME: error: the clang compiler does not support '-mcpu=generic-rv321'
33+
34+
// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=generic-rv32 -march=rv64i | FileCheck -check-prefix=MISMATCH-ARCH %s
35+
// MISMATCH-ARCH: error: the clang compiler does not support '-mcpu=generic-rv32'
36+
37+
// RUN: %clang -target riscv32 -### -c %s 2>&1 -mcpu=generic-rv64 | FileCheck -check-prefix=MISMATCH-MCPU %s
38+
// MISMATCH-MCPU: error: the clang compiler does not support '-mcpu=generic-rv64'

clang/test/Misc/target-invalid-cpu-note.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,10 @@
156156
// AVR-SAME: ttiny4, attiny5, attiny9, attiny10, attiny20, attiny40, attiny102,
157157
// AVR-SAME: attiny104
158158

159+
// RUN: not %clang_cc1 -triple riscv32 -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix RISCV32
160+
// RISCV32: error: unknown target CPU 'not-a-cpu'
161+
// RISCV32: note: valid target CPU values are: generic-rv32, rocket-rv32, sifive-e31
162+
163+
// RUN: not %clang_cc1 -triple riscv64 -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix RISCV64
164+
// RISCV64: error: unknown target CPU 'not-a-cpu'
165+
// RISCV64: note: valid target CPU values are: generic-rv64, rocket-rv64, sifive-u54
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef PROC
2+
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH)
3+
#endif
4+
5+
PROC(INVALID, {"invalid"}, FK_INVALID, {""})
6+
PROC(GENERIC_RV32, {"generic-rv32"}, FK_NONE, {""})
7+
PROC(GENERIC_RV64, {"generic-rv64"}, FK_64BIT, {""})
8+
PROC(ROCKET_RV32, {"rocket-rv32"}, FK_NONE, {""})
9+
PROC(ROCKET_RV64, {"rocket-rv64"}, FK_64BIT, {""})
10+
PROC(SIFIVE_E31, {"sifive-e31"}, FK_NONE, {"rv32imac"})
11+
PROC(SIFIVE_U54, {"sifive-u54"}, FK_64BIT, {"rv64gc"})
12+
13+
#undef PROC

llvm/include/llvm/Support/TargetParser.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,32 @@ IsaVersion getIsaVersion(StringRef GPU);
130130

131131
} // namespace AMDGPU
132132

133+
namespace RISCV {
134+
135+
enum CPUKind : unsigned {
136+
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) CK_##ENUM,
137+
#include "RISCVTargetParser.def"
138+
};
139+
140+
enum FeatureKind : unsigned {
141+
FK_INVALID = 0,
142+
FK_NONE = 1,
143+
FK_STDEXTM = 1 << 2,
144+
FK_STDEXTA = 1 << 3,
145+
FK_STDEXTF = 1 << 4,
146+
FK_STDEXTD = 1 << 5,
147+
FK_STDEXTC = 1 << 6,
148+
FK_64BIT = 1 << 7,
149+
};
150+
151+
bool checkCPUKind(CPUKind Kind, bool IsRV64);
152+
CPUKind parseCPUKind(StringRef CPU);
153+
StringRef getMArchFromMcpu(StringRef CPU);
154+
void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
155+
bool getCPUFeaturesExceptStdExt(CPUKind Kind, std::vector<StringRef> &Features);
156+
157+
} // namespace RISCV
158+
133159
} // namespace llvm
134160

135161
#endif

0 commit comments

Comments
 (0)