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 "CommonArgs.h" 11 12 #include "clang/Basic/CodeGenOptions.h" 13 #include "clang/Driver/Options.h" 14 #include "llvm/Frontend/Debug/Options.h" 15 #include "llvm/Support/FileSystem.h" 16 #include "llvm/Support/Path.h" 17 18 #include <cassert> 19 20 using namespace clang::driver; 21 using namespace clang::driver::tools; 22 using namespace clang; 23 using namespace llvm::opt; 24 25 /// Add -x lang to \p CmdArgs for \p Input. 26 static void addDashXForInput(const ArgList &Args, const InputInfo &Input, 27 ArgStringList &CmdArgs) { 28 CmdArgs.push_back("-x"); 29 // Map the driver type to the frontend type. 30 CmdArgs.push_back(types::getTypeName(Input.getType())); 31 } 32 33 void Flang::addFortranDialectOptions(const ArgList &Args, 34 ArgStringList &CmdArgs) const { 35 Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, 36 options::OPT_ffree_form, 37 options::OPT_ffixed_line_length_EQ, 38 options::OPT_fopenmp, 39 options::OPT_fopenmp_version_EQ, 40 options::OPT_fopenacc, 41 options::OPT_finput_charset_EQ, 42 options::OPT_fimplicit_none, 43 options::OPT_fno_implicit_none, 44 options::OPT_fbackslash, 45 options::OPT_fno_backslash, 46 options::OPT_flogical_abbreviations, 47 options::OPT_fno_logical_abbreviations, 48 options::OPT_fxor_operator, 49 options::OPT_fno_xor_operator, 50 options::OPT_falternative_parameter_statement, 51 options::OPT_fdefault_real_8, 52 options::OPT_fdefault_integer_8, 53 options::OPT_fdefault_double_8, 54 options::OPT_flarge_sizes, 55 options::OPT_fno_automatic}); 56 } 57 58 void Flang::addPreprocessingOptions(const ArgList &Args, 59 ArgStringList &CmdArgs) const { 60 Args.addAllArgs(CmdArgs, 61 {options::OPT_P, options::OPT_D, options::OPT_U, 62 options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); 63 } 64 65 /// @C shouldLoopVersion 66 /// 67 /// Check if Loop Versioning should be enabled. 68 /// We look for the last of one of the following: 69 /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. 70 /// Loop versioning is disabled if the last option is 71 /// -fno-version-loops-for-stride. 72 /// Loop versioning is enabled if the last option is one of: 73 /// -floop-versioning 74 /// -Ofast 75 /// -O4 76 /// -O3 77 /// For all other cases, loop versioning is is disabled. 78 /// 79 /// The gfortran compiler automatically enables the option for -O3 or -Ofast. 80 /// 81 /// @return true if loop-versioning should be enabled, otherwise false. 82 static bool shouldLoopVersion(const ArgList &Args) { 83 const Arg *LoopVersioningArg = Args.getLastArg( 84 options::OPT_Ofast, options::OPT_O, options::OPT_O4, 85 options::OPT_floop_versioning, options::OPT_fno_loop_versioning); 86 if (!LoopVersioningArg) 87 return false; 88 89 if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) 90 return false; 91 92 if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) 93 return true; 94 95 if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || 96 LoopVersioningArg->getOption().matches(options::OPT_O4)) 97 return true; 98 99 if (LoopVersioningArg->getOption().matches(options::OPT_O)) { 100 StringRef S(LoopVersioningArg->getValue()); 101 unsigned OptLevel = 0; 102 // Note -Os or Oz woould "fail" here, so return false. Which is the 103 // desiered behavior. 104 if (S.getAsInteger(10, OptLevel)) 105 return false; 106 107 return OptLevel > 2; 108 } 109 110 llvm_unreachable("We should not end up here"); 111 return false; 112 } 113 114 void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 115 Args.addAllArgs(CmdArgs, 116 {options::OPT_module_dir, options::OPT_fdebug_module_writer, 117 options::OPT_fintrinsic_modules_path, options::OPT_pedantic, 118 options::OPT_std_EQ, options::OPT_W_Joined, 119 options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, 120 options::OPT_funderscoring, options::OPT_fno_underscoring}); 121 122 llvm::codegenoptions::DebugInfoKind DebugInfoKind; 123 if (Args.hasArg(options::OPT_gN_Group)) { 124 Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); 125 DebugInfoKind = debugLevelToInfoKind(*gNArg); 126 } else if (Args.hasArg(options::OPT_g_Flag)) { 127 DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; 128 } else { 129 DebugInfoKind = llvm::codegenoptions::NoDebugInfo; 130 } 131 addDebugInfoKind(CmdArgs, DebugInfoKind); 132 } 133 134 void Flang::addCodegenOptions(const ArgList &Args, 135 ArgStringList &CmdArgs) const { 136 Arg *stackArrays = 137 Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, 138 options::OPT_fno_stack_arrays); 139 if (stackArrays && 140 !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) 141 CmdArgs.push_back("-fstack-arrays"); 142 143 if (shouldLoopVersion(Args)) 144 CmdArgs.push_back("-fversion-loops-for-stride"); 145 146 Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, 147 options::OPT_flang_deprecated_no_hlfir, 148 options::OPT_flang_experimental_polymorphism, 149 options::OPT_fno_ppc_native_vec_elem_order, 150 options::OPT_fppc_native_vec_elem_order}); 151 } 152 153 void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 154 // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of 155 // (RelocationModel, PICLevel, IsPIE). 156 llvm::Reloc::Model RelocationModel; 157 unsigned PICLevel; 158 bool IsPIE; 159 std::tie(RelocationModel, PICLevel, IsPIE) = 160 ParsePICArgs(getToolChain(), Args); 161 162 if (auto *RMName = RelocationModelName(RelocationModel)) { 163 CmdArgs.push_back("-mrelocation-model"); 164 CmdArgs.push_back(RMName); 165 } 166 if (PICLevel > 0) { 167 CmdArgs.push_back("-pic-level"); 168 CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); 169 if (IsPIE) 170 CmdArgs.push_back("-pic-is-pie"); 171 } 172 } 173 174 void Flang::AddAArch64TargetArgs(const ArgList &Args, 175 ArgStringList &CmdArgs) const { 176 // Handle -msve_vector_bits=<bits> 177 if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { 178 StringRef Val = A->getValue(); 179 const Driver &D = getToolChain().getDriver(); 180 if (Val.equals("128") || Val.equals("256") || Val.equals("512") || 181 Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || 182 Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || 183 Val.equals("2048+")) { 184 unsigned Bits = 0; 185 if (Val.ends_with("+")) 186 Val = Val.substr(0, Val.size() - 1); 187 else { 188 [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 189 assert(!Invalid && "Failed to parse value"); 190 CmdArgs.push_back( 191 Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); 192 } 193 194 [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 195 assert(!Invalid && "Failed to parse value"); 196 CmdArgs.push_back( 197 Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); 198 // Silently drop requests for vector-length agnostic code as it's implied. 199 } else if (!Val.equals("scalable")) 200 // Handle the unsupported values passed to msve-vector-bits. 201 D.Diag(diag::err_drv_unsupported_option_argument) 202 << A->getSpelling() << Val; 203 } 204 } 205 206 static void addVSDefines(const ToolChain &TC, const ArgList &Args, 207 ArgStringList &CmdArgs) { 208 209 unsigned ver = 0; 210 const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); 211 ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + 212 vt.getSubminor().value_or(0); 213 CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); 214 CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); 215 CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); 216 217 llvm::Triple triple = TC.getTriple(); 218 if (triple.isAArch64()) { 219 CmdArgs.push_back("-D_M_ARM64=1"); 220 } else if (triple.isX86() && triple.isArch32Bit()) { 221 CmdArgs.push_back("-D_M_IX86=600"); 222 } else if (triple.isX86() && triple.isArch64Bit()) { 223 CmdArgs.push_back("-D_M_X64=100"); 224 } else { 225 llvm_unreachable( 226 "Flang on Windows only supports X86_32, X86_64 and AArch64"); 227 } 228 } 229 230 static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, 231 ArgStringList &CmdArgs) { 232 assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && 233 "can only add VS runtime library on Windows!"); 234 // if -fno-fortran-main has been passed, skip linking Fortran_main.a 235 bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main); 236 if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { 237 CmdArgs.push_back(Args.MakeArgString( 238 "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); 239 } 240 unsigned RTOptionID = options::OPT__SLASH_MT; 241 if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { 242 RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) 243 .Case("static", options::OPT__SLASH_MT) 244 .Case("static_dbg", options::OPT__SLASH_MTd) 245 .Case("dll", options::OPT__SLASH_MD) 246 .Case("dll_dbg", options::OPT__SLASH_MDd) 247 .Default(options::OPT__SLASH_MT); 248 } 249 switch (RTOptionID) { 250 case options::OPT__SLASH_MT: 251 CmdArgs.push_back("-D_MT"); 252 CmdArgs.push_back("--dependent-lib=libcmt"); 253 if (LinkFortranMain) 254 CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib"); 255 CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); 256 CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); 257 break; 258 case options::OPT__SLASH_MTd: 259 CmdArgs.push_back("-D_MT"); 260 CmdArgs.push_back("-D_DEBUG"); 261 CmdArgs.push_back("--dependent-lib=libcmtd"); 262 if (LinkFortranMain) 263 CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib"); 264 CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); 265 CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); 266 break; 267 case options::OPT__SLASH_MD: 268 CmdArgs.push_back("-D_MT"); 269 CmdArgs.push_back("-D_DLL"); 270 CmdArgs.push_back("--dependent-lib=msvcrt"); 271 if (LinkFortranMain) 272 CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib"); 273 CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); 274 CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); 275 break; 276 case options::OPT__SLASH_MDd: 277 CmdArgs.push_back("-D_MT"); 278 CmdArgs.push_back("-D_DEBUG"); 279 CmdArgs.push_back("-D_DLL"); 280 CmdArgs.push_back("--dependent-lib=msvcrtd"); 281 if (LinkFortranMain) 282 CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib"); 283 CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); 284 CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); 285 break; 286 } 287 } 288 289 void Flang::AddAMDGPUTargetArgs(const ArgList &Args, 290 ArgStringList &CmdArgs) const { 291 if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { 292 StringRef Val = A->getValue(); 293 CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); 294 } 295 } 296 297 void Flang::addTargetOptions(const ArgList &Args, 298 ArgStringList &CmdArgs) const { 299 const ToolChain &TC = getToolChain(); 300 const llvm::Triple &Triple = TC.getEffectiveTriple(); 301 const Driver &D = TC.getDriver(); 302 303 std::string CPU = getCPUName(D, Args, Triple); 304 if (!CPU.empty()) { 305 CmdArgs.push_back("-target-cpu"); 306 CmdArgs.push_back(Args.MakeArgString(CPU)); 307 } 308 309 // Add the target features. 310 switch (TC.getArch()) { 311 default: 312 break; 313 case llvm::Triple::aarch64: 314 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 315 AddAArch64TargetArgs(Args, CmdArgs); 316 break; 317 318 case llvm::Triple::r600: 319 case llvm::Triple::amdgcn: 320 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 321 AddAMDGPUTargetArgs(Args, CmdArgs); 322 break; 323 case llvm::Triple::riscv64: 324 case llvm::Triple::x86_64: 325 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 326 break; 327 } 328 329 if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { 330 StringRef Name = A->getValue(); 331 if (Name == "SVML") { 332 if (Triple.getArch() != llvm::Triple::x86 && 333 Triple.getArch() != llvm::Triple::x86_64) 334 D.Diag(diag::err_drv_unsupported_opt_for_target) 335 << Name << Triple.getArchName(); 336 } else if (Name == "LIBMVEC-X86") { 337 if (Triple.getArch() != llvm::Triple::x86 && 338 Triple.getArch() != llvm::Triple::x86_64) 339 D.Diag(diag::err_drv_unsupported_opt_for_target) 340 << Name << Triple.getArchName(); 341 } else if (Name == "SLEEF" || Name == "ArmPL") { 342 if (Triple.getArch() != llvm::Triple::aarch64 && 343 Triple.getArch() != llvm::Triple::aarch64_be) 344 D.Diag(diag::err_drv_unsupported_opt_for_target) 345 << Name << Triple.getArchName(); 346 } 347 348 if (Triple.isOSDarwin()) { 349 // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these 350 // here incase they are added someday 351 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 352 if (A->getValue() == StringRef{"Accelerate"}) { 353 CmdArgs.push_back("-framework"); 354 CmdArgs.push_back("Accelerate"); 355 A->render(Args, CmdArgs); 356 } 357 } 358 } else { 359 A->render(Args, CmdArgs); 360 } 361 } 362 363 if (Triple.isKnownWindowsMSVCEnvironment()) { 364 processVSRuntimeLibrary(TC, Args, CmdArgs); 365 addVSDefines(TC, Args, CmdArgs); 366 } 367 368 // TODO: Add target specific flags, ABI, mtune option etc. 369 } 370 371 void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, 372 const JobAction &JA, const ArgList &Args, 373 ArgStringList &CmdArgs) const { 374 bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); 375 bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || 376 JA.isHostOffloading(C.getActiveOffloadKinds()); 377 378 // Skips the primary input file, which is the input file that the compilation 379 // proccess will be executed upon (e.g. the host bitcode file) and 380 // adds other secondary input (e.g. device bitcode files for embedding to the 381 // -fembed-offload-object argument or the host IR file for proccessing 382 // during device compilation to the fopenmp-host-ir-file-path argument via 383 // OpenMPDeviceInput). This is condensed logic from the ConstructJob 384 // function inside of the Clang driver for pushing on further input arguments 385 // needed for offloading during various phases of compilation. 386 for (size_t i = 1; i < Inputs.size(); ++i) { 387 if (Inputs[i].getType() == types::TY_Nothing) { 388 // contains nothing, so it's skippable 389 } else if (IsHostOffloadingAction) { 390 CmdArgs.push_back( 391 Args.MakeArgString("-fembed-offload-object=" + 392 getToolChain().getInputFilename(Inputs[i]))); 393 } else if (IsOpenMPDevice) { 394 if (Inputs[i].getFilename()) { 395 CmdArgs.push_back("-fopenmp-host-ir-file-path"); 396 CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); 397 } else { 398 llvm_unreachable("missing openmp host-ir file for device offloading"); 399 } 400 } else { 401 llvm_unreachable( 402 "unexpectedly given multiple inputs or given unknown input"); 403 } 404 } 405 406 if (IsOpenMPDevice) { 407 // -fopenmp-is-target-device is passed along to tell the frontend that it is 408 // generating code for a device, so that only the relevant code is emitted. 409 CmdArgs.push_back("-fopenmp-is-target-device"); 410 411 // When in OpenMP offloading mode, enable debugging on the device. 412 Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); 413 if (Args.hasFlag(options::OPT_fopenmp_target_debug, 414 options::OPT_fno_openmp_target_debug, /*Default=*/false)) 415 CmdArgs.push_back("-fopenmp-target-debug"); 416 417 // When in OpenMP offloading mode, forward assumptions information about 418 // thread and team counts in the device. 419 if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, 420 options::OPT_fno_openmp_assume_teams_oversubscription, 421 /*Default=*/false)) 422 CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); 423 if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, 424 options::OPT_fno_openmp_assume_threads_oversubscription, 425 /*Default=*/false)) 426 CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); 427 if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) 428 CmdArgs.push_back("-fopenmp-assume-no-thread-state"); 429 if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) 430 CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); 431 } 432 } 433 434 static void addFloatingPointOptions(const Driver &D, const ArgList &Args, 435 ArgStringList &CmdArgs) { 436 StringRef FPContract; 437 bool HonorINFs = true; 438 bool HonorNaNs = true; 439 bool ApproxFunc = false; 440 bool SignedZeros = true; 441 bool AssociativeMath = false; 442 bool ReciprocalMath = false; 443 444 if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { 445 const StringRef Val = A->getValue(); 446 if (Val == "fast" || Val == "off") { 447 FPContract = Val; 448 } else if (Val == "on") { 449 // Warn instead of error because users might have makefiles written for 450 // gfortran (which accepts -ffp-contract=on) 451 D.Diag(diag::warn_drv_unsupported_option_for_flang) 452 << Val << A->getOption().getName() << "off"; 453 FPContract = "off"; 454 } else 455 // Clang's "fast-honor-pragmas" option is not supported because it is 456 // non-standard 457 D.Diag(diag::err_drv_unsupported_option_argument) 458 << A->getSpelling() << Val; 459 } 460 461 for (const Arg *A : Args) { 462 auto optId = A->getOption().getID(); 463 switch (optId) { 464 // if this isn't an FP option, skip the claim below 465 default: 466 continue; 467 468 case options::OPT_fhonor_infinities: 469 HonorINFs = true; 470 break; 471 case options::OPT_fno_honor_infinities: 472 HonorINFs = false; 473 break; 474 case options::OPT_fhonor_nans: 475 HonorNaNs = true; 476 break; 477 case options::OPT_fno_honor_nans: 478 HonorNaNs = false; 479 break; 480 case options::OPT_fapprox_func: 481 ApproxFunc = true; 482 break; 483 case options::OPT_fno_approx_func: 484 ApproxFunc = false; 485 break; 486 case options::OPT_fsigned_zeros: 487 SignedZeros = true; 488 break; 489 case options::OPT_fno_signed_zeros: 490 SignedZeros = false; 491 break; 492 case options::OPT_fassociative_math: 493 AssociativeMath = true; 494 break; 495 case options::OPT_fno_associative_math: 496 AssociativeMath = false; 497 break; 498 case options::OPT_freciprocal_math: 499 ReciprocalMath = true; 500 break; 501 case options::OPT_fno_reciprocal_math: 502 ReciprocalMath = false; 503 break; 504 case options::OPT_Ofast: 505 [[fallthrough]]; 506 case options::OPT_ffast_math: 507 HonorINFs = false; 508 HonorNaNs = false; 509 AssociativeMath = true; 510 ReciprocalMath = true; 511 ApproxFunc = true; 512 SignedZeros = false; 513 FPContract = "fast"; 514 break; 515 case options::OPT_fno_fast_math: 516 HonorINFs = true; 517 HonorNaNs = true; 518 AssociativeMath = false; 519 ReciprocalMath = false; 520 ApproxFunc = false; 521 SignedZeros = true; 522 // -fno-fast-math should undo -ffast-math so I return FPContract to the 523 // default. It is important to check it is "fast" (the default) so that 524 // --ffp-contract=off -fno-fast-math --> -ffp-contract=off 525 if (FPContract == "fast") 526 FPContract = ""; 527 break; 528 } 529 530 // If we handled this option claim it 531 A->claim(); 532 } 533 534 if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && 535 ApproxFunc && !SignedZeros && 536 (FPContract == "fast" || FPContract == "")) { 537 CmdArgs.push_back("-ffast-math"); 538 return; 539 } 540 541 if (!FPContract.empty()) 542 CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); 543 544 if (!HonorINFs) 545 CmdArgs.push_back("-menable-no-infs"); 546 547 if (!HonorNaNs) 548 CmdArgs.push_back("-menable-no-nans"); 549 550 if (ApproxFunc) 551 CmdArgs.push_back("-fapprox-func"); 552 553 if (!SignedZeros) 554 CmdArgs.push_back("-fno-signed-zeros"); 555 556 if (AssociativeMath && !SignedZeros) 557 CmdArgs.push_back("-mreassociate"); 558 559 if (ReciprocalMath) 560 CmdArgs.push_back("-freciprocal-math"); 561 } 562 563 static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, 564 const InputInfo &Input) { 565 StringRef Format = "yaml"; 566 if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) 567 Format = A->getValue(); 568 569 CmdArgs.push_back("-opt-record-file"); 570 571 const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); 572 if (A) { 573 CmdArgs.push_back(A->getValue()); 574 } else { 575 SmallString<128> F; 576 577 if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { 578 if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) 579 F = FinalOutput->getValue(); 580 } 581 582 if (F.empty()) { 583 // Use the input filename. 584 F = llvm::sys::path::stem(Input.getBaseInput()); 585 } 586 587 SmallString<32> Extension; 588 Extension += "opt."; 589 Extension += Format; 590 591 llvm::sys::path::replace_extension(F, Extension); 592 CmdArgs.push_back(Args.MakeArgString(F)); 593 } 594 595 if (const Arg *A = 596 Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { 597 CmdArgs.push_back("-opt-record-passes"); 598 CmdArgs.push_back(A->getValue()); 599 } 600 601 if (!Format.empty()) { 602 CmdArgs.push_back("-opt-record-format"); 603 CmdArgs.push_back(Format.data()); 604 } 605 } 606 607 void Flang::ConstructJob(Compilation &C, const JobAction &JA, 608 const InputInfo &Output, const InputInfoList &Inputs, 609 const ArgList &Args, const char *LinkingOutput) const { 610 const auto &TC = getToolChain(); 611 const llvm::Triple &Triple = TC.getEffectiveTriple(); 612 const std::string &TripleStr = Triple.getTriple(); 613 614 const Driver &D = TC.getDriver(); 615 ArgStringList CmdArgs; 616 DiagnosticsEngine &Diags = D.getDiags(); 617 618 // Invoke ourselves in -fc1 mode. 619 CmdArgs.push_back("-fc1"); 620 621 // Add the "effective" target triple. 622 CmdArgs.push_back("-triple"); 623 CmdArgs.push_back(Args.MakeArgString(TripleStr)); 624 625 if (isa<PreprocessJobAction>(JA)) { 626 CmdArgs.push_back("-E"); 627 } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { 628 if (JA.getType() == types::TY_Nothing) { 629 CmdArgs.push_back("-fsyntax-only"); 630 } else if (JA.getType() == types::TY_AST) { 631 CmdArgs.push_back("-emit-ast"); 632 } else if (JA.getType() == types::TY_LLVM_IR || 633 JA.getType() == types::TY_LTO_IR) { 634 CmdArgs.push_back("-emit-llvm"); 635 } else if (JA.getType() == types::TY_LLVM_BC || 636 JA.getType() == types::TY_LTO_BC) { 637 CmdArgs.push_back("-emit-llvm-bc"); 638 } else if (JA.getType() == types::TY_PP_Asm) { 639 CmdArgs.push_back("-S"); 640 } else { 641 assert(false && "Unexpected output type!"); 642 } 643 } else if (isa<AssembleJobAction>(JA)) { 644 CmdArgs.push_back("-emit-obj"); 645 } else { 646 assert(false && "Unexpected action class for Flang tool."); 647 } 648 649 const InputInfo &Input = Inputs[0]; 650 types::ID InputType = Input.getType(); 651 652 // Add preprocessing options like -I, -D, etc. if we are using the 653 // preprocessor (i.e. skip when dealing with e.g. binary files). 654 if (types::getPreprocessedType(InputType) != types::TY_INVALID) 655 addPreprocessingOptions(Args, CmdArgs); 656 657 addFortranDialectOptions(Args, CmdArgs); 658 659 // Color diagnostics are parsed by the driver directly from argv and later 660 // re-parsed to construct this job; claim any possible color diagnostic here 661 // to avoid warn_drv_unused_argument. 662 Args.getLastArg(options::OPT_fcolor_diagnostics, 663 options::OPT_fno_color_diagnostics); 664 if (Diags.getDiagnosticOptions().ShowColors) 665 CmdArgs.push_back("-fcolor-diagnostics"); 666 667 // LTO mode is parsed by the Clang driver library. 668 LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); 669 assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); 670 if (LTOMode == LTOK_Full) 671 CmdArgs.push_back("-flto=full"); 672 else if (LTOMode == LTOK_Thin) { 673 Diags.Report( 674 Diags.getCustomDiagID(DiagnosticsEngine::Warning, 675 "the option '-flto=thin' is a work in progress")); 676 CmdArgs.push_back("-flto=thin"); 677 } 678 679 // -fPIC and related options. 680 addPicOptions(Args, CmdArgs); 681 682 // Floating point related options 683 addFloatingPointOptions(D, Args, CmdArgs); 684 685 // Add target args, features, etc. 686 addTargetOptions(Args, CmdArgs); 687 688 // Add Codegen options 689 addCodegenOptions(Args, CmdArgs); 690 691 // Add R Group options 692 Args.AddAllArgs(CmdArgs, options::OPT_R_Group); 693 694 // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. 695 if (willEmitRemarks(Args)) 696 renderRemarksOptions(Args, CmdArgs, Input); 697 698 // Add other compile options 699 addOtherOptions(Args, CmdArgs); 700 701 // Offloading related options 702 addOffloadOptions(C, Inputs, JA, Args, CmdArgs); 703 704 // Forward -Xflang arguments to -fc1 705 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); 706 707 CodeGenOptions::FramePointerKind FPKeepKind = 708 getFramePointerKind(Args, Triple); 709 710 const char *FPKeepKindStr = nullptr; 711 switch (FPKeepKind) { 712 case CodeGenOptions::FramePointerKind::None: 713 FPKeepKindStr = "-mframe-pointer=none"; 714 break; 715 case CodeGenOptions::FramePointerKind::NonLeaf: 716 FPKeepKindStr = "-mframe-pointer=non-leaf"; 717 break; 718 case CodeGenOptions::FramePointerKind::All: 719 FPKeepKindStr = "-mframe-pointer=all"; 720 break; 721 } 722 assert(FPKeepKindStr && "unknown FramePointerKind"); 723 CmdArgs.push_back(FPKeepKindStr); 724 725 // Forward -mllvm options to the LLVM option parser. In practice, this means 726 // forwarding to `-fc1` as that's where the LLVM parser is run. 727 for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 728 A->claim(); 729 A->render(Args, CmdArgs); 730 } 731 732 for (const Arg *A : Args.filtered(options::OPT_mmlir)) { 733 A->claim(); 734 A->render(Args, CmdArgs); 735 } 736 737 // Remove any unsupported gfortran diagnostic options 738 for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { 739 A->claim(); 740 D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) 741 << A->getOption().getName(); 742 } 743 744 // Optimization level for CodeGen. 745 if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { 746 if (A->getOption().matches(options::OPT_O4)) { 747 CmdArgs.push_back("-O3"); 748 D.Diag(diag::warn_O4_is_O3); 749 } else if (A->getOption().matches(options::OPT_Ofast)) { 750 CmdArgs.push_back("-O3"); 751 } else { 752 A->render(Args, CmdArgs); 753 } 754 } 755 756 assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 757 if (Output.isFilename()) { 758 CmdArgs.push_back("-o"); 759 CmdArgs.push_back(Output.getFilename()); 760 } 761 762 assert(Input.isFilename() && "Invalid input."); 763 764 if (Args.getLastArg(options::OPT_save_temps_EQ)) 765 Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); 766 767 addDashXForInput(Args, Input, CmdArgs); 768 769 CmdArgs.push_back(Input.getFilename()); 770 771 // TODO: Replace flang-new with flang once the new driver replaces the 772 // throwaway driver 773 const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); 774 C.addCommand(std::make_unique<Command>(JA, *this, 775 ResponseFileSupport::AtFileUTF8(), 776 Exec, CmdArgs, Inputs, Output)); 777 } 778 779 Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} 780 781 Flang::~Flang() {} 782