1 //===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "RISCV.h" 10 #include "ToolChains/CommonArgs.h" 11 #include "clang/Basic/CharInfo.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/DriverDiagnostic.h" 14 #include "clang/Driver/Options.h" 15 #include "llvm/ADT/Optional.h" 16 #include "llvm/Option/ArgList.h" 17 #include "llvm/Support/Error.h" 18 #include "llvm/Support/RISCVISAInfo.h" 19 #include "llvm/Support/TargetParser.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace clang::driver; 23 using namespace clang::driver::tools; 24 using namespace clang; 25 using namespace llvm::opt; 26 27 // Returns false if an error is diagnosed. 28 static bool getArchFeatures(const Driver &D, StringRef Arch, 29 std::vector<StringRef> &Features, 30 const ArgList &Args) { 31 bool EnableExperimentalExtensions = 32 Args.hasArg(options::OPT_menable_experimental_extensions); 33 auto ISAInfo = 34 llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions); 35 if (!ISAInfo) { 36 handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) { 37 D.Diag(diag::err_drv_invalid_riscv_arch_name) 38 << Arch << ErrMsg.getMessage(); 39 }); 40 41 return false; 42 } 43 44 (*ISAInfo)->toFeatures( 45 Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); }); 46 return true; 47 } 48 49 // Get features except standard extension feature 50 static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple, 51 const llvm::opt::ArgList &Args, 52 const llvm::opt::Arg *A, StringRef Mcpu, 53 std::vector<StringRef> &Features) { 54 bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64); 55 llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu); 56 if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) || 57 !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) { 58 D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); 59 } 60 } 61 62 void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, 63 const ArgList &Args, 64 std::vector<StringRef> &Features) { 65 StringRef MArch = getRISCVArch(Args, Triple); 66 67 if (!getArchFeatures(D, MArch, Features, Args)) 68 return; 69 70 // If users give march and mcpu, get std extension feature from MArch 71 // and other features (ex. mirco architecture feature) from mcpu 72 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) 73 getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); 74 75 // Handle features corresponding to "-ffixed-X" options 76 if (Args.hasArg(options::OPT_ffixed_x1)) 77 Features.push_back("+reserve-x1"); 78 if (Args.hasArg(options::OPT_ffixed_x2)) 79 Features.push_back("+reserve-x2"); 80 if (Args.hasArg(options::OPT_ffixed_x3)) 81 Features.push_back("+reserve-x3"); 82 if (Args.hasArg(options::OPT_ffixed_x4)) 83 Features.push_back("+reserve-x4"); 84 if (Args.hasArg(options::OPT_ffixed_x5)) 85 Features.push_back("+reserve-x5"); 86 if (Args.hasArg(options::OPT_ffixed_x6)) 87 Features.push_back("+reserve-x6"); 88 if (Args.hasArg(options::OPT_ffixed_x7)) 89 Features.push_back("+reserve-x7"); 90 if (Args.hasArg(options::OPT_ffixed_x8)) 91 Features.push_back("+reserve-x8"); 92 if (Args.hasArg(options::OPT_ffixed_x9)) 93 Features.push_back("+reserve-x9"); 94 if (Args.hasArg(options::OPT_ffixed_x10)) 95 Features.push_back("+reserve-x10"); 96 if (Args.hasArg(options::OPT_ffixed_x11)) 97 Features.push_back("+reserve-x11"); 98 if (Args.hasArg(options::OPT_ffixed_x12)) 99 Features.push_back("+reserve-x12"); 100 if (Args.hasArg(options::OPT_ffixed_x13)) 101 Features.push_back("+reserve-x13"); 102 if (Args.hasArg(options::OPT_ffixed_x14)) 103 Features.push_back("+reserve-x14"); 104 if (Args.hasArg(options::OPT_ffixed_x15)) 105 Features.push_back("+reserve-x15"); 106 if (Args.hasArg(options::OPT_ffixed_x16)) 107 Features.push_back("+reserve-x16"); 108 if (Args.hasArg(options::OPT_ffixed_x17)) 109 Features.push_back("+reserve-x17"); 110 if (Args.hasArg(options::OPT_ffixed_x18)) 111 Features.push_back("+reserve-x18"); 112 if (Args.hasArg(options::OPT_ffixed_x19)) 113 Features.push_back("+reserve-x19"); 114 if (Args.hasArg(options::OPT_ffixed_x20)) 115 Features.push_back("+reserve-x20"); 116 if (Args.hasArg(options::OPT_ffixed_x21)) 117 Features.push_back("+reserve-x21"); 118 if (Args.hasArg(options::OPT_ffixed_x22)) 119 Features.push_back("+reserve-x22"); 120 if (Args.hasArg(options::OPT_ffixed_x23)) 121 Features.push_back("+reserve-x23"); 122 if (Args.hasArg(options::OPT_ffixed_x24)) 123 Features.push_back("+reserve-x24"); 124 if (Args.hasArg(options::OPT_ffixed_x25)) 125 Features.push_back("+reserve-x25"); 126 if (Args.hasArg(options::OPT_ffixed_x26)) 127 Features.push_back("+reserve-x26"); 128 if (Args.hasArg(options::OPT_ffixed_x27)) 129 Features.push_back("+reserve-x27"); 130 if (Args.hasArg(options::OPT_ffixed_x28)) 131 Features.push_back("+reserve-x28"); 132 if (Args.hasArg(options::OPT_ffixed_x29)) 133 Features.push_back("+reserve-x29"); 134 if (Args.hasArg(options::OPT_ffixed_x30)) 135 Features.push_back("+reserve-x30"); 136 if (Args.hasArg(options::OPT_ffixed_x31)) 137 Features.push_back("+reserve-x31"); 138 139 // FreeBSD local, because ld.lld doesn't support relaxations 140 // -mno-relax is default, unless -mrelax is specified. 141 if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) 142 Features.push_back("+relax"); 143 else 144 Features.push_back("-relax"); 145 146 // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is 147 // specified. 148 if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) 149 Features.push_back("+save-restore"); 150 else 151 Features.push_back("-save-restore"); 152 153 // Now add any that the user explicitly requested on the command line, 154 // which may override the defaults. 155 handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); 156 } 157 158 StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { 159 assert((Triple.getArch() == llvm::Triple::riscv32 || 160 Triple.getArch() == llvm::Triple::riscv64) && 161 "Unexpected triple"); 162 163 // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not 164 // configured using `--with-abi=`, then the logic for the default choice is 165 // defined in config.gcc. This function is based on the logic in GCC 9.2.0. 166 // 167 // The logic used in GCC 9.2.0 is the following, in order: 168 // 1. Explicit choices using `--with-abi=` 169 // 2. A default based on `--with-arch=`, if provided 170 // 3. A default based on the target triple's arch 171 // 172 // The logic in config.gcc is a little circular but it is not inconsistent. 173 // 174 // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` 175 // and `-mabi=` respectively instead. 176 // 177 // In order to make chosing logic more clear, Clang uses the following logic, 178 // in order: 179 // 1. Explicit choices using `-mabi=` 180 // 2. A default based on the architecture as determined by getRISCVArch 181 // 3. Choose a default based on the triple 182 183 // 1. If `-mabi=` is specified, use it. 184 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) 185 return A->getValue(); 186 187 // 2. Choose a default based on the target architecture. 188 // 189 // rv32g | rv32*d -> ilp32d 190 // rv32e -> ilp32e 191 // rv32* -> ilp32 192 // rv64g | rv64*d -> lp64d 193 // rv64* -> lp64 194 StringRef Arch = getRISCVArch(Args, Triple); 195 196 auto ParseResult = llvm::RISCVISAInfo::parseArchString( 197 Arch, /* EnableExperimentalExtension */ true); 198 if (!ParseResult) 199 // Ignore parsing error, just go 3rd step. 200 consumeError(ParseResult.takeError()); 201 else 202 return llvm::RISCV::computeDefaultABIFromArch(**ParseResult); 203 204 // 3. Choose a default based on the triple 205 // 206 // We deviate from GCC's defaults here: 207 // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. 208 // - On all other OSs we use the double floating point calling convention. 209 if (Triple.getArch() == llvm::Triple::riscv32) { 210 if (Triple.getOS() == llvm::Triple::UnknownOS) 211 return "ilp32"; 212 else 213 return "ilp32d"; 214 } else { 215 if (Triple.getOS() == llvm::Triple::UnknownOS) 216 return "lp64"; 217 else 218 return "lp64d"; 219 } 220 } 221 222 StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, 223 const llvm::Triple &Triple) { 224 assert((Triple.getArch() == llvm::Triple::riscv32 || 225 Triple.getArch() == llvm::Triple::riscv64) && 226 "Unexpected triple"); 227 228 // GCC's logic around choosing a default `-march=` is complex. If GCC is not 229 // configured using `--with-arch=`, then the logic for the default choice is 230 // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We 231 // deviate from GCC's default on additional `-mcpu` option (GCC does not 232 // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march` 233 // nor `-mabi` is specified. 234 // 235 // The logic used in GCC 9.2.0 is the following, in order: 236 // 1. Explicit choices using `--with-arch=` 237 // 2. A default based on `--with-abi=`, if provided 238 // 3. A default based on the target triple's arch 239 // 240 // The logic in config.gcc is a little circular but it is not inconsistent. 241 // 242 // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` 243 // and `-mabi=` respectively instead. 244 // 245 // Clang uses the following logic, in order: 246 // 1. Explicit choices using `-march=` 247 // 2. Based on `-mcpu` if the target CPU has a default ISA string 248 // 3. A default based on `-mabi`, if provided 249 // 4. A default based on the target triple's arch 250 // 251 // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc` 252 // instead of `rv{XLEN}gc` though they are (currently) equivalent. 253 254 // 1. If `-march=` is specified, use it. 255 if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) 256 return A->getValue(); 257 258 // 2. Get march (isa string) based on `-mcpu=` 259 if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { 260 StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue()); 261 // Bypass if target cpu's default march is empty. 262 if (MArch != "") 263 return MArch; 264 } 265 266 // 3. Choose a default based on `-mabi=` 267 // 268 // ilp32e -> rv32e 269 // ilp32 | ilp32f | ilp32d -> rv32imafdc 270 // lp64 | lp64f | lp64d -> rv64imafdc 271 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { 272 StringRef MABI = A->getValue(); 273 274 if (MABI.equals_insensitive("ilp32e")) 275 return "rv32e"; 276 else if (MABI.startswith_insensitive("ilp32")) 277 return "rv32imafdc"; 278 else if (MABI.startswith_insensitive("lp64")) 279 return "rv64imafdc"; 280 } 281 282 // 4. Choose a default based on the triple 283 // 284 // We deviate from GCC's defaults here: 285 // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` 286 // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) 287 if (Triple.getArch() == llvm::Triple::riscv32) { 288 if (Triple.getOS() == llvm::Triple::UnknownOS) 289 return "rv32imac"; 290 else 291 return "rv32imafdc"; 292 } else { 293 if (Triple.getOS() == llvm::Triple::UnknownOS) 294 return "rv64imac"; 295 else 296 return "rv64imafdc"; 297 } 298 } 299