10b57cec5SDimitry Andric //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "MSVC.h"
100b57cec5SDimitry Andric #include "CommonArgs.h"
110b57cec5SDimitry Andric #include "Darwin.h"
120b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
130b57cec5SDimitry Andric #include "clang/Basic/Version.h"
14d409305fSDimitry Andric #include "clang/Config/config.h"
150b57cec5SDimitry Andric #include "clang/Driver/Compilation.h"
160b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
170b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
180b57cec5SDimitry Andric #include "clang/Driver/Options.h"
190b57cec5SDimitry Andric #include "clang/Driver/SanitizerArgs.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
210b57cec5SDimitry Andric #include "llvm/Option/Arg.h"
220b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
230b57cec5SDimitry Andric #include "llvm/Support/ConvertUTF.h"
240b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
250b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
260b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
270b57cec5SDimitry Andric #include "llvm/Support/Path.h"
280b57cec5SDimitry Andric #include "llvm/Support/Process.h"
29fe6060f1SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
3006c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
310b57cec5SDimitry Andric #include <cstdio>
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #ifdef _WIN32
340b57cec5SDimitry Andric   #define WIN32_LEAN_AND_MEAN
350b57cec5SDimitry Andric   #define NOGDI
360b57cec5SDimitry Andric   #ifndef NOMINMAX
370b57cec5SDimitry Andric     #define NOMINMAX
380b57cec5SDimitry Andric   #endif
390b57cec5SDimitry Andric   #include <windows.h>
400b57cec5SDimitry Andric #endif
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric using namespace clang::driver;
430b57cec5SDimitry Andric using namespace clang::driver::toolchains;
440b57cec5SDimitry Andric using namespace clang::driver::tools;
450b57cec5SDimitry Andric using namespace clang;
460b57cec5SDimitry Andric using namespace llvm::opt;
470b57cec5SDimitry Andric 
canExecute(llvm::vfs::FileSystem & VFS,StringRef Path)48fe6060f1SDimitry Andric static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
49fe6060f1SDimitry Andric   auto Status = VFS.status(Path);
50fe6060f1SDimitry Andric   if (!Status)
51fe6060f1SDimitry Andric     return false;
52fe6060f1SDimitry Andric   return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
53fe6060f1SDimitry Andric }
54fe6060f1SDimitry Andric 
550b57cec5SDimitry Andric // Try to find Exe from a Visual Studio distribution.  This first tries to find
560b57cec5SDimitry Andric // an installed copy of Visual Studio and, failing that, looks in the PATH,
570b57cec5SDimitry Andric // making sure that whatever executable that's found is not a same-named exe
580b57cec5SDimitry Andric // from clang itself to prevent clang from falling back to itself.
FindVisualStudioExecutable(const ToolChain & TC,const char * Exe)590b57cec5SDimitry Andric static std::string FindVisualStudioExecutable(const ToolChain &TC,
600b57cec5SDimitry Andric                                               const char *Exe) {
610b57cec5SDimitry Andric   const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
6281ad6265SDimitry Andric   SmallString<128> FilePath(
6381ad6265SDimitry Andric       MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));
640b57cec5SDimitry Andric   llvm::sys::path::append(FilePath, Exe);
65fe6060f1SDimitry Andric   return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const680b57cec5SDimitry Andric void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
690b57cec5SDimitry Andric                                         const InputInfo &Output,
700b57cec5SDimitry Andric                                         const InputInfoList &Inputs,
710b57cec5SDimitry Andric                                         const ArgList &Args,
720b57cec5SDimitry Andric                                         const char *LinkingOutput) const {
730b57cec5SDimitry Andric   ArgStringList CmdArgs;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   assert((Output.isFilename() || Output.isNothing()) && "invalid output");
780b57cec5SDimitry Andric   if (Output.isFilename())
790b57cec5SDimitry Andric     CmdArgs.push_back(
800b57cec5SDimitry Andric         Args.MakeArgString(std::string("-out:") + Output.getFilename()));
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
8381ad6265SDimitry Andric       !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
840b57cec5SDimitry Andric     CmdArgs.push_back("-defaultlib:libcmt");
85e8d8bef9SDimitry Andric     CmdArgs.push_back("-defaultlib:oldnames");
86e8d8bef9SDimitry Andric   }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // If the VC environment hasn't been configured (perhaps because the user
890b57cec5SDimitry Andric   // did not run vcvarsall), try to build a consistent link environment.  If
900b57cec5SDimitry Andric   // the environment variable is set however, assume the user knows what
91fe6060f1SDimitry Andric   // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
92fe6060f1SDimitry Andric   // over env vars.
93349cc55cSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
94349cc55cSDimitry Andric                                      options::OPT__SLASH_winsysroot)) {
95349cc55cSDimitry Andric     // cl.exe doesn't find the DIA SDK automatically, so this too requires
96349cc55cSDimitry Andric     // explicit flags and doesn't automatically look in "DIA SDK" relative
97349cc55cSDimitry Andric     // to the path we found for VCToolChainPath.
98349cc55cSDimitry Andric     llvm::SmallString<128> DIAPath(A->getValue());
99349cc55cSDimitry Andric     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
100349cc55cSDimitry Andric       llvm::sys::path::append(DIAPath, "DIA SDK");
101349cc55cSDimitry Andric 
102349cc55cSDimitry Andric     // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
103349cc55cSDimitry Andric     llvm::sys::path::append(DIAPath, "lib",
10481ad6265SDimitry Andric                             llvm::archToLegacyVCArch(TC.getArch()));
105349cc55cSDimitry Andric     CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
106349cc55cSDimitry Andric   }
107fe6060f1SDimitry Andric   if (!llvm::sys::Process::GetEnv("LIB") ||
108fe6060f1SDimitry Andric       Args.getLastArg(options::OPT__SLASH_vctoolsdir,
109fe6060f1SDimitry Andric                       options::OPT__SLASH_winsysroot)) {
1100b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString(
1110b57cec5SDimitry Andric         Twine("-libpath:") +
11281ad6265SDimitry Andric         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
113a7dea167SDimitry Andric     CmdArgs.push_back(Args.MakeArgString(
114a7dea167SDimitry Andric         Twine("-libpath:") +
11581ad6265SDimitry Andric         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
116fe6060f1SDimitry Andric   }
117fe6060f1SDimitry Andric   if (!llvm::sys::Process::GetEnv("LIB") ||
118fe6060f1SDimitry Andric       Args.getLastArg(options::OPT__SLASH_winsdkdir,
119fe6060f1SDimitry Andric                       options::OPT__SLASH_winsysroot)) {
1200b57cec5SDimitry Andric     if (TC.useUniversalCRT()) {
1210b57cec5SDimitry Andric       std::string UniversalCRTLibPath;
122fe6060f1SDimitry Andric       if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
1230b57cec5SDimitry Andric         CmdArgs.push_back(
1240b57cec5SDimitry Andric             Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric     std::string WindowsSdkLibPath;
127fe6060f1SDimitry Andric     if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
1280b57cec5SDimitry Andric       CmdArgs.push_back(
1290b57cec5SDimitry Andric           Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
13281ad6265SDimitry Andric   if (C.getDriver().IsFlangMode()) {
13381ad6265SDimitry Andric     addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
1345f757f3fSDimitry Andric     addFortranRuntimeLibs(TC, Args, CmdArgs);
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric     // Inform the MSVC linker that we're generating a console application, i.e.
13781ad6265SDimitry Andric     // one with `main` as the "user-defined" entry point. The `main` function is
13881ad6265SDimitry Andric     // defined in flang's runtime libraries.
13981ad6265SDimitry Andric     CmdArgs.push_back("/subsystem:console");
14081ad6265SDimitry Andric   }
14181ad6265SDimitry Andric 
1425ffd83dbSDimitry Andric   // Add the compiler-rt library directories to libpath if they exist to help
1435ffd83dbSDimitry Andric   // the linker find the various sanitizer, builtin, and profiling runtimes.
1445ffd83dbSDimitry Andric   for (const auto &LibPath : TC.getLibraryPaths()) {
1455ffd83dbSDimitry Andric     if (TC.getVFS().exists(LibPath))
1465ffd83dbSDimitry Andric       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
1475ffd83dbSDimitry Andric   }
1485ffd83dbSDimitry Andric   auto CRTPath = TC.getCompilerRTPath();
1495ffd83dbSDimitry Andric   if (TC.getVFS().exists(CRTPath))
1505ffd83dbSDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
1515ffd83dbSDimitry Andric 
1520b57cec5SDimitry Andric   if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
1530b57cec5SDimitry Andric     for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
1540b57cec5SDimitry Andric       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   CmdArgs.push_back("-nologo");
1570b57cec5SDimitry Andric 
158e8d8bef9SDimitry Andric   if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
1590b57cec5SDimitry Andric     CmdArgs.push_back("-debug");
1600b57cec5SDimitry Andric 
16104eeddc0SDimitry Andric   // If we specify /hotpatch, let the linker add padding in front of each
16204eeddc0SDimitry Andric   // function, like MSVC does.
16304eeddc0SDimitry Andric   if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))
16404eeddc0SDimitry Andric     CmdArgs.push_back("-functionpadmin");
16504eeddc0SDimitry Andric 
1660b57cec5SDimitry Andric   // Pass on /Brepro if it was passed to the compiler.
1670b57cec5SDimitry Andric   // Note that /Brepro maps to -mno-incremental-linker-compatible.
1680b57cec5SDimitry Andric   bool DefaultIncrementalLinkerCompatible =
1690b57cec5SDimitry Andric       C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
1700b57cec5SDimitry Andric   if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
1710b57cec5SDimitry Andric                     options::OPT_mno_incremental_linker_compatible,
1720b57cec5SDimitry Andric                     DefaultIncrementalLinkerCompatible))
1730b57cec5SDimitry Andric     CmdArgs.push_back("-Brepro");
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
1760b57cec5SDimitry Andric                          options::OPT_shared);
1770b57cec5SDimitry Andric   if (DLL) {
1780b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-dll"));
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric     SmallString<128> ImplibName(Output.getFilename());
1810b57cec5SDimitry Andric     llvm::sys::path::replace_extension(ImplibName, "lib");
1820b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
185349cc55cSDimitry Andric   if (TC.getSanitizerArgs(Args).needsFuzzer()) {
1860b57cec5SDimitry Andric     if (!Args.hasArg(options::OPT_shared))
1870b57cec5SDimitry Andric       CmdArgs.push_back(
1880b57cec5SDimitry Andric           Args.MakeArgString(std::string("-wholearchive:") +
1890b57cec5SDimitry Andric                              TC.getCompilerRTArgString(Args, "fuzzer")));
1900b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-debug"));
1910b57cec5SDimitry Andric     // Prevent the linker from padding sections we use for instrumentation
1920b57cec5SDimitry Andric     // arrays.
1930b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric 
196349cc55cSDimitry Andric   if (TC.getSanitizerArgs(Args).needsAsanRt()) {
1970b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-debug"));
1980b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
199349cc55cSDimitry Andric     if (TC.getSanitizerArgs(Args).needsSharedRt() ||
2000b57cec5SDimitry Andric         Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
2010b57cec5SDimitry Andric       for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
2020b57cec5SDimitry Andric         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
2030b57cec5SDimitry Andric       // Make sure the dynamic runtime thunk is not optimized out at link time
2040b57cec5SDimitry Andric       // to ensure proper SEH handling.
2050b57cec5SDimitry Andric       CmdArgs.push_back(Args.MakeArgString(
2060b57cec5SDimitry Andric           TC.getArch() == llvm::Triple::x86
2070b57cec5SDimitry Andric               ? "-include:___asan_seh_interceptor"
2080b57cec5SDimitry Andric               : "-include:__asan_seh_interceptor"));
2090b57cec5SDimitry Andric       // Make sure the linker consider all object files from the dynamic runtime
2100b57cec5SDimitry Andric       // thunk.
2110b57cec5SDimitry Andric       CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
2120b57cec5SDimitry Andric           TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
2130b57cec5SDimitry Andric     } else if (DLL) {
2140b57cec5SDimitry Andric       CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
2150b57cec5SDimitry Andric     } else {
2160b57cec5SDimitry Andric       for (const auto &Lib : {"asan", "asan_cxx"}) {
2170b57cec5SDimitry Andric         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
2180b57cec5SDimitry Andric         // Make sure the linker consider all object files from the static lib.
2190b57cec5SDimitry Andric         // This is necessary because instrumented dlls need access to all the
2200b57cec5SDimitry Andric         // interface exported by the static lib in the main executable.
2210b57cec5SDimitry Andric         CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
2220b57cec5SDimitry Andric             TC.getCompilerRT(Args, Lib)));
2230b57cec5SDimitry Andric       }
2240b57cec5SDimitry Andric     }
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
2280b57cec5SDimitry Andric 
229480093f4SDimitry Andric   // Control Flow Guard checks
230a324c340SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
231480093f4SDimitry Andric     StringRef GuardArgs = A->getValue();
232fe6060f1SDimitry Andric     if (GuardArgs.equals_insensitive("cf") ||
233fe6060f1SDimitry Andric         GuardArgs.equals_insensitive("cf,nochecks")) {
234480093f4SDimitry Andric       // MSVC doesn't yet support the "nochecks" modifier.
235480093f4SDimitry Andric       CmdArgs.push_back("-guard:cf");
236fe6060f1SDimitry Andric     } else if (GuardArgs.equals_insensitive("cf-")) {
237480093f4SDimitry Andric       CmdArgs.push_back("-guard:cf-");
238fe6060f1SDimitry Andric     } else if (GuardArgs.equals_insensitive("ehcont")) {
239fe6060f1SDimitry Andric       CmdArgs.push_back("-guard:ehcont");
240fe6060f1SDimitry Andric     } else if (GuardArgs.equals_insensitive("ehcont-")) {
241fe6060f1SDimitry Andric       CmdArgs.push_back("-guard:ehcont-");
242480093f4SDimitry Andric     }
243480093f4SDimitry Andric   }
244480093f4SDimitry Andric 
2450b57cec5SDimitry Andric   if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
2460b57cec5SDimitry Andric                    options::OPT_fno_openmp, false)) {
2470b57cec5SDimitry Andric     CmdArgs.push_back("-nodefaultlib:vcomp.lib");
2480b57cec5SDimitry Andric     CmdArgs.push_back("-nodefaultlib:vcompd.lib");
2490b57cec5SDimitry Andric     CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
2500b57cec5SDimitry Andric                                          TC.getDriver().Dir + "/../lib"));
2510b57cec5SDimitry Andric     switch (TC.getDriver().getOpenMPRuntime(Args)) {
2520b57cec5SDimitry Andric     case Driver::OMPRT_OMP:
2530b57cec5SDimitry Andric       CmdArgs.push_back("-defaultlib:libomp.lib");
2540b57cec5SDimitry Andric       break;
2550b57cec5SDimitry Andric     case Driver::OMPRT_IOMP5:
2560b57cec5SDimitry Andric       CmdArgs.push_back("-defaultlib:libiomp5md.lib");
2570b57cec5SDimitry Andric       break;
2580b57cec5SDimitry Andric     case Driver::OMPRT_GOMP:
2590b57cec5SDimitry Andric       break;
2600b57cec5SDimitry Andric     case Driver::OMPRT_Unknown:
2610b57cec5SDimitry Andric       // Already diagnosed.
2620b57cec5SDimitry Andric       break;
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   // Add compiler-rt lib in case if it was explicitly
2670b57cec5SDimitry Andric   // specified as an argument for --rtlib option.
2680b57cec5SDimitry Andric   if (!Args.hasArg(options::OPT_nostdlib)) {
2690b57cec5SDimitry Andric     AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric 
27206c3fb27SDimitry Andric   StringRef Linker =
27306c3fb27SDimitry Andric       Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
27406c3fb27SDimitry Andric   if (Linker.empty())
27506c3fb27SDimitry Andric     Linker = "link";
27606c3fb27SDimitry Andric   // We need to translate 'lld' into 'lld-link'.
27706c3fb27SDimitry Andric   else if (Linker.equals_insensitive("lld"))
27806c3fb27SDimitry Andric     Linker = "lld-link";
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric   if (Linker == "lld-link") {
28106c3fb27SDimitry Andric     for (Arg *A : Args.filtered(options::OPT_vfsoverlay))
28206c3fb27SDimitry Andric       CmdArgs.push_back(
28306c3fb27SDimitry Andric           Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue()));
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric     if (C.getDriver().isUsingLTO() &&
28606c3fb27SDimitry Andric         Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf,
28706c3fb27SDimitry Andric                      false))
28806c3fb27SDimitry Andric       CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") +
28906c3fb27SDimitry Andric                                            Output.getFilename() + "_dwo"));
29006c3fb27SDimitry Andric   }
29106c3fb27SDimitry Andric 
2920b57cec5SDimitry Andric   // Add filenames, libraries, and other linker inputs.
2930b57cec5SDimitry Andric   for (const auto &Input : Inputs) {
2940b57cec5SDimitry Andric     if (Input.isFilename()) {
2950b57cec5SDimitry Andric       CmdArgs.push_back(Input.getFilename());
2960b57cec5SDimitry Andric       continue;
2970b57cec5SDimitry Andric     }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric     const Arg &A = Input.getInputArg();
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric     // Render -l options differently for the MSVC linker.
3020b57cec5SDimitry Andric     if (A.getOption().matches(options::OPT_l)) {
3030b57cec5SDimitry Andric       StringRef Lib = A.getValue();
3040b57cec5SDimitry Andric       const char *LinkLibArg;
3055f757f3fSDimitry Andric       if (Lib.ends_with(".lib"))
3060b57cec5SDimitry Andric         LinkLibArg = Args.MakeArgString(Lib);
3070b57cec5SDimitry Andric       else
3080b57cec5SDimitry Andric         LinkLibArg = Args.MakeArgString(Lib + ".lib");
3090b57cec5SDimitry Andric       CmdArgs.push_back(LinkLibArg);
3100b57cec5SDimitry Andric       continue;
3110b57cec5SDimitry Andric     }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric     // Otherwise, this is some other kind of linker input option like -Wl, -z,
3140b57cec5SDimitry Andric     // or -L. Render it, even if MSVC doesn't understand it.
3150b57cec5SDimitry Andric     A.renderAsInput(Args, CmdArgs);
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric 
3185f757f3fSDimitry Andric   addHIPRuntimeLibArgs(TC, C, Args, CmdArgs);
31981ad6265SDimitry Andric 
3200b57cec5SDimitry Andric   TC.addProfileRTLibs(Args, CmdArgs);
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   std::vector<const char *> Environment;
3230b57cec5SDimitry Andric 
32406c3fb27SDimitry Andric   // We need to special case some linker paths. In the case of the regular msvc
3250b57cec5SDimitry Andric   // linker, we need to use a special search algorithm.
3260b57cec5SDimitry Andric   llvm::SmallString<128> linkPath;
327fe6060f1SDimitry Andric   if (Linker.equals_insensitive("link")) {
3280b57cec5SDimitry Andric     // If we're using the MSVC linker, it's not sufficient to just use link
3290b57cec5SDimitry Andric     // from the program PATH, because other environments like GnuWin32 install
3300b57cec5SDimitry Andric     // their own link.exe which may come first.
3310b57cec5SDimitry Andric     linkPath = FindVisualStudioExecutable(TC, "link.exe");
3320b57cec5SDimitry Andric 
333fe6060f1SDimitry Andric     if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
3340b57cec5SDimitry Andric       llvm::SmallString<128> ClPath;
3350b57cec5SDimitry Andric       ClPath = TC.GetProgramPath("cl.exe");
336fe6060f1SDimitry Andric       if (canExecute(TC.getVFS(), ClPath)) {
3370b57cec5SDimitry Andric         linkPath = llvm::sys::path::parent_path(ClPath);
3380b57cec5SDimitry Andric         llvm::sys::path::append(linkPath, "link.exe");
339fe6060f1SDimitry Andric         if (!canExecute(TC.getVFS(), linkPath))
3400b57cec5SDimitry Andric           C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
3410b57cec5SDimitry Andric       } else {
3420b57cec5SDimitry Andric         C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
3430b57cec5SDimitry Andric       }
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric 
34606c3fb27SDimitry Andric     // Clang handles passing the proper asan libs to the linker, which goes
34706c3fb27SDimitry Andric     // against link.exe's /INFERASANLIBS which automatically finds asan libs.
34806c3fb27SDimitry Andric     if (TC.getSanitizerArgs(Args).needsAsanRt())
34906c3fb27SDimitry Andric       CmdArgs.push_back("/INFERASANLIBS:NO");
35006c3fb27SDimitry Andric 
3510b57cec5SDimitry Andric #ifdef _WIN32
3520b57cec5SDimitry Andric     // When cross-compiling with VS2017 or newer, link.exe expects to have
3530b57cec5SDimitry Andric     // its containing bin directory at the top of PATH, followed by the
3540b57cec5SDimitry Andric     // native target bin directory.
3550b57cec5SDimitry Andric     // e.g. when compiling for x86 on an x64 host, PATH should start with:
3560b57cec5SDimitry Andric     // /bin/Hostx64/x86;/bin/Hostx64/x64
35781ad6265SDimitry Andric     // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
3580b57cec5SDimitry Andric     if (TC.getIsVS2017OrNewer() &&
3590b57cec5SDimitry Andric         llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
3600b57cec5SDimitry Andric       auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric       auto EnvBlockWide =
3630b57cec5SDimitry Andric           std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
3640b57cec5SDimitry Andric               GetEnvironmentStringsW(), FreeEnvironmentStringsW);
3650b57cec5SDimitry Andric       if (!EnvBlockWide)
3660b57cec5SDimitry Andric         goto SkipSettingEnvironment;
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric       size_t EnvCount = 0;
3690b57cec5SDimitry Andric       size_t EnvBlockLen = 0;
3700b57cec5SDimitry Andric       while (EnvBlockWide[EnvBlockLen] != L'\0') {
3710b57cec5SDimitry Andric         ++EnvCount;
3720b57cec5SDimitry Andric         EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
3730b57cec5SDimitry Andric                        1 /*string null-terminator*/;
3740b57cec5SDimitry Andric       }
3750b57cec5SDimitry Andric       ++EnvBlockLen; // add the block null-terminator
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric       std::string EnvBlock;
3780b57cec5SDimitry Andric       if (!llvm::convertUTF16ToUTF8String(
3790b57cec5SDimitry Andric               llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
3800b57cec5SDimitry Andric                                    EnvBlockLen * sizeof(EnvBlockWide[0])),
3810b57cec5SDimitry Andric               EnvBlock))
3820b57cec5SDimitry Andric         goto SkipSettingEnvironment;
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric       Environment.reserve(EnvCount);
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric       // Now loop over each string in the block and copy them into the
3870b57cec5SDimitry Andric       // environment vector, adjusting the PATH variable as needed when we
3880b57cec5SDimitry Andric       // find it.
3890b57cec5SDimitry Andric       for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
3900b57cec5SDimitry Andric         llvm::StringRef EnvVar(Cursor);
39106c3fb27SDimitry Andric         if (EnvVar.starts_with_insensitive("path=")) {
3920b57cec5SDimitry Andric           constexpr size_t PrefixLen = 5; // strlen("path=")
3930b57cec5SDimitry Andric           Environment.push_back(Args.MakeArgString(
3940b57cec5SDimitry Andric               EnvVar.substr(0, PrefixLen) +
39581ad6265SDimitry Andric               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
3960b57cec5SDimitry Andric               llvm::Twine(llvm::sys::EnvPathSeparator) +
39781ad6265SDimitry Andric               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +
3980b57cec5SDimitry Andric               (EnvVar.size() > PrefixLen
3990b57cec5SDimitry Andric                    ? llvm::Twine(llvm::sys::EnvPathSeparator) +
4000b57cec5SDimitry Andric                          EnvVar.substr(PrefixLen)
4010b57cec5SDimitry Andric                    : "")));
4020b57cec5SDimitry Andric         } else {
4030b57cec5SDimitry Andric           Environment.push_back(Args.MakeArgString(EnvVar));
4040b57cec5SDimitry Andric         }
4050b57cec5SDimitry Andric         Cursor += EnvVar.size() + 1 /*null-terminator*/;
4060b57cec5SDimitry Andric       }
4070b57cec5SDimitry Andric     }
4080b57cec5SDimitry Andric   SkipSettingEnvironment:;
4090b57cec5SDimitry Andric #endif
4100b57cec5SDimitry Andric   } else {
4110b57cec5SDimitry Andric     linkPath = TC.GetProgramPath(Linker.str().c_str());
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric 
414e8d8bef9SDimitry Andric   auto LinkCmd = std::make_unique<Command>(
415e8d8bef9SDimitry Andric       JA, *this, ResponseFileSupport::AtFileUTF16(),
416e8d8bef9SDimitry Andric       Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
4170b57cec5SDimitry Andric   if (!Environment.empty())
4180b57cec5SDimitry Andric     LinkCmd->setEnvironment(Environment);
4190b57cec5SDimitry Andric   C.addCommand(std::move(LinkCmd));
4200b57cec5SDimitry Andric }
4210b57cec5SDimitry Andric 
MSVCToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)4220b57cec5SDimitry Andric MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
4230b57cec5SDimitry Andric                              const ArgList &Args)
4245ffd83dbSDimitry Andric     : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
4255ffd83dbSDimitry Andric       RocmInstallation(D, Triple, Args) {
4260b57cec5SDimitry Andric   getProgramPaths().push_back(getDriver().getInstalledDir());
4270b57cec5SDimitry Andric   if (getDriver().getInstalledDir() != getDriver().Dir)
4280b57cec5SDimitry Andric     getProgramPaths().push_back(getDriver().Dir);
4290b57cec5SDimitry Andric 
430bdd1243dSDimitry Andric   std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
43181ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
43281ad6265SDimitry Andric     VCToolsDir = A->getValue();
43381ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
43481ad6265SDimitry Andric     VCToolsVersion = A->getValue();
43581ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
43681ad6265SDimitry Andric     WinSdkDir = A->getValue();
43781ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
43881ad6265SDimitry Andric     WinSdkVersion = A->getValue();
43981ad6265SDimitry Andric   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
44081ad6265SDimitry Andric     WinSysRoot = A->getValue();
44181ad6265SDimitry Andric 
442e8d8bef9SDimitry Andric   // Check the command line first, that's the user explicitly telling us what to
443e8d8bef9SDimitry Andric   // use. Check the environment next, in case we're being invoked from a VS
444e8d8bef9SDimitry Andric   // command prompt. Failing that, just try to find the newest Visual Studio
445e8d8bef9SDimitry Andric   // version we can and use its default VC toolchain.
44681ad6265SDimitry Andric   llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
44781ad6265SDimitry Andric                                       WinSysRoot, VCToolChainPath, VSLayout) ||
44881ad6265SDimitry Andric       llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
44981ad6265SDimitry Andric                                           VSLayout) ||
45006c3fb27SDimitry Andric       llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion,
45106c3fb27SDimitry Andric                                           VCToolChainPath, VSLayout) ||
45281ad6265SDimitry Andric       llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric 
buildLinker() const4550b57cec5SDimitry Andric Tool *MSVCToolChain::buildLinker() const {
4560b57cec5SDimitry Andric   return new tools::visualstudio::Linker(*this);
4570b57cec5SDimitry Andric }
4580b57cec5SDimitry Andric 
buildAssembler() const4590b57cec5SDimitry Andric Tool *MSVCToolChain::buildAssembler() const {
4600b57cec5SDimitry Andric   if (getTriple().isOSBinFormatMachO())
4610b57cec5SDimitry Andric     return new tools::darwin::Assembler(*this);
4620b57cec5SDimitry Andric   getDriver().Diag(clang::diag::err_no_external_assembler);
4630b57cec5SDimitry Andric   return nullptr;
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric 
466bdd1243dSDimitry Andric ToolChain::UnwindTableLevel
getDefaultUnwindTableLevel(const ArgList & Args) const467bdd1243dSDimitry Andric MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
4680b57cec5SDimitry Andric   // Don't emit unwind tables by default for MachO targets.
4690b57cec5SDimitry Andric   if (getTriple().isOSBinFormatMachO())
470bdd1243dSDimitry Andric     return UnwindTableLevel::None;
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   // All non-x86_32 Windows targets require unwind tables. However, LLVM
4730b57cec5SDimitry Andric   // doesn't know how to generate them for all targets, so only enable
4740b57cec5SDimitry Andric   // the ones that are actually implemented.
475bdd1243dSDimitry Andric   if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
476bdd1243dSDimitry Andric       getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
477bdd1243dSDimitry Andric     return UnwindTableLevel::Asynchronous;
478bdd1243dSDimitry Andric 
479bdd1243dSDimitry Andric   return UnwindTableLevel::None;
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
isPICDefault() const4820b57cec5SDimitry Andric bool MSVCToolChain::isPICDefault() const {
483349cc55cSDimitry Andric   return getArch() == llvm::Triple::x86_64 ||
484349cc55cSDimitry Andric          getArch() == llvm::Triple::aarch64;
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric 
isPIEDefault(const llvm::opt::ArgList & Args) const487349cc55cSDimitry Andric bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
4880b57cec5SDimitry Andric   return false;
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric 
isPICDefaultForced() const4910b57cec5SDimitry Andric bool MSVCToolChain::isPICDefaultForced() const {
492349cc55cSDimitry Andric   return getArch() == llvm::Triple::x86_64 ||
493349cc55cSDimitry Andric          getArch() == llvm::Triple::aarch64;
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric 
AddCudaIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const4960b57cec5SDimitry Andric void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
4970b57cec5SDimitry Andric                                        ArgStringList &CC1Args) const {
4987a6dacacSDimitry Andric   CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric 
AddHIPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const5015ffd83dbSDimitry Andric void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
5025ffd83dbSDimitry Andric                                       ArgStringList &CC1Args) const {
5037a6dacacSDimitry Andric   RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
5045ffd83dbSDimitry Andric }
5055ffd83dbSDimitry Andric 
AddHIPRuntimeLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const50681ad6265SDimitry Andric void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,
50781ad6265SDimitry Andric                                          ArgStringList &CmdArgs) const {
50881ad6265SDimitry Andric   CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
5097a6dacacSDimitry Andric                                      RocmInstallation->getLibPath()),
51081ad6265SDimitry Andric                   "amdhip64.lib"});
51181ad6265SDimitry Andric }
51281ad6265SDimitry Andric 
printVerboseInfo(raw_ostream & OS) const5130b57cec5SDimitry Andric void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
5147a6dacacSDimitry Andric   CudaInstallation->print(OS);
5157a6dacacSDimitry Andric   RocmInstallation->print(OS);
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric std::string
getSubDirectoryPath(llvm::SubDirectoryType Type,llvm::StringRef SubdirParent) const51981ad6265SDimitry Andric MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
52081ad6265SDimitry Andric                                    llvm::StringRef SubdirParent) const {
52181ad6265SDimitry Andric   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
52281ad6265SDimitry Andric                                    SubdirParent);
52381ad6265SDimitry Andric }
52481ad6265SDimitry Andric 
52581ad6265SDimitry Andric std::string
getSubDirectoryPath(llvm::SubDirectoryType Type,llvm::Triple::ArchType TargetArch) const52681ad6265SDimitry Andric MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
5270b57cec5SDimitry Andric                                    llvm::Triple::ArchType TargetArch) const {
52881ad6265SDimitry Andric   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
52981ad6265SDimitry Andric                                    "");
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric // Find the most recent version of Universal CRT or Windows 10 SDK.
5330b57cec5SDimitry Andric // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
5340b57cec5SDimitry Andric // directory by name and uses the last one of the list.
5350b57cec5SDimitry Andric // So we compare entry names lexicographically to find the greatest one.
5360b57cec5SDimitry Andric // Gets the library path required to link against the Windows SDK.
getWindowsSDKLibraryPath(const ArgList & Args,std::string & path) const53781ad6265SDimitry Andric bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,
53881ad6265SDimitry Andric                                              std::string &path) const {
5390b57cec5SDimitry Andric   std::string sdkPath;
5400b57cec5SDimitry Andric   int sdkMajor = 0;
5410b57cec5SDimitry Andric   std::string windowsSDKIncludeVersion;
5420b57cec5SDimitry Andric   std::string windowsSDKLibVersion;
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   path.clear();
54581ad6265SDimitry Andric   if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
54681ad6265SDimitry Andric                               sdkPath, sdkMajor, windowsSDKIncludeVersion,
54781ad6265SDimitry Andric                               windowsSDKLibVersion))
5480b57cec5SDimitry Andric     return false;
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   llvm::SmallString<128> libPath(sdkPath);
5510b57cec5SDimitry Andric   llvm::sys::path::append(libPath, "Lib");
55206c3fb27SDimitry Andric   if (sdkMajor >= 10)
55306c3fb27SDimitry Andric     if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
55406c3fb27SDimitry Andric         WinSdkVersion.has_value())
55506c3fb27SDimitry Andric       windowsSDKLibVersion = *WinSdkVersion;
55681ad6265SDimitry Andric   if (sdkMajor >= 8)
55781ad6265SDimitry Andric     llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
55881ad6265SDimitry Andric   return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
55981ad6265SDimitry Andric                                              path);
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric 
useUniversalCRT() const5620b57cec5SDimitry Andric bool MSVCToolChain::useUniversalCRT() const {
56381ad6265SDimitry Andric   return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric 
getUniversalCRTLibraryPath(const ArgList & Args,std::string & Path) const566fe6060f1SDimitry Andric bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
567fe6060f1SDimitry Andric                                                std::string &Path) const {
5680b57cec5SDimitry Andric   std::string UniversalCRTSdkPath;
5690b57cec5SDimitry Andric   std::string UCRTVersion;
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   Path.clear();
57281ad6265SDimitry Andric   if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
57381ad6265SDimitry Andric                                    WinSysRoot, UniversalCRTSdkPath,
57481ad6265SDimitry Andric                                    UCRTVersion))
5750b57cec5SDimitry Andric     return false;
5760b57cec5SDimitry Andric 
57706c3fb27SDimitry Andric   if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
57806c3fb27SDimitry Andric       WinSdkVersion.has_value())
57906c3fb27SDimitry Andric     UCRTVersion = *WinSdkVersion;
58006c3fb27SDimitry Andric 
58181ad6265SDimitry Andric   StringRef ArchName = llvm::archToWindowsSDKArch(getArch());
5820b57cec5SDimitry Andric   if (ArchName.empty())
5830b57cec5SDimitry Andric     return false;
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
5860b57cec5SDimitry Andric   llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
5870b57cec5SDimitry Andric 
5887a6dacacSDimitry Andric   Path = std::string(LibPath);
5890b57cec5SDimitry Andric   return true;
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric 
getMSVCVersionFromExe(const std::string & BinDir)5920b57cec5SDimitry Andric static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
5930b57cec5SDimitry Andric   VersionTuple Version;
5940b57cec5SDimitry Andric #ifdef _WIN32
5950b57cec5SDimitry Andric   SmallString<128> ClExe(BinDir);
5960b57cec5SDimitry Andric   llvm::sys::path::append(ClExe, "cl.exe");
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric   std::wstring ClExeWide;
5990b57cec5SDimitry Andric   if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
6000b57cec5SDimitry Andric     return Version;
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric   const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
6030b57cec5SDimitry Andric                                                       nullptr);
6040b57cec5SDimitry Andric   if (VersionSize == 0)
6050b57cec5SDimitry Andric     return Version;
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
6080b57cec5SDimitry Andric   if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
6090b57cec5SDimitry Andric                              VersionBlock.data()))
6100b57cec5SDimitry Andric     return Version;
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric   VS_FIXEDFILEINFO *FileInfo = nullptr;
6130b57cec5SDimitry Andric   UINT FileInfoSize = 0;
6140b57cec5SDimitry Andric   if (!::VerQueryValueW(VersionBlock.data(), L"\\",
6150b57cec5SDimitry Andric                         reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
6160b57cec5SDimitry Andric       FileInfoSize < sizeof(*FileInfo))
6170b57cec5SDimitry Andric     return Version;
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
6200b57cec5SDimitry Andric   const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF;
6210b57cec5SDimitry Andric   const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   Version = VersionTuple(Major, Minor, Micro);
6240b57cec5SDimitry Andric #endif
6250b57cec5SDimitry Andric   return Version;
6260b57cec5SDimitry Andric }
6270b57cec5SDimitry Andric 
AddSystemIncludeWithSubfolder(const ArgList & DriverArgs,ArgStringList & CC1Args,const std::string & folder,const Twine & subfolder1,const Twine & subfolder2,const Twine & subfolder3) const6280b57cec5SDimitry Andric void MSVCToolChain::AddSystemIncludeWithSubfolder(
6290b57cec5SDimitry Andric     const ArgList &DriverArgs, ArgStringList &CC1Args,
6300b57cec5SDimitry Andric     const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
6310b57cec5SDimitry Andric     const Twine &subfolder3) const {
6320b57cec5SDimitry Andric   llvm::SmallString<128> path(folder);
6330b57cec5SDimitry Andric   llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
6340b57cec5SDimitry Andric   addSystemInclude(DriverArgs, CC1Args, path);
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const6370b57cec5SDimitry Andric void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
6380b57cec5SDimitry Andric                                               ArgStringList &CC1Args) const {
6390b57cec5SDimitry Andric   if (DriverArgs.hasArg(options::OPT_nostdinc))
6400b57cec5SDimitry Andric     return;
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
6430b57cec5SDimitry Andric     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
6440b57cec5SDimitry Andric                                   "include");
6450b57cec5SDimitry Andric   }
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric   // Add %INCLUDE%-like directories from the -imsvc flag.
6480b57cec5SDimitry Andric   for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
6490b57cec5SDimitry Andric     addSystemInclude(DriverArgs, CC1Args, Path);
6500b57cec5SDimitry Andric 
651fe6060f1SDimitry Andric   auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
652fe6060f1SDimitry Andric     if (auto Val = llvm::sys::Process::GetEnv(Var)) {
653fe6060f1SDimitry Andric       SmallVector<StringRef, 8> Dirs;
654fe6060f1SDimitry Andric       StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
655fe6060f1SDimitry Andric       if (!Dirs.empty()) {
656fe6060f1SDimitry Andric         addSystemIncludes(DriverArgs, CC1Args, Dirs);
657fe6060f1SDimitry Andric         return true;
658fe6060f1SDimitry Andric       }
659fe6060f1SDimitry Andric     }
660fe6060f1SDimitry Andric     return false;
661fe6060f1SDimitry Andric   };
662fe6060f1SDimitry Andric 
663fe6060f1SDimitry Andric   // Add %INCLUDE%-like dirs via /external:env: flags.
664fe6060f1SDimitry Andric   for (const auto &Var :
665fe6060f1SDimitry Andric        DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
666fe6060f1SDimitry Andric     AddSystemIncludesFromEnv(Var);
667fe6060f1SDimitry Andric   }
668fe6060f1SDimitry Andric 
669349cc55cSDimitry Andric   // Add DIA SDK include if requested.
670349cc55cSDimitry Andric   if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
671349cc55cSDimitry Andric                                            options::OPT__SLASH_winsysroot)) {
672349cc55cSDimitry Andric     // cl.exe doesn't find the DIA SDK automatically, so this too requires
673349cc55cSDimitry Andric     // explicit flags and doesn't automatically look in "DIA SDK" relative
674349cc55cSDimitry Andric     // to the path we found for VCToolChainPath.
675349cc55cSDimitry Andric     llvm::SmallString<128> DIASDKPath(A->getValue());
676349cc55cSDimitry Andric     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
677349cc55cSDimitry Andric       llvm::sys::path::append(DIASDKPath, "DIA SDK");
678349cc55cSDimitry Andric     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),
679349cc55cSDimitry Andric                                   "include");
680349cc55cSDimitry Andric   }
681349cc55cSDimitry Andric 
6820b57cec5SDimitry Andric   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
6830b57cec5SDimitry Andric     return;
6840b57cec5SDimitry Andric 
685fe6060f1SDimitry Andric   // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
686fe6060f1SDimitry Andric   // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
687fe6060f1SDimitry Andric   if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
688fe6060f1SDimitry Andric                              options::OPT__SLASH_winsysroot)) {
689fe6060f1SDimitry Andric     bool Found = AddSystemIncludesFromEnv("INCLUDE");
690fe6060f1SDimitry Andric     Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
691fe6060f1SDimitry Andric     if (Found)
6920b57cec5SDimitry Andric       return;
6930b57cec5SDimitry Andric   }
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric   // When built with access to the proper Windows APIs, try to actually find
6960b57cec5SDimitry Andric   // the correct include paths first.
6970b57cec5SDimitry Andric   if (!VCToolChainPath.empty()) {
6980b57cec5SDimitry Andric     addSystemInclude(DriverArgs, CC1Args,
69981ad6265SDimitry Andric                      getSubDirectoryPath(llvm::SubDirectoryType::Include));
70081ad6265SDimitry Andric     addSystemInclude(
70181ad6265SDimitry Andric         DriverArgs, CC1Args,
70281ad6265SDimitry Andric         getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric     if (useUniversalCRT()) {
7050b57cec5SDimitry Andric       std::string UniversalCRTSdkPath;
7060b57cec5SDimitry Andric       std::string UCRTVersion;
70781ad6265SDimitry Andric       if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
70881ad6265SDimitry Andric                                       WinSysRoot, UniversalCRTSdkPath,
709fe6060f1SDimitry Andric                                       UCRTVersion)) {
71006c3fb27SDimitry Andric         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
71106c3fb27SDimitry Andric             WinSdkVersion.has_value())
71206c3fb27SDimitry Andric           UCRTVersion = *WinSdkVersion;
7130b57cec5SDimitry Andric         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
7140b57cec5SDimitry Andric                                       "Include", UCRTVersion, "ucrt");
7150b57cec5SDimitry Andric       }
7160b57cec5SDimitry Andric     }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric     std::string WindowsSDKDir;
719fe6060f1SDimitry Andric     int major = 0;
7200b57cec5SDimitry Andric     std::string windowsSDKIncludeVersion;
7210b57cec5SDimitry Andric     std::string windowsSDKLibVersion;
72281ad6265SDimitry Andric     if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
72381ad6265SDimitry Andric                                WindowsSDKDir, major, windowsSDKIncludeVersion,
72481ad6265SDimitry Andric                                windowsSDKLibVersion)) {
72506c3fb27SDimitry Andric       if (major >= 10)
72606c3fb27SDimitry Andric         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
72706c3fb27SDimitry Andric             WinSdkVersion.has_value())
72806c3fb27SDimitry Andric           windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;
7290b57cec5SDimitry Andric       if (major >= 8) {
7300b57cec5SDimitry Andric         // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
7310b57cec5SDimitry Andric         // Anyway, llvm::sys::path::append is able to manage it.
7320b57cec5SDimitry Andric         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
733fe6060f1SDimitry Andric                                       "Include", windowsSDKIncludeVersion,
7340b57cec5SDimitry Andric                                       "shared");
7350b57cec5SDimitry Andric         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
736fe6060f1SDimitry Andric                                       "Include", windowsSDKIncludeVersion,
7370b57cec5SDimitry Andric                                       "um");
7380b57cec5SDimitry Andric         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
739fe6060f1SDimitry Andric                                       "Include", windowsSDKIncludeVersion,
7400b57cec5SDimitry Andric                                       "winrt");
74104eeddc0SDimitry Andric         if (major >= 10) {
74204eeddc0SDimitry Andric           llvm::VersionTuple Tuple;
74304eeddc0SDimitry Andric           if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
74481ad6265SDimitry Andric               Tuple.getSubminor().value_or(0) >= 17134) {
74504eeddc0SDimitry Andric             AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
74604eeddc0SDimitry Andric                                           "Include", windowsSDKIncludeVersion,
74704eeddc0SDimitry Andric                                           "cppwinrt");
74804eeddc0SDimitry Andric           }
74904eeddc0SDimitry Andric         }
7500b57cec5SDimitry Andric       } else {
7510b57cec5SDimitry Andric         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
752fe6060f1SDimitry Andric                                       "Include");
7530b57cec5SDimitry Andric       }
7540b57cec5SDimitry Andric     }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric     return;
7570b57cec5SDimitry Andric   }
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric #if defined(_WIN32)
7600b57cec5SDimitry Andric   // As a fallback, select default install paths.
7610b57cec5SDimitry Andric   // FIXME: Don't guess drives and paths like this on Windows.
7620b57cec5SDimitry Andric   const StringRef Paths[] = {
7630b57cec5SDimitry Andric     "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
7640b57cec5SDimitry Andric     "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
7650b57cec5SDimitry Andric     "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
7660b57cec5SDimitry Andric     "C:/Program Files/Microsoft Visual Studio 8/VC/include",
7670b57cec5SDimitry Andric     "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
7680b57cec5SDimitry Andric   };
7690b57cec5SDimitry Andric   addSystemIncludes(DriverArgs, CC1Args, Paths);
7700b57cec5SDimitry Andric #endif
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const7730b57cec5SDimitry Andric void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
7740b57cec5SDimitry Andric                                                  ArgStringList &CC1Args) const {
7750b57cec5SDimitry Andric   // FIXME: There should probably be logic here to find libc++ on Windows.
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric 
computeMSVCVersion(const Driver * D,const ArgList & Args) const7780b57cec5SDimitry Andric VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
7790b57cec5SDimitry Andric                                                const ArgList &Args) const {
7800b57cec5SDimitry Andric   bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
7810b57cec5SDimitry Andric   VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
7820b57cec5SDimitry Andric   if (MSVT.empty())
7830eae32dcSDimitry Andric     MSVT = getTriple().getEnvironmentVersion();
7840b57cec5SDimitry Andric   if (MSVT.empty() && IsWindowsMSVC)
78581ad6265SDimitry Andric     MSVT =
78681ad6265SDimitry Andric         getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
7870b57cec5SDimitry Andric   if (MSVT.empty() &&
7880b57cec5SDimitry Andric       Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
7890b57cec5SDimitry Andric                    IsWindowsMSVC)) {
7905f757f3fSDimitry Andric     // -fms-compatibility-version=19.33 is default, aka 2022, 17.3
79106c3fb27SDimitry Andric     // NOTE: when changing this value, also update
79206c3fb27SDimitry Andric     // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst
79306c3fb27SDimitry Andric     // accordingly.
7945f757f3fSDimitry Andric     MSVT = VersionTuple(19, 33);
7950b57cec5SDimitry Andric   }
7960b57cec5SDimitry Andric   return MSVT;
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric std::string
ComputeEffectiveClangTriple(const ArgList & Args,types::ID InputType) const8000b57cec5SDimitry Andric MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
8010b57cec5SDimitry Andric                                            types::ID InputType) const {
8020b57cec5SDimitry Andric   // The MSVC version doesn't care about the architecture, even though it
8030b57cec5SDimitry Andric   // may look at the triple internally.
8040b57cec5SDimitry Andric   VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
80581ad6265SDimitry Andric   MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0),
80681ad6265SDimitry Andric                       MSVT.getSubminor().value_or(0));
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   // For the rest of the triple, however, a computed architecture name may
8090b57cec5SDimitry Andric   // be needed.
8100b57cec5SDimitry Andric   llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
8110b57cec5SDimitry Andric   if (Triple.getEnvironment() == llvm::Triple::MSVC) {
8120b57cec5SDimitry Andric     StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
8130b57cec5SDimitry Andric     if (ObjFmt.empty())
8140b57cec5SDimitry Andric       Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
8150b57cec5SDimitry Andric     else
8160b57cec5SDimitry Andric       Triple.setEnvironmentName(
8170b57cec5SDimitry Andric           (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
8180b57cec5SDimitry Andric   }
8190b57cec5SDimitry Andric   return Triple.getTriple();
8200b57cec5SDimitry Andric }
8210b57cec5SDimitry Andric 
getSupportedSanitizers() const8220b57cec5SDimitry Andric SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
8230b57cec5SDimitry Andric   SanitizerMask Res = ToolChain::getSupportedSanitizers();
8240b57cec5SDimitry Andric   Res |= SanitizerKind::Address;
8250b57cec5SDimitry Andric   Res |= SanitizerKind::PointerCompare;
8260b57cec5SDimitry Andric   Res |= SanitizerKind::PointerSubtract;
8270b57cec5SDimitry Andric   Res |= SanitizerKind::Fuzzer;
8280b57cec5SDimitry Andric   Res |= SanitizerKind::FuzzerNoLink;
8290b57cec5SDimitry Andric   Res &= ~SanitizerKind::CFIMFCall;
8300b57cec5SDimitry Andric   return Res;
8310b57cec5SDimitry Andric }
8320b57cec5SDimitry Andric 
TranslateOptArg(Arg * A,llvm::opt::DerivedArgList & DAL,bool SupportsForcingFramePointer,const char * ExpandChar,const OptTable & Opts)8330b57cec5SDimitry Andric static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
8340b57cec5SDimitry Andric                             bool SupportsForcingFramePointer,
8350b57cec5SDimitry Andric                             const char *ExpandChar, const OptTable &Opts) {
8360b57cec5SDimitry Andric   assert(A->getOption().matches(options::OPT__SLASH_O));
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric   StringRef OptStr = A->getValue();
8390b57cec5SDimitry Andric   for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
8400b57cec5SDimitry Andric     const char &OptChar = *(OptStr.data() + I);
8410b57cec5SDimitry Andric     switch (OptChar) {
8420b57cec5SDimitry Andric     default:
8430b57cec5SDimitry Andric       break;
8440b57cec5SDimitry Andric     case '1':
8450b57cec5SDimitry Andric     case '2':
8460b57cec5SDimitry Andric     case 'x':
8470b57cec5SDimitry Andric     case 'd':
8480b57cec5SDimitry Andric       // Ignore /O[12xd] flags that aren't the last one on the command line.
8490b57cec5SDimitry Andric       // Only the last one gets expanded.
8500b57cec5SDimitry Andric       if (&OptChar != ExpandChar) {
8510b57cec5SDimitry Andric         A->claim();
8520b57cec5SDimitry Andric         break;
8530b57cec5SDimitry Andric       }
8540b57cec5SDimitry Andric       if (OptChar == 'd') {
8550b57cec5SDimitry Andric         DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
8560b57cec5SDimitry Andric       } else {
8570b57cec5SDimitry Andric         if (OptChar == '1') {
8580b57cec5SDimitry Andric           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
8590b57cec5SDimitry Andric         } else if (OptChar == '2' || OptChar == 'x') {
8600b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
8610b57cec5SDimitry Andric           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
8620b57cec5SDimitry Andric         }
8630b57cec5SDimitry Andric         if (SupportsForcingFramePointer &&
8640b57cec5SDimitry Andric             !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
8650b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
8660b57cec5SDimitry Andric         if (OptChar == '1' || OptChar == '2')
8670b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
8680b57cec5SDimitry Andric       }
8690b57cec5SDimitry Andric       break;
8700b57cec5SDimitry Andric     case 'b':
8710b57cec5SDimitry Andric       if (I + 1 != E && isdigit(OptStr[I + 1])) {
8720b57cec5SDimitry Andric         switch (OptStr[I + 1]) {
8730b57cec5SDimitry Andric         case '0':
8740b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
8750b57cec5SDimitry Andric           break;
8760b57cec5SDimitry Andric         case '1':
8770b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
8780b57cec5SDimitry Andric           break;
8790b57cec5SDimitry Andric         case '2':
8800b57cec5SDimitry Andric           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
8810b57cec5SDimitry Andric           break;
8820b57cec5SDimitry Andric         }
8830b57cec5SDimitry Andric         ++I;
8840b57cec5SDimitry Andric       }
8850b57cec5SDimitry Andric       break;
8860b57cec5SDimitry Andric     case 'g':
8870b57cec5SDimitry Andric       A->claim();
8880b57cec5SDimitry Andric       break;
8890b57cec5SDimitry Andric     case 'i':
8900b57cec5SDimitry Andric       if (I + 1 != E && OptStr[I + 1] == '-') {
8910b57cec5SDimitry Andric         ++I;
8920b57cec5SDimitry Andric         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
8930b57cec5SDimitry Andric       } else {
8940b57cec5SDimitry Andric         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
8950b57cec5SDimitry Andric       }
8960b57cec5SDimitry Andric       break;
8970b57cec5SDimitry Andric     case 's':
8980b57cec5SDimitry Andric       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
8990b57cec5SDimitry Andric       break;
9000b57cec5SDimitry Andric     case 't':
9010b57cec5SDimitry Andric       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
9020b57cec5SDimitry Andric       break;
9030b57cec5SDimitry Andric     case 'y': {
9040b57cec5SDimitry Andric       bool OmitFramePointer = true;
9050b57cec5SDimitry Andric       if (I + 1 != E && OptStr[I + 1] == '-') {
9060b57cec5SDimitry Andric         OmitFramePointer = false;
9070b57cec5SDimitry Andric         ++I;
9080b57cec5SDimitry Andric       }
9090b57cec5SDimitry Andric       if (SupportsForcingFramePointer) {
9100b57cec5SDimitry Andric         if (OmitFramePointer)
9110b57cec5SDimitry Andric           DAL.AddFlagArg(A,
9120b57cec5SDimitry Andric                          Opts.getOption(options::OPT_fomit_frame_pointer));
9130b57cec5SDimitry Andric         else
9140b57cec5SDimitry Andric           DAL.AddFlagArg(
9150b57cec5SDimitry Andric               A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
9160b57cec5SDimitry Andric       } else {
9170b57cec5SDimitry Andric         // Don't warn about /Oy- in x86-64 builds (where
9180b57cec5SDimitry Andric         // SupportsForcingFramePointer is false).  The flag having no effect
9190b57cec5SDimitry Andric         // there is a compiler-internal optimization, and people shouldn't have
9200b57cec5SDimitry Andric         // to special-case their build files for x86-64 clang-cl.
9210b57cec5SDimitry Andric         A->claim();
9220b57cec5SDimitry Andric       }
9230b57cec5SDimitry Andric       break;
9240b57cec5SDimitry Andric     }
9250b57cec5SDimitry Andric     }
9260b57cec5SDimitry Andric   }
9270b57cec5SDimitry Andric }
9280b57cec5SDimitry Andric 
TranslateDArg(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)9290b57cec5SDimitry Andric static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
9300b57cec5SDimitry Andric                           const OptTable &Opts) {
9310b57cec5SDimitry Andric   assert(A->getOption().matches(options::OPT_D));
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric   StringRef Val = A->getValue();
9340b57cec5SDimitry Andric   size_t Hash = Val.find('#');
9350b57cec5SDimitry Andric   if (Hash == StringRef::npos || Hash > Val.find('=')) {
9360b57cec5SDimitry Andric     DAL.append(A);
9370b57cec5SDimitry Andric     return;
9380b57cec5SDimitry Andric   }
9390b57cec5SDimitry Andric 
9405ffd83dbSDimitry Andric   std::string NewVal = std::string(Val);
9410b57cec5SDimitry Andric   NewVal[Hash] = '=';
9420b57cec5SDimitry Andric   DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric 
TranslatePermissive(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)945fe6060f1SDimitry Andric static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,
946fe6060f1SDimitry Andric                                 const OptTable &Opts) {
947fe6060f1SDimitry Andric   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));
948fe6060f1SDimitry Andric   DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));
949fe6060f1SDimitry Andric }
950fe6060f1SDimitry Andric 
TranslatePermissiveMinus(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)951fe6060f1SDimitry Andric static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,
952fe6060f1SDimitry Andric                                      const OptTable &Opts) {
953fe6060f1SDimitry Andric   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));
954fe6060f1SDimitry Andric   DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));
955fe6060f1SDimitry Andric }
956fe6060f1SDimitry Andric 
9570b57cec5SDimitry Andric llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList & Args,StringRef BoundArch,Action::OffloadKind OFK) const9580b57cec5SDimitry Andric MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
9595ffd83dbSDimitry Andric                              StringRef BoundArch,
9605ffd83dbSDimitry Andric                              Action::OffloadKind OFK) const {
9610b57cec5SDimitry Andric   DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
9620b57cec5SDimitry Andric   const OptTable &Opts = getDriver().getOpts();
9630b57cec5SDimitry Andric 
9640b57cec5SDimitry Andric   // /Oy and /Oy- don't have an effect on X86-64
9650b57cec5SDimitry Andric   bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric   // The -O[12xd] flag actually expands to several flags.  We must desugar the
9680b57cec5SDimitry Andric   // flags so that options embedded can be negated.  For example, the '-O2' flag
9690b57cec5SDimitry Andric   // enables '-Oy'.  Expanding '-O2' into its constituent flags allows us to
9700b57cec5SDimitry Andric   // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
9710b57cec5SDimitry Andric   // aspect of '-O2'.
9720b57cec5SDimitry Andric   //
9730b57cec5SDimitry Andric   // Note that this expansion logic only applies to the *last* of '[12xd]'.
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric   // First step is to search for the character we'd like to expand.
9760b57cec5SDimitry Andric   const char *ExpandChar = nullptr;
9770b57cec5SDimitry Andric   for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
9780b57cec5SDimitry Andric     StringRef OptStr = A->getValue();
9790b57cec5SDimitry Andric     for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
9800b57cec5SDimitry Andric       char OptChar = OptStr[I];
9810b57cec5SDimitry Andric       char PrevChar = I > 0 ? OptStr[I - 1] : '0';
9820b57cec5SDimitry Andric       if (PrevChar == 'b') {
9830b57cec5SDimitry Andric         // OptChar does not expand; it's an argument to the previous char.
9840b57cec5SDimitry Andric         continue;
9850b57cec5SDimitry Andric       }
9860b57cec5SDimitry Andric       if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
9870b57cec5SDimitry Andric         ExpandChar = OptStr.data() + I;
9880b57cec5SDimitry Andric     }
9890b57cec5SDimitry Andric   }
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric   for (Arg *A : Args) {
9920b57cec5SDimitry Andric     if (A->getOption().matches(options::OPT__SLASH_O)) {
9930b57cec5SDimitry Andric       // The -O flag actually takes an amalgam of other options.  For example,
9940b57cec5SDimitry Andric       // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
9950b57cec5SDimitry Andric       TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
9960b57cec5SDimitry Andric     } else if (A->getOption().matches(options::OPT_D)) {
9970b57cec5SDimitry Andric       // Translate -Dfoo#bar into -Dfoo=bar.
9980b57cec5SDimitry Andric       TranslateDArg(A, *DAL, Opts);
999fe6060f1SDimitry Andric     } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {
1000fe6060f1SDimitry Andric       // Expand /permissive
1001fe6060f1SDimitry Andric       TranslatePermissive(A, *DAL, Opts);
1002fe6060f1SDimitry Andric     } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {
1003fe6060f1SDimitry Andric       // Expand /permissive-
1004fe6060f1SDimitry Andric       TranslatePermissiveMinus(A, *DAL, Opts);
10055ffd83dbSDimitry Andric     } else if (OFK != Action::OFK_HIP) {
10065ffd83dbSDimitry Andric       // HIP Toolchain translates input args by itself.
10070b57cec5SDimitry Andric       DAL->append(A);
10080b57cec5SDimitry Andric     }
10090b57cec5SDimitry Andric   }
10100b57cec5SDimitry Andric 
10110b57cec5SDimitry Andric   return DAL;
10120b57cec5SDimitry Andric }
1013fe6060f1SDimitry Andric 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadKind) const1014fe6060f1SDimitry Andric void MSVCToolChain::addClangTargetOptions(
1015fe6060f1SDimitry Andric     const ArgList &DriverArgs, ArgStringList &CC1Args,
1016fe6060f1SDimitry Andric     Action::OffloadKind DeviceOffloadKind) const {
1017fe6060f1SDimitry Andric   // MSVC STL kindly allows removing all usages of typeid by defining
1018fe6060f1SDimitry Andric   // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
101981ad6265SDimitry Andric   if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,
1020fe6060f1SDimitry Andric                          /*Default=*/false))
1021fe6060f1SDimitry Andric     CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
1022fe6060f1SDimitry Andric }
1023