linjamaki created this revision. Herald added a subscriber: ThomasRaoux. linjamaki published this revision for review. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This patch adds a tool chain (TC) for SPIR-V for demonstration purposes. The TC is not complete but it is functional enough for producing SPIR-V assembly*1 and object code directly via clang from a language of choice, for example: clang -target spirv64 foo.cl -c -o foo.spv clang -target spirv64 baz.clcpp -c -o baz.spv clang -target spirv64 bar.c -S -o bar.spt The SPIR-V code is generated by the SPIRV-LLVM translator tool or other compatible tool named as `llvm-spirv` that is sought in PATH. List of things the TC is missing but not limited to: - Linking and image generation. - Complete and proper overrides from the base TC. - Proper SPIR-V assembly output *1. - Complete command line interface laid out in [1]. *1: The output from the SPIRV-LLVM Translator is its internal text presentation. Changes in the Driver and base ToolChain and Tool: Added a mechanism to work with the lack of SPIR-V backend in LLVM for SPIR-V TC. Until SPIR-V backend lands on LLVM, compilation phases/actions should be bound for SPIR-V in the meantime as following: - compile -> tools::Clang - backend -> tools::SPIRV::Translator - assemble -> tools::SPIRV::Translator However, Driver’s ToolSelector collapses compile-backend-assemble and compile-backend sequences to tools::Clang. To prevent this, added new {use,has}IntegratedBackend properties in ToolChain and Tool to which the ToolSelector reacts on, and which SPIR-V TC overrides. We contributed this patch and the previous one in the stack (D112404 <https://reviews.llvm.org/D112404> - [SPIR-V] Add translator tool) to address Anastasia’s feedback in (https://reviews.llvm.org/D110618#3062078) and other concerns around the SPIR-V tool chain adoption for languages other than HIP. However, we do not currently have the resources to allocate for continuing much further work in this patch unrelated to the needs of the HIP frontend. Thus, please consider this as a potentially useful starting point for further work needed to support other frontends, hopefully good enough minimal code to get this side started with and our patch set integrated to the master. [1]: https://github.com/KhronosGroup/SPIRV-LLVM-Translator/wiki/SPIRV-Toolchain-for-Clang Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112410 Files: clang/include/clang/Driver/Tool.h clang/include/clang/Driver/ToolChain.h clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChain.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/Clang.h clang/lib/Driver/ToolChains/SPIRV.cpp clang/lib/Driver/ToolChains/SPIRV.h clang/test/Driver/spirv-toolchain.c
Index: clang/test/Driver/spirv-toolchain.c =================================================================== --- /dev/null +++ clang/test/Driver/spirv-toolchain.c @@ -0,0 +1,57 @@ +// Check object emission. +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x cl -c %s 2>&1 | FileCheck --check-prefix=SPV64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x ir -c %s 2>&1 | FileCheck --check-prefix=SPV64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x clcpp -c %s 2>&1 | FileCheck --check-prefix=SPV64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x c -c %s 2>&1 | FileCheck --check-prefix=SPV64 %s + +// SPV64: clang{{.*}} "-cc1" "-triple" "spirv64" +// SPV64-SAME: "-o" [[BC:".*bc"]] +// SPV64: {{".*llvm-spirv.*"}} [[BC]] "-o" {{".*o"}} + +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x cl -c %s 2>&1 | FileCheck --check-prefix=SPV32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x ir -c %s 2>&1 | FileCheck --check-prefix=SPV32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x clcpp -c %s 2>&1 | FileCheck --check-prefix=SPV32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x c -c %s 2>&1 | FileCheck --check-prefix=SPV32 %s + +// SPV32: clang{{.*}} "-cc1" "-triple" "spirv32" +// SPV32-SAME: "-o" [[BC:".*bc"]] +// SPV32: {{".*llvm-spirv.*"}} [[BC]] "-o" {{".*o"}} + +//----------------------------------------------------------------------------- +// Check Assembly emission. +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x cl -S %s 2>&1 | FileCheck --check-prefix=SPT64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x ir -S %s 2>&1 | FileCheck --check-prefix=SPT64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x clcpp -c %s 2>&1 | FileCheck --check-prefix=SPV64 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x c -S %s 2>&1 | FileCheck --check-prefix=SPT64 %s + +// SPT64: clang{{.*}} "-cc1" "-triple" "spirv64" +// SPT64-SAME: "-o" [[BC:".*bc"]] +// SPT64: {{".*llvm-spirv.*"}} [[BC]] "-spirv-text" "-o" {{".*s"}} + +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x cl -S %s 2>&1 | FileCheck --check-prefix=SPT32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x ir -S %s 2>&1 | FileCheck --check-prefix=SPT32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x clcpp -c %s 2>&1 | FileCheck --check-prefix=SPV32 %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x c -S %s 2>&1 | FileCheck --check-prefix=SPT32 %s + +// SPT32: clang{{.*}} "-cc1" "-triple" "spirv32" +// SPT32-SAME: "-o" [[BC:".*bc"]] +// SPT32: {{".*llvm-spirv.*"}} [[BC]] "-spirv-text" "-o" {{".*s"}} + +//----------------------------------------------------------------------------- +// Check assembly input -> object output +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x assembler -c %s 2>&1 | FileCheck --check-prefix=ASM %s +// RUN: %clang -### -no-canonical-prefixes -target spirv32 -x assembler -c %s 2>&1 | FileCheck --check-prefix=ASM %s +// ASM: {{".*llvm-spirv.*"}} {{".*"}} "-to-binary" "-o" {{".*o"}} + +//----------------------------------------------------------------------------- +// Check --save-temps. +// RUN: %clang -### -no-canonical-prefixes -target spirv64 -x cl -c %s --save-temps 2>&1 | FileCheck --check-prefix=TMP %s + +// TMP: clang{{.*}} "-cc1" "-triple" "spirv64" +// TMP-SAME: "-E" +// TMP-SAME: "-o" [[I:".*i"]] +// TMP: clang{{.*}} "-cc1" "-triple" "spirv64" +// TMP-SAME: "-o" [[BC:".*bc"]] +// TMP-SAME: [[I]] +// TMP: {{".*llvm-spirv.*"}} [[BC]] "-spirv-text" "-o" [[S:".*s"]] +// TMP: {{".*llvm-spirv.*"}} [[S]] "-to-binary" "-o" {{".*o"}} Index: clang/lib/Driver/ToolChains/SPIRV.h =================================================================== --- clang/lib/Driver/ToolChains/SPIRV.h +++ clang/lib/Driver/ToolChains/SPIRV.h @@ -41,6 +41,37 @@ } // namespace SPIRV } // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY SPIRVToolChain final : public ToolChain { + mutable std::unique_ptr<Tool> Translator; + +public: + SPIRVToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : ToolChain(D, Triple, Args) {} + + bool useIntegratedAs() const override { return true; } + bool useIntegratedBackend() const override { return false; } + + bool IsMathErrnoDefault() const override { return false; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + + clang::driver::Tool *SelectTool(const JobAction &JA) const override; + +protected: + clang::driver::Tool *getTool(Action::ActionClass AC) const override; + +private: + clang::driver::Tool *getTranslator() const; +}; + +} // namespace toolchains } // namespace driver } // namespace clang #endif Index: clang/lib/Driver/ToolChains/SPIRV.cpp =================================================================== --- clang/lib/Driver/ToolChains/SPIRV.cpp +++ clang/lib/Driver/ToolChains/SPIRV.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +using namespace clang::driver::toolchains; using namespace clang::driver::tools; using namespace llvm::opt; @@ -53,3 +54,25 @@ llvm_unreachable("Invalid number of input files."); constructTranslateCommand(C, *this, JA, Output, Inputs[0], FilteredArgs); } + +clang::driver::Tool *SPIRVToolChain::getTranslator() const { + if (!Translator) + Translator = std::make_unique<SPIRV::Translator>(*this); + return Translator.get(); +} + +clang::driver::Tool *SPIRVToolChain::SelectTool(const JobAction &JA) const { + Action::ActionClass AC = JA.getKind(); + return SPIRVToolChain::getTool(AC); +} + +clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const { + switch (AC) { + default: + break; + case Action::BackendJobClass: + case Action::AssembleJobClass: + return SPIRVToolChain::getTranslator(); + } + return ToolChain::getTool(AC); +} Index: clang/lib/Driver/ToolChains/Clang.h =================================================================== --- clang/lib/Driver/ToolChains/Clang.h +++ clang/lib/Driver/ToolChains/Clang.h @@ -26,6 +26,8 @@ /// Clang compiler tool. class LLVM_LIBRARY_VISIBILITY Clang : public Tool { + bool HasBackend; + public: static const char *getBaseInputName(const llvm::opt::ArgList &Args, const InputInfo &Input); @@ -99,11 +101,12 @@ const InputInfo &Input, const llvm::opt::ArgList &Args) const; public: - Clang(const ToolChain &TC); + Clang(const ToolChain &TC, bool HasBackend = true); ~Clang() override; bool hasGoodDiagnostics() const override { return true; } bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedBackend() const override { return HasBackend; } bool hasIntegratedCPP() const override { return true; } bool canEmitIR() const override { return true; } Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -7002,11 +7002,11 @@ Args.ClaimAllArgs(options::OPT_emit_llvm); } -Clang::Clang(const ToolChain &TC) +Clang::Clang(const ToolChain &TC, bool HasBackendVal) // CAUTION! The first constructor argument ("clang") is not arbitrary, // as it is for other tools. Some operations on a Tool actually test // whether that tool is Clang based on the Tool's Name as a string. - : Tool("clang", "clang frontend", TC) {} + : Tool("clang", "clang frontend", TC), HasBackend(HasBackendVal) {} Clang::~Clang() {} Index: clang/lib/Driver/ToolChain.cpp =================================================================== --- clang/lib/Driver/ToolChain.cpp +++ clang/lib/Driver/ToolChain.cpp @@ -262,7 +262,7 @@ Tool *ToolChain::getClang() const { if (!Clang) - Clang.reset(new tools::Clang(*this)); + Clang.reset(new tools::Clang(*this, useIntegratedBackend())); return Clang.get(); } Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -41,6 +41,7 @@ #include "ToolChains/PPCLinux.h" #include "ToolChains/PS4CPU.h" #include "ToolChains/RISCVToolchain.h" +#include "ToolChains/SPIRV.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" #include "ToolChains/VEToolchain.h" @@ -4337,6 +4338,12 @@ if (!T) return nullptr; + // Can't collapse if we don't have codegen support unless we are + // emitting LLVM IR. + bool OutputIsLLVM = types::isLLVMIR(ActionInfo[0].JA->getType()); + if (!T->hasIntegratedBackend() && !(OutputIsLLVM && T->canEmitIR())) + return nullptr; + // When using -fembed-bitcode, it is required to have the same tool (clang) // for both CompilerJA and BackendJA. Otherwise, combine two stages. if (EmbedBitcode) { @@ -4406,6 +4413,12 @@ if (!T) return nullptr; + // Can't collapse if we don't have codegen support unless we are + // emitting LLVM IR. + bool OutputIsLLVM = types::isLLVMIR(ActionInfo[0].JA->getType()); + if (!T->hasIntegratedBackend() && !(OutputIsLLVM && T->canEmitIR())) + return nullptr; + if (T->canEmitIR() && ((SaveTemps && !InputIsBitcode) || EmbedBitcode)) return nullptr; @@ -5419,6 +5432,10 @@ case llvm::Triple::ve: TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args); break; + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + TC = std::make_unique<toolchains::SPIRVToolChain>(*this, Target, Args); + break; default: if (Target.getVendor() == llvm::Triple::Myriad) TC = std::make_unique<toolchains::MyriadToolChain>(*this, Target, Index: clang/include/clang/Driver/ToolChain.h =================================================================== --- clang/include/clang/Driver/ToolChain.h +++ clang/include/clang/Driver/ToolChain.h @@ -387,6 +387,9 @@ /// Check if the toolchain should use the integrated assembler. virtual bool useIntegratedAs() const; + /// Check if the toolchain should use the integrated backend. + virtual bool useIntegratedBackend() const { return true; } + /// Check if the toolchain should use AsmParser to parse inlineAsm when /// integrated assembler is not default. virtual bool parseInlineAsmUsingAsmParser() const { return false; } Index: clang/include/clang/Driver/Tool.h =================================================================== --- clang/include/clang/Driver/Tool.h +++ clang/include/clang/Driver/Tool.h @@ -52,6 +52,7 @@ const ToolChain &getToolChain() const { return TheToolChain; } virtual bool hasIntegratedAssembler() const { return false; } + virtual bool hasIntegratedBackend() const { return true; } virtual bool canEmitIR() const { return false; } virtual bool hasIntegratedCPP() const = 0; virtual bool isLinkJob() const { return false; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits