https://github.com/topperc created https://github.com/llvm/llvm-project/pull/215939
This 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 >From 759b5fba1f7bc3977186014f7d13454941017926 Mon Sep 17 00:00:00 2001 From: Craig Topper <[email protected]> Date: Wed, 12 Aug 2026 14:33:48 -0700 Subject: [PATCH] [RISCV] Support -march=native This 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 --- clang/docs/ReleaseNotes.md | 5 + clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 106 ++++++++++++++------- clang/test/Driver/riscv-cpus.c | 14 +++ 3 files changed, 88 insertions(+), 37 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 9648ad429d040..2917ec7999406 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -532,6 +532,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 c90d771e87a23..b50d0105d01c8 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..da62c2d05c40f 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" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
