| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | #include "Mips.h" |
| 10 | #include "ToolChains/CommonArgs.h" |
| 11 | #include "clang/Driver/Driver.h" |
| 12 | #include "clang/Driver/DriverDiagnostic.h" |
| 13 | #include "clang/Driver/Options.h" |
| 14 | #include "llvm/ADT/StringSwitch.h" |
| 15 | #include "llvm/Option/ArgList.h" |
| 16 | |
| 17 | using namespace clang::driver; |
| 18 | using namespace clang::driver::tools; |
| 19 | using namespace clang; |
| 20 | using namespace llvm::opt; |
| 21 | |
| 22 | |
| 23 | |
| 24 | void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, |
| 25 | StringRef &CPUName, StringRef &ABIName) { |
| 26 | const char *DefMips32CPU = "mips32r2"; |
| 27 | const char *DefMips64CPU = "mips64r2"; |
| 28 | |
| 29 | |
| 30 | |
| 31 | if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && |
| 32 | Triple.isGNUEnvironment()) { |
| 33 | DefMips32CPU = "mips32r6"; |
| 34 | DefMips64CPU = "mips64r6"; |
| 35 | } |
| 36 | |
| 37 | if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) { |
| 38 | DefMips32CPU = "mips32r6"; |
| 39 | DefMips64CPU = "mips64r6"; |
| 40 | } |
| 41 | |
| 42 | |
| 43 | if (Triple.isAndroid()) { |
| 44 | DefMips32CPU = "mips32"; |
| 45 | DefMips64CPU = "mips64r6"; |
| 46 | } |
| 47 | |
| 48 | |
| 49 | if (Triple.isOSOpenBSD()) |
| 50 | DefMips64CPU = "mips3"; |
| 51 | |
| 52 | |
| 53 | |
| 54 | if (Triple.isOSFreeBSD()) { |
| 55 | DefMips32CPU = "mips2"; |
| 56 | DefMips64CPU = "mips3"; |
| 57 | } |
| 58 | |
| 59 | if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ, |
| 60 | options::OPT_mcpu_EQ)) |
| 61 | CPUName = A->getValue(); |
| 62 | |
| 63 | if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { |
| 64 | ABIName = A->getValue(); |
| 65 | |
| 66 | |
| 67 | ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) |
| 68 | .Case("32", "o32") |
| 69 | .Case("64", "n64") |
| 70 | .Default(ABIName); |
| 71 | } |
| 72 | |
| 73 | |
| 74 | if (CPUName.empty() && ABIName.empty()) { |
| 75 | switch (Triple.getArch()) { |
| 76 | default: |
| 77 | llvm_unreachable("Unexpected triple arch name"); |
| 78 | case llvm::Triple::mips: |
| 79 | case llvm::Triple::mipsel: |
| 80 | CPUName = DefMips32CPU; |
| 81 | break; |
| 82 | case llvm::Triple::mips64: |
| 83 | case llvm::Triple::mips64el: |
| 84 | CPUName = DefMips64CPU; |
| 85 | break; |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | if (ABIName.empty() && (Triple.getEnvironment() == llvm::Triple::GNUABIN32)) |
| 90 | ABIName = "n32"; |
| 91 | |
| 92 | if (ABIName.empty() && |
| 93 | (Triple.getVendor() == llvm::Triple::MipsTechnologies || |
| 94 | Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) { |
| 95 | ABIName = llvm::StringSwitch<const char *>(CPUName) |
| 96 | .Case("mips1", "o32") |
| 97 | .Case("mips2", "o32") |
| 98 | .Case("mips3", "n64") |
| 99 | .Case("mips4", "n64") |
| 100 | .Case("mips5", "n64") |
| 101 | .Case("mips32", "o32") |
| 102 | .Case("mips32r2", "o32") |
| 103 | .Case("mips32r3", "o32") |
| 104 | .Case("mips32r5", "o32") |
| 105 | .Case("mips32r6", "o32") |
| 106 | .Case("mips64", "n64") |
| 107 | .Case("mips64r2", "n64") |
| 108 | .Case("mips64r3", "n64") |
| 109 | .Case("mips64r5", "n64") |
| 110 | .Case("mips64r6", "n64") |
| 111 | .Case("octeon", "n64") |
| 112 | .Case("p5600", "o32") |
| 113 | .Default(""); |
| 114 | } |
| 115 | |
| 116 | if (ABIName.empty()) { |
| 117 | |
| 118 | ABIName = Triple.isMIPS32() ? "o32" : "n64"; |
| 119 | } |
| 120 | |
| 121 | if (CPUName.empty()) { |
| 122 | |
| 123 | CPUName = llvm::StringSwitch<const char *>(ABIName) |
| 124 | .Case("o32", DefMips32CPU) |
| 125 | .Cases("n32", "n64", DefMips64CPU) |
| 126 | .Default(""); |
| 127 | } |
| 128 | |
| 129 | |
| 130 | } |
| 131 | |
| 132 | std::string mips::getMipsABILibSuffix(const ArgList &Args, |
| 133 | const llvm::Triple &Triple) { |
| 134 | StringRef CPUName, ABIName; |
| 135 | tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
| 136 | return llvm::StringSwitch<std::string>(ABIName) |
| 137 | .Case("o32", "") |
| 138 | .Case("n32", "32") |
| 139 | .Case("n64", "64"); |
| 140 | } |
| 141 | |
| 142 | |
| 143 | StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) { |
| 144 | return llvm::StringSwitch<llvm::StringRef>(ABI) |
| 145 | .Case("o32", "32") |
| 146 | .Case("n64", "64") |
| 147 | .Default(ABI); |
| 148 | } |
| 149 | |
| 150 | |
| 151 | |
| 152 | mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args) { |
| 153 | mips::FloatABI ABI = mips::FloatABI::Invalid; |
| 154 | if (Arg *A = |
| 155 | Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, |
| 156 | options::OPT_mfloat_abi_EQ)) { |
| 157 | if (A->getOption().matches(options::OPT_msoft_float)) |
| 158 | ABI = mips::FloatABI::Soft; |
| 159 | else if (A->getOption().matches(options::OPT_mhard_float)) |
| 160 | ABI = mips::FloatABI::Hard; |
| 161 | else { |
| 162 | ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue()) |
| 163 | .Case("soft", mips::FloatABI::Soft) |
| 164 | .Case("hard", mips::FloatABI::Hard) |
| 165 | .Default(mips::FloatABI::Invalid); |
| 166 | if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
| 167 | D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
| 168 | ABI = mips::FloatABI::Hard; |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | |
| 174 | if (ABI == mips::FloatABI::Invalid) { |
| 175 | |
| 176 | |
| 177 | |
| 178 | ABI = mips::FloatABI::Hard; |
| 179 | } |
| 180 | |
| 181 | (0) . __assert_fail ("ABI != mips..FloatABI..Invalid && \"must select an ABI\"", "/home/seafit/code_projects/clang_source/clang/lib/Driver/ToolChains/Arch/Mips.cpp", 181, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(ABI != mips::FloatABI::Invalid && "must select an ABI"); |
| 182 | return ABI; |
| 183 | } |
| 184 | |
| 185 | void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
| 186 | const ArgList &Args, |
| 187 | std::vector<StringRef> &Features) { |
| 188 | StringRef CPUName; |
| 189 | StringRef ABIName; |
| 190 | getMipsCPUAndABI(Args, Triple, CPUName, ABIName); |
| 191 | ABIName = getGnuCompatibleMipsABIName(ABIName); |
| 192 | |
| 193 | |
| 194 | |
| 195 | |
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | |
| 205 | |
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | |
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | bool IsN64 = ABIName == "64"; |
| 222 | bool IsPIC = false; |
| 223 | bool NonPIC = false; |
| 224 | |
| 225 | Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, |
| 226 | options::OPT_fpic, options::OPT_fno_pic, |
| 227 | options::OPT_fPIE, options::OPT_fno_PIE, |
| 228 | options::OPT_fpie, options::OPT_fno_pie); |
| 229 | if (LastPICArg) { |
| 230 | Option O = LastPICArg->getOption(); |
| 231 | NonPIC = |
| 232 | (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) || |
| 233 | O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); |
| 234 | IsPIC = |
| 235 | (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || |
| 236 | O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)); |
| 237 | } |
| 238 | |
| 239 | bool UseAbiCalls = false; |
| 240 | |
| 241 | Arg *ABICallsArg = |
| 242 | Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); |
| 243 | UseAbiCalls = |
| 244 | !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls); |
| 245 | |
| 246 | if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) { |
| 247 | D.Diag(diag::warn_drv_unsupported_pic_with_mabicalls) |
| 248 | << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1); |
| 249 | NonPIC = false; |
| 250 | } |
| 251 | |
| 252 | if (ABICallsArg && !UseAbiCalls && IsPIC) { |
| 253 | D.Diag(diag::err_drv_unsupported_noabicalls_pic); |
| 254 | } |
| 255 | |
| 256 | if (!UseAbiCalls) |
| 257 | Features.push_back("+noabicalls"); |
| 258 | else |
| 259 | Features.push_back("-noabicalls"); |
| 260 | |
| 261 | if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, |
| 262 | options::OPT_mno_long_calls)) { |
| 263 | if (A->getOption().matches(options::OPT_mno_long_calls)) |
| 264 | Features.push_back("-long-calls"); |
| 265 | else if (!UseAbiCalls) |
| 266 | Features.push_back("+long-calls"); |
| 267 | else |
| 268 | D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); |
| 269 | } |
| 270 | |
| 271 | mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args); |
| 272 | if (FloatABI == mips::FloatABI::Soft) { |
| 273 | |
| 274 | |
| 275 | |
| 276 | Features.push_back("+soft-float"); |
| 277 | } |
| 278 | |
| 279 | if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { |
| 280 | StringRef Val = StringRef(A->getValue()); |
| 281 | if (Val == "2008") { |
| 282 | if (mips::getIEEE754Standard(CPUName) & mips::Std2008) |
| 283 | Features.push_back("+nan2008"); |
| 284 | else { |
| 285 | Features.push_back("-nan2008"); |
| 286 | D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; |
| 287 | } |
| 288 | } else if (Val == "legacy") { |
| 289 | if (mips::getIEEE754Standard(CPUName) & mips::Legacy) |
| 290 | Features.push_back("-nan2008"); |
| 291 | else { |
| 292 | Features.push_back("+nan2008"); |
| 293 | D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName; |
| 294 | } |
| 295 | } else |
| 296 | D.Diag(diag::err_drv_unsupported_option_argument) |
| 297 | << A->getOption().getName() << Val; |
| 298 | } |
| 299 | |
| 300 | if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { |
| 301 | StringRef Val = StringRef(A->getValue()); |
| 302 | if (Val == "2008") { |
| 303 | if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { |
| 304 | Features.push_back("+abs2008"); |
| 305 | } else { |
| 306 | Features.push_back("-abs2008"); |
| 307 | D.Diag(diag::warn_target_unsupported_abs2008) << CPUName; |
| 308 | } |
| 309 | } else if (Val == "legacy") { |
| 310 | if (mips::getIEEE754Standard(CPUName) & mips::Legacy) { |
| 311 | Features.push_back("-abs2008"); |
| 312 | } else { |
| 313 | Features.push_back("+abs2008"); |
| 314 | D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName; |
| 315 | } |
| 316 | } else { |
| 317 | D.Diag(diag::err_drv_unsupported_option_argument) |
| 318 | << A->getOption().getName() << Val; |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | AddTargetFeature(Args, Features, options::OPT_msingle_float, |
| 323 | options::OPT_mdouble_float, "single-float"); |
| 324 | AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, |
| 325 | "mips16"); |
| 326 | AddTargetFeature(Args, Features, options::OPT_mmicromips, |
| 327 | options::OPT_mno_micromips, "micromips"); |
| 328 | AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp, |
| 329 | "dsp"); |
| 330 | AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2, |
| 331 | "dspr2"); |
| 332 | AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa, |
| 333 | "msa"); |
| 334 | |
| 335 | |
| 336 | |
| 337 | |
| 338 | if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, |
| 339 | options::OPT_mfp64)) { |
| 340 | if (A->getOption().matches(options::OPT_mfp32)) |
| 341 | Features.push_back("-fp64"); |
| 342 | else if (A->getOption().matches(options::OPT_mfpxx)) { |
| 343 | Features.push_back("+fpxx"); |
| 344 | Features.push_back("+nooddspreg"); |
| 345 | } else |
| 346 | Features.push_back("+fp64"); |
| 347 | } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { |
| 348 | Features.push_back("+fpxx"); |
| 349 | Features.push_back("+nooddspreg"); |
| 350 | } else if (mips::isFP64ADefault(Triple, CPUName)) { |
| 351 | Features.push_back("+fp64"); |
| 352 | Features.push_back("+nooddspreg"); |
| 353 | } |
| 354 | |
| 355 | AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, |
| 356 | options::OPT_modd_spreg, "nooddspreg"); |
| 357 | AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, |
| 358 | "nomadd4"); |
| 359 | AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt"); |
| 360 | AddTargetFeature(Args, Features, options::OPT_mcrc, options::OPT_mno_crc, |
| 361 | "crc"); |
| 362 | AddTargetFeature(Args, Features, options::OPT_mvirt, options::OPT_mno_virt, |
| 363 | "virt"); |
| 364 | AddTargetFeature(Args, Features, options::OPT_mginv, options::OPT_mno_ginv, |
| 365 | "ginv"); |
| 366 | |
| 367 | if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) { |
| 368 | StringRef Val = StringRef(A->getValue()); |
| 369 | if (Val == "hazard") { |
| 370 | Arg *B = |
| 371 | Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); |
| 372 | Arg *C = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); |
| 373 | |
| 374 | if (B && B->getOption().matches(options::OPT_mmicromips)) |
| 375 | D.Diag(diag::err_drv_unsupported_indirect_jump_opt) |
| 376 | << "hazard" << "micromips"; |
| 377 | else if (C && C->getOption().matches(options::OPT_mips16)) |
| 378 | D.Diag(diag::err_drv_unsupported_indirect_jump_opt) |
| 379 | << "hazard" << "mips16"; |
| 380 | else if (mips::supportsIndirectJumpHazardBarrier(CPUName)) |
| 381 | Features.push_back("+use-indirect-jump-hazard"); |
| 382 | else |
| 383 | D.Diag(diag::err_drv_unsupported_indirect_jump_opt) |
| 384 | << "hazard" << CPUName; |
| 385 | } else |
| 386 | D.Diag(diag::err_drv_unknown_indirect_jump_opt) << Val; |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { |
| 391 | |
| 392 | |
| 393 | |
| 394 | |
| 395 | return (IEEE754Standard)llvm::StringSwitch<int>(CPU) |
| 396 | .Case("mips1", Legacy) |
| 397 | .Case("mips2", Legacy) |
| 398 | .Case("mips3", Legacy) |
| 399 | .Case("mips4", Legacy) |
| 400 | .Case("mips5", Legacy) |
| 401 | .Case("mips32", Legacy) |
| 402 | .Case("mips32r2", Legacy | Std2008) |
| 403 | .Case("mips32r3", Legacy | Std2008) |
| 404 | .Case("mips32r5", Legacy | Std2008) |
| 405 | .Case("mips32r6", Std2008) |
| 406 | .Case("mips64", Legacy) |
| 407 | .Case("mips64r2", Legacy | Std2008) |
| 408 | .Case("mips64r3", Legacy | Std2008) |
| 409 | .Case("mips64r5", Legacy | Std2008) |
| 410 | .Case("mips64r6", Std2008) |
| 411 | .Default(Std2008); |
| 412 | } |
| 413 | |
| 414 | bool mips::hasCompactBranches(StringRef &CPU) { |
| 415 | |
| 416 | return llvm::StringSwitch<bool>(CPU) |
| 417 | .Case("mips32r6", true) |
| 418 | .Case("mips64r6", true) |
| 419 | .Default(false); |
| 420 | } |
| 421 | |
| 422 | bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) { |
| 423 | Arg *A = Args.getLastArg(options::OPT_mabi_EQ); |
| 424 | return A && (A->getValue() == StringRef(Value)); |
| 425 | } |
| 426 | |
| 427 | bool mips::isUCLibc(const ArgList &Args) { |
| 428 | Arg *A = Args.getLastArg(options::OPT_m_libc_Group); |
| 429 | return A && A->getOption().matches(options::OPT_muclibc); |
| 430 | } |
| 431 | |
| 432 | bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { |
| 433 | if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ)) |
| 434 | return llvm::StringSwitch<bool>(NaNArg->getValue()) |
| 435 | .Case("2008", true) |
| 436 | .Case("legacy", false) |
| 437 | .Default(false); |
| 438 | |
| 439 | |
| 440 | return llvm::StringSwitch<bool>(getCPUName(Args, Triple)) |
| 441 | .Cases("mips32r6", "mips64r6", true) |
| 442 | .Default(false); |
| 443 | |
| 444 | return false; |
| 445 | } |
| 446 | |
| 447 | bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { |
| 448 | if (!Triple.isAndroid()) |
| 449 | return false; |
| 450 | |
| 451 | |
| 452 | return llvm::StringSwitch<bool>(CPUName) |
| 453 | .Case("mips32r6", true) |
| 454 | .Default(false); |
| 455 | } |
| 456 | |
| 457 | bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, |
| 458 | StringRef ABIName, mips::FloatABI FloatABI) { |
| 459 | if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && |
| 460 | Triple.getVendor() != llvm::Triple::MipsTechnologies && |
| 461 | !Triple.isAndroid()) |
| 462 | return false; |
| 463 | |
| 464 | if (ABIName != "32") |
| 465 | return false; |
| 466 | |
| 467 | |
| 468 | |
| 469 | if (FloatABI == mips::FloatABI::Soft) |
| 470 | return false; |
| 471 | |
| 472 | return llvm::StringSwitch<bool>(CPUName) |
| 473 | .Cases("mips2", "mips3", "mips4", "mips5", true) |
| 474 | .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true) |
| 475 | .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true) |
| 476 | .Default(false); |
| 477 | } |
| 478 | |
| 479 | bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple, |
| 480 | StringRef CPUName, StringRef ABIName, |
| 481 | mips::FloatABI FloatABI) { |
| 482 | bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI); |
| 483 | |
| 484 | |
| 485 | if (Arg *A = Args.getLastArg(options::OPT_msingle_float, |
| 486 | options::OPT_mdouble_float)) |
| 487 | if (A->getOption().matches(options::OPT_msingle_float)) |
| 488 | UseFPXX = false; |
| 489 | |
| 490 | return UseFPXX; |
| 491 | } |
| 492 | |
| 493 | bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) { |
| 494 | |
| 495 | |
| 496 | return llvm::StringSwitch<bool>(CPU) |
| 497 | .Case("mips32r2", true) |
| 498 | .Case("mips32r3", true) |
| 499 | .Case("mips32r5", true) |
| 500 | .Case("mips32r6", true) |
| 501 | .Case("mips64r2", true) |
| 502 | .Case("mips64r3", true) |
| 503 | .Case("mips64r5", true) |
| 504 | .Case("mips64r6", true) |
| 505 | .Case("octeon", true) |
| 506 | .Case("p5600", true) |
| 507 | .Default(false); |
| 508 | } |
| 509 | |