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-exception
6//
7//===----------------------------------------------------------------------===//
8#include "SPIRV.h"
9#include "CommonArgs.h"
10#include "clang/Basic/Version.h"
11#include "clang/Driver/Compilation.h"
12#include "clang/Driver/Driver.h"
13#include "clang/Driver/InputInfo.h"
14#include "clang/Driver/Options.h"
15
16using namespace clang::driver;
17using namespace clang::driver::toolchains;
18using namespace clang::driver::tools;
19using namespace llvm::opt;
20
21void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T,
22 const JobAction &JA,
23 const InputInfo &Output,
24 const InputInfo &Input,
25 const llvm::opt::ArgStringList &Args) {
26 llvm::opt::ArgStringList CmdArgs(Args);
27 CmdArgs.push_back(Elt: Input.getFilename());
28
29 if (Input.getType() == types::TY_PP_Asm)
30 CmdArgs.push_back(Elt: "-to-binary");
31 if (Output.getType() == types::TY_PP_Asm)
32 CmdArgs.push_back(Elt: "--spirv-tools-dis");
33
34 CmdArgs.append(IL: {"-o", Output.getFilename()});
35
36 // Try to find "llvm-spirv-<LLVM_VERSION_MAJOR>". Otherwise, fall back to
37 // plain "llvm-spirv".
38 using namespace std::string_literals;
39 auto VersionedTool = "llvm-spirv-"s + std::to_string(LLVM_VERSION_MAJOR);
40 std::string ExeCand = T.getToolChain().GetProgramPath(Name: VersionedTool.c_str());
41 if (!llvm::sys::fs::can_execute(Path: ExeCand))
42 ExeCand = T.getToolChain().GetProgramPath(Name: "llvm-spirv");
43
44 const char *Exec = C.getArgs().MakeArgString(Str: ExeCand);
45 C.addCommand(C: std::make_unique<Command>(args: JA, args: T, args: ResponseFileSupport::None(),
46 args&: Exec, args&: CmdArgs, args: Input, args: Output));
47}
48
49void SPIRV::Translator::ConstructJob(Compilation &C, const JobAction &JA,
50 const InputInfo &Output,
51 const InputInfoList &Inputs,
52 const ArgList &Args,
53 const char *LinkingOutput) const {
54 claimNoWarnArgs(Args);
55 if (Inputs.size() != 1)
56 llvm_unreachable("Invalid number of input files.");
57 constructTranslateCommand(C, T: *this, JA, Output, Input: Inputs[0], Args: {});
58}
59
60clang::driver::Tool *SPIRVToolChain::getTranslator() const {
61 if (!Translator)
62 Translator = std::make_unique<SPIRV::Translator>(args: *this);
63 return Translator.get();
64}
65
66clang::driver::Tool *SPIRVToolChain::SelectTool(const JobAction &JA) const {
67 Action::ActionClass AC = JA.getKind();
68 return SPIRVToolChain::getTool(AC);
69}
70
71clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const {
72 switch (AC) {
73 default:
74 break;
75 case Action::BackendJobClass:
76 case Action::AssembleJobClass:
77 return SPIRVToolChain::getTranslator();
78 }
79 return ToolChain::getTool(AC);
80}
81clang::driver::Tool *SPIRVToolChain::buildLinker() const {
82 return new tools::SPIRV::Linker(*this);
83}
84
85void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
86 const InputInfo &Output,
87 const InputInfoList &Inputs,
88 const ArgList &Args,
89 const char *LinkingOutput) const {
90 const ToolChain &ToolChain = getToolChain();
91 std::string Linker = ToolChain.GetProgramPath(Name: getShortName());
92 ArgStringList CmdArgs;
93 AddLinkerInputs(TC: getToolChain(), Inputs, Args, CmdArgs, JA);
94
95 CmdArgs.push_back(Elt: "-o");
96 CmdArgs.push_back(Elt: Output.getFilename());
97
98 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(),
99 args: Args.MakeArgString(Str: Linker), args&: CmdArgs,
100 args: Inputs, args: Output));
101}
102