| 1 | //===--- Mips.cpp - Tools Implementations -----------------------*- 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 "Mips.h" |
| 10 | #include "clang/Driver/CommonArgs.h" |
| 11 | #include "clang/Driver/Driver.h" |
| 12 | #include "clang/Driver/Options.h" |
| 13 | #include "llvm/ADT/StringSwitch.h" |
| 14 | #include "llvm/Option/ArgList.h" |
| 15 | |
| 16 | using namespace clang::driver; |
| 17 | using namespace clang::driver::tools; |
| 18 | using namespace clang; |
| 19 | using namespace llvm::opt; |
| 20 | |
| 21 | // Get CPU and ABI names. They are not independent |
| 22 | // so we have to calculate them together. |
| 23 | void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, |
| 24 | StringRef &CPUName, StringRef &ABIName) { |
| 25 | const char *DefMips32CPU = "mips32r2" ; |
| 26 | const char *DefMips64CPU = "mips64r2" ; |
| 27 | |
| 28 | // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the |
| 29 | // default for mips64(el)?-img-linux-gnu. |
| 30 | if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && |
| 31 | Triple.isGNUEnvironment()) { |
| 32 | DefMips32CPU = "mips32r6" ; |
| 33 | DefMips64CPU = "mips64r6" ; |
| 34 | } |
| 35 | |
| 36 | if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) { |
| 37 | DefMips32CPU = "mips32r6" ; |
| 38 | DefMips64CPU = "mips64r6" ; |
| 39 | } |
| 40 | |
| 41 | // MIPS3 is the default for mips64*-unknown-openbsd. |
| 42 | if (Triple.isOSOpenBSD()) |
| 43 | DefMips64CPU = "mips3" ; |
| 44 | |
| 45 | // MIPS2 is the default for mips(el)?-unknown-freebsd. |
| 46 | // MIPS3 is the default for mips64(el)?-unknown-freebsd. |
| 47 | if (Triple.isOSFreeBSD()) { |
| 48 | DefMips32CPU = "mips2" ; |
| 49 | DefMips64CPU = "mips3" ; |
| 50 | } |
| 51 | |
| 52 | if (Arg *A = Args.getLastArg(Ids: clang::driver::options::OPT_march_EQ, |
| 53 | Ids: options::OPT_mcpu_EQ)) |
| 54 | CPUName = A->getValue(); |
| 55 | |
| 56 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ)) { |
| 57 | ABIName = A->getValue(); |
| 58 | // Convert a GNU style Mips ABI name to the name |
| 59 | // accepted by LLVM Mips backend. |
| 60 | ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) |
| 61 | .Case(S: "32" , Value: "o32" ) |
| 62 | .Case(S: "64" , Value: "n64" ) |
| 63 | .Default(Value: ABIName); |
| 64 | } |
| 65 | |
| 66 | // Setup default CPU and ABI names. |
| 67 | if (CPUName.empty() && ABIName.empty()) { |
| 68 | switch (Triple.getArch()) { |
| 69 | default: |
| 70 | llvm_unreachable("Unexpected triple arch name" ); |
| 71 | case llvm::Triple::mips: |
| 72 | case llvm::Triple::mipsel: |
| 73 | CPUName = DefMips32CPU; |
| 74 | break; |
| 75 | case llvm::Triple::mips64: |
| 76 | case llvm::Triple::mips64el: |
| 77 | CPUName = DefMips64CPU; |
| 78 | break; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | if (ABIName.empty() && Triple.isABIN32()) |
| 83 | ABIName = "n32" ; |
| 84 | |
| 85 | if (ABIName.empty() && |
| 86 | (Triple.getVendor() == llvm::Triple::MipsTechnologies || |
| 87 | Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) { |
| 88 | ABIName = llvm::StringSwitch<const char *>(CPUName) |
| 89 | .Case(S: "mips1" , Value: "o32" ) |
| 90 | .Case(S: "mips2" , Value: "o32" ) |
| 91 | .Case(S: "mips3" , Value: "n64" ) |
| 92 | .Case(S: "mips4" , Value: "n64" ) |
| 93 | .Case(S: "mips5" , Value: "n64" ) |
| 94 | .Case(S: "mips32" , Value: "o32" ) |
| 95 | .Case(S: "mips32r2" , Value: "o32" ) |
| 96 | .Case(S: "mips32r3" , Value: "o32" ) |
| 97 | .Case(S: "mips32r5" , Value: "o32" ) |
| 98 | .Case(S: "mips32r6" , Value: "o32" ) |
| 99 | .Case(S: "mips64" , Value: "n64" ) |
| 100 | .Case(S: "mips64r2" , Value: "n64" ) |
| 101 | .Case(S: "mips64r3" , Value: "n64" ) |
| 102 | .Case(S: "mips64r5" , Value: "n64" ) |
| 103 | .Case(S: "mips64r6" , Value: "n64" ) |
| 104 | .Case(S: "octeon" , Value: "n64" ) |
| 105 | .Case(S: "p5600" , Value: "o32" ) |
| 106 | .Case(S: "i6400" , Value: "n64" ) |
| 107 | .Case(S: "i6500" , Value: "n64" ) |
| 108 | .Default(Value: "" ); |
| 109 | } |
| 110 | |
| 111 | if (ABIName.empty()) { |
| 112 | // Deduce ABI name from the target triple. |
| 113 | ABIName = Triple.isMIPS32() ? "o32" : "n64" ; |
| 114 | } |
| 115 | |
| 116 | if (CPUName.empty()) { |
| 117 | // Deduce CPU name from ABI name. |
| 118 | CPUName = llvm::StringSwitch<const char *>(ABIName) |
| 119 | .Case(S: "o32" , Value: DefMips32CPU) |
| 120 | .Cases(S0: "n32" , S1: "n64" , Value: DefMips64CPU) |
| 121 | .Default(Value: "" ); |
| 122 | } |
| 123 | |
| 124 | // FIXME: Warn on inconsistent use of -march and -mabi. |
| 125 | } |
| 126 | |
| 127 | std::string mips::getMipsABILibSuffix(const ArgList &Args, |
| 128 | const llvm::Triple &Triple) { |
| 129 | StringRef CPUName, ABIName; |
| 130 | tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
| 131 | return llvm::StringSwitch<std::string>(ABIName) |
| 132 | .Case(S: "o32" , Value: "" ) |
| 133 | .Case(S: "n32" , Value: "32" ) |
| 134 | .Case(S: "n64" , Value: "64" ); |
| 135 | } |
| 136 | |
| 137 | // Convert ABI name to the GNU tools acceptable variant. |
| 138 | StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) { |
| 139 | return llvm::StringSwitch<llvm::StringRef>(ABI) |
| 140 | .Case(S: "o32" , Value: "32" ) |
| 141 | .Case(S: "n64" , Value: "64" ) |
| 142 | .Default(Value: ABI); |
| 143 | } |
| 144 | |
| 145 | // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, |
| 146 | // and -mfloat-abi=. |
| 147 | mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args, |
| 148 | const llvm::Triple &Triple) { |
| 149 | mips::FloatABI ABI = mips::FloatABI::Invalid; |
| 150 | if (Arg *A = |
| 151 | Args.getLastArg(Ids: options::OPT_msoft_float, Ids: options::OPT_mhard_float, |
| 152 | Ids: options::OPT_mfloat_abi_EQ)) { |
| 153 | if (A->getOption().matches(ID: options::OPT_msoft_float)) |
| 154 | ABI = mips::FloatABI::Soft; |
| 155 | else if (A->getOption().matches(ID: options::OPT_mhard_float)) |
| 156 | ABI = mips::FloatABI::Hard; |
| 157 | else { |
| 158 | ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue()) |
| 159 | .Case(S: "soft" , Value: mips::FloatABI::Soft) |
| 160 | .Case(S: "hard" , Value: mips::FloatABI::Hard) |
| 161 | .Default(Value: mips::FloatABI::Invalid); |
| 162 | if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
| 163 | D.Diag(DiagID: clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
| 164 | ABI = mips::FloatABI::Hard; |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | // If unspecified, choose the default based on the platform. |
| 170 | if (ABI == mips::FloatABI::Invalid) { |
| 171 | if (Triple.isOSFreeBSD()) { |
| 172 | // For FreeBSD, assume "soft" on all flavors of MIPS. |
| 173 | ABI = mips::FloatABI::Soft; |
| 174 | } else { |
| 175 | // Assume "hard", because it's a default value used by gcc. |
| 176 | // When we start to recognize specific target MIPS processors, |
| 177 | // we will be able to select the default more correctly. |
| 178 | ABI = mips::FloatABI::Hard; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | assert(ABI != mips::FloatABI::Invalid && "must select an ABI" ); |
| 183 | return ABI; |
| 184 | } |
| 185 | |
| 186 | void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
| 187 | const ArgList &Args, |
| 188 | std::vector<StringRef> &Features) { |
| 189 | StringRef CPUName; |
| 190 | StringRef ABIName; |
| 191 | getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
| 192 | ABIName = getGnuCompatibleMipsABIName(ABI: ABIName); |
| 193 | |
| 194 | // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a |
| 195 | // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI |
| 196 | // extension was developed by Richard Sandiford & Code Sourcery to support |
| 197 | // static code calling PIC code (CPIC). For O32 and N32 this means we have |
| 198 | // several combinations of PIC/static and abicalls. Pure static, static |
| 199 | // with the CPIC extension, and pure PIC code. |
| 200 | |
| 201 | // At final link time, O32 and N32 with CPIC will have another section |
| 202 | // added to the binary which contains the stub functions to perform |
| 203 | // any fixups required for PIC code. |
| 204 | |
| 205 | // For N64, the situation is more regular: code can either be static |
| 206 | // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code |
| 207 | // code for N64. Since Clang has already built the relocation model portion |
| 208 | // of the commandline, we pick add +noabicalls feature in the N64 static |
| 209 | // case. |
| 210 | |
| 211 | // The is another case to be accounted for: -msym32, which enforces that all |
| 212 | // symbols have 32 bits in size. In this case, N64 can in theory use CPIC |
| 213 | // but it is unsupported. |
| 214 | |
| 215 | // The combinations for N64 are: |
| 216 | // a) Static without abicalls and 64bit symbols. |
| 217 | // b) Static with abicalls and 32bit symbols. |
| 218 | // c) PIC with abicalls and 64bit symbols. |
| 219 | |
| 220 | // For case (a) we need to add +noabicalls for N64. |
| 221 | |
| 222 | bool IsN64 = ABIName == "64" ; |
| 223 | bool IsPIC = false; |
| 224 | bool NonPIC = false; |
| 225 | bool HasNaN2008Opt = false; |
| 226 | |
| 227 | Arg *LastPICArg = Args.getLastArg(Ids: options::OPT_fPIC, Ids: options::OPT_fno_PIC, |
| 228 | Ids: options::OPT_fpic, Ids: options::OPT_fno_pic, |
| 229 | Ids: options::OPT_fPIE, Ids: options::OPT_fno_PIE, |
| 230 | Ids: options::OPT_fpie, Ids: options::OPT_fno_pie); |
| 231 | if (LastPICArg) { |
| 232 | Option O = LastPICArg->getOption(); |
| 233 | NonPIC = |
| 234 | (O.matches(ID: options::OPT_fno_PIC) || O.matches(ID: options::OPT_fno_pic) || |
| 235 | O.matches(ID: options::OPT_fno_PIE) || O.matches(ID: options::OPT_fno_pie)); |
| 236 | IsPIC = |
| 237 | (O.matches(ID: options::OPT_fPIC) || O.matches(ID: options::OPT_fpic) || |
| 238 | O.matches(ID: options::OPT_fPIE) || O.matches(ID: options::OPT_fpie)); |
| 239 | } |
| 240 | |
| 241 | bool UseAbiCalls = false; |
| 242 | |
| 243 | Arg *ABICallsArg = |
| 244 | Args.getLastArg(Ids: options::OPT_mabicalls, Ids: options::OPT_mno_abicalls); |
| 245 | UseAbiCalls = |
| 246 | !ABICallsArg || ABICallsArg->getOption().matches(ID: options::OPT_mabicalls); |
| 247 | |
| 248 | if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) { |
| 249 | D.Diag(DiagID: diag::warn_drv_unsupported_pic_with_mabicalls) |
| 250 | << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1); |
| 251 | } |
| 252 | |
| 253 | if (ABICallsArg && !UseAbiCalls && IsPIC) { |
| 254 | D.Diag(DiagID: diag::err_drv_unsupported_noabicalls_pic); |
| 255 | } |
| 256 | |
| 257 | if (CPUName == "i6500" || CPUName == "i6400" ) { |
| 258 | // MIPS cpu i6400 and i6500 support MSA (Mips SIMD Architecture) |
| 259 | // by default. |
| 260 | Features.push_back(x: "+msa" ); |
| 261 | } |
| 262 | |
| 263 | if (!UseAbiCalls) |
| 264 | Features.push_back(x: "+noabicalls" ); |
| 265 | else |
| 266 | Features.push_back(x: "-noabicalls" ); |
| 267 | |
| 268 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mlong_calls, |
| 269 | Ids: options::OPT_mno_long_calls)) { |
| 270 | if (A->getOption().matches(ID: options::OPT_mno_long_calls)) |
| 271 | Features.push_back(x: "-long-calls" ); |
| 272 | else if (!UseAbiCalls) |
| 273 | Features.push_back(x: "+long-calls" ); |
| 274 | else |
| 275 | D.Diag(DiagID: diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); |
| 276 | } |
| 277 | |
| 278 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mxgot, Ids: options::OPT_mno_xgot)) { |
| 279 | if (A->getOption().matches(ID: options::OPT_mxgot)) |
| 280 | Features.push_back(x: "+xgot" ); |
| 281 | else |
| 282 | Features.push_back(x: "-xgot" ); |
| 283 | } |
| 284 | |
| 285 | mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args, Triple); |
| 286 | if (FloatABI == mips::FloatABI::Soft) { |
| 287 | // FIXME: Note, this is a hack. We need to pass the selected float |
| 288 | // mode to the MipsTargetInfoBase to define appropriate macros there. |
| 289 | // Now it is the only method. |
| 290 | Features.push_back(x: "+soft-float" ); |
| 291 | } |
| 292 | |
| 293 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mnan_EQ)) { |
| 294 | StringRef Val = StringRef(A->getValue()); |
| 295 | if (Val == "2008" ) { |
| 296 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Std2008) { |
| 297 | Features.push_back(x: "+nan2008" ); |
| 298 | HasNaN2008Opt = true; |
| 299 | } else { |
| 300 | Features.push_back(x: "-nan2008" ); |
| 301 | D.Diag(DiagID: diag::warn_target_unsupported_nan2008) << CPUName; |
| 302 | } |
| 303 | } else if (Val == "legacy" ) { |
| 304 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Legacy) |
| 305 | Features.push_back(x: "-nan2008" ); |
| 306 | else { |
| 307 | Features.push_back(x: "+nan2008" ); |
| 308 | D.Diag(DiagID: diag::warn_target_unsupported_nanlegacy) << CPUName; |
| 309 | } |
| 310 | } else |
| 311 | D.Diag(DiagID: diag::err_drv_unsupported_option_argument) |
| 312 | << A->getSpelling() << Val; |
| 313 | } |
| 314 | |
| 315 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mabs_EQ)) { |
| 316 | StringRef Val = StringRef(A->getValue()); |
| 317 | if (Val == "2008" ) { |
| 318 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Std2008) { |
| 319 | Features.push_back(x: "+abs2008" ); |
| 320 | } else { |
| 321 | Features.push_back(x: "-abs2008" ); |
| 322 | D.Diag(DiagID: diag::warn_target_unsupported_abs2008) << CPUName; |
| 323 | } |
| 324 | } else if (Val == "legacy" ) { |
| 325 | if (mips::getIEEE754Standard(CPU&: CPUName) & mips::Legacy) { |
| 326 | Features.push_back(x: "-abs2008" ); |
| 327 | } else { |
| 328 | Features.push_back(x: "+abs2008" ); |
| 329 | D.Diag(DiagID: diag::warn_target_unsupported_abslegacy) << CPUName; |
| 330 | } |
| 331 | } else { |
| 332 | D.Diag(DiagID: diag::err_drv_unsupported_option_argument) |
| 333 | << A->getSpelling() << Val; |
| 334 | } |
| 335 | } else if (HasNaN2008Opt) { |
| 336 | Features.push_back(x: "+abs2008" ); |
| 337 | } |
| 338 | |
| 339 | AddTargetFeature(Args, Features, OnOpt: options::OPT_msingle_float, |
| 340 | OffOpt: options::OPT_mdouble_float, FeatureName: "single-float" ); |
| 341 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mips16, OffOpt: options::OPT_mno_mips16, |
| 342 | FeatureName: "mips16" ); |
| 343 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmicromips, |
| 344 | OffOpt: options::OPT_mno_micromips, FeatureName: "micromips" ); |
| 345 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mdsp, OffOpt: options::OPT_mno_dsp, |
| 346 | FeatureName: "dsp" ); |
| 347 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mdspr2, OffOpt: options::OPT_mno_dspr2, |
| 348 | FeatureName: "dspr2" ); |
| 349 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmsa, OffOpt: options::OPT_mno_msa, |
| 350 | FeatureName: "msa" ); |
| 351 | if (Arg *A = Args.getLastArg( |
| 352 | Ids: options::OPT_mstrict_align, Ids: options::OPT_mno_strict_align, |
| 353 | Ids: options::OPT_mno_unaligned_access, Ids: options::OPT_munaligned_access)) { |
| 354 | if (A->getOption().matches(ID: options::OPT_mstrict_align) || |
| 355 | A->getOption().matches(ID: options::OPT_mno_unaligned_access)) |
| 356 | Features.push_back(x: Args.MakeArgString(Str: "+strict-align" )); |
| 357 | else |
| 358 | Features.push_back(x: Args.MakeArgString(Str: "-strict-align" )); |
| 359 | } |
| 360 | |
| 361 | // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32 |
| 362 | // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and |
| 363 | // nooddspreg. |
| 364 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mfp32, Ids: options::OPT_mfpxx, |
| 365 | Ids: options::OPT_mfp64)) { |
| 366 | if (A->getOption().matches(ID: options::OPT_mfp32)) |
| 367 | Features.push_back(x: "-fp64" ); |
| 368 | else if (A->getOption().matches(ID: options::OPT_mfpxx)) { |
| 369 | Features.push_back(x: "+fpxx" ); |
| 370 | Features.push_back(x: "+nooddspreg" ); |
| 371 | } else |
| 372 | Features.push_back(x: "+fp64" ); |
| 373 | } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { |
| 374 | Features.push_back(x: "+fpxx" ); |
| 375 | Features.push_back(x: "+nooddspreg" ); |
| 376 | } else if (Arg *A = Args.getLastArg(Ids: options::OPT_mmsa)) { |
| 377 | if (A->getOption().matches(ID: options::OPT_mmsa)) |
| 378 | Features.push_back(x: "+fp64" ); |
| 379 | } |
| 380 | |
| 381 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mno_odd_spreg, |
| 382 | OffOpt: options::OPT_modd_spreg, FeatureName: "nooddspreg" ); |
| 383 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mno_madd4, OffOpt: options::OPT_mmadd4, |
| 384 | FeatureName: "nomadd4" ); |
| 385 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mmt, OffOpt: options::OPT_mno_mt, FeatureName: "mt" ); |
| 386 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mcrc, OffOpt: options::OPT_mno_crc, |
| 387 | FeatureName: "crc" ); |
| 388 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mvirt, OffOpt: options::OPT_mno_virt, |
| 389 | FeatureName: "virt" ); |
| 390 | AddTargetFeature(Args, Features, OnOpt: options::OPT_mginv, OffOpt: options::OPT_mno_ginv, |
| 391 | FeatureName: "ginv" ); |
| 392 | |
| 393 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mindirect_jump_EQ)) { |
| 394 | StringRef Val = StringRef(A->getValue()); |
| 395 | if (Val == "hazard" ) { |
| 396 | Arg *B = |
| 397 | Args.getLastArg(Ids: options::OPT_mmicromips, Ids: options::OPT_mno_micromips); |
| 398 | Arg *C = Args.getLastArg(Ids: options::OPT_mips16, Ids: options::OPT_mno_mips16); |
| 399 | |
| 400 | if (B && B->getOption().matches(ID: options::OPT_mmicromips)) |
| 401 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
| 402 | << "hazard" << "micromips" ; |
| 403 | else if (C && C->getOption().matches(ID: options::OPT_mips16)) |
| 404 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
| 405 | << "hazard" << "mips16" ; |
| 406 | else if (mips::supportsIndirectJumpHazardBarrier(CPU&: CPUName)) |
| 407 | Features.push_back(x: "+use-indirect-jump-hazard" ); |
| 408 | else |
| 409 | D.Diag(DiagID: diag::err_drv_unsupported_indirect_jump_opt) |
| 410 | << "hazard" << CPUName; |
| 411 | } else |
| 412 | D.Diag(DiagID: diag::err_drv_unknown_indirect_jump_opt) << Val; |
| 413 | } |
| 414 | } |
| 415 | |
| 416 | mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { |
| 417 | // Strictly speaking, mips32r2 and mips64r2 do not conform to the |
| 418 | // IEEE754-2008 standard. Support for this standard was first introduced |
| 419 | // in Release 3. However, other compilers have traditionally allowed it |
| 420 | // for Release 2 so we should do the same. |
| 421 | return (IEEE754Standard)llvm::StringSwitch<int>(CPU) |
| 422 | .Case(S: "mips1" , Value: Legacy) |
| 423 | .Case(S: "mips2" , Value: Legacy) |
| 424 | .Case(S: "mips3" , Value: Legacy) |
| 425 | .Case(S: "mips4" , Value: Legacy) |
| 426 | .Case(S: "mips5" , Value: Legacy) |
| 427 | .Case(S: "mips32" , Value: Legacy) |
| 428 | .Case(S: "mips32r2" , Value: Legacy | Std2008) |
| 429 | .Case(S: "mips32r3" , Value: Legacy | Std2008) |
| 430 | .Case(S: "mips32r5" , Value: Legacy | Std2008) |
| 431 | .Case(S: "mips32r6" , Value: Std2008) |
| 432 | .Case(S: "mips64" , Value: Legacy) |
| 433 | .Case(S: "mips64r2" , Value: Legacy | Std2008) |
| 434 | .Case(S: "mips64r3" , Value: Legacy | Std2008) |
| 435 | .Case(S: "mips64r5" , Value: Legacy | Std2008) |
| 436 | .Case(S: "mips64r6" , Value: Std2008) |
| 437 | .Default(Value: Std2008); |
| 438 | } |
| 439 | |
| 440 | bool mips::hasCompactBranches(StringRef &CPU) { |
| 441 | // mips32r6 and mips64r6 have compact branches. |
| 442 | return llvm::StringSwitch<bool>(CPU) |
| 443 | .Case(S: "mips32r6" , Value: true) |
| 444 | .Case(S: "mips64r6" , Value: true) |
| 445 | .Default(Value: false); |
| 446 | } |
| 447 | |
| 448 | bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) { |
| 449 | Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ); |
| 450 | return A && (A->getValue() == StringRef(Value)); |
| 451 | } |
| 452 | |
| 453 | bool mips::isUCLibc(const ArgList &Args) { |
| 454 | Arg *A = Args.getLastArg(Ids: options::OPT_m_libc_Group); |
| 455 | return A && A->getOption().matches(ID: options::OPT_muclibc); |
| 456 | } |
| 457 | |
| 458 | bool mips::isNaN2008(const Driver &D, const ArgList &Args, |
| 459 | const llvm::Triple &Triple) { |
| 460 | if (Arg *NaNArg = Args.getLastArg(Ids: options::OPT_mnan_EQ)) |
| 461 | return llvm::StringSwitch<bool>(NaNArg->getValue()) |
| 462 | .Case(S: "2008" , Value: true) |
| 463 | .Case(S: "legacy" , Value: false) |
| 464 | .Default(Value: false); |
| 465 | |
| 466 | // NaN2008 is the default for MIPS32r6/MIPS64r6. |
| 467 | return llvm::StringSwitch<bool>(getCPUName(D, Args, T: Triple)) |
| 468 | .Cases(S0: "mips32r6" , S1: "mips64r6" , Value: true) |
| 469 | .Default(Value: false); |
| 470 | } |
| 471 | |
| 472 | bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, |
| 473 | StringRef ABIName, mips::FloatABI FloatABI) { |
| 474 | if (ABIName != "32" ) |
| 475 | return false; |
| 476 | |
| 477 | // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is |
| 478 | // present. |
| 479 | if (FloatABI == mips::FloatABI::Soft) |
| 480 | return false; |
| 481 | |
| 482 | return llvm::StringSwitch<bool>(CPUName) |
| 483 | .Cases(S0: "mips2" , S1: "mips3" , S2: "mips4" , S3: "mips5" , Value: true) |
| 484 | .Cases(S0: "mips32" , S1: "mips32r2" , S2: "mips32r3" , S3: "mips32r5" , Value: true) |
| 485 | .Cases(S0: "mips64" , S1: "mips64r2" , S2: "mips64r3" , S3: "mips64r5" , Value: true) |
| 486 | .Default(Value: false); |
| 487 | } |
| 488 | |
| 489 | bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, |
| 490 | StringRef CPUName, StringRef ABIName, |
| 491 | mips::FloatABI FloatABI) { |
| 492 | bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); |
| 493 | |
| 494 | // FPXX shouldn't be used if -msingle-float is present. |
| 495 | if (Arg *A = Args.getLastArg(Ids: options::OPT_msingle_float, |
| 496 | Ids: options::OPT_mdouble_float)) |
| 497 | if (A->getOption().matches(ID: options::OPT_msingle_float)) |
| 498 | UseFPXX = false; |
| 499 | // FP64 should be used for MSA. |
| 500 | if (Arg *A = Args.getLastArg(Ids: options::OPT_mmsa)) |
| 501 | if (A->getOption().matches(ID: options::OPT_mmsa)) |
| 502 | UseFPXX = llvm::StringSwitch<bool>(CPUName) |
| 503 | .Cases(S0: "mips32r2" , S1: "mips32r3" , S2: "mips32r5" , Value: false) |
| 504 | .Cases(S0: "mips64r2" , S1: "mips64r3" , S2: "mips64r5" , Value: false) |
| 505 | .Default(Value: UseFPXX); |
| 506 | |
| 507 | return UseFPXX; |
| 508 | } |
| 509 | |
| 510 | bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) { |
| 511 | // Supporting the hazard barrier method of dealing with indirect |
| 512 | // jumps requires MIPSR2 support. |
| 513 | return llvm::StringSwitch<bool>(CPU) |
| 514 | .Case(S: "mips32r2" , Value: true) |
| 515 | .Case(S: "mips32r3" , Value: true) |
| 516 | .Case(S: "mips32r5" , Value: true) |
| 517 | .Case(S: "mips32r6" , Value: true) |
| 518 | .Case(S: "mips64r2" , Value: true) |
| 519 | .Case(S: "mips64r3" , Value: true) |
| 520 | .Case(S: "mips64r5" , Value: true) |
| 521 | .Case(S: "mips64r6" , Value: true) |
| 522 | .Case(S: "octeon" , Value: true) |
| 523 | .Case(S: "p5600" , Value: true) |
| 524 | .Case(S: "i6400" , Value: true) |
| 525 | .Case(S: "i6500" , Value: true) |
| 526 | .Default(Value: false); |
| 527 | } |
| 528 | |