// For amdgcn the inputs of the linker job are device bitcode and output is // object file. It calls llvm-link, opt, llc, then lld steps. void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { assert(getToolChain().getTriple().getArch() == llvm::Triple::amdgcn && "Unsupported target"); std::string SubArchName = JA.getOffloadingArch(); assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch"); // Prefix for temporary file name. std::string Prefix = llvm::sys::path::stem(Inputs[0].getFilename()).str() + "-" + SubArchName; // Each command outputs different files. const char *LLVMLinkCommand = constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix); const char *OptCommand = constructOptCommand(C, JA, Inputs, Args, SubArchName, Prefix, LLVMLinkCommand); const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand); constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); }
void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1); const InputInfo &II = Inputs[0]; assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || II.getType() == types::TY_PP_CXX); if (JA.getKind() == Action::PreprocessJobClass) { Args.ClaimAllArgs(); CmdArgs.push_back("-E"); } else { assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. CmdArgs.push_back("-S"); CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. } CmdArgs.push_back("-DMYRIAD2"); // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' // flags, 'g' flags, 'M' flags, optimize flags, warning options, // mcpu flags, mllvm flags, and Xclang flags. // These are spelled the same way in clang and moviCompile. Args.AddAllArgsExcept( CmdArgs, {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, options::OPT_D, options::OPT_U, options::OPT_f_Group, options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, options::OPT_mllvm, options::OPT_Xclang}, {options::OPT_fno_split_dwarf_inlining}); Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. // If we're producing a dependency file, and assembly is the final action, // then the name of the target in the dependency file should be the '.o' // file, not the '.s' file produced by this step. For example, instead of // /tmp/mumble.s: mumble.c .../someheader.h // the filename on the lefthand side should be "mumble.o" if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && C.getActions().size() == 1 && C.getActions()[0]->getKind() == Action::AssembleJobClass) { Arg *A = Args.getLastArg(options::OPT_o); if (A) { CmdArgs.push_back("-MT"); CmdArgs.push_back(Args.MakeArgString(A->getValue())); } } CmdArgs.push_back(II.getFilename()); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs)); }
bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, const std::string &ArchNameStr) const { // FIXME: Remove this hack. const char *ArchName = ArchNameStr.c_str(); if (ArchNameStr == "powerpc") ArchName = "ppc"; else if (ArchNameStr == "powerpc64") ArchName = "ppc64"; // Check if user requested no clang, or clang doesn't understand // this type (we only handle single inputs for now). if (!CCCUseClang || JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) return false; // Otherwise make sure this is an action clang understands. if (isa<PreprocessJobAction>(JA)) { if (!CCCUseClangCPP) { Diag(clang::diag::warn_drv_not_using_clang_cpp); return false; } } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA)) return false; // Use clang for C++? if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) { Diag(clang::diag::warn_drv_not_using_clang_cxx); return false; } // Always use clang for precompiling, regardless of archs. PTH is // platform independent, and this allows the use of the static // analyzer on platforms we don't have full IRgen support for. if (isa<PrecompileJobAction>(JA)) return true; // Finally, don't use clang if this isn't one of the user specified // archs to build. if (!CCCClangArchs.empty() && !CCCClangArchs.count(ArchName)) { Diag(clang::diag::warn_drv_not_using_clang_arch) << ArchName; return false; } return true; }
void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const JobAction &JA) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { // If the current tool chain refers to an OpenMP offloading host, we should // ignore inputs that refer to OpenMP offloading devices - they will be // embedded according to a proper linker script. if (auto *IA = II.getAction()) if (JA.isHostOffloading(Action::OFK_OpenMP) && IA->isDeviceOffloading(Action::OFK_OpenMP)) continue; if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) // Don't try to pass LLVM inputs unless we have native support. D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); // Add filenames immediately. if (II.isFilename()) { CmdArgs.push_back(II.getFilename()); continue; } // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); // Handle reserved library options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) TC.AddCCKextLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_z)) { // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } } // LIBRARY_PATH - included following the user specified library paths. // and only supported on native toolchains. if (!TC.isCrossCompiling()) { addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); } }
bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, const llvm::Triple &Triple) const { // Check if user requested no clang, or clang doesn't understand this type (we // only handle single inputs for now). if (!CCCUseClang || JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) return false; // Otherwise make sure this is an action clang understands. if (isa<PreprocessJobAction>(JA)) { if (!CCCUseClangCPP) { Diag(clang::diag::warn_drv_not_using_clang_cpp); return false; } } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA)) return false; // Use clang for C++? if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) { Diag(clang::diag::warn_drv_not_using_clang_cxx); return false; } // Always use clang for precompiling, AST generation, and rewriting, // regardless of archs. if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST || JA.getType() == types::TY_RewrittenObjC) return true; // Finally, don't use clang if this isn't one of the user specified archs to // build. if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) { Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName(); return false; } return true; }
void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); ArgStringList CmdArgs; // OpenMP uses nvlink to link cubin files. The result will be embedded in the // host binary by the host linker. assert(!JA.isHostOffloading(Action::OFK_OpenMP) && "CUDA toolchain not expected for an OpenMP host device."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else assert(Output.isNothing() && "Invalid output."); if (Args.hasArg(options::OPT_g_Flag)) CmdArgs.push_back("-g"); if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ); assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); CmdArgs.push_back("-arch"); CmdArgs.push_back(Args.MakeArgString(GPUArch)); // Add paths specified in LIBRARY_PATH environment variable as -L options. addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); // Add paths for the default clang library path. SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(TC.getDriver().Dir); llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); // Add linking against library implementing OpenMP calls on NVPTX target. CmdArgs.push_back("-lomptarget-nvptx"); for (const auto &II : Inputs) { if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) { C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); continue; } // Currently, we only pass the input files to the linker, we do not pass // any libraries that may be valid only for the host. if (!II.isFilename()) continue; const char *CubinF = C.addTempFile( C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); CmdArgs.push_back(CubinF); } AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); StringRef GPUArchName; // If this is an OpenMP action we need to extract the device architecture // from the -march=arch option. This option may come from -Xopenmp-target // flag or the default value. if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); assert(!GPUArchName.empty() && "Must have an architecture passed in."); } else GPUArchName = JA.getOffloadingArch(); // Obtain architecture from the action. CudaArch gpu_arch = StringToCudaArch(GPUArchName); assert(gpu_arch != CudaArch::UNKNOWN && "Device action expected to have an architecture."); // Check that our installation's ptxas supports gpu_arch. if (!Args.hasArg(options::OPT_no_cuda_version_check)) { TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); } ArgStringList CmdArgs; CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32"); if (Args.hasFlag(options::OPT_cuda_noopt_device_debug, options::OPT_no_cuda_noopt_device_debug, false)) { // ptxas does not accept -g option if optimization is enabled, so // we ignore the compiler's -O* options if we want debug info. CmdArgs.push_back("-g"); CmdArgs.push_back("--dont-merge-basicblocks"); CmdArgs.push_back("--return-at-end"); } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { // Map the -O we received to -O{0,1,2,3}. // // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's // default, so it may correspond more closely to the spirit of clang -O2. // -O3 seems like the least-bad option when -Osomething is specified to // clang but it isn't handled below. StringRef OOpt = "3"; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) OOpt = "3"; else if (A->getOption().matches(options::OPT_O0)) OOpt = "0"; else if (A->getOption().matches(options::OPT_O)) { // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options. OOpt = llvm::StringSwitch<const char *>(A->getValue()) .Case("1", "1") .Case("2", "2") .Case("3", "3") .Case("s", "2") .Case("z", "2") .Default("2"); } CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); } else { // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond // to no optimizations, but ptxas's default is -O3. CmdArgs.push_back("-O0"); } // Pass -v to ptxas if it was passed to the driver. if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); CmdArgs.push_back("--gpu-name"); CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); for (const auto& II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); // In OpenMP we need to generate relocatable code. if (JA.isOffloading(Action::OFK_OpenMP) && Args.hasFlag(options::OPT_fopenmp_relocatable_target, options::OPT_fnoopenmp_relocatable_target, /*Default=*/ true)) CmdArgs.push_back("-c"); const char *Exec; if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) Exec = A->getValue(); else Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
/// Add OpenMP linker script arguments at the end of the argument list so that /// the fat binary is built by embedding each of the device images into the /// host. The linker script also defines a few symbols required by the code /// generation so that the images can be easily retrieved at runtime by the /// offloading library. This should be used only in tool chains that support /// linker scripts. void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const JobAction &JA) { // If this is not an OpenMP host toolchain, we don't need to do anything. if (!JA.isHostOffloading(Action::OFK_OpenMP)) return; // Create temporary linker script. Keep it if save-temps is enabled. const char *LKS; SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); if (C.getDriver().isSaveTempsEnabled()) { llvm::sys::path::replace_extension(Name, "lk"); LKS = C.getArgs().MakeArgString(Name.c_str()); } else { llvm::sys::path::replace_extension(Name, ""); Name = C.getDriver().GetTemporaryPath(Name, "lk"); LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); } // Add linker script option to the command. CmdArgs.push_back("-T"); CmdArgs.push_back(LKS); // Create a buffer to write the contents of the linker script. std::string LksBuffer; llvm::raw_string_ostream LksStream(LksBuffer); // Get the OpenMP offload tool chains so that we can extract the triple // associated with each device input. auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); assert(OpenMPToolChains.first != OpenMPToolChains.second && "No OpenMP toolchains??"); // Track the input file name and device triple in order to build the script, // inserting binaries in the designated sections. SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; // Add commands to embed target binaries. We ensure that each section and // image is 16-byte aligned. This is not mandatory, but increases the // likelihood of data to be aligned with a cache block in several main host // machines. LksStream << "/*\n"; LksStream << " OpenMP Offload Linker Script\n"; LksStream << " *** Automatically generated by Clang ***\n"; LksStream << "*/\n"; LksStream << "TARGET(binary)\n"; auto DTC = OpenMPToolChains.first; for (auto &II : Inputs) { const Action *A = II.getAction(); // Is this a device linking action? if (A && isa<LinkJobAction>(A) && A->isDeviceOffloading(Action::OFK_OpenMP)) { assert(DTC != OpenMPToolChains.second && "More device inputs than device toolchains??"); InputBinaryInfo.push_back(std::make_pair( DTC->second->getTriple().normalize(), II.getFilename())); ++DTC; LksStream << "INPUT(" << II.getFilename() << ")\n"; } } assert(DTC == OpenMPToolChains.second && "Less device inputs than device toolchains??"); LksStream << "SECTIONS\n"; LksStream << "{\n"; // Put each target binary into a separate section. for (const auto &BI : InputBinaryInfo) { LksStream << " .omp_offloading." << BI.first << " :\n"; LksStream << " ALIGN(0x10)\n"; LksStream << " {\n"; LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first << " = .);\n"; LksStream << " " << BI.second << "\n"; LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first << " = .);\n"; LksStream << " }\n"; } // Add commands to define host entries begin and end. We use 1-byte subalign // so that the linker does not add any padding and the elements in this // section form an array. LksStream << " .omp_offloading.entries :\n"; LksStream << " ALIGN(0x10)\n"; LksStream << " SUBALIGN(0x01)\n"; LksStream << " {\n"; LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; LksStream << " *(.omp_offloading.entries)\n"; LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; LksStream << " }\n"; LksStream << "}\n"; LksStream << "INSERT BEFORE .data\n"; LksStream.flush(); // Dump the contents of the linker script if the user requested that. We // support this option to enable testing of behavior with -###. if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) llvm::errs() << LksBuffer; // If this is a dry run, do not create the linker script file. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) return; // Open script file and write the contents. std::error_code EC; llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); if (EC) { C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); return; } Lksf << LksBuffer; }