diff --git a/clang/include/clang/Driver/Tool.h b/clang/include/clang/Driver/Tool.h --- a/clang/include/clang/Driver/Tool.h +++ b/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; } diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h --- a/clang/include/clang/Driver/ToolChain.h +++ b/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; } diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/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(*this, Target, Args); break; + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + TC = std::make_unique(*this, Target, Args); + break; default: if (Target.getVendor() == llvm::Triple::Myriad) TC = std::make_unique(*this, Target, diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/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(); } diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/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; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/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() {} diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h --- a/clang/lib/Driver/ToolChains/SPIRV.h +++ b/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 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 diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp --- a/clang/lib/Driver/ToolChains/SPIRV.cpp +++ b/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(*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); +} diff --git a/clang/test/Driver/spirv-toolchain.c b/clang/test/Driver/spirv-toolchain.c new file mode 100644 --- /dev/null +++ b/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"}}