diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -223,6 +223,11 @@ element. Clang now matches the gcc behavior on Linux and NetBSD. You can switch back to old API behavior with flag: -fclang-abi-compat=9.0. +- RISC-V now chooses a default `-march=` and `-mabi=` to match (in almost all + cases) the GCC defaults. These do not always match the defaults in clang 9. We + strongly suggest that you explicitly pass `-march=` and `-mabi=` when + compiling for RISC-V, due to how extensible this architecture is. + OpenMP Support in Clang ----------------------- diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h --- a/clang/lib/Driver/ToolChains/Arch/RISCV.h +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -24,6 +24,8 @@ std::vector &Features); StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +StringRef getRISCVArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); } // end namespace riscv } // namespace tools } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -357,14 +357,9 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { - llvm::Optional 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,122 @@ 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. + // + // This 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 + // + // This 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=` + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + StringRef MArch = A->getValue(); + + if (MArch.startswith_lower("rv32")) { + // TODO: 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")) { + // TODO: 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. + // + // This 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 + // + // This 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=` + 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"; + } } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -709,11 +709,9 @@ StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - StringRef MArch = A->getValue(); - CmdArgs.push_back("-march"); - CmdArgs.push_back(MArch.data()); - } + StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple()); + CmdArgs.push_back("-march"); + CmdArgs.push_back(MArchName.data()); break; } case llvm::Triple::sparc: diff --git a/clang/test/Driver/riscv-abi.c b/clang/test/Driver/riscv-abi.c --- a/clang/test/Driver/riscv-abi.c +++ b/clang/test/Driver/riscv-abi.c @@ -16,6 +16,10 @@ // RUN: %clang -target riscv32-unknown-elf %s -### -o %t.o -march=rv32ifd -mabi=ilp32d 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-ILP32D %s +// RUN: %clang -target riscv32-unknown-linux-gnu %s -### -o %t.o 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ILP32D %s +// RUN: %clang -target riscv32-unknown-linux-gnu -x assembler %s -### -o %t.o 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-ILP32D %s // CHECK-ILP32D: "-target-abi" "ilp32d" @@ -42,6 +46,10 @@ // RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64d -mabi=lp64d 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-LP64D %s +// RUN: %clang -target riscv64-unknown-linux-gnu %s -### -o %t.o 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-LP64D %s +// RUN: %clang -target riscv64-unknown-linux-gnu -x assembler %s -### -o %t.o 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-LP64D %s // CHECK-LP64D: "-target-abi" "lp64d" diff --git a/clang/test/Driver/riscv-gnutools.c b/clang/test/Driver/riscv-gnutools.c --- a/clang/test/Driver/riscv-gnutools.c +++ b/clang/test/Driver/riscv-gnutools.c @@ -1,19 +1,40 @@ // Check gnutools are invoked with propagated values for -mabi and -march. +// +// This test also checks the default -march/-mabi for certain targets. -// RUN: %clang -target riscv32 -fno-integrated-as %s -### -c \ -// RUN: 2>&1 | FileCheck -check-prefix=MABI-ILP32 %s +// 32-bit checks -// RUN: %clang -target riscv32 -fno-integrated-as -march=rv32g %s -### -c \ -// RUN: 2>&1 | FileCheck -check-prefix=MABI-ILP32-MARCH-G %s +// Check default on riscv32-unknown-elf +// RUN: %clang -target riscv32-unknown-elf -fno-integrated-as %s -### -c \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV32IMAC-ILP32 %s -// RUN: %clang -target riscv64 -fno-integrated-as %s -### -c \ -// RUN: 2>&1 | FileCheck -check-prefix=MABI-ILP64 %s +// Check default on riscv32-unknown-linux-gnu +// RUN: %clang -target riscv32-unknown-linux-gnu -fno-integrated-as %s -### -c \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV32IMAFDC-ILP32D %s -// RUN: %clang -target riscv64 -fno-integrated-as -march=rv64g %s -### -c \ -// RUN: 2>&1 | FileCheck -check-prefix=MABI-ILP64-MARCH-G %s +// Check default when -march=rv32g specified +// RUN: %clang -target riscv32 -fno-integrated-as %s -### -c -march=rv32g \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV32G-ILP32D %s -// MABI-ILP32: "{{.*}}as{{(.exe)?}}" "-mabi" "ilp32" -// MABI-ILP32-MARCH-G: "{{.*}}as{{(.exe)?}}" "-mabi" "ilp32" "-march" "rv32g" +// CHECK-RV32IMAC-ILP32: "{{.*}}as{{(.exe)?}}" "-mabi" "ilp32" "-march" "rv32imac" +// CHECK-RV32IMAFDC-ILP32D: "{{.*}}as{{(.exe)?}}" "-mabi" "ilp32d" "-march" "rv32imafdc" +// CHECK-RV32G-ILP32D: "{{.*}}as{{(.exe)?}}" "-mabi" "ilp32d" "-march" "rv32g" -// MABI-ILP64: "{{.*}}as{{(.exe)?}}" "-mabi" "lp64" -// MABI-ILP64-MARCH-G: "{{.*}}as{{(.exe)?}}" "-mabi" "lp64" "-march" "rv64g" + +// 64-bit checks + +// Check default on riscv64-unknown-elf +// RUN: %clang -target riscv64-unknown-elf -fno-integrated-as %s -### -c \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV64IMAC-LP64 %s + +// Check default on riscv64-unknown-linux-gnu +// RUN: %clang -target riscv64-unknown-linux-gnu -fno-integrated-as %s -### -c \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV64IMAFDC-LP64D %s + +// Check default when -march=rv64g specified +// RUN: %clang -target riscv64 -fno-integrated-as %s -### -c -march=rv64g \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-RV64G-LP64D %s + +// CHECK-RV64IMAC-LP64: "{{.*}}as{{(.exe)?}}" "-mabi" "lp64" "-march" "rv64imac" +// CHECK-RV64IMAFDC-LP64D: "{{.*}}as{{(.exe)?}}" "-mabi" "lp64d" "-march" "rv64imafdc" +// CHECK-RV64G-LP64D: "{{.*}}as{{(.exe)?}}" "-mabi" "lp64d" "-march" "rv64g"