summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-downstream-compiler.h13
-rw-r--r--source/compiler-core/slang-glslang-compiler.cpp41
-rw-r--r--source/compiler-core/slang-glslang-compiler.h8
-rw-r--r--source/slang-glslang/slang-glslang.cpp2
-rw-r--r--source/slang/slang-compiler.cpp6
-rw-r--r--source/slang/slang-compiler.h9
-rw-r--r--source/slang/slang-emit.cpp63
7 files changed, 139 insertions, 3 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h
index 82aaef107..c96003cc4 100644
--- a/source/compiler-core/slang-downstream-compiler.h
+++ b/source/compiler-core/slang-downstream-compiler.h
@@ -343,6 +343,19 @@ public:
/// True if underlying compiler uses file system to communicate source
virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0;
+
+ virtual SLANG_NO_THROW int SLANG_MCALL link(
+ const uint32_t** modules,
+ const uint32_t* moduleSizes,
+ const uint32_t moduleCount,
+ IArtifact** outArtifact)
+ {
+ SLANG_UNREFERENCED_PARAMETER(modules);
+ SLANG_UNREFERENCED_PARAMETER(moduleSizes);
+ SLANG_UNREFERENCED_PARAMETER(moduleCount);
+ SLANG_UNREFERENCED_PARAMETER(outArtifact);
+ return 0;
+ }
};
class DownstreamCompilerBase : public ComBaseObject, public IDownstreamCompiler
diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp
index b619f468f..540b437c5 100644
--- a/source/compiler-core/slang-glslang-compiler.cpp
+++ b/source/compiler-core/slang-glslang-compiler.cpp
@@ -49,6 +49,11 @@ public:
validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE;
virtual SLANG_NO_THROW SlangResult SLANG_MCALL
disassemble(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE;
+ int link(
+ const uint32_t** modules,
+ const uint32_t* moduleSizes,
+ const uint32_t moduleCount,
+ IArtifact** outArtifact) SLANG_OVERRIDE;
/// Must be called before use
SlangResult init(ISlangSharedLibrary* library);
@@ -66,6 +71,7 @@ protected:
glslang_CompileFunc_1_2 m_compile_1_2 = nullptr;
glslang_ValidateSPIRVFunc m_validate = nullptr;
glslang_DisassembleSPIRVFunc m_disassemble = nullptr;
+ glslang_LinkSPIRVFunc m_link = nullptr;
ComPtr<ISlangSharedLibrary> m_sharedLibrary;
@@ -80,6 +86,7 @@ SlangResult GlslangDownstreamCompiler::init(ISlangSharedLibrary* library)
m_validate = (glslang_ValidateSPIRVFunc)library->findFuncByName("glslang_validateSPIRV");
m_disassemble =
(glslang_DisassembleSPIRVFunc)library->findFuncByName("glslang_disassembleSPIRV");
+ m_link = (glslang_LinkSPIRVFunc)library->findFuncByName("glslang_linkSPIRV");
if (m_compile_1_0 == nullptr && m_compile_1_1 == nullptr && m_compile_1_2 == nullptr)
{
@@ -323,6 +330,32 @@ SlangResult GlslangDownstreamCompiler::disassemble(const uint32_t* contents, int
return SLANG_FAIL;
}
+SlangResult GlslangDownstreamCompiler::link(
+ const uint32_t** modules,
+ const uint32_t* moduleSizes,
+ const uint32_t moduleCount,
+ IArtifact** outArtifact)
+{
+ glslang_LinkRequest request;
+ memset(&request, 0, sizeof(request));
+
+ request.modules = modules;
+ request.moduleSizes = moduleSizes;
+ request.moduleCount = moduleCount;
+
+ if (!m_link(&request))
+ {
+ return SLANG_FAIL;
+ }
+
+ auto artifact = ArtifactUtil::createArtifactForCompileTarget(SLANG_SPIRV);
+ artifact->addRepresentationUnknown(
+ Slang::RawBlob::create(request.linkResult, request.linkResultSize * sizeof(uint32_t)));
+
+ *outArtifact = artifact.detach();
+ return SLANG_OK;
+}
+
bool GlslangDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to)
{
// Can only disassemble blobs that are SPIR-V
@@ -467,6 +500,14 @@ SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers(
return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_DIS);
}
+SlangResult SpirvLinkDownstreamCompilerUtil::locateCompilers(
+ const String& path,
+ ISlangSharedLibraryLoader* loader,
+ DownstreamCompilerSet* set)
+{
+ return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_LINK);
+}
+
#else // SLANG_ENABLE_GLSLANG_SUPPORT
/* static */ SlangResult GlslangDownstreamCompilerUtil::locateCompilers(
diff --git a/source/compiler-core/slang-glslang-compiler.h b/source/compiler-core/slang-glslang-compiler.h
index 73cc61135..d56ad7114 100644
--- a/source/compiler-core/slang-glslang-compiler.h
+++ b/source/compiler-core/slang-glslang-compiler.h
@@ -32,6 +32,14 @@ struct SpirvDisDownstreamCompilerUtil
DownstreamCompilerSet* set);
};
+struct SpirvLinkDownstreamCompilerUtil
+{
+ static SlangResult locateCompilers(
+ const String& path,
+ ISlangSharedLibraryLoader* loader,
+ DownstreamCompilerSet* set);
+};
+
} // namespace Slang
#endif
diff --git a/source/slang-glslang/slang-glslang.cpp b/source/slang-glslang/slang-glslang.cpp
index bbb3f6afc..b3370d803 100644
--- a/source/slang-glslang/slang-glslang.cpp
+++ b/source/slang-glslang/slang-glslang.cpp
@@ -1037,7 +1037,7 @@ extern "C"
request->linkResultSize = linkedBinary.size();
}
- return success;
+ return success == SPV_SUCCESS;
}
catch (...)
{
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 58cc55e71..3839e0722 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -2669,6 +2669,12 @@ bool CodeGenContext::shouldDumpIR()
return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::DumpIr);
}
+bool CodeGenContext::shouldSkipDownstreamLinking()
+{
+ return getTargetProgram()->getOptionSet().getBoolOption(
+ CompilerOptionName::SkipDownstreamLinking);
+}
+
bool CodeGenContext::shouldReportCheckpointIntermediates()
{
return getTargetProgram()->getOptionSet().getBoolOption(
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 10da32400..cfcbe816f 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1384,7 +1384,8 @@ enum class PassThroughMode : SlangPassThroughIntegral
LLVM = SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler'
SpirvOpt = SLANG_PASS_THROUGH_SPIRV_OPT, ///< pass thorugh spirv to spirv-opt
MetalC = SLANG_PASS_THROUGH_METAL,
- Tint = SLANG_PASS_THROUGH_TINT, ///< pass through spirv to Tint API
+ Tint = SLANG_PASS_THROUGH_TINT, ///< pass through spirv to Tint API
+ SpirvLink = SLANG_PASS_THROUGH_SPIRV_LINK, ///< pass through spirv to spirv-link
CountOf = SLANG_PASS_THROUGH_COUNT_OF,
};
void printDiagnosticArg(StringBuilder& sb, PassThroughMode val);
@@ -2886,6 +2887,12 @@ public:
// removed between IR linking and target source generation.
bool removeAvailableInDownstreamIR = false;
+ // Determines if program level compilation like getTargetCode() or getEntryPointCode()
+ // should return a fully linked downstream program or just the glue SPIR-V/DXIL that
+ // imports and uses the precompiled SPIR-V/DXIL from constituent modules.
+ // This is a no-op if modules are not precompiled.
+ bool shouldSkipDownstreamLinking();
+
protected:
CodeGenTarget m_targetFormat = CodeGenTarget::Unknown;
ExtensionTracker* m_extensionTracker = nullptr;
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index ddb4ea67a..94ea66d71 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -2093,10 +2093,71 @@ SlangResult emitSPIRVForEntryPointsDirectly(
if (compiler)
{
#if 0
- // Dump the unoptimized SPIRV after lowering from slang IR -> SPIRV
+ // Dump the unoptimized/unlinked SPIRV after lowering from slang IR -> SPIRV
compiler->disassemble((uint32_t*)spirv.getBuffer(), int(spirv.getCount() / 4));
#endif
+ bool isPrecompilation = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption(
+ CompilerOptionName::EmbedDownstreamIR);
+
+ if (!isPrecompilation && !codeGenContext->shouldSkipDownstreamLinking())
+ {
+ ComPtr<IArtifact> linkedArtifact;
+
+ // collect spirv files
+ List<uint32_t*> spirvFiles;
+ List<uint32_t> spirvSizes;
+
+ // Start with the SPIR-V we just generated.
+ // SPIRV-Tools-link expects the size in 32-bit words
+ // whereas the spirv blob size is in bytes.
+ spirvFiles.add((uint32_t*)spirv.getBuffer());
+ spirvSizes.add(int(spirv.getCount()) / 4);
+
+ // Iterate over all modules in the linkedIR. For each module, if it
+ // contains an embedded downstream ir instruction, add it to the list
+ // of spirv files.
+ auto program = codeGenContext->getProgram();
+
+ program->enumerateIRModules(
+ [&](IRModule* irModule)
+ {
+ for (auto globalInst : irModule->getModuleInst()->getChildren())
+ {
+ if (auto inst = as<IREmbeddedDownstreamIR>(globalInst))
+ {
+ if (inst->getTarget() == CodeGenTarget::SPIRV)
+ {
+ auto slice = inst->getBlob()->getStringSlice();
+ spirvFiles.add((uint32_t*)slice.begin());
+ spirvSizes.add(int(slice.getLength()) / 4);
+ }
+ }
+ }
+ });
+
+ SLANG_ASSERT(int(spirv.getCount()) % 4 == 0);
+ SLANG_ASSERT(spirvFiles.getCount() == spirvSizes.getCount());
+
+ if (spirvFiles.getCount() > 1)
+ {
+ SlangResult linkresult = compiler->link(
+ (const uint32_t**)spirvFiles.getBuffer(),
+ (const uint32_t*)spirvSizes.getBuffer(),
+ (uint32_t)spirvFiles.getCount(),
+ linkedArtifact.writeRef());
+
+ if (linkresult != SLANG_OK)
+ {
+ return SLANG_FAIL;
+ }
+
+ ComPtr<ISlangBlob> blob;
+ linkedArtifact->loadBlob(ArtifactKeep::No, blob.writeRef());
+ artifact = _Move(linkedArtifact);
+ }
+ }
+
if (!codeGenContext->shouldSkipSPIRVValidation())
{
StringBuilder runSpirvValEnvVar;