void Clang::ConstructJob()

in clang/lib/Driver/ToolChains/Clang.cpp [4320:7130]


void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                         const InputInfo &Output, const InputInfoList &Inputs,
                         const ArgList &Args, const char *LinkingOutput) const {
  const auto &TC = getToolChain();
  const llvm::Triple &RawTriple = TC.getTriple();
  const llvm::Triple &Triple = TC.getEffectiveTriple();
  const std::string &TripleStr = Triple.getTriple();

  bool KernelOrKext =
      Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
  const Driver &D = TC.getDriver();
  ArgStringList CmdArgs;

  assert(Inputs.size() >= 1 && "Must have at least one input.");
  // CUDA/HIP compilation may have multiple inputs (source file + results of
  // device-side compilations). OpenMP device jobs also take the host IR as a
  // second input. Module precompilation accepts a list of header files to
  // include as part of the module. All other jobs are expected to have exactly
  // one input.
  bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
  bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda);
  bool IsHIP = JA.isOffloading(Action::OFK_HIP);
  bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP);
  bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
  bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
  bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
                                 JA.isDeviceOffloading(Action::OFK_Host));
  bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
  auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);

  // A header module compilation doesn't have a main input file, so invent a
  // fake one as a placeholder.
  const char *ModuleName = [&]{
    auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
    return ModuleNameArg ? ModuleNameArg->getValue() : "";
  }();
  InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName);

  const InputInfo &Input =
      IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0];

  InputInfoList ModuleHeaderInputs;
  const InputInfo *CudaDeviceInput = nullptr;
  const InputInfo *OpenMPDeviceInput = nullptr;
  for (const InputInfo &I : Inputs) {
    if (&I == &Input) {
      // This is the primary input.
    } else if (IsHeaderModulePrecompile &&
               types::getPrecompiledType(I.getType()) == types::TY_PCH) {
      types::ID Expected = HeaderModuleInput.getType();
      if (I.getType() != Expected) {
        D.Diag(diag::err_drv_module_header_wrong_kind)
            << I.getFilename() << types::getTypeName(I.getType())
            << types::getTypeName(Expected);
      }
      ModuleHeaderInputs.push_back(I);
    } else if ((IsCuda || IsHIP) && !CudaDeviceInput) {
      CudaDeviceInput = &I;
    } else if (IsOpenMPDevice && !OpenMPDeviceInput) {
      OpenMPDeviceInput = &I;
    } else {
      llvm_unreachable("unexpectedly given multiple inputs");
    }
  }

  const llvm::Triple *AuxTriple =
      (IsCuda || IsHIP) ? TC.getAuxTriple() : nullptr;
  bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
  bool IsIAMCU = RawTriple.isOSIAMCU();

  // Adjust IsWindowsXYZ for CUDA/HIP compilations.  Even when compiling in
  // device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not
  // Windows), we need to pass Windows-specific flags to cc1.
  if (IsCuda || IsHIP)
    IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();

  // C++ is not supported for IAMCU.
  if (IsIAMCU && types::isCXX(Input.getType()))
    D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU";

  // Invoke ourselves in -cc1 mode.
  //
  // FIXME: Implement custom jobs for internal actions.
  CmdArgs.push_back("-cc1");

  // Add the "effective" target triple.
  CmdArgs.push_back("-triple");
  CmdArgs.push_back(Args.MakeArgString(TripleStr));

  if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
    DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
    Args.ClaimAllArgs(options::OPT_MJ);
  } else if (const Arg *GenCDBFragment =
                 Args.getLastArg(options::OPT_gen_cdb_fragment_path)) {
    DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C,
                                         TripleStr, Output, Input, Args);
    Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path);
  }

  if (IsCuda || IsHIP) {
    // We have to pass the triple of the host if compiling for a CUDA/HIP device
    // and vice-versa.
    std::string NormalizedTriple;
    if (JA.isDeviceOffloading(Action::OFK_Cuda) ||
        JA.isDeviceOffloading(Action::OFK_HIP))
      NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>()
                             ->getTriple()
                             .normalize();
    else {
      // Host-side compilation.
      NormalizedTriple =
          (IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>()
                  : C.getSingleOffloadToolChain<Action::OFK_HIP>())
              ->getTriple()
              .normalize();
      if (IsCuda) {
        // We need to figure out which CUDA version we're compiling for, as that
        // determines how we load and launch GPU kernels.
        auto *CTC = static_cast<const toolchains::CudaToolChain *>(
            C.getSingleOffloadToolChain<Action::OFK_Cuda>());
        assert(CTC && "Expected valid CUDA Toolchain.");
        if (CTC && CTC->CudaInstallation.version() != CudaVersion::UNKNOWN)
          CmdArgs.push_back(Args.MakeArgString(
              Twine("-target-sdk-version=") +
              CudaVersionToString(CTC->CudaInstallation.version())));
      }
    }
    CmdArgs.push_back("-aux-triple");
    CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
  }

  if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) {
    CmdArgs.push_back("-fsycl-is-device");

    if (Arg *A = Args.getLastArg(options::OPT_sycl_std_EQ)) {
      A->render(Args, CmdArgs);
    } else {
      // Ensure the default version in SYCL mode is 2020.
      CmdArgs.push_back("-sycl-std=2020");
    }
  }

  if (IsOpenMPDevice) {
    // We have to pass the triple of the host if compiling for an OpenMP device.
    std::string NormalizedTriple =
        C.getSingleOffloadToolChain<Action::OFK_Host>()
            ->getTriple()
            .normalize();
    CmdArgs.push_back("-aux-triple");
    CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
  }

  if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
                               Triple.getArch() == llvm::Triple::thumb)) {
    unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
    unsigned Version = 0;
    bool Failure =
        Triple.getArchName().substr(Offset).consumeInteger(10, Version);
    if (Failure || Version < 7)
      D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
                                                << TripleStr;
  }

  // Push all default warning arguments that are specific to
  // the given target.  These come before user provided warning options
  // are provided.
  TC.addClangWarningOptions(CmdArgs);

  // FIXME: Subclass ToolChain for SPIR and move this to addClangWarningOptions.
  if (Triple.isSPIR() || Triple.isSPIRV())
    CmdArgs.push_back("-Wspir-compat");

  // Select the appropriate action.
  RewriteKind rewriteKind = RK_None;

  // If CollectArgsForIntegratedAssembler() isn't called below, claim the args
  // it claims when not running an assembler. Otherwise, clang would emit
  // "argument unused" warnings for assembler flags when e.g. adding "-E" to
  // flags while debugging something. That'd be somewhat inconvenient, and it's
  // also inconsistent with most other flags -- we don't warn on
  // -ffunction-sections not being used in -E mode either for example, even
  // though it's not really used either.
  if (!isa<AssembleJobAction>(JA)) {
    // The args claimed here should match the args used in
    // CollectArgsForIntegratedAssembler().
    if (TC.useIntegratedAs()) {
      Args.ClaimAllArgs(options::OPT_mrelax_all);
      Args.ClaimAllArgs(options::OPT_mno_relax_all);
      Args.ClaimAllArgs(options::OPT_mincremental_linker_compatible);
      Args.ClaimAllArgs(options::OPT_mno_incremental_linker_compatible);
      switch (C.getDefaultToolChain().getArch()) {
      case llvm::Triple::arm:
      case llvm::Triple::armeb:
      case llvm::Triple::thumb:
      case llvm::Triple::thumbeb:
        Args.ClaimAllArgs(options::OPT_mimplicit_it_EQ);
        break;
      default:
        break;
      }
    }
    Args.ClaimAllArgs(options::OPT_Wa_COMMA);
    Args.ClaimAllArgs(options::OPT_Xassembler);
  }

  if (isa<AnalyzeJobAction>(JA)) {
    assert(JA.getType() == types::TY_Plist && "Invalid output type.");
    CmdArgs.push_back("-analyze");
  } else if (isa<MigrateJobAction>(JA)) {
    CmdArgs.push_back("-migrate");
  } else if (isa<PreprocessJobAction>(JA)) {
    if (Output.getType() == types::TY_Dependencies)
      CmdArgs.push_back("-Eonly");
    else {
      CmdArgs.push_back("-E");
      if (Args.hasArg(options::OPT_rewrite_objc) &&
          !Args.hasArg(options::OPT_g_Group))
        CmdArgs.push_back("-P");
    }
  } else if (isa<AssembleJobAction>(JA)) {
    CmdArgs.push_back("-emit-obj");

    CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);

    // Also ignore explicit -force_cpusubtype_ALL option.
    (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
  } else if (isa<PrecompileJobAction>(JA)) {
    if (JA.getType() == types::TY_Nothing)
      CmdArgs.push_back("-fsyntax-only");
    else if (JA.getType() == types::TY_ModuleFile)
      CmdArgs.push_back(IsHeaderModulePrecompile
                            ? "-emit-header-module"
                            : "-emit-module-interface");
    else
      CmdArgs.push_back("-emit-pch");
  } else if (isa<VerifyPCHJobAction>(JA)) {
    CmdArgs.push_back("-verify-pch");
  } else {
    assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
           "Invalid action for clang tool.");
    if (JA.getType() == types::TY_Nothing) {
      CmdArgs.push_back("-fsyntax-only");
    } else if (JA.getType() == types::TY_LLVM_IR ||
               JA.getType() == types::TY_LTO_IR) {
      CmdArgs.push_back("-emit-llvm");
    } else if (JA.getType() == types::TY_LLVM_BC ||
               JA.getType() == types::TY_LTO_BC) {
      // Emit textual llvm IR for AMDGPU offloading for -emit-llvm -S
      if (Triple.isAMDGCN() && IsOpenMPDevice && Args.hasArg(options::OPT_S) &&
          Args.hasArg(options::OPT_emit_llvm)) {
        CmdArgs.push_back("-emit-llvm");
      } else {
        CmdArgs.push_back("-emit-llvm-bc");
      }
    } else if (JA.getType() == types::TY_IFS ||
               JA.getType() == types::TY_IFS_CPP) {
      StringRef ArgStr =
          Args.hasArg(options::OPT_interface_stub_version_EQ)
              ? Args.getLastArgValue(options::OPT_interface_stub_version_EQ)
              : "ifs-v1";
      CmdArgs.push_back("-emit-interface-stubs");
      CmdArgs.push_back(
          Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str()));
    } else if (JA.getType() == types::TY_PP_Asm) {
      CmdArgs.push_back("-S");
    } else if (JA.getType() == types::TY_AST) {
      CmdArgs.push_back("-emit-pch");
    } else if (JA.getType() == types::TY_ModuleFile) {
      CmdArgs.push_back("-module-file-info");
    } else if (JA.getType() == types::TY_RewrittenObjC) {
      CmdArgs.push_back("-rewrite-objc");
      rewriteKind = RK_NonFragile;
    } else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
      CmdArgs.push_back("-rewrite-objc");
      rewriteKind = RK_Fragile;
    } else {
      assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
    }

    // Preserve use-list order by default when emitting bitcode, so that
    // loading the bitcode up in 'opt' or 'llc' and running passes gives the
    // same result as running passes here.  For LTO, we don't need to preserve
    // the use-list order, since serialization to bitcode is part of the flow.
    if (JA.getType() == types::TY_LLVM_BC)
      CmdArgs.push_back("-emit-llvm-uselists");

    if (IsUsingLTO) {
      // Only AMDGPU supports device-side LTO.
      if (IsDeviceOffloadAction && !Triple.isAMDGPU()) {
        D.Diag(diag::err_drv_unsupported_opt_for_target)
            << Args.getLastArg(options::OPT_foffload_lto,
                               options::OPT_foffload_lto_EQ)
                   ->getAsString(Args)
            << Triple.getTriple();
      } else {
        assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin);
        CmdArgs.push_back(Args.MakeArgString(
            Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full")));
        CmdArgs.push_back("-flto-unit");
      }
    }
  }

  if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
    if (!types::isLLVMIR(Input.getType()))
      D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args);
    Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
  }

  if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ))
    Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ);

  if (Args.getLastArg(options::OPT_save_temps_EQ))
    Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);

  auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile,
                                     options::OPT_fmemory_profile_EQ,
                                     options::OPT_fno_memory_profile);
  if (MemProfArg &&
      !MemProfArg->getOption().matches(options::OPT_fno_memory_profile))
    MemProfArg->render(Args, CmdArgs);

  // Embed-bitcode option.
  // Only white-listed flags below are allowed to be embedded.
  if (C.getDriver().embedBitcodeInObject() && !IsUsingLTO &&
      (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
    // Add flags implied by -fembed-bitcode.
    Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
    // Disable all llvm IR level optimizations.
    CmdArgs.push_back("-disable-llvm-passes");

    // Render target options.
    TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());

    // reject options that shouldn't be supported in bitcode
    // also reject kernel/kext
    static const constexpr unsigned kBitcodeOptionIgnorelist[] = {
        options::OPT_mkernel,
        options::OPT_fapple_kext,
        options::OPT_ffunction_sections,
        options::OPT_fno_function_sections,
        options::OPT_fdata_sections,
        options::OPT_fno_data_sections,
        options::OPT_fbasic_block_sections_EQ,
        options::OPT_funique_internal_linkage_names,
        options::OPT_fno_unique_internal_linkage_names,
        options::OPT_funique_section_names,
        options::OPT_fno_unique_section_names,
        options::OPT_funique_basic_block_section_names,
        options::OPT_fno_unique_basic_block_section_names,
        options::OPT_mrestrict_it,
        options::OPT_mno_restrict_it,
        options::OPT_mstackrealign,
        options::OPT_mno_stackrealign,
        options::OPT_mstack_alignment,
        options::OPT_mcmodel_EQ,
        options::OPT_mlong_calls,
        options::OPT_mno_long_calls,
        options::OPT_ggnu_pubnames,
        options::OPT_gdwarf_aranges,
        options::OPT_fdebug_types_section,
        options::OPT_fno_debug_types_section,
        options::OPT_fdwarf_directory_asm,
        options::OPT_fno_dwarf_directory_asm,
        options::OPT_mrelax_all,
        options::OPT_mno_relax_all,
        options::OPT_ftrap_function_EQ,
        options::OPT_ffixed_r9,
        options::OPT_mfix_cortex_a53_835769,
        options::OPT_mno_fix_cortex_a53_835769,
        options::OPT_ffixed_x18,
        options::OPT_mglobal_merge,
        options::OPT_mno_global_merge,
        options::OPT_mred_zone,
        options::OPT_mno_red_zone,
        options::OPT_Wa_COMMA,
        options::OPT_Xassembler,
        options::OPT_mllvm,
    };
    for (const auto &A : Args)
      if (llvm::is_contained(kBitcodeOptionIgnorelist, A->getOption().getID()))
        D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling();

    // Render the CodeGen options that need to be passed.
    if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
                      options::OPT_fno_optimize_sibling_calls))
      CmdArgs.push_back("-mdisable-tail-calls");

    RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args,
                               CmdArgs, JA);

    // Render ABI arguments
    switch (TC.getArch()) {
    default: break;
    case llvm::Triple::arm:
    case llvm::Triple::armeb:
    case llvm::Triple::thumbeb:
      RenderARMABI(D, Triple, Args, CmdArgs);
      break;
    case llvm::Triple::aarch64:
    case llvm::Triple::aarch64_32:
    case llvm::Triple::aarch64_be:
      RenderAArch64ABI(Triple, Args, CmdArgs);
      break;
    }

    // Optimization level for CodeGen.
    if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
      if (A->getOption().matches(options::OPT_O4)) {
        CmdArgs.push_back("-O3");
        D.Diag(diag::warn_O4_is_O3);
      } else {
        A->render(Args, CmdArgs);
      }
    }

    // Input/Output file.
    if (Output.getType() == types::TY_Dependencies) {
      // Handled with other dependency code.
    } else if (Output.isFilename()) {
      CmdArgs.push_back("-o");
      CmdArgs.push_back(Output.getFilename());
    } else {
      assert(Output.isNothing() && "Input output.");
    }

    for (const auto &II : Inputs) {
      addDashXForInput(Args, II, CmdArgs);
      if (II.isFilename())
        CmdArgs.push_back(II.getFilename());
      else
        II.getInputArg().renderAsInput(Args, CmdArgs);
    }

    C.addCommand(std::make_unique<Command>(
        JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(),
        CmdArgs, Inputs, Output));
    return;
  }

  if (C.getDriver().embedBitcodeMarkerOnly() && !IsUsingLTO)
    CmdArgs.push_back("-fembed-bitcode=marker");

  // We normally speed up the clang process a bit by skipping destructors at
  // exit, but when we're generating diagnostics we can rely on some of the
  // cleanup.
  if (!C.isForDiagnostics())
    CmdArgs.push_back("-disable-free");
  CmdArgs.push_back("-clear-ast-before-backend");

#ifdef NDEBUG
  const bool IsAssertBuild = false;
#else
  const bool IsAssertBuild = true;
#endif

  // Disable the verification pass in -asserts builds.
  if (!IsAssertBuild)
    CmdArgs.push_back("-disable-llvm-verifier");

  // Discard value names in assert builds unless otherwise specified.
  if (Args.hasFlag(options::OPT_fdiscard_value_names,
                   options::OPT_fno_discard_value_names, !IsAssertBuild)) {
    if (Args.hasArg(options::OPT_fdiscard_value_names) &&
        llvm::any_of(Inputs, [](const clang::driver::InputInfo &II) {
          return types::isLLVMIR(II.getType());
        })) {
      D.Diag(diag::warn_ignoring_fdiscard_for_bitcode);
    }
    CmdArgs.push_back("-discard-value-names");
  }

  // Set the main file name, so that debug info works even with
  // -save-temps.
  CmdArgs.push_back("-main-file-name");
  CmdArgs.push_back(getBaseInputName(Args, Input));

  // Some flags which affect the language (via preprocessor
  // defines).
  if (Args.hasArg(options::OPT_static))
    CmdArgs.push_back("-static-define");

  if (Args.hasArg(options::OPT_municode))
    CmdArgs.push_back("-DUNICODE");

  if (isa<AnalyzeJobAction>(JA))
    RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);

  if (isa<AnalyzeJobAction>(JA) ||
      (isa<PreprocessJobAction>(JA) && Args.hasArg(options::OPT__analyze)))
    CmdArgs.push_back("-setup-static-analyzer");

  // Enable compatilibily mode to avoid analyzer-config related errors.
  // Since we can't access frontend flags through hasArg, let's manually iterate
  // through them.
  bool FoundAnalyzerConfig = false;
  for (auto Arg : Args.filtered(options::OPT_Xclang))
    if (StringRef(Arg->getValue()) == "-analyzer-config") {
      FoundAnalyzerConfig = true;
      break;
    }
  if (!FoundAnalyzerConfig)
    for (auto Arg : Args.filtered(options::OPT_Xanalyzer))
      if (StringRef(Arg->getValue()) == "-analyzer-config") {
        FoundAnalyzerConfig = true;
        break;
      }
  if (FoundAnalyzerConfig)
    CmdArgs.push_back("-analyzer-config-compatibility-mode=true");

  CheckCodeGenerationOptions(D, Args);

  unsigned FunctionAlignment = ParseFunctionAlignment(TC, Args);
  assert(FunctionAlignment <= 31 && "function alignment will be truncated!");
  if (FunctionAlignment) {
    CmdArgs.push_back("-function-alignment");
    CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment)));
  }

  // We support -falign-loops=N where N is a power of 2. GCC supports more
  // forms.
  if (const Arg *A = Args.getLastArg(options::OPT_falign_loops_EQ)) {
    unsigned Value = 0;
    if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536)
      TC.getDriver().Diag(diag::err_drv_invalid_int_value)
          << A->getAsString(Args) << A->getValue();
    else if (Value & (Value - 1))
      TC.getDriver().Diag(diag::err_drv_alignment_not_power_of_two)
          << A->getAsString(Args) << A->getValue();
    // Treat =0 as unspecified (use the target preference).
    if (Value)
      CmdArgs.push_back(Args.MakeArgString("-falign-loops=" +
                                           Twine(std::min(Value, 65536u))));
  }

  llvm::Reloc::Model RelocationModel;
  unsigned PICLevel;
  bool IsPIE;
  std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args);

  bool IsROPI = RelocationModel == llvm::Reloc::ROPI ||
                RelocationModel == llvm::Reloc::ROPI_RWPI;
  bool IsRWPI = RelocationModel == llvm::Reloc::RWPI ||
                RelocationModel == llvm::Reloc::ROPI_RWPI;

  if (Args.hasArg(options::OPT_mcmse) &&
      !Args.hasArg(options::OPT_fallow_unsupported)) {
    if (IsROPI)
      D.Diag(diag::err_cmse_pi_are_incompatible) << IsROPI;
    if (IsRWPI)
      D.Diag(diag::err_cmse_pi_are_incompatible) << !IsRWPI;
  }

  if (IsROPI && types::isCXX(Input.getType()) &&
      !Args.hasArg(options::OPT_fallow_unsupported))
    D.Diag(diag::err_drv_ropi_incompatible_with_cxx);

  const char *RMName = RelocationModelName(RelocationModel);
  if (RMName) {
    CmdArgs.push_back("-mrelocation-model");
    CmdArgs.push_back(RMName);
  }
  if (PICLevel > 0) {
    CmdArgs.push_back("-pic-level");
    CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
    if (IsPIE)
      CmdArgs.push_back("-pic-is-pie");
  }

  if (RelocationModel == llvm::Reloc::ROPI ||
      RelocationModel == llvm::Reloc::ROPI_RWPI)
    CmdArgs.push_back("-fropi");
  if (RelocationModel == llvm::Reloc::RWPI ||
      RelocationModel == llvm::Reloc::ROPI_RWPI)
    CmdArgs.push_back("-frwpi");

  if (Arg *A = Args.getLastArg(options::OPT_meabi)) {
    CmdArgs.push_back("-meabi");
    CmdArgs.push_back(A->getValue());
  }

  // -fsemantic-interposition is forwarded to CC1: set the
  // "SemanticInterposition" metadata to 1 (make some linkages interposable) and
  // make default visibility external linkage definitions dso_preemptable.
  //
  // -fno-semantic-interposition: if the target supports .Lfoo$local local
  // aliases (make default visibility external linkage definitions dso_local).
  // This is the CC1 default for ELF to match COFF/Mach-O.
  //
  // Otherwise use Clang's traditional behavior: like
  // -fno-semantic-interposition but local aliases are not used. So references
  // can be interposed if not optimized out.
  if (Triple.isOSBinFormatELF()) {
    Arg *A = Args.getLastArg(options::OPT_fsemantic_interposition,
                             options::OPT_fno_semantic_interposition);
    if (RelocationModel != llvm::Reloc::Static && !IsPIE) {
      // The supported targets need to call AsmPrinter::getSymbolPreferLocal.
      bool SupportsLocalAlias =
          Triple.isAArch64() || Triple.isRISCV() || Triple.isX86();
      if (!A)
        CmdArgs.push_back("-fhalf-no-semantic-interposition");
      else if (A->getOption().matches(options::OPT_fsemantic_interposition))
        A->render(Args, CmdArgs);
      else if (!SupportsLocalAlias)
        CmdArgs.push_back("-fhalf-no-semantic-interposition");
    }
  }

  {
    std::string Model;
    if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) {
      if (!TC.isThreadModelSupported(A->getValue()))
        D.Diag(diag::err_drv_invalid_thread_model_for_target)
            << A->getValue() << A->getAsString(Args);
      Model = A->getValue();
    } else
      Model = TC.getThreadModel();
    if (Model != "posix") {
      CmdArgs.push_back("-mthread-model");
      CmdArgs.push_back(Args.MakeArgString(Model));
    }
  }

  Args.AddLastArg(CmdArgs, options::OPT_fveclib);

  if (Args.hasFlag(options::OPT_fmerge_all_constants,
                   options::OPT_fno_merge_all_constants, false))
    CmdArgs.push_back("-fmerge-all-constants");

  if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
                   options::OPT_fdelete_null_pointer_checks, false))
    CmdArgs.push_back("-fno-delete-null-pointer-checks");

  // LLVM Code Generator Options.

  for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file_EQ)) {
    StringRef Map = A->getValue();
    if (!llvm::sys::fs::exists(Map)) {
      D.Diag(diag::err_drv_no_such_file) << Map;
    } else {
      A->render(Args, CmdArgs);
      A->claim();
    }
  }

  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi,
                               options::OPT_mabi_EQ_vec_default)) {
    if (!Triple.isOSAIX())
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getSpelling() << RawTriple.str();
    if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi)
      CmdArgs.push_back("-mabi=vec-extabi");
    else
      CmdArgs.push_back("-mabi=vec-default");
  }

  if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
    // Emit the unsupported option error until the Clang's library integration
    // support for 128-bit long double is available for AIX.
    if (Triple.isOSAIX())
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getSpelling() << RawTriple.str();
  }

  if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
    StringRef v = A->getValue();
    // FIXME: Validate the argument here so we don't produce meaningless errors
    // about -fwarn-stack-size=.
    if (v.empty())
      D.Diag(diag::err_drv_missing_argument) << A->getSpelling() << 1;
    else
      CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + v));
    A->claim();
  }

  if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
                    true))
    CmdArgs.push_back("-fno-jump-tables");

  if (Args.hasFlag(options::OPT_fprofile_sample_accurate,
                   options::OPT_fno_profile_sample_accurate, false))
    CmdArgs.push_back("-fprofile-sample-accurate");

  if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
                    options::OPT_fno_preserve_as_comments, true))
    CmdArgs.push_back("-fno-preserve-as-comments");

  if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
    CmdArgs.push_back("-mregparm");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_maix_struct_return,
                               options::OPT_msvr4_struct_return)) {
    if (!TC.getTriple().isPPC32()) {
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getSpelling() << RawTriple.str();
    } else if (A->getOption().matches(options::OPT_maix_struct_return)) {
      CmdArgs.push_back("-maix-struct-return");
    } else {
      assert(A->getOption().matches(options::OPT_msvr4_struct_return));
      CmdArgs.push_back("-msvr4-struct-return");
    }
  }

  if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
                               options::OPT_freg_struct_return)) {
    if (TC.getArch() != llvm::Triple::x86) {
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getSpelling() << RawTriple.str();
    } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
      CmdArgs.push_back("-fpcc-struct-return");
    } else {
      assert(A->getOption().matches(options::OPT_freg_struct_return));
      CmdArgs.push_back("-freg-struct-return");
    }
  }

  if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
    CmdArgs.push_back("-fdefault-calling-conv=stdcall");

  if (Args.hasArg(options::OPT_fenable_matrix)) {
    // enable-matrix is needed by both the LangOpts and by LLVM.
    CmdArgs.push_back("-fenable-matrix");
    CmdArgs.push_back("-mllvm");
    CmdArgs.push_back("-enable-matrix");
  }

  CodeGenOptions::FramePointerKind FPKeepKind =
                  getFramePointerKind(Args, RawTriple);
  const char *FPKeepKindStr = nullptr;
  switch (FPKeepKind) {
  case CodeGenOptions::FramePointerKind::None:
    FPKeepKindStr = "-mframe-pointer=none";
    break;
  case CodeGenOptions::FramePointerKind::NonLeaf:
    FPKeepKindStr = "-mframe-pointer=non-leaf";
    break;
  case CodeGenOptions::FramePointerKind::All:
    FPKeepKindStr = "-mframe-pointer=all";
    break;
  }
  assert(FPKeepKindStr && "unknown FramePointerKind");
  CmdArgs.push_back(FPKeepKindStr);

  if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
                    options::OPT_fno_zero_initialized_in_bss, true))
    CmdArgs.push_back("-fno-zero-initialized-in-bss");

  bool OFastEnabled = isOptimizationLevelFast(Args);
  // If -Ofast is the optimization level, then -fstrict-aliasing should be
  // enabled.  This alias option is being used to simplify the hasFlag logic.
  OptSpecifier StrictAliasingAliasOption =
      OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
  // We turn strict aliasing off by default if we're in CL mode, since MSVC
  // doesn't do any TBAA.
  bool TBAAOnByDefault = !D.IsCLMode();
  if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
                    options::OPT_fno_strict_aliasing, TBAAOnByDefault))
    CmdArgs.push_back("-relaxed-aliasing");
  if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
                    options::OPT_fno_struct_path_tbaa))
    CmdArgs.push_back("-no-struct-path-tbaa");
  if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
                   false))
    CmdArgs.push_back("-fstrict-enums");
  if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
                    true))
    CmdArgs.push_back("-fno-strict-return");
  if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
                   options::OPT_fno_allow_editor_placeholders, false))
    CmdArgs.push_back("-fallow-editor-placeholders");
  if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
                   options::OPT_fno_strict_vtable_pointers,
                   false))
    CmdArgs.push_back("-fstrict-vtable-pointers");
  if (Args.hasFlag(options::OPT_fforce_emit_vtables,
                   options::OPT_fno_force_emit_vtables,
                   false))
    CmdArgs.push_back("-fforce-emit-vtables");
  if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
                    options::OPT_fno_optimize_sibling_calls))
    CmdArgs.push_back("-mdisable-tail-calls");
  if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls,
                   options::OPT_fescaping_block_tail_calls, false))
    CmdArgs.push_back("-fno-escaping-block-tail-calls");

  Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
                  options::OPT_fno_fine_grained_bitfield_accesses);

  Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
                  options::OPT_fno_experimental_relative_cxx_abi_vtables);

  // Handle segmented stacks.
  if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack,
                   false))
    CmdArgs.push_back("-fsplit-stack");

  // -fprotect-parens=0 is default.
  if (Args.hasFlag(options::OPT_fprotect_parens,
                   options::OPT_fno_protect_parens, false))
    CmdArgs.push_back("-fprotect-parens");

  RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs, JA);

  if (Arg *A = Args.getLastArg(options::OPT_fextend_args_EQ)) {
    const llvm::Triple::ArchType Arch = TC.getArch();
    if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
      StringRef V = A->getValue();
      if (V == "64")
        CmdArgs.push_back("-fextend-arguments=64");
      else if (V != "32")
        D.Diag(diag::err_drv_invalid_argument_to_option)
            << A->getValue() << A->getOption().getName();
    } else
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getOption().getName() << TripleStr;
  }

  if (Arg *A = Args.getLastArg(options::OPT_mdouble_EQ)) {
    if (TC.getArch() == llvm::Triple::avr)
      A->render(Args, CmdArgs);
    else
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
  }

  if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) {
    if (TC.getTriple().isX86())
      A->render(Args, CmdArgs);
    else if (TC.getTriple().isPPC() &&
             (A->getOption().getID() != options::OPT_mlong_double_80))
      A->render(Args, CmdArgs);
    else
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
  }

  // Decide whether to use verbose asm. Verbose assembly is the default on
  // toolchains which have the integrated assembler on by default.
  bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault();
  if (!Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
                    IsIntegratedAssemblerDefault))
    CmdArgs.push_back("-fno-verbose-asm");

  // Parse 'none' or '$major.$minor'. Disallow -fbinutils-version=0 because we
  // use that to indicate the MC default in the backend.
  if (Arg *A = Args.getLastArg(options::OPT_fbinutils_version_EQ)) {
    StringRef V = A->getValue();
    unsigned Num;
    if (V == "none")
      A->render(Args, CmdArgs);
    else if (!V.consumeInteger(10, Num) && Num > 0 &&
             (V.empty() || (V.consume_front(".") &&
                            !V.consumeInteger(10, Num) && V.empty())))
      A->render(Args, CmdArgs);
    else
      D.Diag(diag::err_drv_invalid_argument_to_option)
          << A->getValue() << A->getOption().getName();
  }

  // If toolchain choose to use MCAsmParser for inline asm don't pass the
  // option to disable integrated-as explictly.
  if (!TC.useIntegratedAs() && !TC.parseInlineAsmUsingAsmParser())
    CmdArgs.push_back("-no-integrated-as");

  if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
    CmdArgs.push_back("-mdebug-pass");
    CmdArgs.push_back("Structure");
  }
  if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
    CmdArgs.push_back("-mdebug-pass");
    CmdArgs.push_back("Arguments");
  }

  // Enable -mconstructor-aliases except on darwin, where we have to work around
  // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
  // aliases aren't supported.
  if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX())
    CmdArgs.push_back("-mconstructor-aliases");

  // Darwin's kernel doesn't support guard variables; just die if we
  // try to use them.
  if (KernelOrKext && RawTriple.isOSDarwin())
    CmdArgs.push_back("-fforbid-guard-variables");

  if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
                   Triple.isWindowsGNUEnvironment())) {
    CmdArgs.push_back("-mms-bitfields");
  }

  // Non-PIC code defaults to -fdirect-access-external-data while PIC code
  // defaults to -fno-direct-access-external-data. Pass the option if different
  // from the default.
  if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data,
                               options::OPT_fno_direct_access_external_data))
    if (A->getOption().matches(options::OPT_fdirect_access_external_data) !=
        (PICLevel == 0))
      A->render(Args, CmdArgs);

  if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) {
    CmdArgs.push_back("-fno-plt");
  }

  // -fhosted is default.
  // TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to
  // use Freestanding.
  bool Freestanding =
      Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
      KernelOrKext;
  if (Freestanding)
    CmdArgs.push_back("-ffreestanding");

  // This is a coarse approximation of what llvm-gcc actually does, both
  // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
  // complicated ways.
  auto SanitizeArgs = TC.getSanitizerArgs(Args);
  bool AsyncUnwindTables = Args.hasFlag(
      options::OPT_fasynchronous_unwind_tables,
      options::OPT_fno_asynchronous_unwind_tables,
      (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) &&
          !Freestanding);
  bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables,
                                   options::OPT_fno_unwind_tables, false);
  if (AsyncUnwindTables)
    CmdArgs.push_back("-funwind-tables=2");
  else if (UnwindTables)
    CmdArgs.push_back("-funwind-tables=1");

  // Prepare `-aux-target-cpu` and `-aux-target-feature` unless
  // `--gpu-use-aux-triple-only` is specified.
  if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) &&
      (IsCudaDevice || IsHIPDevice)) {
    const ArgList &HostArgs =
        C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None);
    std::string HostCPU =
        getCPUName(D, HostArgs, *TC.getAuxTriple(), /*FromAs*/ false);
    if (!HostCPU.empty()) {
      CmdArgs.push_back("-aux-target-cpu");
      CmdArgs.push_back(Args.MakeArgString(HostCPU));
    }
    getTargetFeatures(D, *TC.getAuxTriple(), HostArgs, CmdArgs,
                      /*ForAS*/ false, /*IsAux*/ true);
  }

  TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());

  // FIXME: Handle -mtune=.
  (void)Args.hasArg(options::OPT_mtune_EQ);

  if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
    StringRef CM = A->getValue();
    if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" ||
        CM == "tiny") {
      if (Triple.isOSAIX() && CM == "medium")
        CmdArgs.push_back("-mcmodel=large");
      else
        A->render(Args, CmdArgs);
    } else {
      D.Diag(diag::err_drv_invalid_argument_to_option)
          << CM << A->getOption().getName();
    }
  }

  if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) {
    StringRef Value = A->getValue();
    unsigned TLSSize = 0;
    Value.getAsInteger(10, TLSSize);
    if (!Triple.isAArch64() || !Triple.isOSBinFormatELF())
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getOption().getName() << TripleStr;
    if (TLSSize != 12 && TLSSize != 24 && TLSSize != 32 && TLSSize != 48)
      D.Diag(diag::err_drv_invalid_int_value)
          << A->getOption().getName() << Value;
    Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ);
  }

  // Add the target cpu
  std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false);
  if (!CPU.empty()) {
    CmdArgs.push_back("-target-cpu");
    CmdArgs.push_back(Args.MakeArgString(CPU));
  }

  RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs);

  // FIXME: For now we want to demote any errors to warnings, when they have
  // been raised for asking the wrong question of scalable vectors, such as
  // asking for the fixed number of elements. This may happen because code that
  // is not yet ported to work for scalable vectors uses the wrong interfaces,
  // whereas the behaviour is actually correct. Emitting a warning helps bring
  // up scalable vector support in an incremental way. When scalable vector
  // support is stable enough, all uses of wrong interfaces should be considered
  // as errors, but until then, we can live with a warning being emitted by the
  // compiler. This way, Clang can be used to compile code with scalable vectors
  // and identify possible issues.
  if (isa<BackendJobAction>(JA)) {
    CmdArgs.push_back("-mllvm");
    CmdArgs.push_back("-treat-scalable-fixed-error-as-warning");
  }

  // These two are potentially updated by AddClangCLArgs.
  codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
  bool EmitCodeView = false;

  // Add clang-cl arguments.
  types::ID InputType = Input.getType();
  if (D.IsCLMode())
    AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);

  DwarfFissionKind DwarfFission = DwarfFissionKind::None;
  renderDebugOptions(TC, D, RawTriple, Args, EmitCodeView,
                     types::isLLVMIR(InputType), CmdArgs, DebugInfoKind,
                     DwarfFission);

  // Add the split debug info name to the command lines here so we
  // can propagate it to the backend.
  bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) &&
                    (TC.getTriple().isOSBinFormatELF() ||
                     TC.getTriple().isOSBinFormatWasm()) &&
                    (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
                     isa<BackendJobAction>(JA));
  if (SplitDWARF) {
    const char *SplitDWARFOut = SplitDebugName(JA, Args, Input, Output);
    CmdArgs.push_back("-split-dwarf-file");
    CmdArgs.push_back(SplitDWARFOut);
    if (DwarfFission == DwarfFissionKind::Split) {
      CmdArgs.push_back("-split-dwarf-output");
      CmdArgs.push_back(SplitDWARFOut);
    }
  }

  // Pass the linker version in use.
  if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
    CmdArgs.push_back("-target-linker-version");
    CmdArgs.push_back(A->getValue());
  }

  // Explicitly error on some things we know we don't support and can't just
  // ignore.
  if (!Args.hasArg(options::OPT_fallow_unsupported)) {
    Arg *Unsupported;
    if (types::isCXX(InputType) && RawTriple.isOSDarwin() &&
        TC.getArch() == llvm::Triple::x86) {
      if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
          (Unsupported = Args.getLastArg(options::OPT_mkernel)))
        D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
            << Unsupported->getOption().getName();
    }
    // The faltivec option has been superseded by the maltivec option.
    if ((Unsupported = Args.getLastArg(options::OPT_faltivec)))
      D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
          << Unsupported->getOption().getName()
          << "please use -maltivec and include altivec.h explicitly";
    if ((Unsupported = Args.getLastArg(options::OPT_fno_altivec)))
      D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
          << Unsupported->getOption().getName() << "please use -mno-altivec";
  }

  Args.AddAllArgs(CmdArgs, options::OPT_v);

  if (Args.getLastArg(options::OPT_H)) {
    CmdArgs.push_back("-H");
    CmdArgs.push_back("-sys-header-deps");
  }
  Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes);

  if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
    CmdArgs.push_back("-header-include-file");
    CmdArgs.push_back(!D.CCPrintHeadersFilename.empty()
                          ? D.CCPrintHeadersFilename.c_str()
                          : "-");
    CmdArgs.push_back("-sys-header-deps");
  }
  Args.AddLastArg(CmdArgs, options::OPT_P);
  Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);

  if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
    CmdArgs.push_back("-diagnostic-log-file");
    CmdArgs.push_back(!D.CCLogDiagnosticsFilename.empty()
                          ? D.CCLogDiagnosticsFilename.c_str()
                          : "-");
  }

  // Give the gen diagnostics more chances to succeed, by avoiding intentional
  // crashes.
  if (D.CCGenDiagnostics)
    CmdArgs.push_back("-disable-pragma-debug-crash");

  // Allow backend to put its diagnostic files in the same place as frontend
  // crash diagnostics files.
  if (Args.hasArg(options::OPT_fcrash_diagnostics_dir)) {
    StringRef Dir = Args.getLastArgValue(options::OPT_fcrash_diagnostics_dir);
    CmdArgs.push_back("-mllvm");
    CmdArgs.push_back(Args.MakeArgString("-crash-diagnostics-dir=" + Dir));
  }

  bool UseSeparateSections = isUseSeparateSections(Triple);

  if (Args.hasFlag(options::OPT_ffunction_sections,
                   options::OPT_fno_function_sections, UseSeparateSections)) {
    CmdArgs.push_back("-ffunction-sections");
  }

  if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) {
    StringRef Val = A->getValue();
    if (Triple.isX86() && Triple.isOSBinFormatELF()) {
      if (Val != "all" && Val != "labels" && Val != "none" &&
          !Val.startswith("list="))
        D.Diag(diag::err_drv_invalid_value)
            << A->getAsString(Args) << A->getValue();
      else
        A->render(Args, CmdArgs);
    } else if (Triple.isNVPTX()) {
      // Do not pass the option to the GPU compilation. We still want it enabled
      // for the host-side compilation, so seeing it here is not an error.
    } else if (Val != "none") {
      // =none is allowed everywhere. It's useful for overriding the option
      // and is the same as not specifying the option.
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
    }
  }

  bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF();
  if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
                   UseSeparateSections || HasDefaultDataSections)) {
    CmdArgs.push_back("-fdata-sections");
  }

  if (!Args.hasFlag(options::OPT_funique_section_names,
                    options::OPT_fno_unique_section_names, true))
    CmdArgs.push_back("-fno-unique-section-names");

  if (Args.hasFlag(options::OPT_funique_internal_linkage_names,
                   options::OPT_fno_unique_internal_linkage_names, false))
    CmdArgs.push_back("-funique-internal-linkage-names");

  if (Args.hasFlag(options::OPT_funique_basic_block_section_names,
                   options::OPT_fno_unique_basic_block_section_names, false))
    CmdArgs.push_back("-funique-basic-block-section-names");

  if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
                               options::OPT_fno_split_machine_functions)) {
    // This codegen pass is only available on x86-elf targets.
    if (Triple.isX86() && Triple.isOSBinFormatELF()) {
      if (A->getOption().matches(options::OPT_fsplit_machine_functions))
        A->render(Args, CmdArgs);
    } else {
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
    }
  }

  Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions,
                  options::OPT_finstrument_functions_after_inlining,
                  options::OPT_finstrument_function_entry_bare);

  // NVPTX/AMDGCN doesn't support PGO or coverage. There's no runtime support
  // for sampling, overhead of call arc collection is way too high and there's
  // no way to collect the output.
  if (!Triple.isNVPTX() && !Triple.isAMDGCN())
    addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs);

  Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);

  // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled.
  if (RawTriple.isPS4CPU() &&
      !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
    PS4cpu::addProfileRTArgs(TC, Args, CmdArgs);
    PS4cpu::addSanitizerArgs(TC, Args, CmdArgs);
  }

  // Pass options for controlling the default header search paths.
  if (Args.hasArg(options::OPT_nostdinc)) {
    CmdArgs.push_back("-nostdsysteminc");
    CmdArgs.push_back("-nobuiltininc");
  } else {
    if (Args.hasArg(options::OPT_nostdlibinc))
      CmdArgs.push_back("-nostdsysteminc");
    Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
    Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
  }

  // Pass the path to compiler resource files.
  CmdArgs.push_back("-resource-dir");
  CmdArgs.push_back(D.ResourceDir.c_str());

  Args.AddLastArg(CmdArgs, options::OPT_working_directory);

  RenderARCMigrateToolOptions(D, Args, CmdArgs);

  // Add preprocessing options like -I, -D, etc. if we are using the
  // preprocessor.
  //
  // FIXME: Support -fpreprocessed
  if (types::getPreprocessedType(InputType) != types::TY_INVALID)
    AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);

  // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
  // that "The compiler can only warn and ignore the option if not recognized".
  // When building with ccache, it will pass -D options to clang even on
  // preprocessed inputs and configure concludes that -fPIC is not supported.
  Args.ClaimAllArgs(options::OPT_D);

  // Manually translate -O4 to -O3; let clang reject others.
  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
    if (A->getOption().matches(options::OPT_O4)) {
      CmdArgs.push_back("-O3");
      D.Diag(diag::warn_O4_is_O3);
    } else {
      A->render(Args, CmdArgs);
    }
  }

  // Warn about ignored options to clang.
  for (const Arg *A :
       Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
    D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
    A->claim();
  }

  for (const Arg *A :
       Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) {
    D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args);
    A->claim();
  }

  claimNoWarnArgs(Args);

  Args.AddAllArgs(CmdArgs, options::OPT_R_Group);

  for (const Arg *A :
       Args.filtered(options::OPT_W_Group, options::OPT__SLASH_wd)) {
    A->claim();
    if (A->getOption().getID() == options::OPT__SLASH_wd) {
      unsigned WarningNumber;
      if (StringRef(A->getValue()).getAsInteger(10, WarningNumber)) {
        D.Diag(diag::err_drv_invalid_int_value)
            << A->getAsString(Args) << A->getValue();
        continue;
      }

      if (auto Group = diagGroupFromCLWarningID(WarningNumber)) {
        CmdArgs.push_back(Args.MakeArgString(
            "-Wno-" + DiagnosticIDs::getWarningOptionForGroup(*Group)));
      }
      continue;
    }
    A->render(Args, CmdArgs);
  }

  if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
    CmdArgs.push_back("-pedantic");
  Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
  Args.AddLastArg(CmdArgs, options::OPT_w);

  // Fixed point flags
  if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point,
                   /*Default=*/false))
    Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);

  if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ))
    A->render(Args, CmdArgs);

  Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
                  options::OPT_fno_experimental_relative_cxx_abi_vtables);

  if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
    A->render(Args, CmdArgs);

  // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
  // (-ansi is equivalent to -std=c89 or -std=c++98).
  //
  // If a std is supplied, only add -trigraphs if it follows the
  // option.
  bool ImplyVCPPCVer = false;
  bool ImplyVCPPCXXVer = false;
  const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
  if (Std) {
    if (Std->getOption().matches(options::OPT_ansi))
      if (types::isCXX(InputType))
        CmdArgs.push_back("-std=c++98");
      else
        CmdArgs.push_back("-std=c89");
    else
      Std->render(Args, CmdArgs);

    // If -f(no-)trigraphs appears after the language standard flag, honor it.
    if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
                                 options::OPT_ftrigraphs,
                                 options::OPT_fno_trigraphs))
      if (A != Std)
        A->render(Args, CmdArgs);
  } else {
    // Honor -std-default.
    //
    // FIXME: Clang doesn't correctly handle -std= when the input language
    // doesn't match. For the time being just ignore this for C++ inputs;
    // eventually we want to do all the standard defaulting here instead of
    // splitting it between the driver and clang -cc1.
    if (!types::isCXX(InputType)) {
      if (!Args.hasArg(options::OPT__SLASH_std)) {
        Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=",
                                  /*Joined=*/true);
      } else
        ImplyVCPPCVer = true;
    }
    else if (IsWindowsMSVC)
      ImplyVCPPCXXVer = true;

    Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
                    options::OPT_fno_trigraphs);

    // HIP headers has minimum C++ standard requirements. Therefore set the
    // default language standard.
    if (IsHIP)
      CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11");
  }

  // GCC's behavior for -Wwrite-strings is a bit strange:
  //  * In C, this "warning flag" changes the types of string literals from
  //    'char[N]' to 'const char[N]', and thus triggers an unrelated warning
  //    for the discarded qualifier.
  //  * In C++, this is just a normal warning flag.
  //
  // Implementing this warning correctly in C is hard, so we follow GCC's
  // behavior for now. FIXME: Directly diagnose uses of a string literal as
  // a non-const char* in C, rather than using this crude hack.
  if (!types::isCXX(InputType)) {
    // FIXME: This should behave just like a warning flag, and thus should also
    // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
    Arg *WriteStrings =
        Args.getLastArg(options::OPT_Wwrite_strings,
                        options::OPT_Wno_write_strings, options::OPT_w);
    if (WriteStrings &&
        WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
      CmdArgs.push_back("-fconst-strings");
  }

  // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
  // during C++ compilation, which it is by default. GCC keeps this define even
  // in the presence of '-w', match this behavior bug-for-bug.
  if (types::isCXX(InputType) &&
      Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
                   true)) {
    CmdArgs.push_back("-fdeprecated-macro");
  }

  // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
  if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
    if (Asm->getOption().matches(options::OPT_fasm))
      CmdArgs.push_back("-fgnu-keywords");
    else
      CmdArgs.push_back("-fno-gnu-keywords");
  }

  if (!ShouldEnableAutolink(Args, TC, JA))
    CmdArgs.push_back("-fno-autolink");

  // Add in -fdebug-compilation-dir if necessary.
  const char *DebugCompilationDir =
      addDebugCompDirArg(Args, CmdArgs, D.getVFS());

  addDebugPrefixMapArg(D, Args, CmdArgs);

  if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
                               options::OPT_ftemplate_depth_EQ)) {
    CmdArgs.push_back("-ftemplate-depth");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
    CmdArgs.push_back("-foperator-arrow-depth");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
    CmdArgs.push_back("-fconstexpr-depth");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
    CmdArgs.push_back("-fconstexpr-steps");
    CmdArgs.push_back(A->getValue());
  }

  if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
    CmdArgs.push_back("-fexperimental-new-constant-interpreter");

  if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
    CmdArgs.push_back("-fbracket-depth");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
                               options::OPT_Wlarge_by_value_copy_def)) {
    if (A->getNumValues()) {
      StringRef bytes = A->getValue();
      CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
    } else
      CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
  }

  if (Args.hasArg(options::OPT_relocatable_pch))
    CmdArgs.push_back("-relocatable-pch");

  if (const Arg *A = Args.getLastArg(options::OPT_fcf_runtime_abi_EQ)) {
    static const char *kCFABIs[] = {
      "standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1",
    };

    if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs))
      D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue();
    else
      A->render(Args, CmdArgs);
  }

  if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
    CmdArgs.push_back("-fconstant-string-class");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
    CmdArgs.push_back("-ftabstop");
    CmdArgs.push_back(A->getValue());
  }

  if (Args.hasFlag(options::OPT_fstack_size_section,
                   options::OPT_fno_stack_size_section, RawTriple.isPS4()))
    CmdArgs.push_back("-fstack-size-section");

  if (Args.hasArg(options::OPT_fstack_usage)) {
    CmdArgs.push_back("-stack-usage-file");

    if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
      SmallString<128> OutputFilename(OutputOpt->getValue());
      llvm::sys::path::replace_extension(OutputFilename, "su");
      CmdArgs.push_back(Args.MakeArgString(OutputFilename));
    } else
      CmdArgs.push_back(
          Args.MakeArgString(Twine(getBaseInputStem(Args, Inputs)) + ".su"));
  }

  CmdArgs.push_back("-ferror-limit");
  if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
    CmdArgs.push_back(A->getValue());
  else
    CmdArgs.push_back("19");

  if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
    CmdArgs.push_back("-fmacro-backtrace-limit");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
    CmdArgs.push_back("-ftemplate-backtrace-limit");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
    CmdArgs.push_back("-fconstexpr-backtrace-limit");
    CmdArgs.push_back(A->getValue());
  }

  if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
    CmdArgs.push_back("-fspell-checking-limit");
    CmdArgs.push_back(A->getValue());
  }

  // Pass -fmessage-length=.
  unsigned MessageLength = 0;
  if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
    StringRef V(A->getValue());
    if (V.getAsInteger(0, MessageLength))
      D.Diag(diag::err_drv_invalid_argument_to_option)
          << V << A->getOption().getName();
  } else {
    // If -fmessage-length=N was not specified, determine whether this is a
    // terminal and, if so, implicitly define -fmessage-length appropriately.
    MessageLength = llvm::sys::Process::StandardErrColumns();
  }
  if (MessageLength != 0)
    CmdArgs.push_back(
        Args.MakeArgString("-fmessage-length=" + Twine(MessageLength)));

  // -fvisibility= and -fvisibility-ms-compat are of a piece.
  if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
                                     options::OPT_fvisibility_ms_compat)) {
    if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
      CmdArgs.push_back("-fvisibility");
      CmdArgs.push_back(A->getValue());
    } else {
      assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
      CmdArgs.push_back("-fvisibility");
      CmdArgs.push_back("hidden");
      CmdArgs.push_back("-ftype-visibility");
      CmdArgs.push_back("default");
    }
  }

  if (!RawTriple.isPS4())
    if (const Arg *A =
            Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
                            options::OPT_fno_visibility_from_dllstorageclass)) {
      if (A->getOption().matches(
              options::OPT_fvisibility_from_dllstorageclass)) {
        CmdArgs.push_back("-fvisibility-from-dllstorageclass");
        Args.AddLastArg(CmdArgs, options::OPT_fvisibility_dllexport_EQ);
        Args.AddLastArg(CmdArgs, options::OPT_fvisibility_nodllstorageclass_EQ);
        Args.AddLastArg(CmdArgs, options::OPT_fvisibility_externs_dllimport_EQ);
        Args.AddLastArg(CmdArgs,
                        options::OPT_fvisibility_externs_nodllstorageclass_EQ);
      }
    }

  if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) {
    if (Triple.isOSAIX())
      CmdArgs.push_back("-mignore-xcoff-visibility");
    else
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
  }


  if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden,
                    options::OPT_fno_visibility_inlines_hidden, false))
    CmdArgs.push_back("-fvisibility-inlines-hidden");

  Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var,
                           options::OPT_fno_visibility_inlines_hidden_static_local_var);
  Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
  Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);

  if (Args.hasFlag(options::OPT_fnew_infallible,
                   options::OPT_fno_new_infallible, false))
    CmdArgs.push_back("-fnew-infallible");

  if (Args.hasFlag(options::OPT_fno_operator_names,
                   options::OPT_foperator_names, false))
    CmdArgs.push_back("-fno-operator-names");

  // Forward -f (flag) options which we can pass directly.
  Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
  Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
  Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs);
  Args.AddLastArg(CmdArgs, options::OPT_femulated_tls,
                  options::OPT_fno_emulated_tls);

  // AltiVec-like language extensions aren't relevant for assembling.
  if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm)
    Args.AddLastArg(CmdArgs, options::OPT_fzvector);

  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
  Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);

  // Forward flags for OpenMP. We don't do this if the current action is an
  // device offloading action other than OpenMP.
  if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
                   options::OPT_fno_openmp, false) &&
      (JA.isDeviceOffloading(Action::OFK_None) ||
       JA.isDeviceOffloading(Action::OFK_OpenMP))) {
    switch (D.getOpenMPRuntime(Args)) {
    case Driver::OMPRT_OMP:
    case Driver::OMPRT_IOMP5:
      // Clang can generate useful OpenMP code for these two runtime libraries.
      CmdArgs.push_back("-fopenmp");

      // If no option regarding the use of TLS in OpenMP codegeneration is
      // given, decide a default based on the target. Otherwise rely on the
      // options and pass the right information to the frontend.
      if (!Args.hasFlag(options::OPT_fopenmp_use_tls,
                        options::OPT_fnoopenmp_use_tls, /*Default=*/true))
        CmdArgs.push_back("-fnoopenmp-use-tls");
      Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
                      options::OPT_fno_openmp_simd);
      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder);
      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
      if (!Args.hasFlag(options::OPT_fopenmp_extensions,
                        options::OPT_fno_openmp_extensions, /*Default=*/true))
        CmdArgs.push_back("-fno-openmp-extensions");
      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ);
      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ);
      Args.AddAllArgs(CmdArgs,
                      options::OPT_fopenmp_cuda_teams_reduction_recs_num_EQ);
      if (Args.hasFlag(options::OPT_fopenmp_optimistic_collapse,
                       options::OPT_fno_openmp_optimistic_collapse,
                       /*Default=*/false))
        CmdArgs.push_back("-fopenmp-optimistic-collapse");

      // When in OpenMP offloading mode with NVPTX target, forward
      // cuda-mode flag
      if (Args.hasFlag(options::OPT_fopenmp_cuda_mode,
                       options::OPT_fno_openmp_cuda_mode, /*Default=*/false))
        CmdArgs.push_back("-fopenmp-cuda-mode");

      // When in OpenMP offloading mode, enable or disable the new device
      // runtime.
      if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime,
                       options::OPT_fno_openmp_target_new_runtime,
                       /*Default=*/true))
        CmdArgs.push_back("-fopenmp-target-new-runtime");

      // When in OpenMP offloading mode, enable debugging on the device.
      Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
      if (Args.hasFlag(options::OPT_fopenmp_target_debug,
                       options::OPT_fno_openmp_target_debug, /*Default=*/false))
        CmdArgs.push_back("-fopenmp-target-debug");

      // When in OpenMP offloading mode with NVPTX target, check if full runtime
      // is required.
      if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime,
                       options::OPT_fno_openmp_cuda_force_full_runtime,
                       /*Default=*/false))
        CmdArgs.push_back("-fopenmp-cuda-force-full-runtime");

      // When in OpenMP offloading mode, forward assumptions information about
      // thread and team counts in the device.
      if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
                       options::OPT_fno_openmp_assume_teams_oversubscription,
                       /*Default=*/false))
        CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");
      if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,
                       options::OPT_fno_openmp_assume_threads_oversubscription,
                       /*Default=*/false))
        CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
      break;
    default:
      // By default, if Clang doesn't know how to generate useful OpenMP code
      // for a specific runtime library, we just don't pass the '-fopenmp' flag
      // down to the actual compilation.
      // FIXME: It would be better to have a mode which *only* omits IR
      // generation based on the OpenMP support so that we get consistent
      // semantic analysis, etc.
      break;
    }
  } else {
    Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
                    options::OPT_fno_openmp_simd);
    Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
    if (!Args.hasFlag(options::OPT_fopenmp_extensions,
                      options::OPT_fno_openmp_extensions, /*Default=*/true))
      CmdArgs.push_back("-fno-openmp-extensions");
  }

  SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);

  const XRayArgs &XRay = TC.getXRayArgs();
  XRay.addArgs(TC, Args, CmdArgs, InputType);

  for (const auto &Filename :
       Args.getAllArgValues(options::OPT_fprofile_list_EQ)) {
    if (D.getVFS().exists(Filename))
      CmdArgs.push_back(Args.MakeArgString("-fprofile-list=" + Filename));
    else
      D.Diag(clang::diag::err_drv_no_such_file) << Filename;
  }

  if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
    StringRef S0 = A->getValue(), S = S0;
    unsigned Size, Offset = 0;
    if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86())
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << A->getAsString(Args) << TripleStr;
    else if (S.consumeInteger(10, Size) ||
             (!S.empty() && (!S.consume_front(",") ||
                             S.consumeInteger(10, Offset) || !S.empty())))
      D.Diag(diag::err_drv_invalid_argument_to_option)
          << S0 << A->getOption().getName();
    else if (Size < Offset)
      D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument);
    else {
      CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size)));
      CmdArgs.push_back(Args.MakeArgString(
          "-fpatchable-function-entry-offset=" + Twine(Offset)));
    }
  }

  if (TC.SupportsProfiling()) {
    Args.AddLastArg(CmdArgs, options::OPT_pg);

    llvm::Triple::ArchType Arch = TC.getArch();
    if (Arg *A = Args.getLastArg(options::OPT_mfentry)) {
      if (Arch == llvm::Triple::systemz || TC.getTriple().isX86())
        A->render(Args, CmdArgs);
      else
        D.Diag(diag::err_drv_unsupported_opt_for_target)
            << A->getAsString(Args) << TripleStr;
    }
    if (Arg *A = Args.getLastArg(options::OPT_mnop_mcount)) {
      if (Arch == llvm::Triple::systemz)
        A->render(Args, CmdArgs);
      else
        D.Diag(diag::err_drv_unsupported_opt_for_target)
            << A->getAsString(Args) << TripleStr;
    }
    if (Arg *A = Args.getLastArg(options::OPT_mrecord_mcount)) {
      if (Arch == llvm::Triple::systemz)
        A->render(Args, CmdArgs);
      else
        D.Diag(diag::err_drv_unsupported_opt_for_target)
            << A->getAsString(Args) << TripleStr;
    }
  }

  if (Args.getLastArg(options::OPT_fapple_kext) ||
      (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
    CmdArgs.push_back("-fapple-kext");

  Args.AddLastArg(CmdArgs, options::OPT_altivec_src_compat);
  Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions_EQ);
  Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
  Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
  Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
  Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
  Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
  Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
  Args.AddLastArg(CmdArgs, options::OPT_malign_double);
  Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);

  if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
    CmdArgs.push_back("-ftrapv-handler");
    CmdArgs.push_back(A->getValue());
  }

  Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);

  // -fno-strict-overflow implies -fwrapv if it isn't disabled, but
  // -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
  if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
    if (A->getOption().matches(options::OPT_fwrapv))
      CmdArgs.push_back("-fwrapv");
  } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
                                      options::OPT_fno_strict_overflow)) {
    if (A->getOption().matches(options::OPT_fno_strict_overflow))
      CmdArgs.push_back("-fwrapv");
  }

  if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
                               options::OPT_fno_reroll_loops))
    if (A->getOption().matches(options::OPT_freroll_loops))
      CmdArgs.push_back("-freroll-loops");

  Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
                  options::OPT_fno_finite_loops);

  Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
  Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
                  options::OPT_fno_unroll_loops);

  Args.AddLastArg(CmdArgs, options::OPT_pthread);

  if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
                   options::OPT_mno_speculative_load_hardening, false))
    CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));

  RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
  RenderSCPOptions(TC, Args, CmdArgs);
  RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);

  Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ);

  // Translate -mstackrealign
  if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
                   false))
    CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));

  if (Args.hasArg(options::OPT_mstack_alignment)) {
    StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
    CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
  }

  if (Args.hasArg(options::OPT_mstack_probe_size)) {
    StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size);

    if (!Size.empty())
      CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size));
    else
      CmdArgs.push_back("-mstack-probe-size=0");
  }

  if (!Args.hasFlag(options::OPT_mstack_arg_probe,
                    options::OPT_mno_stack_arg_probe, true))
    CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe"));

  if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
                               options::OPT_mno_restrict_it)) {
    if (A->getOption().matches(options::OPT_mrestrict_it)) {
      CmdArgs.push_back("-mllvm");
      CmdArgs.push_back("-arm-restrict-it");
    } else {
      CmdArgs.push_back("-mllvm");
      CmdArgs.push_back("-arm-no-restrict-it");
    }
  } else if (Triple.isOSWindows() &&
             (Triple.getArch() == llvm::Triple::arm ||
              Triple.getArch() == llvm::Triple::thumb)) {
    // Windows on ARM expects restricted IT blocks
    CmdArgs.push_back("-mllvm");
    CmdArgs.push_back("-arm-restrict-it");
  }

  // Forward -cl options to -cc1
  RenderOpenCLOptions(Args, CmdArgs, InputType);

  if (IsHIP) {
    if (Args.hasFlag(options::OPT_fhip_new_launch_api,
                     options::OPT_fno_hip_new_launch_api, true))
      CmdArgs.push_back("-fhip-new-launch-api");
    if (Args.hasFlag(options::OPT_fgpu_allow_device_init,
                     options::OPT_fno_gpu_allow_device_init, false))
      CmdArgs.push_back("-fgpu-allow-device-init");
  }

  if (IsCuda || IsHIP) {
    if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
      CmdArgs.push_back("-fgpu-rdc");
    if (Args.hasFlag(options::OPT_fgpu_defer_diag,
                     options::OPT_fno_gpu_defer_diag, false))
      CmdArgs.push_back("-fgpu-defer-diag");
    if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads,
                     options::OPT_fno_gpu_exclude_wrong_side_overloads,
                     false)) {
      CmdArgs.push_back("-fgpu-exclude-wrong-side-overloads");
      CmdArgs.push_back("-fgpu-defer-diag");
    }
  }

  if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
    CmdArgs.push_back(
        Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
  }

  // Forward -f options with positive and negative forms; we translate these by
  // hand.  Do not propagate PGO options to the GPU-side compilations as the
  // profile info is for the host-side compilation only.
  if (!(IsCudaDevice || IsHIPDevice)) {
    if (Arg *A = getLastProfileSampleUseArg(Args)) {
      auto *PGOArg = Args.getLastArg(
          options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ,
          options::OPT_fcs_profile_generate,
          options::OPT_fcs_profile_generate_EQ, options::OPT_fprofile_use,
          options::OPT_fprofile_use_EQ);
      if (PGOArg)
        D.Diag(diag::err_drv_argument_not_allowed_with)
            << "SampleUse with PGO options";

      StringRef fname = A->getValue();
      if (!llvm::sys::fs::exists(fname))
        D.Diag(diag::err_drv_no_such_file) << fname;
      else
        A->render(Args, CmdArgs);
    }
    Args.AddLastArg(CmdArgs, options::OPT_fprofile_remapping_file_EQ);

    if (Args.hasFlag(options::OPT_fpseudo_probe_for_profiling,
                     options::OPT_fno_pseudo_probe_for_profiling, false)) {
      CmdArgs.push_back("-fpseudo-probe-for-profiling");
      // Enforce -funique-internal-linkage-names if it's not explicitly turned
      // off.
      if (Args.hasFlag(options::OPT_funique_internal_linkage_names,
                       options::OPT_fno_unique_internal_linkage_names, true))
        CmdArgs.push_back("-funique-internal-linkage-names");
    }
  }
  RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs);

  if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
                    options::OPT_fno_assume_sane_operator_new))
    CmdArgs.push_back("-fno-assume-sane-operator-new");

  // -fblocks=0 is default.
  if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
                   TC.IsBlocksDefault()) ||
      (Args.hasArg(options::OPT_fgnu_runtime) &&
       Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
       !Args.hasArg(options::OPT_fno_blocks))) {
    CmdArgs.push_back("-fblocks");

    if (!Args.hasArg(options::OPT_fgnu_runtime) && !TC.hasBlocksRuntime())
      CmdArgs.push_back("-fblocks-runtime-optional");
  }

  // -fencode-extended-block-signature=1 is default.
  if (TC.IsEncodeExtendedBlockSignatureDefault())
    CmdArgs.push_back("-fencode-extended-block-signature");

  if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
                   false) &&
      types::isCXX(InputType)) {
    CmdArgs.push_back("-fcoroutines-ts");
  }

  Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
                  options::OPT_fno_double_square_bracket_attributes);

  // -faccess-control is default.
  if (Args.hasFlag(options::OPT_fno_access_control,
                   options::OPT_faccess_control, false))
    CmdArgs.push_back("-fno-access-control");

  // -felide-constructors is the default.
  if (Args.hasFlag(options::OPT_fno_elide_constructors,
                   options::OPT_felide_constructors, false))
    CmdArgs.push_back("-fno-elide-constructors");

  ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();

  if (KernelOrKext || (types::isCXX(InputType) &&
                       (RTTIMode == ToolChain::RM_Disabled)))
    CmdArgs.push_back("-fno-rtti");

  // -fshort-enums=0 is default for all architectures except Hexagon and z/OS.
  if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums,
                   TC.getArch() == llvm::Triple::hexagon || Triple.isOSzOS()))
    CmdArgs.push_back("-fshort-enums");

  RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs);

  // -fuse-cxa-atexit is default.
  if (!Args.hasFlag(
          options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
          !RawTriple.isOSAIX() && !RawTriple.isOSWindows() &&
              TC.getArch() != llvm::Triple::xcore &&
              ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) ||
               RawTriple.hasEnvironment())) ||
      KernelOrKext)
    CmdArgs.push_back("-fno-use-cxa-atexit");

  if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit,
                   options::OPT_fno_register_global_dtors_with_atexit,
                   RawTriple.isOSDarwin() && !KernelOrKext))
    CmdArgs.push_back("-fregister-global-dtors-with-atexit");

  // -fno-use-line-directives is default.
  if (Args.hasFlag(options::OPT_fuse_line_directives,
                   options::OPT_fno_use_line_directives, false))
    CmdArgs.push_back("-fuse-line-directives");

  // -fno-minimize-whitespace is default.
  if (Args.hasFlag(options::OPT_fminimize_whitespace,
                   options::OPT_fno_minimize_whitespace, false)) {
    types::ID InputType = Inputs[0].getType();
    if (!isDerivedFromC(InputType))
      D.Diag(diag::err_drv_minws_unsupported_input_type)
          << types::getTypeName(InputType);
    CmdArgs.push_back("-fminimize-whitespace");
  }

  // -fms-extensions=0 is default.
  if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
                   IsWindowsMSVC))
    CmdArgs.push_back("-fms-extensions");

  // -fms-compatibility=0 is default.
  bool IsMSVCCompat = Args.hasFlag(
      options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility,
      (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
                                     options::OPT_fno_ms_extensions, true)));
  if (IsMSVCCompat)
    CmdArgs.push_back("-fms-compatibility");

  // Handle -fgcc-version, if present.
  VersionTuple GNUCVer;
  if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
    // Check that the version has 1 to 3 components and the minor and patch
    // versions fit in two decimal digits.
    StringRef Val = A->getValue();
    Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable.
    bool Invalid = GNUCVer.tryParse(Val);
    unsigned Minor = GNUCVer.getMinor().getValueOr(0);
    unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
    if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
      D.Diag(diag::err_drv_invalid_value)
          << A->getAsString(Args) << A->getValue();
    }
  } else if (!IsMSVCCompat) {
    // Imitate GCC 4.2.1 by default if -fms-compatibility is not in effect.
    GNUCVer = VersionTuple(4, 2, 1);
  }
  if (!GNUCVer.empty()) {
    CmdArgs.push_back(
        Args.MakeArgString("-fgnuc-version=" + GNUCVer.getAsString()));
  }

  VersionTuple MSVT = TC.computeMSVCVersion(&D, Args);
  if (!MSVT.empty())
    CmdArgs.push_back(
        Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));

  bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
  if (ImplyVCPPCVer) {
    StringRef LanguageStandard;
    if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
      Std = StdArg;
      LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
                             .Case("c11", "-std=c11")
                             .Case("c17", "-std=c17")
                             .Default("");
      if (LanguageStandard.empty())
        D.Diag(clang::diag::warn_drv_unused_argument)
            << StdArg->getAsString(Args);
    }
    CmdArgs.push_back(LanguageStandard.data());
  }
  if (ImplyVCPPCXXVer) {
    StringRef LanguageStandard;
    if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
      Std = StdArg;
      LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
                             .Case("c++14", "-std=c++14")
                             .Case("c++17", "-std=c++17")
                             .Case("c++20", "-std=c++20")
                             .Case("c++latest", "-std=c++2b")
                             .Default("");
      if (LanguageStandard.empty())
        D.Diag(clang::diag::warn_drv_unused_argument)
            << StdArg->getAsString(Args);
    }

    if (LanguageStandard.empty()) {
      if (IsMSVC2015Compatible)
        LanguageStandard = "-std=c++14";
      else
        LanguageStandard = "-std=c++11";
    }

    CmdArgs.push_back(LanguageStandard.data());
  }

  // -fno-borland-extensions is default.
  if (Args.hasFlag(options::OPT_fborland_extensions,
                   options::OPT_fno_borland_extensions, false))
    CmdArgs.push_back("-fborland-extensions");

  // -fno-declspec is default, except for PS4.
  if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
                   RawTriple.isPS4()))
    CmdArgs.push_back("-fdeclspec");
  else if (Args.hasArg(options::OPT_fno_declspec))
    CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.

  // -fthreadsafe-static is default, except for MSVC compatibility versions less
  // than 19.
  if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
                    options::OPT_fno_threadsafe_statics,
                    !types::isOpenCL(InputType) &&
                        (!IsWindowsMSVC || IsMSVC2015Compatible)))
    CmdArgs.push_back("-fno-threadsafe-statics");

  // -fno-delayed-template-parsing is default, except when targeting MSVC.
  // Many old Windows SDK versions require this to parse.
  // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their
  // compiler. We should be able to disable this by default at some point.
  if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
                   options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
    CmdArgs.push_back("-fdelayed-template-parsing");

  // -fgnu-keywords default varies depending on language; only pass if
  // specified.
  Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords,
                  options::OPT_fno_gnu_keywords);

  if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
                   false))
    CmdArgs.push_back("-fgnu89-inline");

  if (Args.hasArg(options::OPT_fno_inline))
    CmdArgs.push_back("-fno-inline");

  Args.AddLastArg(CmdArgs, options::OPT_finline_functions,
                  options::OPT_finline_hint_functions,
                  options::OPT_fno_inline_functions);

  // FIXME: Find a better way to determine whether the language has modules
  // support by default, or just assume that all languages do.
  bool HaveModules =
      Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") ||
              Std->containsValue("c++latest"));
  RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);

  if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
                   options::OPT_fno_pch_validate_input_files_content, false))
    CmdArgs.push_back("-fvalidate-ast-input-files-content");
  if (Args.hasFlag(options::OPT_fpch_instantiate_templates,
                   options::OPT_fno_pch_instantiate_templates, false))
    CmdArgs.push_back("-fpch-instantiate-templates");
  if (Args.hasFlag(options::OPT_fpch_codegen, options::OPT_fno_pch_codegen,
                   false))
    CmdArgs.push_back("-fmodules-codegen");
  if (Args.hasFlag(options::OPT_fpch_debuginfo, options::OPT_fno_pch_debuginfo,
                   false))
    CmdArgs.push_back("-fmodules-debuginfo");

  Args.AddLastArg(CmdArgs, options::OPT_flegacy_pass_manager,
                  options::OPT_fno_legacy_pass_manager);

  ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind);
  RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None,
                    Input, CmdArgs);

  if (types::isObjC(Input.getType()) &&
      Args.hasFlag(options::OPT_fobjc_encode_cxx_class_template_spec,
                   options::OPT_fno_objc_encode_cxx_class_template_spec,
                   !Runtime.isNeXTFamily()))
    CmdArgs.push_back("-fobjc-encode-cxx-class-template-spec");

  if (Args.hasFlag(options::OPT_fapplication_extension,
                   options::OPT_fno_application_extension, false))
    CmdArgs.push_back("-fapplication-extension");

  // Handle GCC-style exception args.
  bool EH = false;
  if (!C.getDriver().IsCLMode())
    EH = addExceptionArgs(Args, InputType, TC, KernelOrKext, Runtime, CmdArgs);

  // Handle exception personalities
  Arg *A = Args.getLastArg(
      options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions,
      options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions);
  if (A) {
    const Option &Opt = A->getOption();
    if (Opt.matches(options::OPT_fsjlj_exceptions))
      CmdArgs.push_back("-exception-model=sjlj");
    if (Opt.matches(options::OPT_fseh_exceptions))
      CmdArgs.push_back("-exception-model=seh");
    if (Opt.matches(options::OPT_fdwarf_exceptions))
      CmdArgs.push_back("-exception-model=dwarf");
    if (Opt.matches(options::OPT_fwasm_exceptions))
      CmdArgs.push_back("-exception-model=wasm");
  } else {
    switch (TC.GetExceptionModel(Args)) {
    default:
      break;
    case llvm::ExceptionHandling::DwarfCFI:
      CmdArgs.push_back("-exception-model=dwarf");
      break;
    case llvm::ExceptionHandling::SjLj:
      CmdArgs.push_back("-exception-model=sjlj");
      break;
    case llvm::ExceptionHandling::WinEH:
      CmdArgs.push_back("-exception-model=seh");
      break;
    }
  }

  // C++ "sane" operator new.
  if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
                    options::OPT_fno_assume_sane_operator_new))
    CmdArgs.push_back("-fno-assume-sane-operator-new");

  // -frelaxed-template-template-args is off by default, as it is a severe
  // breaking change until a corresponding change to template partial ordering
  // is provided.
  if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
                   options::OPT_fno_relaxed_template_template_args, false))
    CmdArgs.push_back("-frelaxed-template-template-args");

  // -fsized-deallocation is off by default, as it is an ABI-breaking change for
  // most platforms.
  if (Args.hasFlag(options::OPT_fsized_deallocation,
                   options::OPT_fno_sized_deallocation, false))
    CmdArgs.push_back("-fsized-deallocation");

  // -faligned-allocation is on by default in C++17 onwards and otherwise off
  // by default.
  if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation,
                               options::OPT_fno_aligned_allocation,
                               options::OPT_faligned_new_EQ)) {
    if (A->getOption().matches(options::OPT_fno_aligned_allocation))
      CmdArgs.push_back("-fno-aligned-allocation");
    else
      CmdArgs.push_back("-faligned-allocation");
  }

  // The default new alignment can be specified using a dedicated option or via
  // a GCC-compatible option that also turns on aligned allocation.
  if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ,
                               options::OPT_faligned_new_EQ))
    CmdArgs.push_back(
        Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue()));

  // -fconstant-cfstrings is default, and may be subject to argument translation
  // on Darwin.
  if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
                    options::OPT_fno_constant_cfstrings) ||
      !Args.hasFlag(options::OPT_mconstant_cfstrings,
                    options::OPT_mno_constant_cfstrings))
    CmdArgs.push_back("-fno-constant-cfstrings");

  // -fno-pascal-strings is default, only pass non-default.
  if (Args.hasFlag(options::OPT_fpascal_strings,
                   options::OPT_fno_pascal_strings, false))
    CmdArgs.push_back("-fpascal-strings");

  // Honor -fpack-struct= and -fpack-struct, if given. Note that
  // -fno-pack-struct doesn't apply to -fpack-struct=.
  if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
    std::string PackStructStr = "-fpack-struct=";
    PackStructStr += A->getValue();
    CmdArgs.push_back(Args.MakeArgString(PackStructStr));
  } else if (Args.hasFlag(options::OPT_fpack_struct,
                          options::OPT_fno_pack_struct, false)) {
    CmdArgs.push_back("-fpack-struct=1");
  }

  // Handle -fmax-type-align=N and -fno-type-align
  bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
  if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
    if (!SkipMaxTypeAlign) {
      std::string MaxTypeAlignStr = "-fmax-type-align=";
      MaxTypeAlignStr += A->getValue();
      CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
    }
  } else if (RawTriple.isOSDarwin()) {
    if (!SkipMaxTypeAlign) {
      std::string MaxTypeAlignStr = "-fmax-type-align=16";
      CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
    }
  }

  if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true))
    CmdArgs.push_back("-Qn");

  // -fno-common is the default, set -fcommon only when that flag is set.
  if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false))
    CmdArgs.push_back("-fcommon");

  // -fsigned-bitfields is default, and clang doesn't yet support
  // -funsigned-bitfields.
  if (!Args.hasFlag(options::OPT_fsigned_bitfields,
                    options::OPT_funsigned_bitfields))
    D.Diag(diag::warn_drv_clang_unsupported)
        << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);

  // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
  if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
    D.Diag(diag::err_drv_clang_unsupported)
        << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);

  // -finput_charset=UTF-8 is default. Reject others
  if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) {
    StringRef value = inputCharset->getValue();
    if (!value.equals_insensitive("utf-8"))
      D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args)
                                          << value;
  }

  // -fexec_charset=UTF-8 is default. Reject others
  if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) {
    StringRef value = execCharset->getValue();
    if (!value.equals_insensitive("utf-8"))
      D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args)
                                          << value;
  }

  RenderDiagnosticsOptions(D, Args, CmdArgs);

  // -fno-asm-blocks is default.
  if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
                   false))
    CmdArgs.push_back("-fasm-blocks");

  // -fgnu-inline-asm is default.
  if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
                    options::OPT_fno_gnu_inline_asm, true))
    CmdArgs.push_back("-fno-gnu-inline-asm");

  // Enable vectorization per default according to the optimization level
  // selected. For optimization levels that want vectorization we use the alias
  // option to simplify the hasFlag logic.
  bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
  OptSpecifier VectorizeAliasOption =
      EnableVec ? options::OPT_O_Group : options::OPT_fvectorize;
  if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
                   options::OPT_fno_vectorize, EnableVec))
    CmdArgs.push_back("-vectorize-loops");

  // -fslp-vectorize is enabled based on the optimization level selected.
  bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
  OptSpecifier SLPVectAliasOption =
      EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize;
  if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
                   options::OPT_fno_slp_vectorize, EnableSLPVec))
    CmdArgs.push_back("-vectorize-slp");

  ParseMPreferVectorWidth(D, Args, CmdArgs);

  Args.AddLastArg(CmdArgs, options::OPT_fshow_overloads_EQ);
  Args.AddLastArg(CmdArgs,
                  options::OPT_fsanitize_undefined_strip_path_components_EQ);

  // -fdollars-in-identifiers default varies depending on platform and
  // language; only pass if specified.
  if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
                               options::OPT_fno_dollars_in_identifiers)) {
    if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
      CmdArgs.push_back("-fdollars-in-identifiers");
    else
      CmdArgs.push_back("-fno-dollars-in-identifiers");
  }

  // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
  // practical purposes.
  if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
                               options::OPT_fno_unit_at_a_time)) {
    if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
      D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
  }

  if (Args.hasFlag(options::OPT_fapple_pragma_pack,
                   options::OPT_fno_apple_pragma_pack, false))
    CmdArgs.push_back("-fapple-pragma-pack");

  if (Args.hasFlag(options::OPT_fxl_pragma_pack,
                   options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX()))
    CmdArgs.push_back("-fxl-pragma-pack");

  // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
  if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple))
    renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA);

  bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
                                     options::OPT_fno_rewrite_imports, false);
  if (RewriteImports)
    CmdArgs.push_back("-frewrite-imports");

  // Enable rewrite includes if the user's asked for it or if we're generating
  // diagnostics.
  // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
  // nice to enable this when doing a crashdump for modules as well.
  if (Args.hasFlag(options::OPT_frewrite_includes,
                   options::OPT_fno_rewrite_includes, false) ||
      (C.isForDiagnostics() && !HaveModules))
    CmdArgs.push_back("-frewrite-includes");

  // Only allow -traditional or -traditional-cpp outside in preprocessing modes.
  if (Arg *A = Args.getLastArg(options::OPT_traditional,
                               options::OPT_traditional_cpp)) {
    if (isa<PreprocessJobAction>(JA))
      CmdArgs.push_back("-traditional-cpp");
    else
      D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
  }

  Args.AddLastArg(CmdArgs, options::OPT_dM);
  Args.AddLastArg(CmdArgs, options::OPT_dD);

  Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ);

  // Handle serialized diagnostics.
  if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
    CmdArgs.push_back("-serialize-diagnostic-file");
    CmdArgs.push_back(Args.MakeArgString(A->getValue()));
  }

  if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
    CmdArgs.push_back("-fretain-comments-from-system-headers");

  // Forward -fcomment-block-commands to -cc1.
  Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
  // Forward -fparse-all-comments to -cc1.
  Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments);

  // Turn -fplugin=name.so into -load name.so
  for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) {
    CmdArgs.push_back("-load");
    CmdArgs.push_back(A->getValue());
    A->claim();
  }

  // Turn -fplugin-arg-pluginname-key=value into
  // -plugin-arg-pluginname key=value
  // GCC has an actual plugin_argument struct with key/value pairs that it
  // passes to its plugins, but we don't, so just pass it on as-is.
  //
  // The syntax for -fplugin-arg- is ambiguous if both plugin name and
  // argument key are allowed to contain dashes. GCC therefore only
  // allows dashes in the key. We do the same.
  for (const Arg *A : Args.filtered(options::OPT_fplugin_arg)) {
    auto ArgValue = StringRef(A->getValue());
    auto FirstDashIndex = ArgValue.find('-');
    StringRef PluginName = ArgValue.substr(0, FirstDashIndex);
    StringRef Arg = ArgValue.substr(FirstDashIndex + 1);

    A->claim();
    if (FirstDashIndex == StringRef::npos || Arg.empty()) {
      if (PluginName.empty()) {
        D.Diag(diag::warn_drv_missing_plugin_name) << A->getAsString(Args);
      } else {
        D.Diag(diag::warn_drv_missing_plugin_arg)
            << PluginName << A->getAsString(Args);
      }
      continue;
    }

    CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-arg-") + PluginName));
    CmdArgs.push_back(Args.MakeArgString(Arg));
  }

  // Forward -fpass-plugin=name.so to -cc1.
  for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) {
    CmdArgs.push_back(
        Args.MakeArgString(Twine("-fpass-plugin=") + A->getValue()));
    A->claim();
  }

  // Setup statistics file output.
  SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
  if (!StatsFile.empty())
    CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile));

  // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
  // parser.
  // -finclude-default-header flag is for preprocessor,
  // do not pass it to other cc1 commands when save-temps is enabled
  if (C.getDriver().isSaveTempsEnabled() &&
      !isa<PreprocessJobAction>(JA)) {
    for (auto Arg : Args.filtered(options::OPT_Xclang)) {
      Arg->claim();
      if (StringRef(Arg->getValue()) != "-finclude-default-header")
        CmdArgs.push_back(Arg->getValue());
    }
  }
  else {
    Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
  }
  for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
    A->claim();

    // We translate this by hand to the -cc1 argument, since nightly test uses
    // it and developers have been trained to spell it with -mllvm. Both
    // spellings are now deprecated and should be removed.
    if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") {
      CmdArgs.push_back("-disable-llvm-optzns");
    } else {
      A->render(Args, CmdArgs);
    }
  }

  // With -save-temps, we want to save the unoptimized bitcode output from the
  // CompileJobAction, use -disable-llvm-passes to get pristine IR generated
  // by the frontend.
  // When -fembed-bitcode is enabled, optimized bitcode is emitted because it
  // has slightly different breakdown between stages.
  // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of
  // pristine IR generated by the frontend. Ideally, a new compile action should
  // be added so both IR can be captured.
  if ((C.getDriver().isSaveTempsEnabled() ||
       JA.isHostOffloading(Action::OFK_OpenMP)) &&
      !(C.getDriver().embedBitcodeInObject() && !IsUsingLTO) &&
      isa<CompileJobAction>(JA))
    CmdArgs.push_back("-disable-llvm-passes");

  Args.AddAllArgs(CmdArgs, options::OPT_undef);

  const char *Exec = D.getClangProgramPath();

  // Optionally embed the -cc1 level arguments into the debug info or a
  // section, for build analysis.
  // Also record command line arguments into the debug info if
  // -grecord-gcc-switches options is set on.
  // By default, -gno-record-gcc-switches is set on and no recording.
  auto GRecordSwitches =
      Args.hasFlag(options::OPT_grecord_command_line,
                   options::OPT_gno_record_command_line, false);
  auto FRecordSwitches =
      Args.hasFlag(options::OPT_frecord_command_line,
                   options::OPT_fno_record_command_line, false);
  if (FRecordSwitches && !Triple.isOSBinFormatELF())
    D.Diag(diag::err_drv_unsupported_opt_for_target)
        << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
        << TripleStr;
  if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) {
    ArgStringList OriginalArgs;
    for (const auto &Arg : Args)
      Arg->render(Args, OriginalArgs);

    SmallString<256> Flags;
    EscapeSpacesAndBackslashes(Exec, Flags);
    for (const char *OriginalArg : OriginalArgs) {
      SmallString<128> EscapedArg;
      EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
      Flags += " ";
      Flags += EscapedArg;
    }
    auto FlagsArgString = Args.MakeArgString(Flags);
    if (TC.UseDwarfDebugFlags() || GRecordSwitches) {
      CmdArgs.push_back("-dwarf-debug-flags");
      CmdArgs.push_back(FlagsArgString);
    }
    if (FRecordSwitches) {
      CmdArgs.push_back("-record-command-line");
      CmdArgs.push_back(FlagsArgString);
    }
  }

  // Host-side cuda compilation receives all device-side outputs in a single
  // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
  if ((IsCuda || IsHIP) && CudaDeviceInput) {
      CmdArgs.push_back("-fcuda-include-gpubinary");
      CmdArgs.push_back(CudaDeviceInput->getFilename());
      if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
        CmdArgs.push_back("-fgpu-rdc");
  }

  if (IsCuda) {
    if (Args.hasFlag(options::OPT_fcuda_short_ptr,
                     options::OPT_fno_cuda_short_ptr, false))
      CmdArgs.push_back("-fcuda-short-ptr");
  }

  if (IsCuda || IsHIP) {
    // Determine the original source input.
    const Action *SourceAction = &JA;
    while (SourceAction->getKind() != Action::InputClass) {
      assert(!SourceAction->getInputs().empty() && "unexpected root action!");
      SourceAction = SourceAction->getInputs()[0];
    }
    auto CUID = cast<InputAction>(SourceAction)->getId();
    if (!CUID.empty())
      CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID)));
  }

  if (IsHIP)
    CmdArgs.push_back("-fcuda-allow-variadic-functions");

  if (IsCudaDevice || IsHIPDevice) {
    StringRef InlineThresh =
        Args.getLastArgValue(options::OPT_fgpu_inline_threshold_EQ);
    if (!InlineThresh.empty()) {
      std::string ArgStr =
          std::string("-inline-threshold=") + InlineThresh.str();
      CmdArgs.append({"-mllvm", Args.MakeArgStringRef(ArgStr)});
    }
  }

  // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
  // to specify the result of the compile phase on the host, so the meaningful
  // device declarations can be identified. Also, -fopenmp-is-device is passed
  // along to tell the frontend that it is generating code for a device, so that
  // only the relevant declarations are emitted.
  if (IsOpenMPDevice) {
    CmdArgs.push_back("-fopenmp-is-device");
    if (OpenMPDeviceInput) {
      CmdArgs.push_back("-fopenmp-host-ir-file-path");
      CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename()));
    }
  }

  if (Triple.isAMDGPU()) {
    handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);

    if (Args.hasFlag(options::OPT_munsafe_fp_atomics,
                     options::OPT_mno_unsafe_fp_atomics, /*Default=*/false))
      CmdArgs.push_back("-munsafe-fp-atomics");
  }

  // For all the host OpenMP offloading compile jobs we need to pass the targets
  // information using -fopenmp-targets= option.
  if (JA.isHostOffloading(Action::OFK_OpenMP)) {
    SmallString<128> TargetInfo("-fopenmp-targets=");

    Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
    assert(Tgts && Tgts->getNumValues() &&
           "OpenMP offloading has to have targets specified.");
    for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
      if (i)
        TargetInfo += ',';
      // We need to get the string from the triple because it may be not exactly
      // the same as the one we get directly from the arguments.
      llvm::Triple T(Tgts->getValue(i));
      TargetInfo += T.getTriple();
    }
    CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
  }

  bool VirtualFunctionElimination =
      Args.hasFlag(options::OPT_fvirtual_function_elimination,
                   options::OPT_fno_virtual_function_elimination, false);
  if (VirtualFunctionElimination) {
    // VFE requires full LTO (currently, this might be relaxed to allow ThinLTO
    // in the future).
    if (LTOMode != LTOK_Full)
      D.Diag(diag::err_drv_argument_only_allowed_with)
          << "-fvirtual-function-elimination"
          << "-flto=full";

    CmdArgs.push_back("-fvirtual-function-elimination");
  }

  // VFE requires whole-program-vtables, and enables it by default.
  bool WholeProgramVTables = Args.hasFlag(
      options::OPT_fwhole_program_vtables,
      options::OPT_fno_whole_program_vtables, VirtualFunctionElimination);
  if (VirtualFunctionElimination && !WholeProgramVTables) {
    D.Diag(diag::err_drv_argument_not_allowed_with)
        << "-fno-whole-program-vtables"
        << "-fvirtual-function-elimination";
  }

  if (WholeProgramVTables) {
    // Propagate -fwhole-program-vtables if this is an LTO compile.
    if (IsUsingLTO)
      CmdArgs.push_back("-fwhole-program-vtables");
    // Check if we passed LTO options but they were suppressed because this is a
    // device offloading action, or we passed device offload LTO options which
    // were suppressed because this is not the device offload action.
    // Otherwise, issue an error.
    else if (!D.isUsingLTO(!IsDeviceOffloadAction))
      D.Diag(diag::err_drv_argument_only_allowed_with)
          << "-fwhole-program-vtables"
          << "-flto";
  }

  bool DefaultsSplitLTOUnit =
      (WholeProgramVTables || SanitizeArgs.needsLTO()) &&
      (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit());
  bool SplitLTOUnit =
      Args.hasFlag(options::OPT_fsplit_lto_unit,
                   options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
  if (SanitizeArgs.needsLTO() && !SplitLTOUnit)
    D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit"
                                                    << "-fsanitize=cfi";
  if (SplitLTOUnit)
    CmdArgs.push_back("-fsplit-lto-unit");

  if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel,
                               options::OPT_fno_global_isel)) {
    CmdArgs.push_back("-mllvm");
    if (A->getOption().matches(options::OPT_fglobal_isel)) {
      CmdArgs.push_back("-global-isel=1");

      // GISel is on by default on AArch64 -O0, so don't bother adding
      // the fallback remarks for it. Other combinations will add a warning of
      // some kind.
      bool IsArchSupported = Triple.getArch() == llvm::Triple::aarch64;
      bool IsOptLevelSupported = false;

      Arg *A = Args.getLastArg(options::OPT_O_Group);
      if (Triple.getArch() == llvm::Triple::aarch64) {
        if (!A || A->getOption().matches(options::OPT_O0))
          IsOptLevelSupported = true;
      }
      if (!IsArchSupported || !IsOptLevelSupported) {
        CmdArgs.push_back("-mllvm");
        CmdArgs.push_back("-global-isel-abort=2");

        if (!IsArchSupported)
          D.Diag(diag::warn_drv_global_isel_incomplete) << Triple.getArchName();
        else
          D.Diag(diag::warn_drv_global_isel_incomplete_opt);
      }
    } else {
      CmdArgs.push_back("-global-isel=0");
    }
  }

  if (Args.hasArg(options::OPT_forder_file_instrumentation)) {
     CmdArgs.push_back("-forder-file-instrumentation");
     // Enable order file instrumentation when ThinLTO is not on. When ThinLTO is
     // on, we need to pass these flags as linker flags and that will be handled
     // outside of the compiler.
     if (!IsUsingLTO) {
       CmdArgs.push_back("-mllvm");
       CmdArgs.push_back("-enable-order-file-instrumentation");
     }
  }

  if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128,
                               options::OPT_fno_force_enable_int128)) {
    if (A->getOption().matches(options::OPT_fforce_enable_int128))
      CmdArgs.push_back("-fforce-enable-int128");
  }

  if (Args.hasFlag(options::OPT_fkeep_static_consts,
                   options::OPT_fno_keep_static_consts, false))
    CmdArgs.push_back("-fkeep-static-consts");

  if (Args.hasFlag(options::OPT_fcomplete_member_pointers,
                   options::OPT_fno_complete_member_pointers, false))
    CmdArgs.push_back("-fcomplete-member-pointers");

  if (!Args.hasFlag(options::OPT_fcxx_static_destructors,
                    options::OPT_fno_cxx_static_destructors, true))
    CmdArgs.push_back("-fno-c++-static-destructors");

  addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);

  if (Arg *A = Args.getLastArg(options::OPT_moutline_atomics,
                               options::OPT_mno_outline_atomics)) {
    // Option -moutline-atomics supported for AArch64 target only.
    if (!Triple.isAArch64()) {
      D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt)
          << Triple.getArchName() << A->getOption().getName();
    } else {
      if (A->getOption().matches(options::OPT_moutline_atomics)) {
        CmdArgs.push_back("-target-feature");
        CmdArgs.push_back("+outline-atomics");
      } else {
        CmdArgs.push_back("-target-feature");
        CmdArgs.push_back("-outline-atomics");
      }
    }
  } else if (Triple.isAArch64() &&
             getToolChain().IsAArch64OutlineAtomicsDefault(Args)) {
    CmdArgs.push_back("-target-feature");
    CmdArgs.push_back("+outline-atomics");
  }

  if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig,
                   (TC.getTriple().isOSBinFormatELF() ||
                    TC.getTriple().isOSBinFormatCOFF()) &&
                       !TC.getTriple().isPS4() && !TC.getTriple().isVE() &&
                       !TC.getTriple().isOSNetBSD() &&
                       !Distro(D.getVFS(), TC.getTriple()).IsGentoo() &&
                       !TC.getTriple().isAndroid() && TC.useIntegratedAs()))
    CmdArgs.push_back("-faddrsig");

  if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) &&
      (EH || AsyncUnwindTables || UnwindTables ||
       DebugInfoKind != codegenoptions::NoDebugInfo))
    CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1");

  if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) {
    std::string Str = A->getAsString(Args);
    if (!TC.getTriple().isOSBinFormatELF())
      D.Diag(diag::err_drv_unsupported_opt_for_target)
          << Str << TC.getTripleString();
    CmdArgs.push_back(Args.MakeArgString(Str));
  }

  // Add the output path to the object file for CodeView debug infos.
  if (EmitCodeView && Output.isFilename())
    addDebugObjectName(Args, CmdArgs, DebugCompilationDir,
                       Output.getFilename());

  // Add the "-o out -x type src.c" flags last. This is done primarily to make
  // the -cc1 command easier to edit when reproducing compiler crashes.
  if (Output.getType() == types::TY_Dependencies) {
    // Handled with other dependency code.
  } else if (Output.isFilename()) {
    if (Output.getType() == clang::driver::types::TY_IFS_CPP ||
        Output.getType() == clang::driver::types::TY_IFS) {
      SmallString<128> OutputFilename(Output.getFilename());
      llvm::sys::path::replace_extension(OutputFilename, "ifs");
      CmdArgs.push_back("-o");
      CmdArgs.push_back(Args.MakeArgString(OutputFilename));
    } else {
      CmdArgs.push_back("-o");
      CmdArgs.push_back(Output.getFilename());
    }
  } else {
    assert(Output.isNothing() && "Invalid output.");
  }

  addDashXForInput(Args, Input, CmdArgs);

  ArrayRef<InputInfo> FrontendInputs = Input;
  if (IsHeaderModulePrecompile)
    FrontendInputs = ModuleHeaderInputs;
  else if (Input.isNothing())
    FrontendInputs = {};

  for (const InputInfo &Input : FrontendInputs) {
    if (Input.isFilename())
      CmdArgs.push_back(Input.getFilename());
    else
      Input.getInputArg().renderAsInput(Args, CmdArgs);
  }

  if (D.CC1Main && !D.CCGenDiagnostics) {
    // Invoke the CC1 directly in this process
    C.addCommand(std::make_unique<CC1Command>(JA, *this,
                                              ResponseFileSupport::AtFileUTF8(),
                                              Exec, CmdArgs, Inputs, Output));
  } else {
    C.addCommand(std::make_unique<Command>(JA, *this,
                                           ResponseFileSupport::AtFileUTF8(),
                                           Exec, CmdArgs, Inputs, Output));
  }

  // Make the compile command echo its inputs for /showFilenames.
  if (Output.getType() == types::TY_Object &&
      Args.hasFlag(options::OPT__SLASH_showFilenames,
                   options::OPT__SLASH_showFilenames_, false)) {
    C.getJobs().getJobs().back()->PrintInputFilenames = true;
  }

  if (Arg *A = Args.getLastArg(options::OPT_pg))
    if (FPKeepKind == CodeGenOptions::FramePointerKind::None &&
        !Args.hasArg(options::OPT_mfentry))
      D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
                                                      << A->getAsString(Args);

  // Claim some arguments which clang supports automatically.

  // -fpch-preprocess is used with gcc to add a special marker in the output to
  // include the PCH file.
  Args.ClaimAllArgs(options::OPT_fpch_preprocess);

  // Claim some arguments which clang doesn't support, but we don't
  // care to warn the user about.
  Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
  Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);

  // Disable warnings for clang -E -emit-llvm foo.c
  Args.ClaimAllArgs(options::OPT_emit_llvm);
}