From d72f9f6f72a7a74d7466a1e301e1853fea5daa25 Mon Sep 17 00:00:00 2001 From: cheneym2 Date: Mon, 5 Aug 2024 15:37:46 -0400 Subject: Initial support for precompiled DXIL in slang-modules (#4755) * Add embedded precompiled binary IR ops Add IR operations to embed precompiled DXIL or SPIR-V blobs into IR. Adds a BlobLit literal that is mostly identical to StringLit except for its inability to be displayed, e.g. in dumped IR. In the future, the blob might be dumped as hexadecimal, but for now it is summarized as "". * EmbeddedDXIL and SPIR-V options The options, '-embed-dxil' and '-embed-spirv' in slangc, will cause a target dxil or spirv to be compiled and stored in the translation unit IR when written to a slang-module. Subsequent changes actually implement the options. * Per-translation unit DXIL precompilation When -embed-dxil is specified, perform a precompilation to DXIL of each TU, linked only with stdlib. Embed the resulting DXIL for the TU in a IR op. Being part of IR, the precompiled DXIL can be serialized to disk in a slang-module. Upon loading slang-modules, the new IR op will be searched for and the precompiled DXIL blob is saved with the loaded Module. During linking, if all the Modules have precompiled blobs they will be sent to the downstream compile commands as libraries instead of source, skipping the downstream compilation, using DXC only for linking. Fixes Issue #4580 * Remove placeholder embedded SPIRV support Code was added only to sketch out how other precompiled bins will be supported. * Remove the rest of the SPIRV placeholder support * Fix warnings, test error on non-windows * Remove lib_6_6 hack, add dxil_lib capability * Allocate blob value from irmodule memarena * Add null check after memarena allocation * Restore the request->e2erequest code path for generatewholeprogram * Update capability handling, move EmbedDXIL enum to end to preserve abi * Remove lib_6_6 hack * Move ICompileRequest functions to end --- source/slang/slang-compiler-tu.cpp | 115 +++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 source/slang/slang-compiler-tu.cpp (limited to 'source/slang/slang-compiler-tu.cpp') diff --git a/source/slang/slang-compiler-tu.cpp b/source/slang/slang-compiler-tu.cpp new file mode 100644 index 000000000..b007e7b71 --- /dev/null +++ b/source/slang/slang-compiler-tu.cpp @@ -0,0 +1,115 @@ +// slang-compiler-tu.cpp: Compiles translation units to target language +// and emit precompiled blobs into IR + +#include "../core/slang-basic.h" +#include "slang-compiler.h" +#include "slang-ir-insts.h" +#include "slang-capability.h" + +namespace Slang +{ + SLANG_NO_THROW SlangResult SLANG_MCALL Module::precompileForTargets( + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq, + TargetRequest* targetReq) + { + auto module = getIRModule(); + Slang::Session* session = endToEndReq->getSession(); + Slang::ASTBuilder* astBuilder = session->getGlobalASTBuilder(); + Slang::Linkage* builtinLinkage = session->getBuiltinLinkage(); + Slang::Linkage linkage(session, astBuilder, builtinLinkage); + + CapabilityName precompileRequirement = CapabilityName::Invalid; + switch (targetReq->getTarget()) + { + case CodeGenTarget::DXIL: + linkage.addTarget(Slang::CodeGenTarget::DXIL); + precompileRequirement = CapabilityName::dxil_lib; + break; + default: + assert(!"Unhandled target"); + break; + } + SLANG_ASSERT(precompileRequirement != CapabilityName::Invalid); + + // Ensure precompilation capability requirements are met. + auto targetCaps = targetReq->getTargetCaps(); + auto precompileRequirementsCapabilitySet = CapabilitySet(precompileRequirement); + if (targetCaps.atLeastOneSetImpliedInOther(precompileRequirementsCapabilitySet) == CapabilitySet::ImpliesReturnFlags::NotImplied) + { + // If `RestrictiveCapabilityCheck` is true we will error, else we will warn. + // error ...: dxil libraries require $0, entry point compiled with $1. + // warn ...: dxil libraries require $0, entry point compiled with $1, implicitly upgrading capabilities. + maybeDiagnoseWarningOrError( + sink, + targetReq->getOptionSet(), + DiagnosticCategory::Capability, + SourceLoc(), + Diagnostics::incompatibleWithPrecompileLib, + Diagnostics::incompatibleWithPrecompileLibRestrictive, + precompileRequirementsCapabilitySet, + targetCaps); + + // add precompile requirements to the cooked targetCaps + targetCaps.join(precompileRequirementsCapabilitySet); + if (targetCaps.isInvalid()) + { + sink->diagnose(SourceLoc(), Diagnostics::unknownCapability, targetCaps); + return SLANG_FAIL; + } + else + { + targetReq->setTargetCaps(targetCaps); + } + } + + List> allComponentTypes; + allComponentTypes.add(this); // Add Module as a component type + + for (auto entryPoint : this->getEntryPoints()) + { + allComponentTypes.add(entryPoint); // Add the entry point as a component type + } + + auto composite = CompositeComponentType::create( + &linkage, + allComponentTypes); + + TargetProgram tp(composite, targetReq); + tp.getOrCreateLayout(sink); + Slang::Index const entryPointCount = m_entryPoints.getCount(); + + CodeGenContext::EntryPointIndices entryPointIndices; + + entryPointIndices.setCount(entryPointCount); + for (Index i = 0; i < entryPointCount; i++) + entryPointIndices[i] = i; + CodeGenContext::Shared sharedCodeGenContext(&tp, entryPointIndices, sink, endToEndReq); + CodeGenContext codeGenContext(&sharedCodeGenContext); + + ComPtr outArtifact; + SlangResult res = codeGenContext.emitTranslationUnit(outArtifact); + if (res != SLANG_OK) + { + return res; + } + + ISlangBlob* blob; + outArtifact->loadBlob(ArtifactKeep::Yes, &blob); + + auto builder = IRBuilder(module); + builder.setInsertInto(module); + + switch (targetReq->getTarget()) + { + case CodeGenTarget::DXIL: + builder.emitEmbeddedDXIL(blob); + break; + default: + assert(!"Unhandled target"); + break; + } + + return SLANG_OK; + } +} -- cgit v1.2.3