[clang] 3f9b064 - [RISCV] Support -march=native (#215939)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 13 14:47:41 PDT 2026
Author: Craig Topper
Date: 2026-08-13T14:47:36-07:00
New Revision: 3f9b06428f54a1382ff56f0be2f0ba7c70b70e2a
URL: https://github.com/llvm/llvm-project/commit/3f9b06428f54a1382ff56f0be2f0ba7c70b70e2a
DIFF: https://github.com/llvm/llvm-project/commit/3f9b06428f54a1382ff56f0be2f0ba7c70b70e2a.diff
LOG: [RISCV] Support -march=native (#215939)
-march=native is how to do a native compilation on X86 so it is included in the
build scripts of many projects. ARM and AArch64 also support this
probably for compatibility with X86.
This patch does the same for RISC-V. If -march=native is provided by
itself, I treat it like -mcpu=native. If -mcpu is also provided then the
-mcpu will be used only for -mtune and the ISA string will derive from
the host CPU.
Assisted-by: Claude
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Driver/ToolChains/Arch/RISCV.cpp
clang/test/Driver/riscv-cpus.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index e4a6f72f8fec5..4962f9f137b5a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -535,6 +535,11 @@ features cannot lower the translation-unit ABI level;
#### RISC-V Support
+- Added `-march=native` for better compatibility with ARM, AArch64, and X86. This
+ option will be treated like `-mcpu=native` if `-mcpu` is not present. If
+ `-mcpu` is present, the ISA will be selected from the host CPU and the tune
+ CPU will be selected from `-mcpu`.
+
#### CUDA/HIP Language Changes
- HIP compilations now add the `include/libhipcxx` directory from the selected
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index 5af6b8f7e0022..c97ce34a9fc77 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -77,14 +77,22 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
bool CPUFastScalarUnaligned = false;
bool CPUFastVectorUnaligned = false;
- // If users give march and mcpu, get std extension feature from MArch
- // and other features (ex. mirco architecture feature) from mcpu
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPU = A->getValue();
+ StringRef CPU;
+ Arg *CPUArg = nullptr;
+
+ if ((CPUArg = Args.getLastArg(options::OPT_mcpu_EQ))) {
+ CPU = CPUArg->getValue();
+ } else if ((CPUArg = Args.getLastArg(options::OPT_march_EQ))) {
+ StringRef MArchValue = CPUArg->getValue();
+ if (MArchValue == "native")
+ CPU = "native";
+ }
+
+ if (!CPU.empty()) {
if (CPU == "native")
CPU = llvm::sys::getHostCPUName();
- if (!isValidRISCVCPU(D, A, Triple, CPU))
+ if (!isValidRISCVCPU(D, CPUArg, Triple, CPU))
return;
if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))
@@ -272,6 +280,28 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
}
}
+static std::string getMArchFromMcpu(StringRef CPU, const llvm::Triple &Triple) {
+ if (CPU == "native") {
+ CPU = llvm::sys::getHostCPUName();
+ // If the target cpu is unrecognized, use target features.
+ if (CPU.starts_with("generic")) {
+ auto FeatureMap = llvm::sys::getHostCPUFeatures();
+ // hwprobe may be unavailable on older Linux versions.
+ if (!FeatureMap.empty()) {
+ std::vector<std::string> Features;
+ for (auto &F : FeatureMap)
+ Features.push_back(((F.second ? "+" : "-") + F.first()).str());
+ auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
+ Triple.isRISCV32() ? 32 : 64, Features);
+ if (ParseResult)
+ return (*ParseResult)->toString();
+ }
+ }
+ }
+
+ return llvm::RISCV::getMArchFromMcpu(CPU).str();
+}
+
std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
assert(Triple.isRISCV() && "Unexpected triple");
@@ -294,46 +324,42 @@ std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// and `-mabi=` respectively instead.
//
// Clang uses the following logic, in order:
- // 1. Explicit choices using `-march=`
- // 2. Based on `-mcpu` if the target CPU has a default ISA string
+ // 1. Explicit choices using `-march=` (`-march=native` means the host CPU)
+ // 2. Based on `-mcpu` if `-march=` is not specified and the target CPU has a
+ // default ISA string
// 3. A default based on `-mabi`, if provided
// 4. A default based on the target triple's arch
//
// Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
// instead of `rv{XLEN}gc` though they are (currently) equivalent.
- // 1. If `-march=` is specified, use it unless the value is "unset".
+ // 1. If `-march=` is specified, use it unless the value is "unset". A value
+ // of "native" is an alias for `-mcpu=native` and selects the ISA string of
+ // the host CPU.
+ bool HasMArch = false;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- StringRef MArch = A->getValue();
- if (MArch != "unset")
- return MArch.str();
+ StringRef MArchValue = A->getValue();
+ if (MArchValue != "unset") {
+ HasMArch = true;
+ if (MArchValue != "native")
+ return MArchValue.str();
+
+ std::string MArch = getMArchFromMcpu(MArchValue, Triple);
+ if (!MArch.empty())
+ return MArch;
+ }
}
- // 2. Get march (isa string) based on `-mcpu=`
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPU = A->getValue();
- if (CPU == "native") {
- CPU = llvm::sys::getHostCPUName();
- // If the target cpu is unrecognized, use target features.
- if (CPU.starts_with("generic")) {
- auto FeatureMap = llvm::sys::getHostCPUFeatures();
- // hwprobe may be unavailable on older Linux versions.
- if (!FeatureMap.empty()) {
- std::vector<std::string> Features;
- for (auto &F : FeatureMap)
- Features.push_back(((F.second ? "+" : "-") + F.first()).str());
- auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
- Triple.isRISCV32() ? 32 : 64, Features);
- if (ParseResult)
- return (*ParseResult)->toString();
- }
- }
+ // 2. Get march (isa string) based on `-mcpu=`. This is only used if `-march=`
+ // was not specified, so a `-march=native` that failed to determine the host
+ // ISA string above does not fall back to `-mcpu=`.
+ if (!HasMArch) {
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ std::string MArch = getMArchFromMcpu(A->getValue(), Triple);
+ // Bypass if target cpu's default march is empty.
+ if (!MArch.empty())
+ return MArch;
}
-
- StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
- // Bypass if target cpu's default march is empty.
- if (!MArch.empty())
- return MArch.str();
}
// 3. Choose a default based on `-mabi=`
@@ -383,9 +409,15 @@ std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
std::string CPU;
- // If we have -mcpu, use that.
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ // If we have -mcpu, use that. Otherwise, check for -march=native.
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
CPU = A->getValue();
+ } else if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ // `-march=native` is an alias for `-mcpu=native`.
+ StringRef MArchValue = A->getValue();
+ if (MArchValue == "native")
+ CPU = "native";
+ }
// Handle CPU name is 'native'.
if (CPU == "native")
diff --git a/clang/test/Driver/riscv-cpus.c b/clang/test/Driver/riscv-cpus.c
index dffdf8dbda9a6..89a3875adeed8 100644
--- a/clang/test/Driver/riscv-cpus.c
+++ b/clang/test/Driver/riscv-cpus.c
@@ -133,6 +133,20 @@
// RUN: FileCheck --input-file=%t.err -check-prefix=MCPU-NATIVE %s
// MCPU-NATIVE-NOT: "-target-cpu" "native"
+// -march=native is an alias for -mcpu=native. We cannot check much for it, but
+// it should be replaced by a valid CPU string and never treated as an ISA
+// string.
+// RUN: %clang --target=riscv64 -### -c %s -march=native 2> %t.err || true
+// RUN: FileCheck --input-file=%t.err -check-prefix=MARCH-NATIVE %s
+// MARCH-NATIVE-NOT: "-target-cpu" "native"
+// MARCH-NATIVE-NOT: invalid arch name 'native'
+
+// -mcpu takes priority over -march=native when choosing the target CPU,
+// regardless of the order of the options.
+// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=native -mcpu=rocket-rv64 | FileCheck -check-prefix=MARCH-NATIVE-MCPU %s
+// RUN: %clang --target=riscv64 -### -c %s 2>&1 -mcpu=rocket-rv64 -march=native | FileCheck -check-prefix=MARCH-NATIVE-MCPU %s
+// MARCH-NATIVE-MCPU: "-target-cpu" "rocket-rv64"
+
// RUN: %clang --target=riscv32 -### -c %s 2>&1 -mtune=rocket-rv32 | FileCheck -check-prefix=MTUNE-ROCKET32 %s
// MTUNE-ROCKET32: "-tune-cpu" "rocket-rv32"
@@ -389,6 +403,10 @@
// MARCH-UNSET: "-target-feature" "+c"
// MARCH-UNSET-SAME: "-target-abi" "ilp32"
+// Invalid -march= is an error even with a valid -mcpu
+// RUN: not %clang --target=riscv32 -### -c %s 2>&1 -march=rv32imc -march=bad -mcpu=sifive-e31 | FileCheck -check-prefix=MARCH-INVALID-MCPU %s
+// MARCH-INVALID-MCPU: invalid arch name 'bad', string must begin with rv32{i,e,g,y}, rv64{i,e,g,y}, or a supported profile name
+
// Check interaction between -mcpu and mtune, -mtune won't affect arch related
// target feature, but -mcpu will.
//
More information about the cfe-commits
mailing list