1 //===-- Flang.cpp - Flang+LLVM ToolChain 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 "Flang.h" 10 #include "Arch/RISCV.h" 11 #include "CommonArgs.h" 12 13 #include "clang/Basic/CodeGenOptions.h" 14 #include "clang/Driver/Options.h" 15 #include "llvm/Frontend/Debug/Options.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/TargetParser/Host.h" 19 #include "llvm/TargetParser/RISCVISAInfo.h" 20 #include "llvm/TargetParser/RISCVTargetParser.h" 21 22 #include <cassert> 23 24 using namespace clang::driver; 25 using namespace clang::driver::tools; 26 using namespace clang; 27 using namespace llvm::opt; 28 29 /// Add -x lang to \p CmdArgs for \p Input. 30 static void addDashXForInput(const ArgList &Args, const InputInfo &Input, 31 ArgStringList &CmdArgs) { 32 CmdArgs.push_back("-x"); 33 // Map the driver type to the frontend type. 34 CmdArgs.push_back(types::getTypeName(Input.getType())); 35 } 36 37 void Flang::addFortranDialectOptions(const ArgList &Args, 38 ArgStringList &CmdArgs) const { 39 Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, 40 options::OPT_ffree_form, 41 options::OPT_ffixed_line_length_EQ, 42 options::OPT_fopenacc, 43 options::OPT_finput_charset_EQ, 44 options::OPT_fimplicit_none, 45 options::OPT_fno_implicit_none, 46 options::OPT_fbackslash, 47 options::OPT_fno_backslash, 48 options::OPT_flogical_abbreviations, 49 options::OPT_fno_logical_abbreviations, 50 options::OPT_fxor_operator, 51 options::OPT_fno_xor_operator, 52 options::OPT_falternative_parameter_statement, 53 options::OPT_fdefault_real_8, 54 options::OPT_fdefault_integer_8, 55 options::OPT_fdefault_double_8, 56 options::OPT_flarge_sizes, 57 options::OPT_fno_automatic, 58 options::OPT_fhermetic_module_files, 59 options::OPT_frealloc_lhs, 60 options::OPT_fno_realloc_lhs, 61 options::OPT_fsave_main_program, 62 options::OPT_fno_save_main_program}); 63 } 64 65 void Flang::addPreprocessingOptions(const ArgList &Args, 66 ArgStringList &CmdArgs) const { 67 Args.addAllArgs(CmdArgs, 68 {options::OPT_P, options::OPT_D, options::OPT_U, 69 options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); 70 } 71 72 /// @C shouldLoopVersion 73 /// 74 /// Check if Loop Versioning should be enabled. 75 /// We look for the last of one of the following: 76 /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. 77 /// Loop versioning is disabled if the last option is 78 /// -fno-version-loops-for-stride. 79 /// Loop versioning is enabled if the last option is one of: 80 /// -floop-versioning 81 /// -Ofast 82 /// -O4 83 /// -O3 84 /// For all other cases, loop versioning is is disabled. 85 /// 86 /// The gfortran compiler automatically enables the option for -O3 or -Ofast. 87 /// 88 /// @return true if loop-versioning should be enabled, otherwise false. 89 static bool shouldLoopVersion(const ArgList &Args) { 90 const Arg *LoopVersioningArg = Args.getLastArg( 91 options::OPT_Ofast, options::OPT_O, options::OPT_O4, 92 options::OPT_floop_versioning, options::OPT_fno_loop_versioning); 93 if (!LoopVersioningArg) 94 return false; 95 96 if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) 97 return false; 98 99 if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) 100 return true; 101 102 if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || 103 LoopVersioningArg->getOption().matches(options::OPT_O4)) 104 return true; 105 106 if (LoopVersioningArg->getOption().matches(options::OPT_O)) { 107 StringRef S(LoopVersioningArg->getValue()); 108 unsigned OptLevel = 0; 109 // Note -Os or Oz woould "fail" here, so return false. Which is the 110 // desiered behavior. 111 if (S.getAsInteger(10, OptLevel)) 112 return false; 113 114 return OptLevel > 2; 115 } 116 117 llvm_unreachable("We should not end up here"); 118 return false; 119 } 120 121 void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 122 Args.addAllArgs(CmdArgs, 123 {options::OPT_module_dir, options::OPT_fdebug_module_writer, 124 options::OPT_fintrinsic_modules_path, options::OPT_pedantic, 125 options::OPT_std_EQ, options::OPT_W_Joined, 126 options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, 127 options::OPT_funderscoring, options::OPT_fno_underscoring, 128 options::OPT_funsigned, options::OPT_fno_unsigned}); 129 130 llvm::codegenoptions::DebugInfoKind DebugInfoKind; 131 if (Args.hasArg(options::OPT_gN_Group)) { 132 Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); 133 DebugInfoKind = debugLevelToInfoKind(*gNArg); 134 } else if (Args.hasArg(options::OPT_g_Flag)) { 135 DebugInfoKind = llvm::codegenoptions::FullDebugInfo; 136 } else { 137 DebugInfoKind = llvm::codegenoptions::NoDebugInfo; 138 } 139 addDebugInfoKind(CmdArgs, DebugInfoKind); 140 } 141 142 void Flang::addCodegenOptions(const ArgList &Args, 143 ArgStringList &CmdArgs) const { 144 Arg *stackArrays = 145 Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, 146 options::OPT_fno_stack_arrays); 147 if (stackArrays && 148 !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) 149 CmdArgs.push_back("-fstack-arrays"); 150 151 if (shouldLoopVersion(Args)) 152 CmdArgs.push_back("-fversion-loops-for-stride"); 153 154 Args.addAllArgs(CmdArgs, 155 {options::OPT_flang_experimental_hlfir, 156 options::OPT_flang_deprecated_no_hlfir, 157 options::OPT_fno_ppc_native_vec_elem_order, 158 options::OPT_fppc_native_vec_elem_order, 159 options::OPT_finit_global_zero, 160 options::OPT_fno_init_global_zero, options::OPT_ftime_report, 161 options::OPT_ftime_report_EQ, options::OPT_funroll_loops, 162 options::OPT_fno_unroll_loops}); 163 } 164 165 void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 166 // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of 167 // (RelocationModel, PICLevel, IsPIE). 168 llvm::Reloc::Model RelocationModel; 169 unsigned PICLevel; 170 bool IsPIE; 171 std::tie(RelocationModel, PICLevel, IsPIE) = 172 ParsePICArgs(getToolChain(), Args); 173 174 if (auto *RMName = RelocationModelName(RelocationModel)) { 175 CmdArgs.push_back("-mrelocation-model"); 176 CmdArgs.push_back(RMName); 177 } 178 if (PICLevel > 0) { 179 CmdArgs.push_back("-pic-level"); 180 CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); 181 if (IsPIE) 182 CmdArgs.push_back("-pic-is-pie"); 183 } 184 } 185 186 void Flang::AddAArch64TargetArgs(const ArgList &Args, 187 ArgStringList &CmdArgs) const { 188 // Handle -msve_vector_bits=<bits> 189 if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { 190 StringRef Val = A->getValue(); 191 const Driver &D = getToolChain().getDriver(); 192 if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" || 193 Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" || 194 Val == "1024+" || Val == "2048+") { 195 unsigned Bits = 0; 196 if (!Val.consume_back("+")) { 197 [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 198 assert(!Invalid && "Failed to parse value"); 199 CmdArgs.push_back( 200 Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); 201 } 202 203 [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 204 assert(!Invalid && "Failed to parse value"); 205 CmdArgs.push_back( 206 Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); 207 // Silently drop requests for vector-length agnostic code as it's implied. 208 } else if (Val != "scalable") 209 // Handle the unsupported values passed to msve-vector-bits. 210 D.Diag(diag::err_drv_unsupported_option_argument) 211 << A->getSpelling() << Val; 212 } 213 } 214 215 void Flang::AddLoongArch64TargetArgs(const ArgList &Args, 216 ArgStringList &CmdArgs) const { 217 const Driver &D = getToolChain().getDriver(); 218 // Currently, flang only support `-mabi=lp64d` in LoongArch64. 219 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { 220 StringRef V = A->getValue(); 221 if (V != "lp64d") { 222 D.Diag(diag::err_drv_argument_not_allowed_with) << "-mabi" << V; 223 } 224 } 225 226 if (const Arg *A = Args.getLastArg(options::OPT_mannotate_tablejump, 227 options::OPT_mno_annotate_tablejump)) { 228 if (A->getOption().matches(options::OPT_mannotate_tablejump)) { 229 CmdArgs.push_back("-mllvm"); 230 CmdArgs.push_back("-loongarch-annotate-tablejump"); 231 } 232 } 233 } 234 235 void Flang::AddPPCTargetArgs(const ArgList &Args, 236 ArgStringList &CmdArgs) const { 237 const Driver &D = getToolChain().getDriver(); 238 bool VecExtabi = false; 239 240 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { 241 StringRef V = A->getValue(); 242 if (V == "vec-extabi") 243 VecExtabi = true; 244 else if (V == "vec-default") 245 VecExtabi = false; 246 else 247 D.Diag(diag::err_drv_unsupported_option_argument) 248 << A->getSpelling() << V; 249 } 250 251 const llvm::Triple &T = getToolChain().getTriple(); 252 if (VecExtabi) { 253 if (!T.isOSAIX()) { 254 D.Diag(diag::err_drv_unsupported_opt_for_target) 255 << "-mabi=vec-extabi" << T.str(); 256 } 257 CmdArgs.push_back("-mabi=vec-extabi"); 258 } 259 } 260 261 void Flang::AddRISCVTargetArgs(const ArgList &Args, 262 ArgStringList &CmdArgs) const { 263 const llvm::Triple &Triple = getToolChain().getTriple(); 264 // Handle -mrvv-vector-bits=<bits> 265 if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { 266 StringRef Val = A->getValue(); 267 const Driver &D = getToolChain().getDriver(); 268 269 // Get minimum VLen from march. 270 unsigned MinVLen = 0; 271 std::string Arch = riscv::getRISCVArch(Args, Triple); 272 auto ISAInfo = llvm::RISCVISAInfo::parseArchString( 273 Arch, /*EnableExperimentalExtensions*/ true); 274 // Ignore parsing error. 275 if (!errorToBool(ISAInfo.takeError())) 276 MinVLen = (*ISAInfo)->getMinVLen(); 277 278 // If the value is "zvl", use MinVLen from march. Otherwise, try to parse 279 // as integer as long as we have a MinVLen. 280 unsigned Bits = 0; 281 if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { 282 Bits = MinVLen; 283 } else if (!Val.getAsInteger(10, Bits)) { 284 // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that 285 // at least MinVLen. 286 if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || 287 Bits > 65536 || !llvm::isPowerOf2_32(Bits)) 288 Bits = 0; 289 } 290 291 // If we got a valid value try to use it. 292 if (Bits != 0) { 293 unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; 294 CmdArgs.push_back( 295 Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); 296 CmdArgs.push_back( 297 Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); 298 } else if (Val != "scalable") { 299 // Handle the unsupported values passed to mrvv-vector-bits. 300 D.Diag(diag::err_drv_unsupported_option_argument) 301 << A->getSpelling() << Val; 302 } 303 } 304 } 305 306 void Flang::AddX86_64TargetArgs(const ArgList &Args, 307 ArgStringList &CmdArgs) const { 308 if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { 309 StringRef Value = A->getValue(); 310 if (Value == "intel" || Value == "att") { 311 CmdArgs.push_back(Args.MakeArgString("-mllvm")); 312 CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); 313 } else { 314 getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) 315 << A->getSpelling() << Value; 316 } 317 } 318 } 319 320 static void addVSDefines(const ToolChain &TC, const ArgList &Args, 321 ArgStringList &CmdArgs) { 322 323 unsigned ver = 0; 324 const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); 325 ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + 326 vt.getSubminor().value_or(0); 327 CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); 328 CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); 329 CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); 330 331 const llvm::Triple &triple = TC.getTriple(); 332 if (triple.isAArch64()) { 333 CmdArgs.push_back("-D_M_ARM64=1"); 334 } else if (triple.isX86() && triple.isArch32Bit()) { 335 CmdArgs.push_back("-D_M_IX86=600"); 336 } else if (triple.isX86() && triple.isArch64Bit()) { 337 CmdArgs.push_back("-D_M_X64=100"); 338 } else { 339 llvm_unreachable( 340 "Flang on Windows only supports X86_32, X86_64 and AArch64"); 341 } 342 } 343 344 static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, 345 ArgStringList &CmdArgs) { 346 assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && 347 "can only add VS runtime library on Windows!"); 348 // if -fno-fortran-main has been passed, skip linking Fortran_main.a 349 if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { 350 CmdArgs.push_back(Args.MakeArgString( 351 "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); 352 } 353 unsigned RTOptionID = options::OPT__SLASH_MT; 354 if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { 355 RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) 356 .Case("static", options::OPT__SLASH_MT) 357 .Case("static_dbg", options::OPT__SLASH_MTd) 358 .Case("dll", options::OPT__SLASH_MD) 359 .Case("dll_dbg", options::OPT__SLASH_MDd) 360 .Default(options::OPT__SLASH_MT); 361 } 362 switch (RTOptionID) { 363 case options::OPT__SLASH_MT: 364 CmdArgs.push_back("-D_MT"); 365 CmdArgs.push_back("--dependent-lib=libcmt"); 366 CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); 367 CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); 368 break; 369 case options::OPT__SLASH_MTd: 370 CmdArgs.push_back("-D_MT"); 371 CmdArgs.push_back("-D_DEBUG"); 372 CmdArgs.push_back("--dependent-lib=libcmtd"); 373 CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); 374 CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); 375 break; 376 case options::OPT__SLASH_MD: 377 CmdArgs.push_back("-D_MT"); 378 CmdArgs.push_back("-D_DLL"); 379 CmdArgs.push_back("--dependent-lib=msvcrt"); 380 CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); 381 CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); 382 break; 383 case options::OPT__SLASH_MDd: 384 CmdArgs.push_back("-D_MT"); 385 CmdArgs.push_back("-D_DEBUG"); 386 CmdArgs.push_back("-D_DLL"); 387 CmdArgs.push_back("--dependent-lib=msvcrtd"); 388 CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); 389 CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); 390 break; 391 } 392 } 393 394 void Flang::AddAMDGPUTargetArgs(const ArgList &Args, 395 ArgStringList &CmdArgs) const { 396 if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { 397 StringRef Val = A->getValue(); 398 CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); 399 } 400 401 const ToolChain &TC = getToolChain(); 402 TC.addClangTargetOptions(Args, CmdArgs, Action::OffloadKind::OFK_OpenMP); 403 } 404 405 void Flang::addTargetOptions(const ArgList &Args, 406 ArgStringList &CmdArgs) const { 407 const ToolChain &TC = getToolChain(); 408 const llvm::Triple &Triple = TC.getEffectiveTriple(); 409 const Driver &D = TC.getDriver(); 410 411 std::string CPU = getCPUName(D, Args, Triple); 412 if (!CPU.empty()) { 413 CmdArgs.push_back("-target-cpu"); 414 CmdArgs.push_back(Args.MakeArgString(CPU)); 415 } 416 417 addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple); 418 419 // Add the target features. 420 switch (TC.getArch()) { 421 default: 422 break; 423 case llvm::Triple::aarch64: 424 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 425 AddAArch64TargetArgs(Args, CmdArgs); 426 break; 427 428 case llvm::Triple::r600: 429 case llvm::Triple::amdgcn: 430 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 431 AddAMDGPUTargetArgs(Args, CmdArgs); 432 break; 433 case llvm::Triple::riscv64: 434 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 435 AddRISCVTargetArgs(Args, CmdArgs); 436 break; 437 case llvm::Triple::x86_64: 438 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 439 AddX86_64TargetArgs(Args, CmdArgs); 440 break; 441 case llvm::Triple::ppc: 442 case llvm::Triple::ppc64: 443 case llvm::Triple::ppc64le: 444 AddPPCTargetArgs(Args, CmdArgs); 445 break; 446 case llvm::Triple::loongarch64: 447 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 448 AddLoongArch64TargetArgs(Args, CmdArgs); 449 break; 450 } 451 452 if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { 453 StringRef Name = A->getValue(); 454 if (Name == "SVML") { 455 if (Triple.getArch() != llvm::Triple::x86 && 456 Triple.getArch() != llvm::Triple::x86_64) 457 D.Diag(diag::err_drv_unsupported_opt_for_target) 458 << Name << Triple.getArchName(); 459 } else if (Name == "LIBMVEC-X86") { 460 if (Triple.getArch() != llvm::Triple::x86 && 461 Triple.getArch() != llvm::Triple::x86_64) 462 D.Diag(diag::err_drv_unsupported_opt_for_target) 463 << Name << Triple.getArchName(); 464 } else if (Name == "SLEEF" || Name == "ArmPL") { 465 if (Triple.getArch() != llvm::Triple::aarch64 && 466 Triple.getArch() != llvm::Triple::aarch64_be) 467 D.Diag(diag::err_drv_unsupported_opt_for_target) 468 << Name << Triple.getArchName(); 469 } 470 471 if (Triple.isOSDarwin()) { 472 // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these 473 // here incase they are added someday 474 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 475 if (A->getValue() == StringRef{"Accelerate"}) { 476 CmdArgs.push_back("-framework"); 477 CmdArgs.push_back("Accelerate"); 478 } 479 } 480 } 481 A->render(Args, CmdArgs); 482 } 483 484 if (Triple.isKnownWindowsMSVCEnvironment()) { 485 processVSRuntimeLibrary(TC, Args, CmdArgs); 486 addVSDefines(TC, Args, CmdArgs); 487 } 488 489 // TODO: Add target specific flags, ABI, mtune option etc. 490 if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { 491 CmdArgs.push_back("-tune-cpu"); 492 if (A->getValue() == StringRef{"native"}) 493 CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); 494 else 495 CmdArgs.push_back(A->getValue()); 496 } 497 } 498 499 void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, 500 const JobAction &JA, const ArgList &Args, 501 ArgStringList &CmdArgs) const { 502 bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); 503 bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || 504 JA.isHostOffloading(C.getActiveOffloadKinds()); 505 506 // Skips the primary input file, which is the input file that the compilation 507 // proccess will be executed upon (e.g. the host bitcode file) and 508 // adds other secondary input (e.g. device bitcode files for embedding to the 509 // -fembed-offload-object argument or the host IR file for proccessing 510 // during device compilation to the fopenmp-host-ir-file-path argument via 511 // OpenMPDeviceInput). This is condensed logic from the ConstructJob 512 // function inside of the Clang driver for pushing on further input arguments 513 // needed for offloading during various phases of compilation. 514 for (size_t i = 1; i < Inputs.size(); ++i) { 515 if (Inputs[i].getType() == types::TY_Nothing) { 516 // contains nothing, so it's skippable 517 } else if (IsHostOffloadingAction) { 518 CmdArgs.push_back( 519 Args.MakeArgString("-fembed-offload-object=" + 520 getToolChain().getInputFilename(Inputs[i]))); 521 } else if (IsOpenMPDevice) { 522 if (Inputs[i].getFilename()) { 523 CmdArgs.push_back("-fopenmp-host-ir-file-path"); 524 CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); 525 } else { 526 llvm_unreachable("missing openmp host-ir file for device offloading"); 527 } 528 } else { 529 llvm_unreachable( 530 "unexpectedly given multiple inputs or given unknown input"); 531 } 532 } 533 534 if (IsOpenMPDevice) { 535 // -fopenmp-is-target-device is passed along to tell the frontend that it is 536 // generating code for a device, so that only the relevant code is emitted. 537 CmdArgs.push_back("-fopenmp-is-target-device"); 538 539 // When in OpenMP offloading mode, enable debugging on the device. 540 Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); 541 if (Args.hasFlag(options::OPT_fopenmp_target_debug, 542 options::OPT_fno_openmp_target_debug, /*Default=*/false)) 543 CmdArgs.push_back("-fopenmp-target-debug"); 544 545 // When in OpenMP offloading mode, forward assumptions information about 546 // thread and team counts in the device. 547 if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, 548 options::OPT_fno_openmp_assume_teams_oversubscription, 549 /*Default=*/false)) 550 CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); 551 if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, 552 options::OPT_fno_openmp_assume_threads_oversubscription, 553 /*Default=*/false)) 554 CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); 555 if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) 556 CmdArgs.push_back("-fopenmp-assume-no-thread-state"); 557 if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) 558 CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); 559 if (Args.hasArg(options::OPT_nogpulib)) 560 CmdArgs.push_back("-nogpulib"); 561 } 562 563 addOpenMPHostOffloadingArgs(C, JA, Args, CmdArgs); 564 } 565 566 static void addFloatingPointOptions(const Driver &D, const ArgList &Args, 567 ArgStringList &CmdArgs) { 568 StringRef FPContract; 569 bool HonorINFs = true; 570 bool HonorNaNs = true; 571 bool ApproxFunc = false; 572 bool SignedZeros = true; 573 bool AssociativeMath = false; 574 bool ReciprocalMath = false; 575 576 if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { 577 const StringRef Val = A->getValue(); 578 if (Val == "fast" || Val == "off") { 579 FPContract = Val; 580 } else if (Val == "on") { 581 // Warn instead of error because users might have makefiles written for 582 // gfortran (which accepts -ffp-contract=on) 583 D.Diag(diag::warn_drv_unsupported_option_for_flang) 584 << Val << A->getOption().getName() << "off"; 585 FPContract = "off"; 586 } else 587 // Clang's "fast-honor-pragmas" option is not supported because it is 588 // non-standard 589 D.Diag(diag::err_drv_unsupported_option_argument) 590 << A->getSpelling() << Val; 591 } 592 593 for (const Arg *A : Args) { 594 auto optId = A->getOption().getID(); 595 switch (optId) { 596 // if this isn't an FP option, skip the claim below 597 default: 598 continue; 599 600 case options::OPT_fhonor_infinities: 601 HonorINFs = true; 602 break; 603 case options::OPT_fno_honor_infinities: 604 HonorINFs = false; 605 break; 606 case options::OPT_fhonor_nans: 607 HonorNaNs = true; 608 break; 609 case options::OPT_fno_honor_nans: 610 HonorNaNs = false; 611 break; 612 case options::OPT_fapprox_func: 613 ApproxFunc = true; 614 break; 615 case options::OPT_fno_approx_func: 616 ApproxFunc = false; 617 break; 618 case options::OPT_fsigned_zeros: 619 SignedZeros = true; 620 break; 621 case options::OPT_fno_signed_zeros: 622 SignedZeros = false; 623 break; 624 case options::OPT_fassociative_math: 625 AssociativeMath = true; 626 break; 627 case options::OPT_fno_associative_math: 628 AssociativeMath = false; 629 break; 630 case options::OPT_freciprocal_math: 631 ReciprocalMath = true; 632 break; 633 case options::OPT_fno_reciprocal_math: 634 ReciprocalMath = false; 635 break; 636 case options::OPT_Ofast: 637 [[fallthrough]]; 638 case options::OPT_ffast_math: 639 HonorINFs = false; 640 HonorNaNs = false; 641 AssociativeMath = true; 642 ReciprocalMath = true; 643 ApproxFunc = true; 644 SignedZeros = false; 645 FPContract = "fast"; 646 break; 647 case options::OPT_fno_fast_math: 648 HonorINFs = true; 649 HonorNaNs = true; 650 AssociativeMath = false; 651 ReciprocalMath = false; 652 ApproxFunc = false; 653 SignedZeros = true; 654 // -fno-fast-math should undo -ffast-math so I return FPContract to the 655 // default. It is important to check it is "fast" (the default) so that 656 // --ffp-contract=off -fno-fast-math --> -ffp-contract=off 657 if (FPContract == "fast") 658 FPContract = ""; 659 break; 660 } 661 662 // If we handled this option claim it 663 A->claim(); 664 } 665 666 if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && 667 ApproxFunc && !SignedZeros && 668 (FPContract == "fast" || FPContract.empty())) { 669 CmdArgs.push_back("-ffast-math"); 670 return; 671 } 672 673 if (!FPContract.empty()) 674 CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); 675 676 if (!HonorINFs) 677 CmdArgs.push_back("-menable-no-infs"); 678 679 if (!HonorNaNs) 680 CmdArgs.push_back("-menable-no-nans"); 681 682 if (ApproxFunc) 683 CmdArgs.push_back("-fapprox-func"); 684 685 if (!SignedZeros) 686 CmdArgs.push_back("-fno-signed-zeros"); 687 688 if (AssociativeMath && !SignedZeros) 689 CmdArgs.push_back("-mreassociate"); 690 691 if (ReciprocalMath) 692 CmdArgs.push_back("-freciprocal-math"); 693 } 694 695 static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, 696 const InputInfo &Input) { 697 StringRef Format = "yaml"; 698 if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) 699 Format = A->getValue(); 700 701 CmdArgs.push_back("-opt-record-file"); 702 703 const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); 704 if (A) { 705 CmdArgs.push_back(A->getValue()); 706 } else { 707 SmallString<128> F; 708 709 if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { 710 if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) 711 F = FinalOutput->getValue(); 712 } 713 714 if (F.empty()) { 715 // Use the input filename. 716 F = llvm::sys::path::stem(Input.getBaseInput()); 717 } 718 719 SmallString<32> Extension; 720 Extension += "opt."; 721 Extension += Format; 722 723 llvm::sys::path::replace_extension(F, Extension); 724 CmdArgs.push_back(Args.MakeArgString(F)); 725 } 726 727 if (const Arg *A = 728 Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { 729 CmdArgs.push_back("-opt-record-passes"); 730 CmdArgs.push_back(A->getValue()); 731 } 732 733 if (!Format.empty()) { 734 CmdArgs.push_back("-opt-record-format"); 735 CmdArgs.push_back(Format.data()); 736 } 737 } 738 739 void Flang::ConstructJob(Compilation &C, const JobAction &JA, 740 const InputInfo &Output, const InputInfoList &Inputs, 741 const ArgList &Args, const char *LinkingOutput) const { 742 const auto &TC = getToolChain(); 743 const llvm::Triple &Triple = TC.getEffectiveTriple(); 744 const std::string &TripleStr = Triple.getTriple(); 745 746 const Driver &D = TC.getDriver(); 747 ArgStringList CmdArgs; 748 DiagnosticsEngine &Diags = D.getDiags(); 749 750 // Invoke ourselves in -fc1 mode. 751 CmdArgs.push_back("-fc1"); 752 753 // Add the "effective" target triple. 754 CmdArgs.push_back("-triple"); 755 CmdArgs.push_back(Args.MakeArgString(TripleStr)); 756 757 if (isa<PreprocessJobAction>(JA)) { 758 CmdArgs.push_back("-E"); 759 if (Args.getLastArg(options::OPT_dM)) { 760 CmdArgs.push_back("-dM"); 761 } 762 } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { 763 if (JA.getType() == types::TY_Nothing) { 764 CmdArgs.push_back("-fsyntax-only"); 765 } else if (JA.getType() == types::TY_AST) { 766 CmdArgs.push_back("-emit-ast"); 767 } else if (JA.getType() == types::TY_LLVM_IR || 768 JA.getType() == types::TY_LTO_IR) { 769 CmdArgs.push_back("-emit-llvm"); 770 } else if (JA.getType() == types::TY_LLVM_BC || 771 JA.getType() == types::TY_LTO_BC) { 772 CmdArgs.push_back("-emit-llvm-bc"); 773 } else if (JA.getType() == types::TY_PP_Asm) { 774 CmdArgs.push_back("-S"); 775 } else { 776 assert(false && "Unexpected output type!"); 777 } 778 } else if (isa<AssembleJobAction>(JA)) { 779 CmdArgs.push_back("-emit-obj"); 780 } else if (isa<PrecompileJobAction>(JA)) { 781 // The precompile job action is only needed for options such as -mcpu=help. 782 // Those will already have been handled by the fc1 driver. 783 } else { 784 assert(false && "Unexpected action class for Flang tool."); 785 } 786 787 const InputInfo &Input = Inputs[0]; 788 types::ID InputType = Input.getType(); 789 790 // Add preprocessing options like -I, -D, etc. if we are using the 791 // preprocessor (i.e. skip when dealing with e.g. binary files). 792 if (types::getPreprocessedType(InputType) != types::TY_INVALID) 793 addPreprocessingOptions(Args, CmdArgs); 794 795 addFortranDialectOptions(Args, CmdArgs); 796 797 // 'flang -E' always produces output that is suitable for use as fixed form 798 // Fortran. However it is only valid free form source if the original is also 799 // free form. 800 if (InputType == types::TY_PP_Fortran && 801 !Args.getLastArg(options::OPT_ffixed_form, options::OPT_ffree_form)) 802 CmdArgs.push_back("-ffixed-form"); 803 804 handleColorDiagnosticsArgs(D, Args, CmdArgs); 805 806 // LTO mode is parsed by the Clang driver library. 807 LTOKind LTOMode = D.getLTOMode(); 808 assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); 809 if (LTOMode == LTOK_Full) 810 CmdArgs.push_back("-flto=full"); 811 else if (LTOMode == LTOK_Thin) { 812 Diags.Report( 813 Diags.getCustomDiagID(DiagnosticsEngine::Warning, 814 "the option '-flto=thin' is a work in progress")); 815 CmdArgs.push_back("-flto=thin"); 816 } 817 818 // -fPIC and related options. 819 addPicOptions(Args, CmdArgs); 820 821 // Floating point related options 822 addFloatingPointOptions(D, Args, CmdArgs); 823 824 // Add target args, features, etc. 825 addTargetOptions(Args, CmdArgs); 826 827 llvm::Reloc::Model RelocationModel = 828 std::get<0>(ParsePICArgs(getToolChain(), Args)); 829 // Add MCModel information 830 addMCModel(D, Args, Triple, RelocationModel, CmdArgs); 831 832 // Add Codegen options 833 addCodegenOptions(Args, CmdArgs); 834 835 // Add R Group options 836 Args.AddAllArgs(CmdArgs, options::OPT_R_Group); 837 838 // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. 839 if (willEmitRemarks(Args)) 840 renderRemarksOptions(Args, CmdArgs, Input); 841 842 // Add other compile options 843 addOtherOptions(Args, CmdArgs); 844 845 // Disable all warnings 846 // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption 847 Args.AddLastArg(CmdArgs, options::OPT_w); 848 849 // Forward flags for OpenMP. We don't do this if the current action is an 850 // device offloading action other than OpenMP. 851 if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, 852 options::OPT_fno_openmp, false) && 853 (JA.isDeviceOffloading(Action::OFK_None) || 854 JA.isDeviceOffloading(Action::OFK_OpenMP))) { 855 switch (D.getOpenMPRuntime(Args)) { 856 case Driver::OMPRT_OMP: 857 case Driver::OMPRT_IOMP5: 858 // Clang can generate useful OpenMP code for these two runtime libraries. 859 CmdArgs.push_back("-fopenmp"); 860 Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); 861 862 if (Args.hasArg(options::OPT_fopenmp_force_usm)) 863 CmdArgs.push_back("-fopenmp-force-usm"); 864 // TODO: OpenMP support isn't "done" yet, so for now we warn that it 865 // is experimental. 866 D.Diag(diag::warn_openmp_experimental); 867 868 // FIXME: Clang supports a whole bunch more flags here. 869 break; 870 default: 871 // By default, if Clang doesn't know how to generate useful OpenMP code 872 // for a specific runtime library, we just don't pass the '-fopenmp' flag 873 // down to the actual compilation. 874 // FIXME: It would be better to have a mode which *only* omits IR 875 // generation based on the OpenMP support so that we get consistent 876 // semantic analysis, etc. 877 const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); 878 D.Diag(diag::warn_drv_unsupported_openmp_library) 879 << A->getSpelling() << A->getValue(); 880 break; 881 } 882 } 883 884 // Pass the path to compiler resource files. 885 CmdArgs.push_back("-resource-dir"); 886 CmdArgs.push_back(D.ResourceDir.c_str()); 887 888 // Offloading related options 889 addOffloadOptions(C, Inputs, JA, Args, CmdArgs); 890 891 // Forward -Xflang arguments to -fc1 892 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); 893 894 CodeGenOptions::FramePointerKind FPKeepKind = 895 getFramePointerKind(Args, Triple); 896 897 const char *FPKeepKindStr = nullptr; 898 switch (FPKeepKind) { 899 case CodeGenOptions::FramePointerKind::None: 900 FPKeepKindStr = "-mframe-pointer=none"; 901 break; 902 case CodeGenOptions::FramePointerKind::Reserved: 903 FPKeepKindStr = "-mframe-pointer=reserved"; 904 break; 905 case CodeGenOptions::FramePointerKind::NonLeaf: 906 FPKeepKindStr = "-mframe-pointer=non-leaf"; 907 break; 908 case CodeGenOptions::FramePointerKind::All: 909 FPKeepKindStr = "-mframe-pointer=all"; 910 break; 911 } 912 assert(FPKeepKindStr && "unknown FramePointerKind"); 913 CmdArgs.push_back(FPKeepKindStr); 914 915 // Forward -mllvm options to the LLVM option parser. In practice, this means 916 // forwarding to `-fc1` as that's where the LLVM parser is run. 917 for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 918 A->claim(); 919 A->render(Args, CmdArgs); 920 } 921 922 for (const Arg *A : Args.filtered(options::OPT_mmlir)) { 923 A->claim(); 924 A->render(Args, CmdArgs); 925 } 926 927 // Remove any unsupported gfortran diagnostic options 928 for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { 929 A->claim(); 930 D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) 931 << A->getOption().getName(); 932 } 933 934 // Optimization level for CodeGen. 935 if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { 936 if (A->getOption().matches(options::OPT_O4)) { 937 CmdArgs.push_back("-O3"); 938 D.Diag(diag::warn_O4_is_O3); 939 } else if (A->getOption().matches(options::OPT_Ofast)) { 940 CmdArgs.push_back("-O3"); 941 D.Diag(diag::warn_drv_deprecated_arg_ofast_for_flang); 942 } else { 943 A->render(Args, CmdArgs); 944 } 945 } 946 947 renderCommonIntegerOverflowOptions(Args, CmdArgs); 948 949 assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 950 if (Output.isFilename()) { 951 CmdArgs.push_back("-o"); 952 CmdArgs.push_back(Output.getFilename()); 953 } 954 955 if (Args.getLastArg(options::OPT_save_temps_EQ)) 956 Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); 957 958 addDashXForInput(Args, Input, CmdArgs); 959 960 bool FRecordCmdLine = false; 961 bool GRecordCmdLine = false; 962 if (shouldRecordCommandLine(TC, Args, FRecordCmdLine, GRecordCmdLine)) { 963 const char *CmdLine = renderEscapedCommandLine(TC, Args); 964 if (FRecordCmdLine) { 965 CmdArgs.push_back("-record-command-line"); 966 CmdArgs.push_back(CmdLine); 967 } 968 if (TC.UseDwarfDebugFlags() || GRecordCmdLine) { 969 CmdArgs.push_back("-dwarf-debug-flags"); 970 CmdArgs.push_back(CmdLine); 971 } 972 } 973 974 // The input could be Ty_Nothing when "querying" options such as -mcpu=help 975 // are used. 976 ArrayRef<InputInfo> FrontendInputs = Input; 977 if (Input.isNothing()) 978 FrontendInputs = {}; 979 980 for (const InputInfo &Input : FrontendInputs) { 981 if (Input.isFilename()) 982 CmdArgs.push_back(Input.getFilename()); 983 else 984 Input.getInputArg().renderAsInput(Args, CmdArgs); 985 } 986 987 const char *Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); 988 C.addCommand(std::make_unique<Command>(JA, *this, 989 ResponseFileSupport::AtFileUTF8(), 990 Exec, CmdArgs, Inputs, Output)); 991 } 992 993 Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {} 994 995 Flang::~Flang() {} 996