150 lines · cpp
1//===--- SPIRV.cpp - SPIR-V Tool Implementations ----------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#include "SPIRV.h"9#include "clang/Driver/CommonArgs.h"10#include "clang/Driver/Compilation.h"11#include "clang/Driver/Driver.h"12#include "clang/Driver/InputInfo.h"13#include "clang/Options/Options.h"14 15using namespace clang::driver;16using namespace clang::driver::toolchains;17using namespace clang::driver::tools;18using namespace llvm::opt;19 20void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T,21 const JobAction &JA,22 const InputInfo &Output,23 const InputInfo &Input,24 const llvm::opt::ArgStringList &Args) {25 llvm::opt::ArgStringList CmdArgs(Args);26 CmdArgs.push_back(Input.getFilename());27 28 assert(Input.getType() != types::TY_PP_Asm && "Unexpected input type");29 30 if (Output.getType() == types::TY_PP_Asm)31 CmdArgs.push_back("--spirv-tools-dis");32 33 CmdArgs.append({"-o", Output.getFilename()});34 35 // Try to find "llvm-spirv-<LLVM_VERSION_MAJOR>". Otherwise, fall back to36 // plain "llvm-spirv".37 using namespace std::string_literals;38 auto VersionedTool = "llvm-spirv-"s + std::to_string(LLVM_VERSION_MAJOR);39 std::string ExeCand = T.getToolChain().GetProgramPath(VersionedTool.c_str());40 if (!llvm::sys::fs::can_execute(ExeCand))41 ExeCand = T.getToolChain().GetProgramPath("llvm-spirv");42 43 const char *Exec = C.getArgs().MakeArgString(ExeCand);44 C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(),45 Exec, CmdArgs, Input, Output));46}47 48void SPIRV::constructAssembleCommand(Compilation &C, const Tool &T,49 const JobAction &JA,50 const InputInfo &Output,51 const InputInfo &Input,52 const llvm::opt::ArgStringList &Args) {53 llvm::opt::ArgStringList CmdArgs(Args);54 CmdArgs.push_back(Input.getFilename());55 56 assert(Input.getType() == types::TY_PP_Asm && "Unexpected input type");57 58 CmdArgs.append({"-o", Output.getFilename()});59 60 // Try to find "spirv-as-<LLVM_VERSION_MAJOR>". Otherwise, fall back to61 // plain "spirv-as".62 using namespace std::string_literals;63 auto VersionedTool = "spirv-as-"s + std::to_string(LLVM_VERSION_MAJOR);64 std::string ExeCand = T.getToolChain().GetProgramPath(VersionedTool.c_str());65 if (!llvm::sys::fs::can_execute(ExeCand))66 ExeCand = T.getToolChain().GetProgramPath("spirv-as");67 68 const char *Exec = C.getArgs().MakeArgString(ExeCand);69 C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(),70 Exec, CmdArgs, Input, Output));71}72 73void SPIRV::Translator::ConstructJob(Compilation &C, const JobAction &JA,74 const InputInfo &Output,75 const InputInfoList &Inputs,76 const ArgList &Args,77 const char *LinkingOutput) const {78 claimNoWarnArgs(Args);79 if (Inputs.size() != 1)80 llvm_unreachable("Invalid number of input files.");81 constructTranslateCommand(C, *this, JA, Output, Inputs[0], {});82}83 84void SPIRV::Assembler::ConstructJob(Compilation &C, const JobAction &JA,85 const InputInfo &Output,86 const InputInfoList &Inputs,87 const ArgList &Args,88 const char *AssembleOutput) const {89 claimNoWarnArgs(Args);90 if (Inputs.size() != 1)91 llvm_unreachable("Invalid number of input files.");92 constructAssembleCommand(C, *this, JA, Output, Inputs[0], {});93}94 95clang::driver::Tool *SPIRVToolChain::getAssembler() const {96 if (!Assembler)97 Assembler = std::make_unique<SPIRV::Assembler>(*this);98 return Assembler.get();99}100 101clang::driver::Tool *SPIRVToolChain::SelectTool(const JobAction &JA) const {102 Action::ActionClass AC = JA.getKind();103 return SPIRVToolChain::getTool(AC);104}105 106clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const {107 switch (AC) {108 default:109 break;110 case Action::AssembleJobClass:111 return SPIRVToolChain::getAssembler();112 }113 return ToolChain::getTool(AC);114}115clang::driver::Tool *SPIRVToolChain::buildLinker() const {116 return new tools::SPIRV::Linker(*this);117}118 119void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA,120 const InputInfo &Output,121 const InputInfoList &Inputs,122 const ArgList &Args,123 const char *LinkingOutput) const {124 const ToolChain &ToolChain = getToolChain();125 std::string Linker = ToolChain.GetProgramPath(getShortName());126 ArgStringList CmdArgs;127 AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);128 129 CmdArgs.push_back("-o");130 CmdArgs.push_back(Output.getFilename());131 132 // Use of --sycl-link will call the clang-sycl-linker instead of133 // the default linker (spirv-link).134 if (Args.hasArg(options::OPT_sycl_link))135 Linker = ToolChain.GetProgramPath("clang-sycl-linker");136 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),137 Args.MakeArgString(Linker), CmdArgs,138 Inputs, Output));139}140 141SPIRVToolChain::SPIRVToolChain(const Driver &D, const llvm::Triple &Triple,142 const ArgList &Args)143 : ToolChain(D, Triple, Args) {144 // TODO: Revisit need/use of --sycl-link option once SYCL toolchain is145 // available and SYCL linking support is moved there.146 NativeLLVMSupport = Args.hasArg(options::OPT_sycl_link);147}148 149bool SPIRVToolChain::HasNativeLLVMSupport() const { return NativeLLVMSupport; }150