summaryrefslogtreecommitdiffstats
path: root/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Driver/ToolChains/Arch/RISCV.cpp')
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.cpp139
1 files changed, 127 insertions, 12 deletions
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index a26f723a507..8c343b8693f 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -357,14 +357,9 @@ static bool getArchFeatures(const Driver &D, StringRef MArch,
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
- llvm::Optional<StringRef> MArch;
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- MArch = A->getValue();
- else if (Triple.getOS() == llvm::Triple::Linux)
- // RISC-V Linux defaults to rv{32,64}gc.
- MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc";
+ StringRef MArch = getRISCVArch(Args, Triple);
- if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args))
+ if (!getArchFeatures(D, MArch, Features, Args))
return;
// Handle features corresponding to "-ffixed-X" options
@@ -455,12 +450,132 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
Triple.getArch() == llvm::Triple::riscv64) &&
"Unexpected triple");
+ // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
+ // configured using `--with-abi=`, then the logic for the default choice is
+ // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
+ // deviate from GCC's default only on baremetal targets (UnknownOS) where
+ // neither `-march` nor `-mabi` is specified.
+ //
+ // The logic uses the following, in order:
+ // 1. Explicit choices using `--with-abi=`
+ // 2. A default based on `--with-arch=`, if provided
+ // 3. A default based on the target triple's arch
+ //
+ // The logic in config.gcc is a little circular but it is not inconsistent.
+ //
+ // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
+ // and `-mabi=` respectively instead.
+
+ // 1. If `-mabi=` is specified, use it.
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
return A->getValue();
- // RISC-V Linux defaults to ilp32d/lp64d
- if (Triple.getOS() == llvm::Triple::Linux)
- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d";
- else
- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64";
+ // 2. Choose a default based on `-march=`
+ //
+ // rv32g | rv32*d -> ilp32d
+ // rv32e -> ilp32e
+ // rv32* -> ilp32
+ // rv64g | rv64*d -> lp64d
+ // rv64* -> lp64
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ StringRef MArch = A->getValue();
+
+ if (MArch.startswith_lower("rv32")) {
+ // FIXME: parse `March` to find `D` extension properly
+ if (MArch.substr(4).contains_lower("d") ||
+ MArch.startswith_lower("rv32g"))
+ return "ilp32d";
+ else if (MArch.startswith_lower("rv32e"))
+ return "ilp32e";
+ else
+ return "ilp32";
+ } else if (MArch.startswith_lower("rv64")) {
+ // FIXME: parse `March` to find `D` extension properly
+ if (MArch.substr(4).contains_lower("d") ||
+ MArch.startswith_lower("rv64g"))
+ return "lp64d";
+ else
+ return "lp64";
+ }
+ }
+
+ // 3. Choose a default based on the triple
+ //
+ // We deviate from GCC's defaults here:
+ // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
+ // - On all other OSs we use the double floating point calling convention.
+ if (Triple.getArch() == llvm::Triple::riscv32) {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "ilp32";
+ else
+ return "ilp32d";
+ } else {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "lp64";
+ else
+ return "lp64d";
+ }
+}
+
+StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ assert((Triple.getArch() == llvm::Triple::riscv32 ||
+ Triple.getArch() == llvm::Triple::riscv64) &&
+ "Unexpected triple");
+
+ // GCC's logic around choosing a default `-march=` is complex. If GCC is not
+ // configured using `--with-arch=`, then the logic for the default choice is
+ // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
+ // deviate from GCC's default only on baremetal targets (UnknownOS) where
+ // neither `-march` nor `-mabi` is specified.
+ //
+ // The logic uses the following, in order:
+ // 1. Explicit choices using `--with-arch=`
+ // 2. A default based on `--with-abi=`, if provided
+ // 3. A default based on the target triple's arch
+ //
+ // The logic in config.gcc is a little circular but it is not inconsistent.
+ //
+ // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
+ // and `-mabi=` respectively instead.
+ //
+ // 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.
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+
+ // 2. Choose a default based on `-mabi=`
+ //
+ // ilp32e -> rv32e
+ // ilp32 | ilp32f | ilp32d -> rv32imafdc
+ // lp64 | lp64f | lp64d -> rv64imafdc
+ if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ StringRef MABI = A->getValue();
+
+ if (MABI.equals_lower("ilp32e"))
+ return "rv32e";
+ else if (MABI.startswith_lower("ilp32"))
+ return "rv32imafdc";
+ else if (MABI.startswith_lower("lp64"))
+ return "rv64imafdc";
+ }
+
+ // 3. Choose a default based on the triple
+ //
+ // We deviate from GCC's defaults here:
+ // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
+ // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
+ if (Triple.getArch() == llvm::Triple::riscv32) {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "rv32imac";
+ else
+ return "rv32imafdc";
+ } else {
+ if (Triple.getOS() == llvm::Triple::UnknownOS)
+ return "rv64imac";
+ else
+ return "rv64imafdc";
+ }
}
OpenPOWER on IntegriCloud