From 67e186f0169591c48d24bd8ff7e4e4e715e8fa45 Mon Sep 17 00:00:00 2001 From: Yong He Date: Mon, 9 Oct 2023 14:03:43 -0700 Subject: Run curated spirv-opt passes through slang-glslang. (#3266) * Run curated spirv-opt passes through slang-glslang. * Cleanup. * Replace spirv-dis downstream compiler with glslang. * delete slang-spirv-opt.cpp. --------- Co-authored-by: Yong He --- .github/workflows/windows-selfhosted.yml | 1 + .github/workflows/windows.yml | 1 + .../compiler-core/compiler-core.vcxproj | 2 - .../compiler-core/compiler-core.vcxproj.filters | 6 - build/visual-studio/slang/slang.vcxproj | 2 - build/visual-studio/slang/slang.vcxproj.filters | 6 - github_test.sh | 1 + slang.h | 1 + .../slang-downstream-compiler-util.cpp | 5 +- .../compiler-core/slang-downstream-compiler-util.h | 1 + source/compiler-core/slang-glslang-compiler.cpp | 43 ++++++-- source/compiler-core/slang-glslang-compiler.h | 11 ++ source/compiler-core/slang-spirv-dis-compiler.cpp | 105 ------------------ source/compiler-core/slang-spirv-dis-compiler.h | 26 ----- source/core/slang-type-text-util.cpp | 3 +- source/slang-glslang/slang-glslang.cpp | 30 +++++ source/slang-glslang/slang-glslang.h | 8 +- source/slang/slang-compiler.cpp | 122 +++++++++++---------- source/slang/slang-compiler.h | 3 + source/slang/slang-emit-spirv.cpp | 24 ++-- source/slang/slang-emit.cpp | 32 +++++- source/slang/slang-ir-inline.cpp | 29 ----- source/slang/slang-ir-inline.h | 3 - source/slang/slang-spirv-opt.cpp | 66 ----------- source/slang/slang-spirv-opt.h | 10 -- tools/gfx/slang.slang | 2 + 26 files changed, 204 insertions(+), 339 deletions(-) delete mode 100644 source/compiler-core/slang-spirv-dis-compiler.cpp delete mode 100644 source/compiler-core/slang-spirv-dis-compiler.h delete mode 100644 source/slang/slang-spirv-opt.cpp delete mode 100644 source/slang/slang-spirv-opt.h diff --git a/.github/workflows/windows-selfhosted.yml b/.github/workflows/windows-selfhosted.yml index 6daab9673..f726db8b6 100644 --- a/.github/workflows/windows-selfhosted.yml +++ b/.github/workflows/windows-selfhosted.yml @@ -42,6 +42,7 @@ jobs: $ErrorActionPreference = "SilentlyContinue" where.exe spirv-dis spirv-dis --version + $env:SLANG_RUN_SPIRV_VALIDATION='1' .\bin\windows-${{matrix.testPlatform}}\${{matrix.configuration}}\slang-test.exe tests/ -use-test-server -server-count 8 -emit-spirv-directly -expected-failure-list tests/expected-failure.txt -api vk 2>&1 - name: test diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 182ac3867..9f48ccd0a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -65,6 +65,7 @@ jobs: $slangTestBinDir = ".\bin\windows-${{matrix.testPlatform}}\${{matrix.configuration}}\"; $spirvToolsBinDir = ".\external\slang-binaries\spirv-tools\windows-${{matrix.testPlatform}}\bin\"; $env:Path += ";$slangTestBinDir;$spirvToolsBinDir"; + $env:SLANG_RUN_SPIRV_VALIDATION='1'; Expand-Archive "vk_swiftshader_windows_${{matrix.testPlatform}}.zip" -DestinationPath $slangTestBinDir; & "$slangTestBinDir\slang-test.exe" -api all-dx12 -appveyor -bindir "$slangTestBinDir\" -platform ${{matrix.testPlatform}} -configuration ${{matrix.configuration}} -category ${{matrix.testCategory}} -expected-failure-list tests/expected-failure-github.txt 2>&1; diff --git a/build/visual-studio/compiler-core/compiler-core.vcxproj b/build/visual-studio/compiler-core/compiler-core.vcxproj index e5b9c5fdb..e2202aaca 100644 --- a/build/visual-studio/compiler-core/compiler-core.vcxproj +++ b/build/visual-studio/compiler-core/compiler-core.vcxproj @@ -312,7 +312,6 @@ - @@ -361,7 +360,6 @@ - diff --git a/build/visual-studio/compiler-core/compiler-core.vcxproj.filters b/build/visual-studio/compiler-core/compiler-core.vcxproj.filters index 14c7aa7da..2d4e3663d 100644 --- a/build/visual-studio/compiler-core/compiler-core.vcxproj.filters +++ b/build/visual-studio/compiler-core/compiler-core.vcxproj.filters @@ -150,9 +150,6 @@ Header Files - - Header Files - Header Files @@ -293,9 +290,6 @@ Source Files - - Source Files - Source Files diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj index 52db5fb4b..2e180e9ed 100644 --- a/build/visual-studio/slang/slang.vcxproj +++ b/build/visual-studio/slang/slang.vcxproj @@ -506,7 +506,6 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla - @@ -719,7 +718,6 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla - diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters index 67e22c3ea..10cc7c103 100644 --- a/build/visual-studio/slang/slang.vcxproj.filters +++ b/build/visual-studio/slang/slang.vcxproj.filters @@ -606,9 +606,6 @@ Header Files - - Header Files - Header Files @@ -1241,9 +1238,6 @@ Source Files - - Source Files - Source Files diff --git a/github_test.sh b/github_test.sh index cb8dff723..a970454d0 100644 --- a/github_test.sh +++ b/github_test.sh @@ -38,4 +38,5 @@ SLANG_TEST=${OUTPUTDIR}slang-test export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$OUTPUTDIR export PATH=$PATH:${OUTPUTDIR} +export SLANG_RUN_SPIRV_VALIDATION=1 ${SLANG_TEST} -bindir ${OUTPUTDIR} -travis -category ${SLANG_TEST_CATEGORY} ${SLANG_TEST_FLAGS} -api all-vk -expected-failure-list tests/expected-failure-github.txt diff --git a/slang.h b/slang.h index 14e9a30e2..78b56c546 100644 --- a/slang.h +++ b/slang.h @@ -640,6 +640,7 @@ extern "C" SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C or C++ compiler, which is decided by the source type SLANG_PASS_THROUGH_NVRTC, ///< NVRTC Cuda compiler SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' - includes LLVM and Clang + SLANG_PASS_THROUGH_SPIRV_OPT, ///< SPIRV-opt SLANG_PASS_THROUGH_COUNT_OF, }; diff --git a/source/compiler-core/slang-downstream-compiler-util.cpp b/source/compiler-core/slang-downstream-compiler-util.cpp index 44d750be8..52bf03acc 100644 --- a/source/compiler-core/slang-downstream-compiler-util.cpp +++ b/source/compiler-core/slang-downstream-compiler-util.cpp @@ -23,7 +23,6 @@ #include "slang-dxc-compiler.h" #include "slang-glslang-compiler.h" #include "slang-llvm-compiler.h" -#include "slang-spirv-dis-compiler.h" namespace Slang { @@ -55,6 +54,7 @@ struct DownstreamCompilerInfos infos.infos[int(SLANG_PASS_THROUGH_DXC)] = Info(SourceLanguageFlag::HLSL); infos.infos[int(SLANG_PASS_THROUGH_FXC)] = Info(SourceLanguageFlag::HLSL); infos.infos[int(SLANG_PASS_THROUGH_GLSLANG)] = Info(SourceLanguageFlag::GLSL); + infos.infos[int(SLANG_PASS_THROUGH_SPIRV_OPT)] = Info(SourceLanguageFlag::SPIRV); return infos; } @@ -327,8 +327,9 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() outFuncs[int(SLANG_PASS_THROUGH_DXC)] = &DXCDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_FXC)] = &FXCDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_GLSLANG)] = &GlslangDownstreamCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_SPIRV_OPT)] = &SpirvOptDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_LLVM)] = &LLVMDownstreamCompilerUtil::locateCompilers; - outFuncs[int(SLANG_PASS_THROUGH_SPIRV_DIS)] = &SPIRVDisDownstreamCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_SPIRV_DIS)] = &SpirvDisDownstreamCompilerUtil::locateCompilers; } static String _getParentPath(const String& path) diff --git a/source/compiler-core/slang-downstream-compiler-util.h b/source/compiler-core/slang-downstream-compiler-util.h index 6aad1ca90..84b8edcca 100644 --- a/source/compiler-core/slang-downstream-compiler-util.h +++ b/source/compiler-core/slang-downstream-compiler-util.h @@ -24,6 +24,7 @@ struct DownstreamCompilerInfo C = SourceLanguageFlags(1) << SLANG_SOURCE_LANGUAGE_C, CPP = SourceLanguageFlags(1) << SLANG_SOURCE_LANGUAGE_CPP, CUDA = SourceLanguageFlags(1) << SLANG_SOURCE_LANGUAGE_CUDA, + SPIRV = SourceLanguageFlags(1) << SLANG_SOURCE_LANGUAGE_SPIRV, }; }; diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index 4c0bc74d7..0335c33b4 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -52,7 +52,7 @@ public: /// Must be called before use SlangResult init(ISlangSharedLibrary* library); - GlslangDownstreamCompiler() {} + GlslangDownstreamCompiler(SlangPassThrough compilerType) : m_compilerType(compilerType) {} protected: @@ -63,6 +63,8 @@ protected: glslang_CompileFunc_1_2 m_compile_1_2 = nullptr; ComPtr m_sharedLibrary; + + SlangPassThrough m_compilerType; }; SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library) @@ -80,7 +82,7 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library) m_sharedLibrary = library; // It's not clear how to query for a version, but we can get a version number from the header - m_desc = Desc(SLANG_PASS_THROUGH_GLSLANG); + m_desc = Desc(m_compilerType); Slang::String filename; if (m_compile_1_2) @@ -173,9 +175,9 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact* sourceArtifact = options.sourceArtifacts[0]; - if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_GLSL || options.targetType != SLANG_SPIRV) + if (options.targetType != SLANG_SPIRV) { - SLANG_ASSERT(!"Can only compile GLSL to SPIR-V"); + SLANG_ASSERT(!"Can only compile to SPIR-V"); return SLANG_FAIL; } @@ -199,7 +201,19 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, memset(&request, 0, sizeof(request)); request.sizeInBytes = sizeof(request); - request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV; + switch (options.sourceLanguage) + { + case SLANG_SOURCE_LANGUAGE_GLSL: + request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV; + break; + case SLANG_SOURCE_LANGUAGE_SPIRV: + request.action = GLSLANG_ACTION_OPTIMIZE_SPIRV; + break; + default: + SLANG_ASSERT(!"Can only handle GLSL or SPIR-V as input."); + return SLANG_FAIL; + } + request.sourcePath = sourcePath.getBuffer(); request.slangStage = options.stage; @@ -340,7 +354,7 @@ SlangResult GlslangDownstreamCompiler::getVersionString(slang::IBlob** outVersio return SLANG_OK; } -/* static */SlangResult GlslangDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +static SlangResult locateGlslangSpirvDownstreamCompiler(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set, SlangPassThrough compilerType) { ComPtr library; @@ -367,7 +381,7 @@ SlangResult GlslangDownstreamCompiler::getVersionString(slang::IBlob** outVersio return SLANG_FAIL; } - auto compiler = new GlslangDownstreamCompiler; + auto compiler = new GlslangDownstreamCompiler(compilerType); ComPtr compilerIntf(compiler); SLANG_RETURN_ON_FAIL(compiler->init(library)); @@ -375,6 +389,21 @@ SlangResult GlslangDownstreamCompiler::getVersionString(slang::IBlob** outVersio return SLANG_OK; } +SlangResult GlslangDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_GLSLANG); +} + +SlangResult SpirvOptDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_OPT); +} + +SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_DIS); +} + #else // SLANG_ENABLE_GLSLANG_SUPPORT /* static */SlangResult GlslangDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) diff --git a/source/compiler-core/slang-glslang-compiler.h b/source/compiler-core/slang-glslang-compiler.h index ea4352a0b..577bcaacc 100644 --- a/source/compiler-core/slang-glslang-compiler.h +++ b/source/compiler-core/slang-glslang-compiler.h @@ -13,6 +13,17 @@ struct GlslangDownstreamCompilerUtil static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); }; + +struct SpirvOptDownstreamCompilerUtil +{ + static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); +}; + +struct SpirvDisDownstreamCompilerUtil +{ + static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); +}; + } #endif diff --git a/source/compiler-core/slang-spirv-dis-compiler.cpp b/source/compiler-core/slang-spirv-dis-compiler.cpp deleted file mode 100644 index 9b40254ce..000000000 --- a/source/compiler-core/slang-spirv-dis-compiler.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "slang-spirv-dis-compiler.h" -#include "../core/slang-common.h" -#include "../core/slang-string-util.h" -#include "../core/slang-string.h" -#include "slang-artifact-desc-util.h" -#include "slang-artifact-representation.h" -#include "slang-artifact-util.h" -#include "slang-artifact-representation-impl.h" -namespace Slang -{ - -SlangResult SPIRVDisDownstreamCompilerUtil::locateCompilers( - const String&, - ISlangSharedLibraryLoader*, - DownstreamCompilerSet* set) -{ - // TODO: We could check that the compiler is actually present in PATH (or - // explicitly given) - ComPtr com( - new SPIRVDisDownstreamCompiler(DownstreamCompilerDesc(SLANG_PASS_THROUGH_SPIRV_DIS))); - set->addCompiler(com); - - return SLANG_OK; -} - -SlangResult SLANG_MCALL SPIRVDisDownstreamCompiler::convert( - IArtifact* from, - const ArtifactDesc& to, - IArtifact** outArtifact) noexcept -{ - const auto& fromDesc = from->getDesc(); - if(to.kind != ArtifactKind::Assembly || - to.payload != ArtifactPayload::SPIRV || - to.flags != 0 || - fromDesc.kind != ArtifactKind::Executable || - fromDesc.payload != ArtifactPayload::SPIRV || - fromDesc.flags != 0) - return SLANG_E_INVALID_ARG; - - ISlangBlob* fromBlob; - SLANG_RETURN_ON_FAIL(from->loadBlob(ArtifactKeep::No, &fromBlob)); - - // Set up our process - CommandLine commandLine; - commandLine.m_executableLocation.setName("spirv-dis"); - commandLine.addArg("--comment"); - - RefPtr p; - SLANG_RETURN_ON_FAIL(Process::create(commandLine, 0, p)); - - auto inputStream = p->getStream(StdStreamType::In); - if (!inputStream) - return SLANG_FAIL; - - auto outputStream = p->getStream(StdStreamType::Out); - List outBytes; - const auto err = p->getStream(StdStreamType::ErrorOut); - List errData; - - SLANG_RETURN_ON_FAIL(StreamUtil::readAndWrite( - inputStream, - ArrayView((Byte*)fromBlob->getBufferPointer(), (Index)fromBlob->getBufferSize()), - outputStream, - outBytes, - err, - errData)); - - // Wait for it to finish - if(!p->waitForTermination(1000)) - return SLANG_FAIL; - - if (errData.getCount()) - fwrite(errData.getBuffer(), 1, (size_t)errData.getCount(), stderr); - - StringBuilder sbOutput; - List lines; - StringUtil::calcLines(StringUtil::trimEndOfLine(UnownedStringSlice((const char*)outBytes.getBuffer())), lines); - for (auto line : lines) - { - sbOutput << StringUtil::trimEndOfLine(line) << "\n"; - } - // If spirv-dis failed, we fail - const auto ret = p->getReturnValue(); - if(ret != 0) - return SLANG_FAIL; - - // Return as a file artifact - - auto disassemblyBlob = StringBlob::moveCreate(sbOutput); - - auto artifact = ArtifactUtil::createArtifact(to); - artifact->addRepresentationUnknown(disassemblyBlob); - - *outArtifact = artifact.detach(); - return SLANG_OK; -} - -SlangResult SLANG_MCALL SPIRVDisDownstreamCompiler::compile( - const CompileOptions&, - IArtifact**) noexcept -{ - SLANG_UNIMPLEMENTED_X(__func__); -} - -} diff --git a/source/compiler-core/slang-spirv-dis-compiler.h b/source/compiler-core/slang-spirv-dis-compiler.h deleted file mode 100644 index fb01627cd..000000000 --- a/source/compiler-core/slang-spirv-dis-compiler.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "slang-downstream-compiler-util.h" - -#include "../core/slang-platform.h" - -namespace Slang -{ - -struct SPIRVDisDownstreamCompilerUtil -{ - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); -}; - -class SPIRVDisDownstreamCompiler : public DownstreamCompilerBase -{ -public: - SPIRVDisDownstreamCompiler(const Desc& desc) : DownstreamCompilerBase(desc) {} - - virtual SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) noexcept override; - - virtual bool SLANG_MCALL isFileBased() noexcept override { return true; } - virtual SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) noexcept override; -}; - -} diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp index 2196fbaa8..e6305c3ec 100644 --- a/source/core/slang-type-text-util.cpp +++ b/source/core/slang-type-text-util.cpp @@ -80,12 +80,13 @@ static const NamesDescriptionValue s_compilerInfos[] = { SLANG_PASS_THROUGH_DXC, "dxc", "DXC HLSL compiler" }, { SLANG_PASS_THROUGH_GLSLANG, "glslang", "GLSLANG GLSL compiler" }, { SLANG_PASS_THROUGH_SPIRV_DIS, "spirv-dis", "spirv-tools SPIRV disassembler" }, - { SLANG_PASS_THROUGH_VISUAL_STUDIO, "visualstudio,vs", "Visual Studio C/C++ compiler" }, { SLANG_PASS_THROUGH_CLANG, "clang", "Clang C/C++ compiler" }, + { SLANG_PASS_THROUGH_VISUAL_STUDIO, "visualstudio,vs", "Visual Studio C/C++ compiler" }, { SLANG_PASS_THROUGH_GCC, "gcc", "GCC C/C++ compiler" }, { SLANG_PASS_THROUGH_GENERIC_C_CPP, "genericcpp,c,cpp", "A generic C++ compiler (can be any one of visual studio, clang or gcc depending on system and availability)" }, { SLANG_PASS_THROUGH_NVRTC, "nvrtc", "NVRTC CUDA compiler" }, { SLANG_PASS_THROUGH_LLVM, "llvm", "LLVM/Clang `slang-llvm`" }, + { SLANG_PASS_THROUGH_SPIRV_OPT, "spirv-opt", "spirv-tools SPIRV optimizer" }, }; static const NamesDescriptionValue s_archiveTypeInfos[] = diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp index 32834232f..fcaa9e70d 100644 --- a/source/slang-glslang/slang-glslang.cpp +++ b/source/slang-glslang/slang-glslang.cpp @@ -413,6 +413,32 @@ static void glslang_optimizeSPIRV(spv_target_env targetEnv, const glslang_Compil } } +static int spirv_Optimize_1_2(const glslang_CompileRequest_1_2& request) +{ + std::vector diagnostics; + std::vector spirvBuffer; + size_t inputBlobSize = (char*)request.inputEnd - (char*)request.inputBegin; + spirvBuffer.resize(inputBlobSize / sizeof(uint32_t)); + memcpy(spirvBuffer.data(), request.inputBegin, inputBlobSize); + + glslang_optimizeSPIRV(SPV_ENV_UNIVERSAL_1_5, request, diagnostics, spirvBuffer); + if (request.outputFunc) + { + request.outputFunc(spirvBuffer.data(), spirvBuffer.size() * sizeof(uint32_t), request.outputUserData); + } + if (request.diagnosticFunc) + { + for (auto& diagnostic : diagnostics) + { + request.diagnosticFunc( + (void*)diagnostic.message.c_str(), + diagnostic.message.size() * sizeof(char), + request.diagnosticUserData); + } + } + return SLANG_OK; +} + static glslang::EShTargetLanguageVersion _makeTargetLanguageVersion(int majorVersion, int minorVersion) { return glslang::EShTargetLanguageVersion((uint32_t(majorVersion) << 16) | (uint32_t(minorVersion) << 8)); @@ -770,6 +796,10 @@ static int _compile(const glslang_CompileRequest_1_2& request) case GLSLANG_ACTION_DISSASSEMBLE_SPIRV: result = glslang_dissassembleSPIRV(request); break; + + case GLSLANG_ACTION_OPTIMIZE_SPIRV: + result = spirv_Optimize_1_2(request); + break; } return result; diff --git a/source/slang-glslang/slang-glslang.h b/source/slang-glslang/slang-glslang.h index 40c574e08..68c24d889 100644 --- a/source/slang-glslang/slang-glslang.h +++ b/source/slang-glslang/slang-glslang.h @@ -12,6 +12,7 @@ enum { GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV, GLSLANG_ACTION_DISSASSEMBLE_SPIRV, + GLSLANG_ACTION_OPTIMIZE_SPIRV, }; struct glsl_SPIRVVersion @@ -128,17 +129,17 @@ struct glslang_CompileRequest_1_2 const char* entryPointName; // The name of the entrypoint that will appear in output spirv. }; -void glslang_CompileRequest_1_0::set(const glslang_CompileRequest_1_1& in) +inline void glslang_CompileRequest_1_0::set(const glslang_CompileRequest_1_1& in) { SLANG_GLSLANG_COMPILE_REQUEST_1_0(SLANG_GLSLANG_FIELD_COPY) } -void glslang_CompileRequest_1_1::set(const glslang_CompileRequest_1_0& in) +inline void glslang_CompileRequest_1_1::set(const glslang_CompileRequest_1_0& in) { SLANG_GLSLANG_COMPILE_REQUEST_1_0(SLANG_GLSLANG_FIELD_COPY) } -void glslang_CompileRequest_1_2::set(const glslang_CompileRequest_1_1& in) +inline void glslang_CompileRequest_1_2::set(const glslang_CompileRequest_1_1& in) { memcpy(this, &in, sizeof(in)); } @@ -147,5 +148,4 @@ typedef int (*glslang_CompileFunc_1_0)(glslang_CompileRequest_1_0* request); typedef int (*glslang_CompileFunc_1_1)(glslang_CompileRequest_1_1* request); typedef int (*glslang_CompileFunc_1_2)(glslang_CompileRequest_1_2* request); - #endif diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 9b14fd2f7..997466d49 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -953,6 +953,71 @@ namespace Slang return false; } + SlangResult passthroughDownstreamDiagnostics(DiagnosticSink* sink, IDownstreamCompiler* compiler, IArtifact* artifact) + { + auto diagnostics = findAssociatedRepresentation(artifact); + + if (!diagnostics) + return SLANG_OK; + + if (diagnostics->getCount()) + { + StringBuilder compilerText; + DownstreamCompilerUtil::appendAsText(compiler->getDesc(), compilerText); + + StringBuilder builder; + + auto const diagnosticCount = diagnostics->getCount(); + for (Index i = 0; i < diagnosticCount; ++i) + { + const auto& diagnostic = *diagnostics->getAt(i); + + builder.clear(); + + const Severity severity = _getDiagnosticSeverity(diagnostic.severity); + + if (diagnostic.filePath.count == 0 && diagnostic.location.line == 0 && severity == Severity::Note) + { + // If theres no filePath line number and it's info, output severity and text alone + builder << getSeverityName(severity) << " : "; + } + else + { + if (diagnostic.filePath.count) + { + builder << asStringSlice(diagnostic.filePath); + } + + if (diagnostic.location.line) + { + builder << "(" << diagnostic.location.line << ")"; + } + + builder << ": "; + + if (diagnostic.stage == ArtifactDiagnostic::Stage::Link) + { + builder << "link "; + } + + builder << getSeverityName(severity); + builder << " " << asStringSlice(diagnostic.code) << ": "; + } + + builder << asStringSlice(diagnostic.text); + reportExternalCompileError(compilerText.getBuffer(), severity, SLANG_OK, builder.getUnownedSlice(), sink); + } + } + + // If any errors are emitted, then we are done + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) + { + return SLANG_FAIL; + } + + return SLANG_OK; + } + SlangResult CodeGenContext::emitWithDownstreamForEntryPoints(ComPtr& outArtifact) { outArtifact.setNull(); @@ -1421,62 +1486,7 @@ namespace Slang (std::chrono::high_resolution_clock::now() - downstreamStartTime).count() * 0.000000001; getSession()->addDownstreamCompileTime(downstreamElapsedTime); - auto diagnostics = findAssociatedRepresentation(artifact); - - if (diagnostics->getCount()) - { - StringBuilder compilerText; - DownstreamCompilerUtil::appendAsText(compiler->getDesc(), compilerText); - - StringBuilder builder; - - auto const diagnosticCount = diagnostics->getCount(); - for (Index i = 0; i < diagnosticCount; ++i) - { - const auto& diagnostic = *diagnostics->getAt(i); - - builder.clear(); - - const Severity severity = _getDiagnosticSeverity(diagnostic.severity); - - if (diagnostic.filePath.count == 0 && diagnostic.location.line == 0 && severity == Severity::Note) - { - // If theres no filePath line number and it's info, output severity and text alone - builder << getSeverityName(severity) << " : "; - } - else - { - if (diagnostic.filePath.count) - { - builder << asStringSlice(diagnostic.filePath); - } - - if (diagnostic.location.line) - { - builder << "(" << diagnostic.location.line <<")"; - } - - builder << ": "; - - if (diagnostic.stage == ArtifactDiagnostic::Stage::Link) - { - builder << "link "; - } - - builder << getSeverityName(severity); - builder << " " << asStringSlice(diagnostic.code) << ": "; - } - - builder << asStringSlice(diagnostic.text); - reportExternalCompileError(compilerText.getBuffer(), severity, SLANG_OK, builder.getUnownedSlice(), sink); - } - } - - // If any errors are emitted, then we are done - if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) - { - return SLANG_FAIL; - } + SLANG_RETURN_ON_FAIL(passthroughDownstreamDiagnostics(getSink(), compiler, artifact)); // Copy over all of the information associated with the source into the output if (sourceArtifact) diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index c5bd3348c..c3f2d8e70 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1197,6 +1197,7 @@ namespace Slang GenericCCpp = SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C/C++ compiler NVRTC = SLANG_PASS_THROUGH_NVRTC, ///< NVRTC CUDA compiler LLVM = SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' + SpirvOpt = SLANG_PASS_THROUGH_SPIRV_OPT, ///< pass thorugh spirv to spirv-opt CountOf = SLANG_PASS_THROUGH_COUNT_OF, }; void printDiagnosticArg(StringBuilder& sb, PassThroughMode val); @@ -3153,6 +3154,8 @@ namespace Slang DiagnosticSink* sink, const LoadedModuleDictionary* additionalLoadedModules); + SlangResult passthroughDownstreamDiagnostics(DiagnosticSink* sink, IDownstreamCompiler* compiler, IArtifact* artifact); + // // The following functions are utilties to convert between // matching "external" (public API) and "internal" (implementation) diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 6d71f1a2c..16a88b8af 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -4815,18 +4815,22 @@ SlangResult emitSPIRVFromIR( (uint8_t const*) context.m_words.getBuffer(), context.m_words.getCount() * Index(sizeof(context.m_words[0]))); - const auto validationResult = debugValidateSPIRV(spirvOut); - // If validation isn't available, don't say it failed, it's just a debug - // feature so we can skip - if(SLANG_FAILED(validationResult) && validationResult != SLANG_E_NOT_AVAILABLE) + StringBuilder runSpirvValEnvVar; + PlatformUtil::getEnvironmentVariable(UnownedStringSlice("SLANG_RUN_SPIRV_VALIDATION"), runSpirvValEnvVar); + if (runSpirvValEnvVar.getUnownedSlice() == "1") { - codeGenContext->getSink()->diagnoseWithoutSourceView( - SourceLoc{}, - Diagnostics::spirvValidationFailed - ); - return validationResult; + const auto validationResult = debugValidateSPIRV(spirvOut); + // If validation isn't available, don't say it failed, it's just a debug + // feature so we can skip + if (SLANG_FAILED(validationResult) && validationResult != SLANG_E_NOT_AVAILABLE) + { + codeGenContext->getSink()->diagnoseWithoutSourceView( + SourceLoc{}, + Diagnostics::spirvValidationFailed + ); + return validationResult; + } } - return SLANG_OK; } diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 86136a010..57ca736e3 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -73,7 +73,6 @@ #include "slang-legalize-types.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" -#include "slang-spirv-opt.h" #include "slang-syntax.h" #include "slang-type-layout.h" #include "slang-visitor.h" @@ -931,8 +930,7 @@ Result linkAndOptimizeIR( if (isKhronosTarget(targetRequest) && targetRequest->shouldEmitSPIRVDirectly()) { - //performIntrinsicFunctionFunctionInlining(irModule); - performSpirvInlining(irModule); + performIntrinsicFunctionFunctionInlining(irModule); eliminateDeadCode(irModule); } eliminateMultiLevelBreak(irModule); @@ -1289,10 +1287,36 @@ SlangResult emitSPIRVForEntryPointsDirectly( spirv = _Move(outSpirv); } #endif - auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(codeGenContext->getTargetFormat())); artifact->addRepresentationUnknown(ListBlob::moveCreate(spirv)); + IDownstreamCompiler* compiler = codeGenContext->getSession()->getOrLoadDownstreamCompiler( + PassThroughMode::SpirvOpt, codeGenContext->getSink()); + if (compiler) + { + ComPtr optimizedArtifact; + DownstreamCompileOptions downstreamOptions; + downstreamOptions.sourceArtifacts = makeSlice(artifact.readRef(), 1); + downstreamOptions.targetType = SLANG_SPIRV; + downstreamOptions.sourceLanguage = SLANG_SOURCE_LANGUAGE_SPIRV; + auto linkage = codeGenContext->getLinkage(); + switch (linkage->optimizationLevel) + { + case OptimizationLevel::None: downstreamOptions.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::None; break; + case OptimizationLevel::Default: downstreamOptions.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Default; break; + case OptimizationLevel::High: downstreamOptions.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::High; break; + case OptimizationLevel::Maximal: downstreamOptions.optimizationLevel = DownstreamCompileOptions::OptimizationLevel::Maximal; break; + default: SLANG_ASSERT(!"Unhandled optimization level"); break; + } + + if (SLANG_SUCCEEDED(compiler->compile(downstreamOptions, optimizedArtifact.writeRef()))) + { + artifact = _Move(optimizedArtifact); + } + + SLANG_RETURN_ON_FAIL(passthroughDownstreamDiagnostics(codeGenContext->getSink(), compiler, artifact)); + } + ArtifactUtil::addAssociated(artifact, linkedIR.metadata); outArtifact.swap(artifact); diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp index 3b01d7dde..01dfdc42d 100644 --- a/source/slang/slang-ir-inline.cpp +++ b/source/slang/slang-ir-inline.cpp @@ -1019,33 +1019,4 @@ bool inlineCall(IRCall* call) return pass.considerCallSite(call); } - -struct SpirvInliningPass : InliningPassBase -{ - typedef InliningPassBase Super; - - SpirvInliningPass(IRModule* module) - : Super(module) - {} - - bool shouldInline(CallSiteInfo const& info) - { - if (!info.callee->findDecoration()) - return true; - return false; - } -}; - -void performSpirvInlining(IRModule* module) -{ - SLANG_PROFILE; - while (true) - { - SpirvInliningPass pass(module); - if (pass.considerAllCallSites()) - continue; - break; - } -} - } // namespace Slang diff --git a/source/slang/slang-ir-inline.h b/source/slang/slang-ir-inline.h index 5e888ad07..539bb26c0 100644 --- a/source/slang/slang-ir-inline.h +++ b/source/slang/slang-ir-inline.h @@ -34,9 +34,6 @@ namespace Slang /// Inline simple intrinsic functions whose definition is a single asm block. void performIntrinsicFunctionFunctionInlining(IRModule* module); - /// Inline all functions for SPIRV emit. - void performSpirvInlining(IRModule* module); - /// Inline a specific call. bool inlineCall(IRCall* call); } diff --git a/source/slang/slang-spirv-opt.cpp b/source/slang/slang-spirv-opt.cpp deleted file mode 100644 index 786358324..000000000 --- a/source/slang/slang-spirv-opt.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "slang-spirv-opt.h" -#include "slang-spirv-val.h" - -namespace Slang -{ - -struct RemoveFileRAII -{ - String fileName; - - RemoveFileRAII(String inFileName) - :fileName(inFileName) - {} - - ~RemoveFileRAII() - { - File::remove(fileName); - } -}; - -SlangResult optimizeSPIRV(const List& spirv, String& outErr, List& outSpv) -{ - // Set up our process - CommandLine commandLine; - commandLine.m_executableLocation.setName("spirv-opt"); - commandLine.addArg("--eliminate-dead-functions"); - commandLine.addArg("--eliminate-local-single-block"); - commandLine.addArg("--eliminate-local-single-store"); - commandLine.addArg("--eliminate-dead-code-aggressive"); - - commandLine.addArg("-o"); - String outFileName; - File::generateTemporary(UnownedStringSlice("out_spv"), outFileName); - RemoveFileRAII removeFile(outFileName); - - commandLine.addArg(outFileName); - - RefPtr p; - - // If we failed to even start the process, then spirv-opt isn't available - SLANG_RETURN_ON_FAIL(Process::create(commandLine, 0, p)); - const auto in = p->getStream(StdStreamType::In); - const auto out = p->getStream(StdStreamType::Out); - const auto err = p->getStream(StdStreamType::ErrorOut); - - List outErrData; - SLANG_RETURN_ON_FAIL(StreamUtil::readAndWrite(in, spirv.getArrayView(), out, outSpv, err, outErrData)); - - outSpv.clear(); - File::readAllBytes(outFileName, outSpv); - - SLANG_RETURN_ON_FAIL(p->waitForTermination(3600000)); - - outErr = String( - reinterpret_cast(outErrData.begin()), - reinterpret_cast(outErrData.end()) - ); - - const auto ret = p->getReturnValue(); - if (ret != 0) - return SLANG_FAIL; - - return debugValidateSPIRV(outSpv); -} - -} diff --git a/source/slang/slang-spirv-opt.h b/source/slang/slang-spirv-opt.h deleted file mode 100644 index c7dfde157..000000000 --- a/source/slang/slang-spirv-opt.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include "slang-compiler.h" - -namespace Slang -{ -SlangResult optimizeSPIRV(const List& spirv, String& outErr, List& outSpv); -} - diff --git a/tools/gfx/slang.slang b/tools/gfx/slang.slang index 1fd06560f..aa28fae82 100644 --- a/tools/gfx/slang.slang +++ b/tools/gfx/slang.slang @@ -84,12 +84,14 @@ enum SlangPassThrough : int SLANG_PASS_THROUGH_FXC, SLANG_PASS_THROUGH_DXC, SLANG_PASS_THROUGH_GLSLANG, + SLANG_PASS_THROUGH_SPIRV_DIS, SLANG_PASS_THROUGH_CLANG, ///< Clang C/C++ compiler SLANG_PASS_THROUGH_VISUAL_STUDIO, ///< Visual studio C/C++ compiler SLANG_PASS_THROUGH_GCC, ///< GCC C/C++ compiler SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C or C++ compiler, which is decided by the source type SLANG_PASS_THROUGH_NVRTC, ///< NVRTC Cuda compiler SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' - includes LLVM and Clang + SLANG_PASS_THROUGH_SPIRV_OPT, SLANG_PASS_THROUGH_COUNT_OF, }; -- cgit v1.2.3