10eae32dcSDimitry Andric //===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- C++ -*-===// 20eae32dcSDimitry Andric // 30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60eae32dcSDimitry Andric // 70eae32dcSDimitry Andric //===----------------------------------------------------------------------===// 80eae32dcSDimitry Andric 90eae32dcSDimitry Andric #include "HIPAMD.h" 100eae32dcSDimitry Andric #include "AMDGPU.h" 110eae32dcSDimitry Andric #include "CommonArgs.h" 120eae32dcSDimitry Andric #include "HIPUtility.h" 13*0fca6ea1SDimitry Andric #include "SPIRV.h" 140eae32dcSDimitry Andric #include "clang/Basic/Cuda.h" 150eae32dcSDimitry Andric #include "clang/Basic/TargetID.h" 160eae32dcSDimitry Andric #include "clang/Driver/Compilation.h" 170eae32dcSDimitry Andric #include "clang/Driver/Driver.h" 180eae32dcSDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 190eae32dcSDimitry Andric #include "clang/Driver/InputInfo.h" 200eae32dcSDimitry Andric #include "clang/Driver/Options.h" 210eae32dcSDimitry Andric #include "clang/Driver/SanitizerArgs.h" 220eae32dcSDimitry Andric #include "llvm/Support/Alignment.h" 230eae32dcSDimitry Andric #include "llvm/Support/FileSystem.h" 240eae32dcSDimitry Andric #include "llvm/Support/Path.h" 2506c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h" 260eae32dcSDimitry Andric 270eae32dcSDimitry Andric using namespace clang::driver; 280eae32dcSDimitry Andric using namespace clang::driver::toolchains; 290eae32dcSDimitry Andric using namespace clang::driver::tools; 300eae32dcSDimitry Andric using namespace clang; 310eae32dcSDimitry Andric using namespace llvm::opt; 320eae32dcSDimitry Andric 330eae32dcSDimitry Andric #if defined(_WIN32) || defined(_WIN64) 340eae32dcSDimitry Andric #define NULL_FILE "nul" 350eae32dcSDimitry Andric #else 360eae32dcSDimitry Andric #define NULL_FILE "/dev/null" 370eae32dcSDimitry Andric #endif 380eae32dcSDimitry Andric 390eae32dcSDimitry Andric static bool shouldSkipSanitizeOption(const ToolChain &TC, 400eae32dcSDimitry Andric const llvm::opt::ArgList &DriverArgs, 410eae32dcSDimitry Andric StringRef TargetID, 420eae32dcSDimitry Andric const llvm::opt::Arg *A) { 430eae32dcSDimitry Andric // For actions without targetID, do nothing. 440eae32dcSDimitry Andric if (TargetID.empty()) 450eae32dcSDimitry Andric return false; 460eae32dcSDimitry Andric Option O = A->getOption(); 470eae32dcSDimitry Andric if (!O.matches(options::OPT_fsanitize_EQ)) 480eae32dcSDimitry Andric return false; 490eae32dcSDimitry Andric 500eae32dcSDimitry Andric if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize, 5181ad6265SDimitry Andric options::OPT_fno_gpu_sanitize, true)) 520eae32dcSDimitry Andric return true; 530eae32dcSDimitry Andric 540eae32dcSDimitry Andric auto &Diags = TC.getDriver().getDiags(); 550eae32dcSDimitry Andric 560eae32dcSDimitry Andric // For simplicity, we only allow -fsanitize=address 570eae32dcSDimitry Andric SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); 580eae32dcSDimitry Andric if (K != SanitizerKind::Address) 590eae32dcSDimitry Andric return true; 600eae32dcSDimitry Andric 610eae32dcSDimitry Andric llvm::StringMap<bool> FeatureMap; 620eae32dcSDimitry Andric auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap); 630eae32dcSDimitry Andric 640eae32dcSDimitry Andric assert(OptionalGpuArch && "Invalid Target ID"); 650eae32dcSDimitry Andric (void)OptionalGpuArch; 660eae32dcSDimitry Andric auto Loc = FeatureMap.find("xnack"); 670eae32dcSDimitry Andric if (Loc == FeatureMap.end() || !Loc->second) { 680eae32dcSDimitry Andric Diags.Report( 690eae32dcSDimitry Andric clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature) 700eae32dcSDimitry Andric << A->getAsString(DriverArgs) << TargetID << "xnack+"; 710eae32dcSDimitry Andric return true; 720eae32dcSDimitry Andric } 730eae32dcSDimitry Andric return false; 740eae32dcSDimitry Andric } 750eae32dcSDimitry Andric 7681ad6265SDimitry Andric void AMDGCN::Linker::constructLlvmLinkCommand(Compilation &C, 7781ad6265SDimitry Andric const JobAction &JA, 7881ad6265SDimitry Andric const InputInfoList &Inputs, 7981ad6265SDimitry Andric const InputInfo &Output, 8081ad6265SDimitry Andric const llvm::opt::ArgList &Args) const { 8181ad6265SDimitry Andric // Construct llvm-link command. 8281ad6265SDimitry Andric // The output from llvm-link is a bitcode file. 8381ad6265SDimitry Andric ArgStringList LlvmLinkArgs; 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric assert(!Inputs.empty() && "Must have at least one input."); 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric LlvmLinkArgs.append({"-o", Output.getFilename()}); 8881ad6265SDimitry Andric for (auto Input : Inputs) 8981ad6265SDimitry Andric LlvmLinkArgs.push_back(Input.getFilename()); 9081ad6265SDimitry Andric 9181ad6265SDimitry Andric // Look for archive of bundled bitcode in arguments, and add temporary files 9281ad6265SDimitry Andric // for the extracted archive of bitcode to inputs. 9381ad6265SDimitry Andric auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); 9481ad6265SDimitry Andric AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LlvmLinkArgs, "amdgcn", 955f757f3fSDimitry Andric TargetID, /*IsBitCodeSDL=*/true); 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric const char *LlvmLink = 9881ad6265SDimitry Andric Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); 9981ad6265SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 10081ad6265SDimitry Andric LlvmLink, LlvmLinkArgs, Inputs, 10181ad6265SDimitry Andric Output)); 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 1040eae32dcSDimitry Andric void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, 1050eae32dcSDimitry Andric const InputInfoList &Inputs, 1060eae32dcSDimitry Andric const InputInfo &Output, 1070eae32dcSDimitry Andric const llvm::opt::ArgList &Args) const { 1080eae32dcSDimitry Andric // Construct lld command. 1090eae32dcSDimitry Andric // The output from ld.lld is an HSA code object file. 110bdd1243dSDimitry Andric ArgStringList LldArgs{"-flavor", 111bdd1243dSDimitry Andric "gnu", 112bdd1243dSDimitry Andric "-m", 113bdd1243dSDimitry Andric "elf64_amdgpu", 114bdd1243dSDimitry Andric "--no-undefined", 115bdd1243dSDimitry Andric "-shared", 1160eae32dcSDimitry Andric "-plugin-opt=-amdgpu-internalize-symbols"}; 1175f757f3fSDimitry Andric if (Args.hasArg(options::OPT_hipstdpar)) 1185f757f3fSDimitry Andric LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar"); 1190eae32dcSDimitry Andric 1200eae32dcSDimitry Andric auto &TC = getToolChain(); 1210eae32dcSDimitry Andric auto &D = TC.getDriver(); 1220eae32dcSDimitry Andric assert(!Inputs.empty() && "Must have at least one input."); 1230eae32dcSDimitry Andric bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin; 1240eae32dcSDimitry Andric addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], IsThinLTO); 1250eae32dcSDimitry Andric 1260eae32dcSDimitry Andric // Extract all the -m options 1270eae32dcSDimitry Andric std::vector<llvm::StringRef> Features; 1280eae32dcSDimitry Andric amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features); 1290eae32dcSDimitry Andric 1300eae32dcSDimitry Andric // Add features to mattr such as cumode 1310eae32dcSDimitry Andric std::string MAttrString = "-plugin-opt=-mattr="; 1320eae32dcSDimitry Andric for (auto OneFeature : unifyTargetFeatures(Features)) { 1330eae32dcSDimitry Andric MAttrString.append(Args.MakeArgString(OneFeature)); 1340eae32dcSDimitry Andric if (OneFeature != Features.back()) 1350eae32dcSDimitry Andric MAttrString.append(","); 1360eae32dcSDimitry Andric } 1370eae32dcSDimitry Andric if (!Features.empty()) 1380eae32dcSDimitry Andric LldArgs.push_back(Args.MakeArgString(MAttrString)); 1390eae32dcSDimitry Andric 1400eae32dcSDimitry Andric // ToDo: Remove this option after AMDGPU backend supports ISA-level linking. 1410eae32dcSDimitry Andric // Since AMDGPU backend currently does not support ISA-level linking, all 1420eae32dcSDimitry Andric // called functions need to be imported. 1430eae32dcSDimitry Andric if (IsThinLTO) 1440eae32dcSDimitry Andric LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all")); 1450eae32dcSDimitry Andric 146*0fca6ea1SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 147*0fca6ea1SDimitry Andric LldArgs.push_back( 148*0fca6ea1SDimitry Andric Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0))); 149*0fca6ea1SDimitry Andric } 150*0fca6ea1SDimitry Andric 1510eae32dcSDimitry Andric if (C.getDriver().isSaveTempsEnabled()) 1520eae32dcSDimitry Andric LldArgs.push_back("-save-temps"); 1530eae32dcSDimitry Andric 1540eae32dcSDimitry Andric addLinkerCompressDebugSectionsOption(TC, Args, LldArgs); 1550eae32dcSDimitry Andric 15606c3fb27SDimitry Andric // Given that host and device linking happen in separate processes, the device 15706c3fb27SDimitry Andric // linker doesn't always have the visibility as to which device symbols are 15806c3fb27SDimitry Andric // needed by a program, especially for the device symbol dependencies that are 15906c3fb27SDimitry Andric // introduced through the host symbol resolution. 16006c3fb27SDimitry Andric // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B() 16106c3fb27SDimitry Andric // (B.obj) In this case, the device linker doesn't know that A.obj actually 16206c3fb27SDimitry Andric // depends on the kernel functions in B.obj. When linking to static device 16306c3fb27SDimitry Andric // library, the device linker may drop some of the device global symbols if 16406c3fb27SDimitry Andric // they aren't referenced. As a workaround, we are adding to the 16506c3fb27SDimitry Andric // --whole-archive flag such that all global symbols would be linked in. 16606c3fb27SDimitry Andric LldArgs.push_back("--whole-archive"); 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) { 16906c3fb27SDimitry Andric StringRef ArgVal = Arg->getValue(1); 17006c3fb27SDimitry Andric auto SplitArg = ArgVal.split("-mllvm="); 17106c3fb27SDimitry Andric if (!SplitArg.second.empty()) { 17206c3fb27SDimitry Andric LldArgs.push_back( 17306c3fb27SDimitry Andric Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second)); 17406c3fb27SDimitry Andric } else { 17506c3fb27SDimitry Andric LldArgs.push_back(Args.MakeArgString(ArgVal)); 17606c3fb27SDimitry Andric } 17706c3fb27SDimitry Andric Arg->claim(); 17806c3fb27SDimitry Andric } 17981ad6265SDimitry Andric 1800eae32dcSDimitry Andric LldArgs.append({"-o", Output.getFilename()}); 1810eae32dcSDimitry Andric for (auto Input : Inputs) 1820eae32dcSDimitry Andric LldArgs.push_back(Input.getFilename()); 1830eae32dcSDimitry Andric 18481ad6265SDimitry Andric // Look for archive of bundled bitcode in arguments, and add temporary files 18581ad6265SDimitry Andric // for the extracted archive of bitcode to inputs. 18681ad6265SDimitry Andric auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); 18781ad6265SDimitry Andric AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LldArgs, "amdgcn", 1885f757f3fSDimitry Andric TargetID, /*IsBitCodeSDL=*/true); 18981ad6265SDimitry Andric 19006c3fb27SDimitry Andric LldArgs.push_back("--no-whole-archive"); 19106c3fb27SDimitry Andric 1920eae32dcSDimitry Andric const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); 1930eae32dcSDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 1940eae32dcSDimitry Andric Lld, LldArgs, Inputs, Output)); 1950eae32dcSDimitry Andric } 1960eae32dcSDimitry Andric 197*0fca6ea1SDimitry Andric // For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode 198*0fca6ea1SDimitry Andric // and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It 199*0fca6ea1SDimitry Andric // calls llvm-link and then the llvm-spirv translator. Once the SPIR-V BE will 200*0fca6ea1SDimitry Andric // be promoted from experimental, we will switch to using that. TODO: consider 201*0fca6ea1SDimitry Andric // if we want to run any targeted optimisations over IR here, over generic 202*0fca6ea1SDimitry Andric // SPIR-V. 203*0fca6ea1SDimitry Andric void AMDGCN::Linker::constructLinkAndEmitSpirvCommand( 204*0fca6ea1SDimitry Andric Compilation &C, const JobAction &JA, const InputInfoList &Inputs, 205*0fca6ea1SDimitry Andric const InputInfo &Output, const llvm::opt::ArgList &Args) const { 206*0fca6ea1SDimitry Andric assert(!Inputs.empty() && "Must have at least one input."); 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric constructLlvmLinkCommand(C, JA, Inputs, Output, Args); 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric // Linked BC is now in Output 211*0fca6ea1SDimitry Andric 212*0fca6ea1SDimitry Andric // Emit SPIR-V binary. 213*0fca6ea1SDimitry Andric llvm::opt::ArgStringList TrArgs{ 214*0fca6ea1SDimitry Andric "--spirv-max-version=1.6", 215*0fca6ea1SDimitry Andric "--spirv-ext=+all", 216*0fca6ea1SDimitry Andric "--spirv-allow-extra-diexpressions", 217*0fca6ea1SDimitry Andric "--spirv-allow-unknown-intrinsics", 218*0fca6ea1SDimitry Andric "--spirv-lower-const-expr", 219*0fca6ea1SDimitry Andric "--spirv-preserve-auxdata", 220*0fca6ea1SDimitry Andric "--spirv-debug-info-version=nonsemantic-shader-200"}; 221*0fca6ea1SDimitry Andric SPIRV::constructTranslateCommand(C, *this, JA, Output, Output, TrArgs); 222*0fca6ea1SDimitry Andric } 223*0fca6ea1SDimitry Andric 2240eae32dcSDimitry Andric // For amdgcn the inputs of the linker job are device bitcode and output is 22581ad6265SDimitry Andric // either an object file or bitcode (-emit-llvm). It calls llvm-link, opt, 22681ad6265SDimitry Andric // llc, then lld steps. 2270eae32dcSDimitry Andric void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, 2280eae32dcSDimitry Andric const InputInfo &Output, 2290eae32dcSDimitry Andric const InputInfoList &Inputs, 2300eae32dcSDimitry Andric const ArgList &Args, 2310eae32dcSDimitry Andric const char *LinkingOutput) const { 2320eae32dcSDimitry Andric if (Inputs.size() > 0 && 2330eae32dcSDimitry Andric Inputs[0].getType() == types::TY_Image && 2340eae32dcSDimitry Andric JA.getType() == types::TY_Object) 2350eae32dcSDimitry Andric return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, 2360eae32dcSDimitry Andric Args, JA, *this); 2370eae32dcSDimitry Andric 2380eae32dcSDimitry Andric if (JA.getType() == types::TY_HIP_FATBIN) 2390eae32dcSDimitry Andric return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, 2400eae32dcSDimitry Andric Args, *this); 2410eae32dcSDimitry Andric 24281ad6265SDimitry Andric if (JA.getType() == types::TY_LLVM_BC) 24381ad6265SDimitry Andric return constructLlvmLinkCommand(C, JA, Inputs, Output, Args); 24481ad6265SDimitry Andric 245*0fca6ea1SDimitry Andric if (getToolChain().getTriple().isSPIRV()) 246*0fca6ea1SDimitry Andric return constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args); 247*0fca6ea1SDimitry Andric 2480eae32dcSDimitry Andric return constructLldCommand(C, JA, Inputs, Output, Args); 2490eae32dcSDimitry Andric } 2500eae32dcSDimitry Andric 2510eae32dcSDimitry Andric HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, 2520eae32dcSDimitry Andric const ToolChain &HostTC, const ArgList &Args) 2530eae32dcSDimitry Andric : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { 2540eae32dcSDimitry Andric // Lookup binaries into the driver directory, this is used to 2550eae32dcSDimitry Andric // discover the clang-offload-bundler executable. 2560eae32dcSDimitry Andric getProgramPaths().push_back(getDriver().Dir); 2570eae32dcSDimitry Andric 2580eae32dcSDimitry Andric // Diagnose unsupported sanitizer options only once. 25981ad6265SDimitry Andric if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, 26081ad6265SDimitry Andric true)) 26181ad6265SDimitry Andric return; 262bdd1243dSDimitry Andric for (auto *A : Args.filtered(options::OPT_fsanitize_EQ)) { 2630eae32dcSDimitry Andric SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); 2640eae32dcSDimitry Andric if (K != SanitizerKind::Address) 2650eae32dcSDimitry Andric D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target) 2660eae32dcSDimitry Andric << A->getAsString(Args) << getTriple().str(); 2670eae32dcSDimitry Andric } 2680eae32dcSDimitry Andric } 2690eae32dcSDimitry Andric 2700eae32dcSDimitry Andric void HIPAMDToolChain::addClangTargetOptions( 2710eae32dcSDimitry Andric const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, 2720eae32dcSDimitry Andric Action::OffloadKind DeviceOffloadingKind) const { 2730eae32dcSDimitry Andric HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); 2740eae32dcSDimitry Andric 2750eae32dcSDimitry Andric assert(DeviceOffloadingKind == Action::OFK_HIP && 2760eae32dcSDimitry Andric "Only HIP offloading kinds are supported for GPUs."); 2770eae32dcSDimitry Andric 2780eae32dcSDimitry Andric CC1Args.push_back("-fcuda-is-device"); 2790eae32dcSDimitry Andric 2800eae32dcSDimitry Andric if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, 2810eae32dcSDimitry Andric false)) 2820eae32dcSDimitry Andric CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"}); 2835f757f3fSDimitry Andric if (DriverArgs.hasArgNoClaim(options::OPT_hipstdpar)) 2845f757f3fSDimitry Andric CC1Args.append({"-mllvm", "-amdgpu-enable-hipstdpar"}); 2850eae32dcSDimitry Andric 2860eae32dcSDimitry Andric StringRef MaxThreadsPerBlock = 2870eae32dcSDimitry Andric DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); 2880eae32dcSDimitry Andric if (!MaxThreadsPerBlock.empty()) { 2890eae32dcSDimitry Andric std::string ArgStr = 290bdd1243dSDimitry Andric (Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock).str(); 2910eae32dcSDimitry Andric CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); 2920eae32dcSDimitry Andric } 2930eae32dcSDimitry Andric 2940eae32dcSDimitry Andric CC1Args.push_back("-fcuda-allow-variadic-functions"); 2950eae32dcSDimitry Andric 2960eae32dcSDimitry Andric // Default to "hidden" visibility, as object level linking will not be 2970eae32dcSDimitry Andric // supported for the foreseeable future. 2980eae32dcSDimitry Andric if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, 2990eae32dcSDimitry Andric options::OPT_fvisibility_ms_compat)) { 300bdd1243dSDimitry Andric CC1Args.append({"-fvisibility=hidden"}); 3010eae32dcSDimitry Andric CC1Args.push_back("-fapply-global-visibility-to-externs"); 3020eae32dcSDimitry Andric } 3030eae32dcSDimitry Andric 304*0fca6ea1SDimitry Andric // For SPIR-V we embed the command-line into the generated binary, in order to 305*0fca6ea1SDimitry Andric // retrieve it at JIT time and be able to do target specific compilation with 306*0fca6ea1SDimitry Andric // options that match the user-supplied ones. 307*0fca6ea1SDimitry Andric if (getTriple().isSPIRV() && 308*0fca6ea1SDimitry Andric !DriverArgs.hasArg(options::OPT_fembed_bitcode_marker)) 309*0fca6ea1SDimitry Andric CC1Args.push_back("-fembed-bitcode=marker"); 310*0fca6ea1SDimitry Andric 311bdd1243dSDimitry Andric for (auto BCFile : getDeviceLibs(DriverArgs)) { 3120eae32dcSDimitry Andric CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" 3130eae32dcSDimitry Andric : "-mlink-bitcode-file"); 3140eae32dcSDimitry Andric CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); 31581ad6265SDimitry Andric } 3160eae32dcSDimitry Andric } 3170eae32dcSDimitry Andric 3180eae32dcSDimitry Andric llvm::opt::DerivedArgList * 3190eae32dcSDimitry Andric HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, 3200eae32dcSDimitry Andric StringRef BoundArch, 3210eae32dcSDimitry Andric Action::OffloadKind DeviceOffloadKind) const { 3220eae32dcSDimitry Andric DerivedArgList *DAL = 3230eae32dcSDimitry Andric HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); 3240eae32dcSDimitry Andric if (!DAL) 3250eae32dcSDimitry Andric DAL = new DerivedArgList(Args.getBaseArgs()); 3260eae32dcSDimitry Andric 3270eae32dcSDimitry Andric const OptTable &Opts = getDriver().getOpts(); 3280eae32dcSDimitry Andric 3290eae32dcSDimitry Andric for (Arg *A : Args) { 33006c3fb27SDimitry Andric if (!shouldSkipSanitizeOption(*this, Args, BoundArch, A)) 3310eae32dcSDimitry Andric DAL->append(A); 3320eae32dcSDimitry Andric } 3330eae32dcSDimitry Andric 3340eae32dcSDimitry Andric if (!BoundArch.empty()) { 3350eae32dcSDimitry Andric DAL->eraseArg(options::OPT_mcpu_EQ); 3360eae32dcSDimitry Andric DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch); 3370eae32dcSDimitry Andric checkTargetID(*DAL); 3380eae32dcSDimitry Andric } 3390eae32dcSDimitry Andric 3400eae32dcSDimitry Andric return DAL; 3410eae32dcSDimitry Andric } 3420eae32dcSDimitry Andric 3430eae32dcSDimitry Andric Tool *HIPAMDToolChain::buildLinker() const { 344*0fca6ea1SDimitry Andric assert(getTriple().getArch() == llvm::Triple::amdgcn || 345*0fca6ea1SDimitry Andric getTriple().getArch() == llvm::Triple::spirv64); 3460eae32dcSDimitry Andric return new tools::AMDGCN::Linker(*this); 3470eae32dcSDimitry Andric } 3480eae32dcSDimitry Andric 3490eae32dcSDimitry Andric void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { 350*0fca6ea1SDimitry Andric AMDGPUToolChain::addClangWarningOptions(CC1Args); 3510eae32dcSDimitry Andric HostTC.addClangWarningOptions(CC1Args); 3520eae32dcSDimitry Andric } 3530eae32dcSDimitry Andric 3540eae32dcSDimitry Andric ToolChain::CXXStdlibType 3550eae32dcSDimitry Andric HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const { 3560eae32dcSDimitry Andric return HostTC.GetCXXStdlibType(Args); 3570eae32dcSDimitry Andric } 3580eae32dcSDimitry Andric 3590eae32dcSDimitry Andric void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 3600eae32dcSDimitry Andric ArgStringList &CC1Args) const { 3610eae32dcSDimitry Andric HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); 3620eae32dcSDimitry Andric } 3630eae32dcSDimitry Andric 3640eae32dcSDimitry Andric void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs( 3650eae32dcSDimitry Andric const ArgList &Args, ArgStringList &CC1Args) const { 3660eae32dcSDimitry Andric HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); 3670eae32dcSDimitry Andric } 3680eae32dcSDimitry Andric 3690eae32dcSDimitry Andric void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args, 3700eae32dcSDimitry Andric ArgStringList &CC1Args) const { 3710eae32dcSDimitry Andric HostTC.AddIAMCUIncludeArgs(Args, CC1Args); 3720eae32dcSDimitry Andric } 3730eae32dcSDimitry Andric 3740eae32dcSDimitry Andric void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, 3750eae32dcSDimitry Andric ArgStringList &CC1Args) const { 37606c3fb27SDimitry Andric RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); 3770eae32dcSDimitry Andric } 3780eae32dcSDimitry Andric 3790eae32dcSDimitry Andric SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const { 3800eae32dcSDimitry Andric // The HIPAMDToolChain only supports sanitizers in the sense that it allows 3810eae32dcSDimitry Andric // sanitizer arguments on the command line if they are supported by the host 3820eae32dcSDimitry Andric // toolchain. The HIPAMDToolChain will actually ignore any command line 3830eae32dcSDimitry Andric // arguments for any of these "supported" sanitizers. That means that no 3840eae32dcSDimitry Andric // sanitization of device code is actually supported at this time. 3850eae32dcSDimitry Andric // 3860eae32dcSDimitry Andric // This behavior is necessary because the host and device toolchains 3870eae32dcSDimitry Andric // invocations often share the command line, so the device toolchain must 3880eae32dcSDimitry Andric // tolerate flags meant only for the host toolchain. 3890eae32dcSDimitry Andric return HostTC.getSupportedSanitizers(); 3900eae32dcSDimitry Andric } 3910eae32dcSDimitry Andric 3920eae32dcSDimitry Andric VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, 3930eae32dcSDimitry Andric const ArgList &Args) const { 3940eae32dcSDimitry Andric return HostTC.computeMSVCVersion(D, Args); 3950eae32dcSDimitry Andric } 3960eae32dcSDimitry Andric 3970eae32dcSDimitry Andric llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> 398bdd1243dSDimitry Andric HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { 3990eae32dcSDimitry Andric llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs; 400*0fca6ea1SDimitry Andric if (DriverArgs.hasArg(options::OPT_nogpulib) || 401*0fca6ea1SDimitry Andric (getTriple().getArch() == llvm::Triple::spirv64 && 402*0fca6ea1SDimitry Andric getTriple().getVendor() == llvm::Triple::AMD)) 4030eae32dcSDimitry Andric return {}; 4040eae32dcSDimitry Andric ArgStringList LibraryPaths; 4050eae32dcSDimitry Andric 4060eae32dcSDimitry Andric // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. 40706c3fb27SDimitry Andric for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg()) 4080eae32dcSDimitry Andric LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); 4090eae32dcSDimitry Andric 4100eae32dcSDimitry Andric addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); 4110eae32dcSDimitry Andric 4120eae32dcSDimitry Andric // Maintain compatability with --hip-device-lib. 4130eae32dcSDimitry Andric auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); 4140eae32dcSDimitry Andric if (!BCLibArgs.empty()) { 4150eae32dcSDimitry Andric llvm::for_each(BCLibArgs, [&](StringRef BCName) { 4160eae32dcSDimitry Andric StringRef FullName; 417bdd1243dSDimitry Andric for (StringRef LibraryPath : LibraryPaths) { 4180eae32dcSDimitry Andric SmallString<128> Path(LibraryPath); 4190eae32dcSDimitry Andric llvm::sys::path::append(Path, BCName); 4200eae32dcSDimitry Andric FullName = Path; 4210eae32dcSDimitry Andric if (llvm::sys::fs::exists(FullName)) { 4220eae32dcSDimitry Andric BCLibs.push_back(FullName); 4230eae32dcSDimitry Andric return; 4240eae32dcSDimitry Andric } 4250eae32dcSDimitry Andric } 4260eae32dcSDimitry Andric getDriver().Diag(diag::err_drv_no_such_file) << BCName; 4270eae32dcSDimitry Andric }); 4280eae32dcSDimitry Andric } else { 42906c3fb27SDimitry Andric if (!RocmInstallation->hasDeviceLibrary()) { 4300eae32dcSDimitry Andric getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; 4310eae32dcSDimitry Andric return {}; 4320eae32dcSDimitry Andric } 4330eae32dcSDimitry Andric StringRef GpuArch = getGPUArch(DriverArgs); 4340eae32dcSDimitry Andric assert(!GpuArch.empty() && "Must have an explicit GPU arch."); 4350eae32dcSDimitry Andric 4360eae32dcSDimitry Andric // If --hip-device-lib is not set, add the default bitcode libraries. 4370eae32dcSDimitry Andric if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, 43881ad6265SDimitry Andric options::OPT_fno_gpu_sanitize, true) && 4390eae32dcSDimitry Andric getSanitizerArgs(DriverArgs).needsAsanRt()) { 44006c3fb27SDimitry Andric auto AsanRTL = RocmInstallation->getAsanRTLPath(); 4410eae32dcSDimitry Andric if (AsanRTL.empty()) { 4420eae32dcSDimitry Andric unsigned DiagID = getDriver().getDiags().getCustomDiagID( 4430eae32dcSDimitry Andric DiagnosticsEngine::Error, 4440eae32dcSDimitry Andric "AMDGPU address sanitizer runtime library (asanrtl) is not found. " 4450eae32dcSDimitry Andric "Please install ROCm device library which supports address " 4460eae32dcSDimitry Andric "sanitizer"); 4470eae32dcSDimitry Andric getDriver().Diag(DiagID); 4480eae32dcSDimitry Andric return {}; 4490eae32dcSDimitry Andric } else 450bdd1243dSDimitry Andric BCLibs.emplace_back(AsanRTL, /*ShouldInternalize=*/false); 4510eae32dcSDimitry Andric } 4520eae32dcSDimitry Andric 4530eae32dcSDimitry Andric // Add the HIP specific bitcode library. 45406c3fb27SDimitry Andric BCLibs.push_back(RocmInstallation->getHIPPath()); 4550eae32dcSDimitry Andric 4560eae32dcSDimitry Andric // Add common device libraries like ocml etc. 457bdd1243dSDimitry Andric for (StringRef N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) 458bdd1243dSDimitry Andric BCLibs.emplace_back(N); 4590eae32dcSDimitry Andric 4600eae32dcSDimitry Andric // Add instrument lib. 4610eae32dcSDimitry Andric auto InstLib = 4620eae32dcSDimitry Andric DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ); 4630eae32dcSDimitry Andric if (InstLib.empty()) 4640eae32dcSDimitry Andric return BCLibs; 4650eae32dcSDimitry Andric if (llvm::sys::fs::exists(InstLib)) 4660eae32dcSDimitry Andric BCLibs.push_back(InstLib); 4670eae32dcSDimitry Andric else 4680eae32dcSDimitry Andric getDriver().Diag(diag::err_drv_no_such_file) << InstLib; 4690eae32dcSDimitry Andric } 4700eae32dcSDimitry Andric 4710eae32dcSDimitry Andric return BCLibs; 4720eae32dcSDimitry Andric } 4730eae32dcSDimitry Andric 4740eae32dcSDimitry Andric void HIPAMDToolChain::checkTargetID( 4750eae32dcSDimitry Andric const llvm::opt::ArgList &DriverArgs) const { 4760eae32dcSDimitry Andric auto PTID = getParsedTargetID(DriverArgs); 4770eae32dcSDimitry Andric if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { 4780eae32dcSDimitry Andric getDriver().Diag(clang::diag::err_drv_bad_target_id) 47981ad6265SDimitry Andric << *PTID.OptionalTargetID; 4800eae32dcSDimitry Andric } 4810eae32dcSDimitry Andric } 482