diff options
| author | Theresa Foley <10618364+tangent-vector@users.noreply.github.com> | 2022-04-11 12:01:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-11 12:01:31 -0700 |
| commit | 1409a5379d38ac153eabb4c19c7f4463a8b030ca (patch) | |
| tree | 0b5abbc64dbb46521b52453c9bee09469f032a2c /source | |
| parent | 2aac3700741f47caa6e8d674872979e2cdc251ab (diff) | |
Refactor: eliminate BackEndCompileRequest (#2178)
An earlier refactoring pass over the compiler codebase split the
type that had been called `CompileRequest` into three distinct
pieces:
* `FrontEndCompileRequest` which was supposed to own state and
options related to running the compiler front end and producing
IR + reflection (e.g., what translation units and source
files/strings are included).
* `BackEndCompileRequest` which was supposed to own state and options
related to running the compiler back end to translate the IR
for a `ComponentType` (program) into output code. (Note that the
`BackEndCompileRequest` was conceived of as orthogonal to the
`TargetRequest`s, which store per-target and target-specific
options.)
* `EndToEndCompileRequest` which was an umbrella object that owns
separate front-end and back-end requests, plus any state that is
only relevant when doing a true end-to-end compile (such as the
kinds of compiles initiated with `slangc`). As originally conceived,
the only state that this type was supposed to own was stuff related
to "pass-through" compilation, as well as state related to writing
of generated code to output files.
That refactoring work was very useful at the time, because it allowed
us to "scrub" the back end compilation steps to remove all
dependencies on front-end and AST state (this was important for our
goals of enabling linking and codegen from serialized Slang IR).
At this point, however, it is clear that the hierarchy that was built
up serves very little purpose:
* The `BackEndCompileRequest` type is only used in two places:
* As part of an `EndToEndCompileRequest`, where the settings on
the `BackEndCompileRequest` can be configured, but only through
the `EndToEndCompileRequest`
* As part of on-demand code generation through the `IComponentType`
APIs. In this case, the settings stored on the
`BackEndCompileRequest` are not accessible to the application
at all, and will always use their default values, so that
instantiating a "request" object doesn't really make any sense.
* The `FrontEndCompileRequest` type has a similar situation:
* Front-end compilation as part of an `EndToEndCompileRequest`
supports user configuration of `FrontEndCompileRequest` settings,
but only through the `EndToEndCompileRequest`
* Front-end compilation triggered by an `import` or a `loadModule()`
call does not support user configuration of settings at all. It
will always derive all relevant settings from thsoe on the
session ("linkage").
In addition, subsequent changes have been made to the compiler that
show a bit of a "code smell" and/or forward-looking worries for this
decomposition:
* In some cases we've had to add the same setting to multiple types
in the breakdown (front-end, back-end, end-to-end, linkage, target,
etc.) which makes it harder for us to validate that all the possible
mixtures of state work correctly.
* Related to the above, in some cases we have manual logic that copies
state from one of the objects in the breakdown to another, in order
to ensure that the user's intention is actually followed.
* As a forward-looking concern, it seems that developers have sometimes
added new configuration options and state to places that don't really
make sense according to the rationale of the original decomposition
(e.g., we probably don't want to have a lot of state that is only
available via end-to-end requests, given that the API structure is
meant to push users *away* from end-to-end compiles).
As a result of all of the above, I've been planning a large refactor
with the following big-picture goals:
* Eliminate `BackEndCompileRequest`
* Move all relevant state/options from the back-end request to
the end-to-end request, since that is the only place they could
be set anyway.
* Introduce a transient "context" type to be used for the duration
of code generation that serves the main functions that back-end
requests really served in the codebase
* Make `EndToEndCompileRequest` be a subclass of
`FrontEndCompileRequest`
* Consider addding a transient "context" type for front-end
compiles that can be used in `import`-like cases rather than
needing a full front-end request object. If this works, then
eliminate `FrontEndCompileRequest` and be back to world with
just a single `CompileRequest` type
* Move *all* compiler configuration options to a distinct type (named
something like `CompilerConfig` or `CompilerOptions` or whatever)
which stores setting as key-value pairs, and has a notion of
"inheritance" such that one configuration can extend or build on top
of another. Make all the relevant types use this catch-all structure
instead of redundantly storing flags in many places.
This change deals with the first of those bullets: removeal of
`BackEndCompileRequest`. The addition of the `CodeGenContext` type is
perhaps an unncessary additional step, but making that change helps
clean up a bunch of the code related to per-target code generation,
so I think it is the right choice.
Co-authored-by: Yong He <yonghe@outlook.com>
Diffstat (limited to 'source')
27 files changed, 759 insertions, 728 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 906a21d53..88c4edec5 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -584,6 +584,9 @@ namespace Slang Expr* SemanticsVisitor::maybeResolveOverloadedExpr(Expr* expr, LookupMask mask, DiagnosticSink* diagSink) { + if (IsErrorExpr(expr)) + return expr; + if( auto overloadedExpr = as<OverloadedExpr>(expr) ) { return _resolveOverloadedExprImpl(overloadedExpr, mask, diagSink); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 448cdeb88..e12f97640 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -216,6 +216,7 @@ namespace Slang } else { + arg = ExpectATypeRepr(arg); typeArg = CoerceToProperType(TypeExp(arg)); } } diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 14912d719..1b20a869d 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -20,7 +20,6 @@ #include "slang-parser.h" #include "slang-preprocessor.h" #include "slang-type-layout.h" -#include "slang-emit.h" #include "slang-glsl-extension-tracker.h" #include "slang-emit-cuda.h" @@ -587,18 +586,29 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return PassThroughMode::None; } - bool isPassThroughEnabled( - EndToEndCompileRequest* endToEndReq) + EndToEndCompileRequest* CodeGenContext::isPassThroughEnabled() { + auto endToEndReq = isEndToEndCompile(); + // If there isn't an end-to-end compile going on, // there can be no pass-through. // - if (!endToEndReq) return false; + if (!endToEndReq) + return nullptr; - // And if pass-through isn't set, we don't need - // access to the translation unit. - return endToEndReq->m_passThrough != PassThroughMode::None; + // And if pass-through isn't set on that end-to-end compile, + // then we clearly areb't doing a pass-through compile. + // + if(endToEndReq->m_passThrough == PassThroughMode::None) + return nullptr; + + // If we have confirmed that pass-through compilation is going on, + // we return the end-to-end request, because it has all the + // relevant state that we need to implement pass-through mode. + // + return endToEndReq; } + /// If there is a pass-through compile going on, find the translation unit for the given entry point. /// Assumes isPassThroughEnabled has already been called TranslationUnitRequest* getPassThroughTranslationUnit( @@ -613,11 +623,10 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return translationUnit; } - TranslationUnitRequest* findPassThroughTranslationUnit( - EndToEndCompileRequest* endToEndReq, + TranslationUnitRequest* CodeGenContext::findPassThroughTranslationUnit( Int entryPointIndex) { - if (isPassThroughEnabled(endToEndReq)) + if (auto endToEndReq = isPassThroughEnabled()) return getPassThroughTranslationUnit(endToEndReq, entryPointIndex); return nullptr; } @@ -652,20 +661,14 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } } - SlangResult emitEntryPointsSource( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, - ExtensionTracker* extensionTracker, + SlangResult CodeGenContext::emitEntryPointsSource( String& outSource) { outSource = String(); - if(isPassThroughEnabled(endToEndReq)) + if(auto endToEndReq = isPassThroughEnabled()) { - for (auto entryPointIndex : entryPointIndices) + for (auto entryPointIndex : getEntryPointIndices()) { auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndex); SLANG_ASSERT(translationUnit); @@ -676,7 +679,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // mode. StringBuilder codeBuilder; - if (target == CodeGenTarget::GLSL) + if (getTargetFormat() == CodeGenTarget::GLSL) { // Special case GLSL int translationUnitCounter = 0; @@ -711,30 +714,10 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) else { return emitEntryPointsSourceFromIR( - compileRequest, - entryPointIndices, - target, - targetReq, - extensionTracker, outSource); } } - SlangResult emitEntryPointSource( - BackEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, - ExtensionTracker* extensionTracker, - String& outSource) - { - List<Int> entryPointIndices; - entryPointIndices.add(entryPointIndex); - return emitEntryPointsSource(compileRequest, entryPointIndices, targetReq, - target, endToEndReq, extensionTracker, outSource); - } - String GetHLSLProfileName(Profile profile) { switch( profile.getFamily() ) @@ -868,21 +851,19 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } } - String calcSourcePathForEntryPoints( - EndToEndCompileRequest* endToEndReq, - const List<Int>& entryPointIndices) + String CodeGenContext::calcSourcePathForEntryPoints() { String failureMode = "slang-generated"; - if (entryPointIndices.getCount() != 1) + if (getEntryPointCount() != 1) return failureMode; - auto entryPointIndex = entryPointIndices[0]; - auto translationUnitRequest = findPassThroughTranslationUnit(endToEndReq, entryPointIndex); + auto entryPointIndex = getSingleEntryPointIndex(); + auto translationUnitRequest = findPassThroughTranslationUnit(entryPointIndex); if (!translationUnitRequest) return failureMode; const auto& sourceFiles = translationUnitRequest->getSourceFiles(); - auto sink = endToEndReq->getSink(); + auto sink = getSink(); const Index numSourceFiles = sourceFiles.getCount(); @@ -903,15 +884,6 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } } - String calcSourcePathForEntryPoint( - EndToEndCompileRequest* endToEndReq, - Int entryPointIndex) - { - List<Int> entryPointIndices; - entryPointIndices.add(entryPointIndex); - return calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); - } - // Helper function for cases where we can assume a single entry point Int assertSingleEntryPoint(List<Int> const& entryPointIndices) { SLANG_ASSERT(entryPointIndices.getCount() == 1); @@ -1012,31 +984,29 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } } - SlangResult emitWithDownstreamForEntryPoints( - ComponentType* program, - BackEndCompileRequest* slangRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, + SlangResult CodeGenContext::emitWithDownstreamForEntryPoints( RefPtr<DownstreamCompileResult>& outResult) { outResult.setNull(); - auto sink = slangRequest->getSink(); - - auto session = slangRequest->getSession(); - + auto sink = getSink(); + auto session = getSession(); CodeGenTarget sourceTarget = CodeGenTarget::None; SourceLanguage sourceLanguage = SourceLanguage::Unknown; + auto target = getTargetFormat(); RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); - PassThroughMode compilerType = endToEndReq ? endToEndReq->m_passThrough : PassThroughMode::None; + PassThroughMode compilerType; - // If we are not in pass through, lookup the default compiler for the emitted source type - if (compilerType == PassThroughMode::None) + if (auto endToEndReq = isPassThroughEnabled()) + { + compilerType = endToEndReq->m_passThrough; + } + else { + // If we are not in pass through, lookup the default compiler for the emitted source type + // Get the default source codegen type for a given target sourceTarget = _getDefaultSourceForTarget(target); compilerType = (PassThroughMode)session->getDownstreamCompilerForTransition((SlangCompileTarget)sourceTarget, (SlangCompileTarget)target); @@ -1070,7 +1040,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // Set compiler specific args { - auto linkage = targetReq->getLinkage(); + auto linkage = getLinkage(); auto name = TypeTextUtil::getPassThroughName((SlangPassThrough)compilerType); const Index nameIndex = linkage->m_downstreamArgs.findName(name); @@ -1087,17 +1057,15 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) /* This is more convoluted than the other scenarios, because when we invoke C/C++ compiler we would ideally like to use the original file. We want to do this because we want includes relative to the source file to work, and for that to work most easily we want to use the original file, if there is one */ - if (isPassThroughEnabled(endToEndReq)) + if (auto endToEndReq = isPassThroughEnabled()) { // If we are pass through, we may need to set extension tracker state. if (GLSLExtensionTracker* glslTracker = as<GLSLExtensionTracker>(extensionTracker)) { - trackGLSLTargetCaps(glslTracker, targetReq->getTargetCaps()); + trackGLSLTargetCaps(glslTracker, getTargetCaps()); } - // TODO(DG): Review this assertion later - SLANG_ASSERT(entryPointIndices.getCount() == 1); - auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndices[0]); + auto translationUnit = getPassThroughTranslationUnit(endToEndReq, getSingleEntryPointIndex()); // We are just passing thru, so it's whatever it originally was sourceLanguage = translationUnit->sourceLanguage; @@ -1118,7 +1086,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) preprocessorDefinitions.Add(define.Key, define.Value); } { - auto linkage = targetReq->getLinkage(); + auto linkage = getLinkage(); for (auto& define : linkage->preprocessorDefinitions) { preprocessorDefinitions.Add(define.Key, define.Value); @@ -1134,7 +1102,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) On invoking DXC for example include paths do not appear to be set at all (even with pass-through). */ - auto linkage = targetReq->getLinkage(); + auto linkage = getLinkage(); // Add all the search paths @@ -1156,8 +1124,10 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { // If it's not file based we can set an appropriate path name, and it doesn't matter if it doesn't // exist on the file system - options.sourceContentsPath = calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); - SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, entryPointIndices, targetReq, sourceTarget, endToEndReq, extensionTracker, options.sourceContents)); + options.sourceContentsPath = calcSourcePathForEntryPoints(); + + CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents)); } else { @@ -1173,8 +1143,9 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } else { - SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, entryPointIndices, targetReq, sourceTarget, endToEndReq, extensionTracker, options.sourceContents)); - maybeDumpIntermediate(slangRequest, options.sourceContents.getBuffer(), sourceTarget); + CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(options.sourceContents)); + sourceCodeGenContext.maybeDumpIntermediate(options.sourceContents.getBuffer()); sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget); } @@ -1213,8 +1184,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } // Set the file sytem and source manager, as *may* be used by downstream compiler - options.fileSystemExt = slangRequest->getFileSystemExt(); - options.sourceManager = slangRequest->getSourceManager(); + options.fileSystemExt = getFileSystemExt(); + options.sourceManager = getSourceManager(); // Set the source type options.sourceLanguage = SlangSourceLanguage(sourceLanguage); @@ -1226,23 +1197,16 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) compilerType == PassThroughMode::Dxc || compilerType == PassThroughMode::Glslang) { - if (entryPointIndices.getCount() != 1) - { - // We only support a single entry point on this target - SLANG_ASSERT(!"Can only compile with a single entry point on this target"); - return SLANG_FAIL; - } + auto entryPointIndex = getSingleEntryPointIndex(); - const Index entryPointIndex = entryPointIndices[0]; - - auto entryPoint = program->getEntryPoint(entryPointIndex); - auto profile = getEffectiveProfile(entryPoint, targetReq); + auto entryPoint = getEntryPoint(entryPointIndex); + auto profile = getEffectiveProfile(entryPoint, getTargetReq()); options.stage = SlangStage(profile.getStage()); // Set the entry point name options.entryPointName = getText(entryPoint->getName()); - auto entryPointNameOverride = program->getEntryPointNameOverride(entryPointIndex); + auto entryPointNameOverride = getProgram()->getEntryPointNameOverride(entryPointIndex); if (entryPointNameOverride.getLength() != 0) { options.entryPointName = entryPointNameOverride; @@ -1272,7 +1236,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } // Set the matrix layout - options.matrixLayout = targetReq->getDefaultMatrixLayoutMode(); + options.matrixLayout = getTargetReq()->getDefaultMatrixLayoutMode(); } else if (compilerType == PassThroughMode::Fxc) { @@ -1287,7 +1251,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) target = CodeGenTarget::ShaderSharedLibrary; } - if (!isPassThroughEnabled(endToEndReq)) + if (!isPassThroughEnabled()) { if (_isCPUHostTarget(target)) { @@ -1301,7 +1265,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // Need to configure for the compilation { - auto linkage = targetReq->getLinkage(); + auto linkage = getLinkage(); switch (linkage->optimizationLevel) { @@ -1322,7 +1286,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) default: SLANG_ASSERT(!"Unhandled debug level"); break; } - switch( targetReq->getFloatingPointMode() ) + switch( getTargetReq()->getFloatingPointMode()) { case FloatingPointMode::Default: options.floatingPointMode = DownstreamCompiler::FloatingPointMode::Default; break; case FloatingPointMode::Precise: options.floatingPointMode = DownstreamCompiler::FloatingPointMode::Precise; break; @@ -1346,10 +1310,10 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // because we always perform code generation on a single // entry point at a time. // - Index entryPointCount = slangRequest->getProgram()->getEntryPointCount(); + Index entryPointCount = getEntryPointCount(); for(Index ee = 0; ee < entryPointCount; ++ee) { - auto stage = slangRequest->getProgram()->getEntryPoint(ee)->getStage(); + auto stage = getEntryPoint(ee)->getStage(); switch(stage) { default: @@ -1401,7 +1365,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) SLANG_RETURN_ON_FAIL(compiler->compile(options, downstreamCompileResult)); auto downstreamElapsedTime = (std::chrono::high_resolution_clock::now() - downstreamStartTime).count() * 0.000000001; - slangRequest->getSession()->addDownstreamCompileTime(downstreamElapsedTime); + getSession()->addDownstreamCompileTime(downstreamElapsedTime); const auto& diagnostics = downstreamCompileResult->getDiagnostics(); @@ -1461,15 +1425,14 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return SLANG_OK; } - SlangResult dissassembleWithDownstream( - BackEndCompileRequest* slangRequest, - CodeGenTarget target, + SlangResult CodeGenContext::dissassembleWithDownstream( const void* data, size_t dataSizeInBytes, ISlangBlob** outBlob) { - auto session = slangRequest->getSession(); - auto sink = slangRequest->getSink(); + auto session = getSession(); + auto sink = getSink(); + auto target = getTargetFormat(); // Get the downstream compiler that can be used for this target @@ -1495,23 +1458,19 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return SLANG_OK; } - SlangResult dissassembleWithDownstream( - BackEndCompileRequest* slangRequest, - CodeGenTarget target, + SlangResult CodeGenContext::dissassembleWithDownstream( DownstreamCompileResult* downstreamResult, ISlangBlob** outBlob) { ComPtr<ISlangBlob> codeBlob; SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(codeBlob)); - return dissassembleWithDownstream(slangRequest, target, codeBlob->getBufferPointer(), codeBlob->getBufferSize(), outBlob); + return dissassembleWithDownstream(codeBlob->getBufferPointer(), codeBlob->getBufferSize(), outBlob); } SlangResult emitSPIRVForEntryPointsDirectly( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - List<uint8_t>& spirvOut); + CodeGenContext* codeGenContext, + List<uint8_t>& spirvOut); static CodeGenTarget _getIntermediateTarget(CodeGenTarget target) { @@ -1525,68 +1484,50 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } /// Function to simplify the logic around emitting, and dissassembling - static SlangResult _emitEntryPoints( - ComponentType* program, - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, + SlangResult CodeGenContext::_emitEntryPoints( RefPtr<DownstreamCompileResult>& outDownstreamResult) { + auto target = getTargetFormat(); switch (target) { case CodeGenTarget::SPIRVAssembly: case CodeGenTarget::DXBytecodeAssembly: case CodeGenTarget::DXILAssembly: { - RefPtr<DownstreamCompileResult> code; - - // Compile the intermediate target + // First compile to an intermediate target for the corresponding binary format. const CodeGenTarget intermediateTarget = _getIntermediateTarget(target); - SLANG_RETURN_ON_FAIL(_emitEntryPoints(program, compileRequest, entryPointIndices, targetReq, intermediateTarget, endToEndReq, code)); + CodeGenContext intermediateContext(this, intermediateTarget); - maybeDumpIntermediate(compileRequest, code, intermediateTarget); + RefPtr<DownstreamCompileResult> code; + SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(code)); + intermediateContext.maybeDumpIntermediate(code); + // Then disassemble the intermediate binary result to get the desired output // Output the disassembly ComPtr<ISlangBlob> disassemblyBlob; - SLANG_RETURN_ON_FAIL(dissassembleWithDownstream(compileRequest, intermediateTarget, code, disassemblyBlob.writeRef())); + SLANG_RETURN_ON_FAIL(intermediateContext.dissassembleWithDownstream(code, disassemblyBlob.writeRef())); outDownstreamResult = new BlobDownstreamCompileResult(DownstreamDiagnostics(), disassemblyBlob); return SLANG_OK; } case CodeGenTarget::SPIRV: + if (getTargetReq()->shouldEmitSPIRVDirectly()) + { + List<uint8_t> spirv; + SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(this, spirv)); + auto spirvBlob = ListBlob::moveCreate(spirv); + outDownstreamResult = new BlobDownstreamCompileResult(DownstreamDiagnostics(), spirvBlob); + return SLANG_OK; + } + /* fall through to: */ case CodeGenTarget::DXIL: case CodeGenTarget::DXBytecode: case CodeGenTarget::PTX: case CodeGenTarget::ShaderHostCallable: case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: - { - RefPtr<DownstreamCompileResult> downstreamResult; - - if (target == CodeGenTarget::SPIRV && targetReq->shouldEmitSPIRVDirectly()) - { - List<uint8_t> spirv; - SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPointsDirectly(compileRequest, entryPointIndices, targetReq, spirv)); - auto spirvBlob = ListBlob::moveCreate(spirv); - downstreamResult = new BlobDownstreamCompileResult(DownstreamDiagnostics(), spirvBlob); - } - else - { - SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints( - program, - compileRequest, - entryPointIndices, - targetReq, - target, - endToEndReq, - downstreamResult)); - } - - outDownstreamResult = downstreamResult; + SLANG_RETURN_ON_FAIL(emitWithDownstreamForEntryPoints(outDownstreamResult)); return SLANG_OK; - } default: break; } @@ -1595,16 +1536,11 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } // Do emit logic for a zero or more entry points - CompileResult emitEntryPoints( - ComponentType* program, - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq) + CompileResult CodeGenContext::emitEntryPoints() { CompileResult result; - auto target = targetReq->getTarget(); + auto target = getTargetFormat(); switch (target) { @@ -1621,15 +1557,9 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { RefPtr<DownstreamCompileResult> downstreamResult; - if (SLANG_SUCCEEDED(_emitEntryPoints(program, - compileRequest, - entryPointIndices, - targetReq, - target, - endToEndReq, - downstreamResult))) + if (SLANG_SUCCEEDED(_emitEntryPoints(downstreamResult))) { - maybeDumpIntermediate(compileRequest, downstreamResult, target); + maybeDumpIntermediate(downstreamResult); result = CompileResult(downstreamResult); } } @@ -1643,19 +1573,15 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target); + CodeGenContext subContext(this, target, extensionTracker); + String code; - if (SLANG_FAILED(emitEntryPointsSource(compileRequest, - entryPointIndices, - targetReq, - target, - endToEndReq, - extensionTracker, - code))) + if (SLANG_FAILED(subContext.emitEntryPointsSource(code))) { return result; } - maybeDumpIntermediate(compileRequest, code.getBuffer(), target); + subContext.maybeDumpIntermediate(code.getBuffer()); result = CompileResult(code); } break; @@ -1676,19 +1602,6 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return result; } - // Do emit logic for a single entry point - CompileResult emitEntryPoint( - ComponentType* program, - BackEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq) - { - List<Int> entryPointIndices; - entryPointIndices.add(entryPointIndex); - return emitEntryPoints(program, compileRequest, entryPointIndices, targetReq, endToEndReq); - } - enum class OutputFileKind { Text, @@ -1696,7 +1609,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) }; static void writeOutputFile( - BackEndCompileRequest* compileRequest, + CodeGenContext* context, FILE* file, String const& path, void const* data, @@ -1705,7 +1618,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) size_t count = fwrite(data, size, 1, file); if (count != 1) { - compileRequest->getSink()->diagnose( + context->getSink()->diagnose( SourceLoc(), Diagnostics::cannotWriteOutputFile, path); @@ -1713,7 +1626,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } static void writeOutputFile( - BackEndCompileRequest* compileRequest, + CodeGenContext* context, ISlangWriter* writer, String const& path, void const* data, @@ -1722,7 +1635,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) if (SLANG_FAILED(writer->write((const char*)data, size))) { - compileRequest->getSink()->diagnose( + context->getSink()->diagnose( SourceLoc(), Diagnostics::cannotWriteOutputFile, path); @@ -1730,7 +1643,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } static void writeOutputFile( - BackEndCompileRequest* compileRequest, + CodeGenContext* context, String const& path, void const* data, size_t size, @@ -1741,19 +1654,19 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) kind == OutputFileKind::Binary ? "wb" : "w"); if (!file) { - compileRequest->getSink()->diagnose( + context->getSink()->diagnose( SourceLoc(), Diagnostics::cannotWriteOutputFile, path); return; } - writeOutputFile(compileRequest, file, path, data, size); + writeOutputFile(context, file, path, data, size); fclose(file); } static void writeCompileResultToFile( - BackEndCompileRequest* compileRequest, + CodeGenContext* context, String const& outputPath, CompileResult const& result) { @@ -1762,7 +1675,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case ResultFormat::Text: { auto text = result.outputString; - writeOutputFile(compileRequest, + writeOutputFile(context, outputPath, text.begin(), text.end() - text.begin(), @@ -1778,7 +1691,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) SLANG_UNEXPECTED("No blob to emit"); return; } - writeOutputFile(compileRequest, + writeOutputFile(context, outputPath, blob->getBufferPointer(), blob->getBufferSize(), @@ -1793,16 +1706,6 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } - static void writeEntryPointResultToFile( - BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - String const& outputPath, - CompileResult const& result) - { - SLANG_UNUSED(entryPoint); - writeCompileResultToFile(compileRequest, outputPath, result); - } - static void writeOutputToConsole( ISlangWriter* writer, String const& text) @@ -1810,13 +1713,13 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) writer->write(text.getBuffer(), text.getLength()); } - static void writeCompileRequestToStandardOutput( - EndToEndCompileRequest* compileRequest, - TargetRequest* targetReq, - CompileResult const& result) + static void writeCompileResultToStandardOutput( + CodeGenContext* codeGenContext, + EndToEndCompileRequest* endToEndReq, + CompileResult const& result) { - ISlangWriter* writer = compileRequest->getWriter(WriterChannel::StdOutput); - auto backEndReq = compileRequest->getBackEndReq(); + auto targetReq = codeGenContext->getTargetReq(); + ISlangWriter* writer = endToEndReq->getWriter(WriterChannel::StdOutput); switch (result.format) { @@ -1863,7 +1766,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { ComPtr<ISlangBlob> disassemblyBlob; - if (SLANG_SUCCEEDED(dissassembleWithDownstream(backEndReq, targetReq->getTarget(), blobData, blobSize, disassemblyBlob.writeRef()))) + if (SLANG_SUCCEEDED(codeGenContext->dissassembleWithDownstream(blobData, blobSize, disassemblyBlob.writeRef()))) { const UnownedStringSlice disassembly = StringUtil::getSlice(disassemblyBlob); writeOutputToConsole(writer, disassembly); @@ -1891,7 +1794,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) writer->setMode(SLANG_WRITER_MODE_BINARY); writeOutputFile( - backEndReq, + codeGenContext, writer, "stdout", blobData, @@ -1907,23 +1810,11 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } - static void writeEntryPointResultToStandardOutput( - EndToEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - TargetRequest* targetReq, - CompileResult const& result) + void EndToEndCompileRequest::writeWholeProgramResult( + TargetRequest* targetReq) { - SLANG_UNUSED(entryPoint); - writeCompileRequestToStandardOutput(compileRequest, targetReq, result); - } - - static void writeWholeProgramResult( - EndToEndCompileRequest* compileRequest, - TargetRequest* targetReq) - { - auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); + auto program = getSpecializedGlobalAndEntryPointsComponentType(); auto targetProgram = program->getTargetProgram(targetReq); - auto backEndReq = compileRequest->getBackEndReq(); auto& result = targetProgram->getExistingWholeProgramResult(); @@ -1931,34 +1822,37 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) if (result.format == ResultFormat::None) return; + CodeGenContext::EntryPointIndices entryPointIndices; + for (Index i = 0; i < program->getEntryPointCount(); ++i) + entryPointIndices.add(i); + CodeGenContext::Shared sharedCodeGenContext(targetProgram, entryPointIndices, getSink(), this); + CodeGenContext codeGenContext(&sharedCodeGenContext); + // It is possible that we are dynamically discovering entry // points (using `[shader(...)]` attributes), so that there // might be entry points added to the program that did not // get paths specified via command-line options. // RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - if (compileRequest->m_targetInfos.TryGetValue(targetReq, targetInfo)) + if (m_targetInfos.TryGetValue(targetReq, targetInfo)) { String outputPath = targetInfo->wholeTargetOutputPath; if (outputPath != "") { - writeCompileResultToFile(backEndReq, outputPath, result); + writeCompileResultToFile(&codeGenContext, outputPath, result); return; } } - writeCompileRequestToStandardOutput(compileRequest, targetReq, result); + writeCompileResultToStandardOutput(&codeGenContext, this, result); } - static void writeEntryPointResult( - ComponentType* currentProgram, - EndToEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq) + void EndToEndCompileRequest::writeEntryPointResult( + TargetRequest* targetReq, + Int entryPointIndex) { - auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); + auto program = getSpecializedGlobalAndEntryPointsComponentType(); auto targetProgram = program->getTargetProgram(targetReq); - auto backEndReq = compileRequest->getBackEndReq(); auto& result = targetProgram->getExistingEntryPointResult(entryPointIndex); @@ -1966,29 +1860,35 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) if (result.format == ResultFormat::None) return; + CodeGenContext::EntryPointIndices entryPointIndices; + entryPointIndices.add(entryPointIndex); + + CodeGenContext::Shared sharedCodeGenContext(targetProgram, entryPointIndices, getSink(), this); + CodeGenContext codeGenContext(&sharedCodeGenContext); + // It is possible that we are dynamically discovering entry // points (using `[shader(...)]` attributes), so that there // might be entry points added to the program that did not // get paths specified via command-line options. // RefPtr<EndToEndCompileRequest::TargetInfo> targetInfo; - auto entryPoint = currentProgram->getEntryPoint(entryPointIndex); - if(compileRequest->m_targetInfos.TryGetValue(targetReq, targetInfo)) + auto entryPoint = program->getEntryPoint(entryPointIndex); + if(m_targetInfos.TryGetValue(targetReq, targetInfo)) { String outputPath; if(targetInfo->entryPointOutputPaths.TryGetValue(entryPointIndex, outputPath)) { - writeEntryPointResultToFile(backEndReq, entryPoint, outputPath, result); + writeCompileResultToFile(&codeGenContext, outputPath, result); return; } } - writeEntryPointResultToStandardOutput(compileRequest, entryPoint, targetReq, result); + writeCompileResultToStandardOutput(&codeGenContext, this, result); } CompileResult& TargetProgram::_createWholeProgramResult( - BackEndCompileRequest* backEndRequest, - EndToEndCompileRequest* endToEndRequest) + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq) { // We want to call `emitEntryPoints` function to generate code that contains // all the entrypoints defined in `m_program`. @@ -2001,20 +1901,19 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) entryPointIndices[i] = i; auto& result = m_wholeProgramResult; - result = emitEntryPoints( - m_program, - backEndRequest, - entryPointIndices, - m_targetReq, - endToEndRequest); + + CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); + CodeGenContext codeGenContext(&sharedCodeGenContext); + + result = codeGenContext.emitEntryPoints(); return result; } CompileResult& TargetProgram::_createEntryPointResult( Int entryPointIndex, - BackEndCompileRequest* backEndRequest, - EndToEndCompileRequest* endToEndRequest) + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq) { // It is possible that entry points goot added to the `Program` // *after* we created this `TargetProgram`, so there might be @@ -2028,15 +1927,15 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) m_entryPointResults.setCount(entryPointIndex+1); auto& result = m_entryPointResults[entryPointIndex]; - result = emitEntryPoint( - m_program, - backEndRequest, - entryPointIndex, - m_targetReq, - endToEndRequest); - return result; + CodeGenContext::EntryPointIndices entryPointIndices; + entryPointIndices.add(entryPointIndex); + CodeGenContext::Shared sharedCodeGenContext(this, entryPointIndices, sink, endToEndReq); + CodeGenContext codeGenContext(&sharedCodeGenContext); + result = codeGenContext.emitEntryPoints(); + + return result; } CompileResult& TargetProgram::getOrCreateWholeProgramResult( @@ -2055,17 +1954,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return result; } - RefPtr<BackEndCompileRequest> backEndRequest = new BackEndCompileRequest( - m_program->getLinkage(), - sink, - m_program); - - backEndRequest->shouldDumpIR = - (m_targetReq->getTargetFlags() & SLANG_TARGET_FLAG_DUMP_IR) != 0; - - return _createWholeProgramResult( - backEndRequest, - nullptr); + return _createWholeProgramResult(sink); } CompileResult& TargetProgram::getOrCreateEntryPointResult( @@ -2088,36 +1977,23 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return result; } - RefPtr<BackEndCompileRequest> backEndRequest = new BackEndCompileRequest( - m_program->getLinkage(), - sink, - m_program); - backEndRequest->shouldDumpIR = - (m_targetReq->getTargetFlags() & SLANG_TARGET_FLAG_DUMP_IR) != 0; - backEndRequest->shouldDumpIntermediates = m_targetReq->shouldDumpIntermediates(); - return _createEntryPointResult( entryPointIndex, - backEndRequest, - nullptr); + sink); } - void generateOutputForTarget( - BackEndCompileRequest* compileReq, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq) + void EndToEndCompileRequest::generateOutput( + TargetProgram* targetProgram) { - auto program = compileReq->getProgram(); - auto targetProgram = program->getTargetProgram(targetReq); + auto program = targetProgram->getProgram(); + auto targetReq = targetProgram->getTargetReq(); // Generate target code any entry points that // have been requested for compilation. auto entryPointCount = program->getEntryPointCount(); if (targetReq->isWholeProgramRequest()) { - targetProgram->_createWholeProgramResult( - compileReq, - endToEndReq); + targetProgram->_createWholeProgramResult(getSink(), this); } else { @@ -2125,8 +2001,8 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) { targetProgram->_createEntryPointResult( ii, - compileReq, - endToEndReq); + getSink(), + this); } } } @@ -2308,20 +2184,18 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) } - static void _generateOutput( - BackEndCompileRequest* compileRequest, - EndToEndCompileRequest* endToEndReq) + void EndToEndCompileRequest::generateOutput( + ComponentType* program) { // When dynamic dispatch is disabled, the program must // be fully specialized by now. So we check if we still // have unspecialized generic/existential parameters, // and report them as an error. // - auto program = compileRequest->getProgram(); auto specializationParamCount = program->getSpecializationParamCount(); - if (compileRequest->disableDynamicDispatch && specializationParamCount != 0) + if (disableDynamicDispatch && specializationParamCount != 0) { - auto sink = compileRequest->getSink(); + auto sink = getSink(); for( Index ii = 0; ii < specializationParamCount; ++ii ) { @@ -2347,56 +2221,48 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // Go through the code-generation targets that the user // has specified, and generate code for each of them. // - auto linkage = compileRequest->getLinkage(); + auto linkage = getLinkage(); for (auto targetReq : linkage->targets) { - generateOutputForTarget(compileRequest, targetReq, endToEndReq); + auto targetProgram = program->getTargetProgram(targetReq); + generateOutput(targetProgram); } } - void generateOutput( - BackEndCompileRequest* compileRequest) + void EndToEndCompileRequest::generateOutput() { - _generateOutput(compileRequest, nullptr); - } - - void generateOutput( - EndToEndCompileRequest* compileRequest) - { - _generateOutput(compileRequest->getBackEndReq(), compileRequest); + generateOutput(getSpecializedGlobalAndEntryPointsComponentType()); // If we are in command-line mode, we might be expected to actually // write output to one or more files here. - if (compileRequest->m_isCommandLineCompile) + if (m_isCommandLineCompile) { - auto linkage = compileRequest->getLinkage(); - auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); + auto linkage = getLinkage(); + auto program = getSpecializedGlobalAndEntryPointsComponentType(); for (auto targetReq : linkage->targets) { - Index entryPointCount = program->getEntryPointCount(); - if (targetReq->isWholeProgramRequest()) { + if (targetReq->isWholeProgramRequest()) + { writeWholeProgramResult( - compileRequest, targetReq); } else { + Index entryPointCount = program->getEntryPointCount(); for (Index ee = 0; ee < entryPointCount; ++ee) { writeEntryPointResult( - program, - compileRequest, - ee, - targetReq); + targetReq, + ee); } } } - compileRequest->maybeCreateContainer(); - compileRequest->maybeWriteContainer(compileRequest->m_containerOutputPath); + maybeCreateContainer(); + maybeWriteContainer(m_containerOutputPath); - _writeDependencyFile(compileRequest); + _writeDependencyFile(this); } } @@ -2404,8 +2270,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // - void dumpIntermediate( - BackEndCompileRequest* request, + void CodeGenContext::dumpIntermediate( void const* data, size_t size, char const* ext, @@ -2427,7 +2292,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) #endif String path; - path.append(request->m_dumpIntermediatePrefix); + path.append(getIntermediateDumpPrefix()); path.append(id); path.append(ext); @@ -2438,36 +2303,32 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) fclose(file); } - void dumpIntermediateText( - BackEndCompileRequest* compileRequest, + void CodeGenContext::dumpIntermediateText( void const* data, size_t size, char const* ext) { - dumpIntermediate(compileRequest, data, size, ext, false); + dumpIntermediate(data, size, ext, false); } - void dumpIntermediateBinary( - BackEndCompileRequest* compileRequest, + void CodeGenContext::dumpIntermediateBinary( void const* data, size_t size, char const* ext) { - dumpIntermediate(compileRequest, data, size, ext, true); + dumpIntermediate(data, size, ext, true); } - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, - DownstreamCompileResult* compileResult, - CodeGenTarget target) + void CodeGenContext::maybeDumpIntermediate( + DownstreamCompileResult* compileResult) { - if (!compileRequest->shouldDumpIntermediates) + if (!shouldDumpIntermediates()) return; ComPtr<ISlangBlob> blob; if (SLANG_SUCCEEDED(compileResult->getBinary(blob))) { - maybeDumpIntermediate(compileRequest, blob->getBufferPointer(), blob->getBufferSize(), target); + maybeDumpIntermediate(blob->getBufferPointer(), blob->getBufferSize()); } } @@ -2497,15 +2358,14 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return nullptr; } - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, + void CodeGenContext::maybeDumpIntermediate( void const* data, - size_t size, - CodeGenTarget target) + size_t size) { - if (!compileRequest->shouldDumpIntermediates) + if (!shouldDumpIntermediates()) return; + auto target = getTargetFormat(); switch (target) { case CodeGenTarget::CPPSource: @@ -2518,7 +2378,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::GLSL: case CodeGenTarget::HLSL: { - dumpIntermediateText(compileRequest, data, size, _getTargetExtension(target)); + dumpIntermediateText(data, size, _getTargetExtension(target)); break; } @@ -2537,13 +2397,13 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) const char* ext = _getTargetExtension(target); SLANG_ASSERT(ext); - dumpIntermediateBinary(compileRequest, data, size, ext); + dumpIntermediateBinary(data, size, ext); ComPtr<ISlangBlob> disassemblyBlob; - if (SLANG_SUCCEEDED(dissassembleWithDownstream(compileRequest, target, data, size, disassemblyBlob.writeRef()))) + if (SLANG_SUCCEEDED(dissassembleWithDownstream(data, size, disassemblyBlob.writeRef()))) { StringBuilder buf; buf << ext << ".asm"; - dumpIntermediateText(compileRequest, disassemblyBlob->getBufferPointer(), disassemblyBlob->getBufferSize(), buf.getBuffer()); + dumpIntermediateText(disassemblyBlob->getBufferPointer(), disassemblyBlob->getBufferSize(), buf.getBuffer()); } break; } @@ -2552,21 +2412,92 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) case CodeGenTarget::ShaderSharedLibrary: case CodeGenTarget::HostExecutable: { - dumpIntermediateBinary(compileRequest, data, size, _getTargetExtension(target)); + dumpIntermediateBinary(data, size, _getTargetExtension(target)); break; } default: break; } } - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, - char const* text, - CodeGenTarget target) + void CodeGenContext::maybeDumpIntermediate( + char const* text) { - if (!compileRequest->shouldDumpIntermediates) + if (!shouldDumpIntermediates()) return; - maybeDumpIntermediate(compileRequest, text, strlen(text), target); + maybeDumpIntermediate(text, strlen(text)); + } + + IRDumpOptions CodeGenContext::getIRDumpOptions() + { + if (auto endToEndReq = isEndToEndCompile()) + { + return endToEndReq->getFrontEndReq()->m_irDumpOptions; + } + return IRDumpOptions(); + } + + bool CodeGenContext::shouldValidateIR() + { + if (auto endToEndReq = isEndToEndCompile()) + { + if (endToEndReq->getFrontEndReq()->shouldValidateIR) + return true; + } + + return false; + } + + bool CodeGenContext::shouldDumpIR() + { + if (getTargetReq()->getTargetFlags() & SLANG_TARGET_FLAG_DUMP_IR) + return true; + + if (auto endToEndReq = isEndToEndCompile()) + { + if (endToEndReq->getFrontEndReq()->shouldDumpIR) + return true; + } + + return false; + } + + bool CodeGenContext::shouldDumpIntermediates() + { + if (getTargetReq()->shouldDumpIntermediates()) + return true; + if (auto endToEndReq = isEndToEndCompile()) + { + if (endToEndReq->shouldDumpIntermediates) + return true; + } + return false; + } + + String CodeGenContext::getIntermediateDumpPrefix() + { + if (auto endToEndReq = isEndToEndCompile()) + { + return endToEndReq->m_dumpIntermediatePrefix; + } + return String(); + } + + bool CodeGenContext::getUseUnknownImageFormatAsDefault() + { + if (auto endToEndReq = isEndToEndCompile()) + { + return endToEndReq->useUnknownImageFormatAsDefault; + } + return false; + } + + bool CodeGenContext::isSpecializationDisabled() + { + if (auto endToEndReq = isEndToEndCompile()) + { + return endToEndReq->disableSpecialization; + } + return false; } } diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 7f8257777..bf715d5d4 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -133,11 +133,11 @@ namespace Slang Maximal = SLANG_OPTIMIZATION_LEVEL_MAXIMAL, }; + struct CodeGenContext; + class EndToEndCompileRequest; + class FrontEndCompileRequest; class Linkage; class Module; - class FrontEndCompileRequest; - class BackEndCompileRequest; - class EndToEndCompileRequest; class TranslationUnitRequest; // Result of compiling an entry point. @@ -2143,8 +2143,9 @@ namespace Slang } CompileResult& _createWholeProgramResult( - BackEndCompileRequest* backEndRequest, - EndToEndCompileRequest* endToEndRequest); + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq = nullptr); + /// Internal helper for `getOrCreateEntryPointResult`. /// /// This is used so that command-line and API-based @@ -2154,8 +2155,8 @@ namespace Slang /// CompileResult& _createEntryPointResult( Int entryPointIndex, - BackEndCompileRequest* backEndRequest, - EndToEndCompileRequest* endToEndRequest); + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq = nullptr); RefPtr<IRModule> getOrCreateIRModuleForLayout(DiagnosticSink* sink); @@ -2185,40 +2186,257 @@ namespace Slang RefPtr<IRModule> m_irModuleForLayout; }; - /// A request to generate code for a program - class BackEndCompileRequest : public CompileRequestBase + /// A back-end-specific object to track optional feaures/capabilities/extensions + /// that are discovered to be used by a program/kernel as part of code generation. + class ExtensionTracker : public RefObject { + // TODO: The existence of this type is evidence of a design/architecture problem. + // + // A better formulation of things requires a few key changes: + // + // 1. All optional capabilities need to be enumerated as part of the `CapabilitySet` + // system, so that they can be reasoned about uniformly across different targets + // and different layers of the compiler. + // + // 2. The front-end should be responsible for either or both of: + // + // * Checking that `public` or otherwise externally-visible items (declarations/definitions) + // explicitly declare the capabilities they require, and that they only ever + // make use of items that are comatible with those required capabilities. + // + // * Inferring the capabilities required by items that are not externally visible, + // and attaching those capabilities explicit as a modifier or other synthesized AST node. + // + // 3. The capabilities required by a given `ComponentType` and its entry points should be + // explicitly know-able, and they should be something we can compare to the capabilities + // of a code generation target *before* back-end code generation is started. We should be + // able to issue error messages around lacking capabilities in a way the user can understand, + // in terms of the high-level-language entities. + public: - BackEndCompileRequest( - Linkage* linkage, - DiagnosticSink* sink, - ComponentType* program = nullptr); + }; - // Should we dump intermediate results along the way, for debugging? - bool shouldDumpIntermediates = false; + /// A context for code generation in the compiler back-end + struct CodeGenContext + { + public: + typedef List<Index> EntryPointIndices; - ComponentType* getProgram() { return m_program; } - void setProgram(ComponentType* program) { m_program = program; } + struct Shared + { + public: + Shared( + TargetProgram* targetProgram, + EntryPointIndices const& entryPointIndices, + DiagnosticSink* sink, + EndToEndCompileRequest* endToEndReq) + : targetProgram(targetProgram) + , entryPointIndices(entryPointIndices) + , sink(sink) + , endToEndReq(endToEndReq) + {} + +// Shared( +// TargetProgram* targetProgram, +// EndToEndCompileRequest* endToEndReq); + + TargetProgram* targetProgram = nullptr; + EntryPointIndices entryPointIndices; + DiagnosticSink* sink = nullptr; + EndToEndCompileRequest* endToEndReq = nullptr; + }; + + CodeGenContext( + Shared* shared) + : m_shared(shared) + , m_targetFormat(shared->targetProgram->getTargetReq()->getTarget()) + {} + + CodeGenContext( + CodeGenContext* base, + CodeGenTarget targetFormat, + ExtensionTracker* extensionTracker = nullptr) + : m_shared(base->m_shared) + , m_targetFormat(targetFormat) + , m_extensionTracker(extensionTracker) + {} + + /// Get the diagnostic sink + DiagnosticSink* getSink() + { + return m_shared->sink; + } + + TargetProgram* getTargetProgram() + { + return m_shared->targetProgram; + } + + EntryPointIndices const& getEntryPointIndices() + { + return m_shared->entryPointIndices; + } + + CodeGenTarget getTargetFormat() + { + return m_targetFormat; + } + + ExtensionTracker* getExtensionTracker() + { + return m_extensionTracker; + } + + TargetRequest* getTargetReq() + { + return getTargetProgram()->getTargetReq(); + } + + CapabilitySet getTargetCaps() + { + return getTargetReq()->getTargetCaps(); + } + + CodeGenTarget getFinalTargetFormat() + { + return getTargetReq()->getTarget(); + } + + ComponentType* getProgram() + { + return getTargetProgram()->getProgram(); + } + + Linkage* getLinkage() + { + return getProgram()->getLinkage(); + } + + Session* getSession() + { + return getLinkage()->getSessionImpl(); + } + + /// Get the source manager + SourceManager* getSourceManager() + { + return getLinkage()->getSourceManager(); + } + + ISlangFileSystemExt* getFileSystemExt() + { + return getLinkage()->getFileSystemExt(); + } + + EndToEndCompileRequest* isEndToEndCompile() + { + return m_shared->endToEndReq; + } + + EndToEndCompileRequest* isPassThroughEnabled(); + + Count getEntryPointCount() + { + return getEntryPointIndices().getCount(); + } + + EntryPoint* getEntryPoint(Index index) + { + return getProgram()->getEntryPoint(index); + } + + Index getSingleEntryPointIndex() + { + SLANG_ASSERT(getEntryPointCount() == 1); + return getEntryPointIndices()[0]; + } - // Should R/W images without explicit formats be assumed to have "unknown" format? // - // The default behavior is to make a best-effort guess as to what format is intended. + + IRDumpOptions getIRDumpOptions(); + + bool shouldValidateIR(); + bool shouldDumpIR(); + + bool shouldDumpIntermediates(); + String getIntermediateDumpPrefix(); + + bool getUseUnknownImageFormatAsDefault(); + + bool isSpecializationDisabled(); + // - bool useUnknownImageFormatAsDefault = false; - // If true will disable generics/existential value specialization pass. - bool disableSpecialization = false; + CompileResult emitEntryPoints(); - // If true will disable generating dynamic dispatch code. - bool disableDynamicDispatch = false; + SlangResult dissassembleWithDownstream( + const void* data, + size_t dataSizeInBytes, + ISlangBlob** outBlob); - // The default IR dumping options - IRDumpOptions m_irDumpOptions; + SlangResult dissassembleWithDownstream( + DownstreamCompileResult* downstreamResult, + ISlangBlob** outBlob); - String m_dumpIntermediatePrefix; + protected: + CodeGenTarget m_targetFormat = CodeGenTarget::Unknown; + ExtensionTracker* m_extensionTracker = nullptr; + + // Helper to dump intermediate output when debugging + void maybeDumpIntermediate( + void const* data, + size_t size); + void maybeDumpIntermediate( + char const* text); + + void maybeDumpIntermediate( + DownstreamCompileResult* compileResult); + + void dumpIntermediate( + void const* data, + size_t size, + char const* ext, + bool isBinary); + + void dumpIntermediateText( + void const* data, + size_t size, + char const* ext); + + void dumpIntermediateBinary( + void const* data, + size_t size, + char const* ext); + + /* Emits entry point source taking into account if a pass-through or not. Uses 'targetFormat' to determine + the target (not targetReq) */ + SlangResult emitEntryPointsSource( + String& outSource); + + SlangResult emitEntryPointsSourceFromIR( + String& outSource); + + SlangResult emitWithDownstreamForEntryPoints( + RefPtr<DownstreamCompileResult>& outResult); + + /* Determines a suitable filename to identify the input for a given entry point being compiled. + If the end-to-end compile is a pass-through case, will attempt to find the (unique) source file + pathname for the translation unit containing the entry point at `entryPointIndex. + If the compilation is not in a pass-through case, then always returns `"slang-generated"`. + @param endToEndReq The end-to-end compile request which might be using pass-through compilation + @param entryPointIndex The index of the entry point to compute a filename for. + @return the appropriate source filename */ + String calcSourcePathForEntryPoints(); + + TranslationUnitRequest* findPassThroughTranslationUnit( + Int entryPointIndex); + + + SlangResult _emitEntryPoints( + RefPtr<DownstreamCompileResult>& outDownstreamResult); private: - RefPtr<ComponentType> m_program; + Shared* m_shared = nullptr; }; /// A compile request that spans the front and back ends of the compiler @@ -2402,7 +2620,6 @@ namespace Slang NamePool* getNamePool() { return getLinkage()->getNamePool(); } FrontEndCompileRequest* getFrontEndReq() { return m_frontEndReq; } - BackEndCompileRequest* getBackEndReq() { return m_backEndReq; } ComponentType* getUnspecializedGlobalComponentType() { return getFrontEndReq()->getGlobalComponentType(); } ComponentType* getUnspecializedGlobalAndEntryPointsComponentType() @@ -2422,10 +2639,47 @@ namespace Slang m_linkage = nullptr; m_frontEndReq = nullptr; } + + void generateOutput(); + + + // Note: The following settings used to be considered part of the "back-end" compile + // request, but were only being used as part of end-to-end compilation anyway, + // so they were moved here. + // + + // Should we dump intermediate results along the way, for debugging? + bool shouldDumpIntermediates = false; + + // Should R/W images without explicit formats be assumed to have "unknown" format? + // + // The default behavior is to make a best-effort guess as to what format is intended. + // + bool useUnknownImageFormatAsDefault = false; + + // If true will disable generics/existential value specialization pass. + bool disableSpecialization = false; + + // If true will disable generating dynamic dispatch code. + bool disableDynamicDispatch = false; + + // The default IR dumping options +// IRDumpOptions m_irDumpOptions; + + String m_dumpIntermediatePrefix; + private: + void writeWholeProgramResult( + TargetRequest* targetReq); + void writeEntryPointResult( + TargetRequest* targetReq, + Int entryPointIndex); ISlangUnknown* getInterface(const Guid& guid); + void generateOutput(ComponentType* program); + void generateOutput(TargetProgram* targetProgram); + void init(); Session* m_session = nullptr; @@ -2435,35 +2689,12 @@ namespace Slang RefPtr<ComponentType> m_specializedGlobalComponentType; RefPtr<ComponentType> m_specializedGlobalAndEntryPointsComponentType; List<RefPtr<ComponentType>> m_specializedEntryPoints; - RefPtr<BackEndCompileRequest> m_backEndReq; // For output RefPtr<StdWriters> m_writers; }; - void generateOutput( - BackEndCompileRequest* compileRequest); - - void generateOutput( - EndToEndCompileRequest* compileRequest); - - // Helper to dump intermediate output when debugging - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, - void const* data, - size_t size, - CodeGenTarget target); - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, - char const* text, - CodeGenTarget target); - - void maybeDumpIntermediate( - BackEndCompileRequest* compileRequest, - DownstreamCompileResult* compileResult, - CodeGenTarget target); - /* Returns SLANG_OK if pass through support is available */ SlangResult checkExternalCompilerSupport(Session* session, PassThroughMode passThrough); /* Report an error appearing from external compiler to the diagnostic sink error to the diagnostic sink. @@ -2473,41 +2704,6 @@ namespace Slang @param sink The diagnostic sink to report to */ void reportExternalCompileError(const char* compilerName, SlangResult res, const UnownedStringSlice& diagnostic, DiagnosticSink* sink); - /* Determines a suitable filename to identify the input for a given entry point being compiled. - If the end-to-end compile is a pass-through case, will attempt to find the (unique) source file - pathname for the translation unit containing the entry point at `entryPointIndex. - If the compilation is not in a pass-through case, then always returns `"slang-generated"`. - @param endToEndReq The end-to-end compile request which might be using pass-through compilation - @param entryPointIndex The index of the entry point to compute a filename for. - @return the appropriate source filename */ - String calcSourcePathForEntryPoint(EndToEndCompileRequest* endToEndReq, Int entryPointIndex); - String calcSourcePathForEntryPoints(EndToEndCompileRequest* endToEndReq, const List<Int>& entryPointIndices); - - class ExtensionTracker : public RefObject - { - public: - }; - - /* Emits entry point source taking into account if a pass-through or not. Uses 'target' to determine - the target (not targetReq) */ - SlangResult emitEntryPointsSource( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, - ExtensionTracker* extensionTracker, - String& outSource); - - SlangResult emitEntryPointSource( - BackEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq, - CodeGenTarget target, - EndToEndCompileRequest* endToEndReq, - ExtensionTracker* extensionTracker, - String& outSource); - // // Information about BaseType that's useful for checking literals diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index eb178a366..edadcef48 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -92,14 +92,11 @@ struct CLikeSourceEmitter::ComputeEmitActionsContext CLikeSourceEmitter::CLikeSourceEmitter(const Desc& desc) { m_writer = desc.sourceWriter; - m_sourceLanguage = getSourceLanguage(desc.target); + m_sourceLanguage = getSourceLanguage(desc.codeGenContext->getTargetFormat()); SLANG_ASSERT(m_sourceLanguage != SourceLanguage::Unknown); - m_target = desc.target; - m_targetCaps = desc.targetCaps; - - m_compileRequest = desc.compileRequest; - m_targetRequest = desc.targetRequest; + m_target = desc.codeGenContext->getTargetFormat(); + m_codeGenContext = desc.codeGenContext; m_entryPointStage = desc.entryPointStage; m_effectiveProfile = desc.effectiveProfile; } diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index aa5a22697..6a3a31f78 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -22,10 +22,7 @@ class CLikeSourceEmitter: public SourceEmitterBase public: struct Desc { - BackEndCompileRequest* compileRequest = nullptr; - - /// The target language we want to generate code for - CodeGenTarget target = CodeGenTarget::Unknown; + CodeGenContext* codeGenContext = nullptr; /// The stage for the entry point we are being asked to compile Stage entryPointStage = Stage::Unknown; @@ -34,15 +31,7 @@ public: /// combining information from the target and entry point. Profile effectiveProfile = Profile::RawEnum::Unknown; - /// The capabilities of the target - CapabilitySet targetCaps; - - /// The associated extension tracker - ExtensionTracker* extensionTracker = nullptr; - SourceWriter* sourceWriter = nullptr; - - TargetRequest* targetRequest = nullptr; }; enum @@ -202,13 +191,13 @@ public: /// Get the source manager - SourceManager* getSourceManager() { return m_compileRequest->getSourceManager(); } + SourceManager* getSourceManager() { return m_codeGenContext->getSourceManager(); } /// Get the source writer used SourceWriter* getSourceWriter() const { return m_writer; } /// Get the diagnostic sink - DiagnosticSink* getSink() { return m_compileRequest->getSink();} + DiagnosticSink* getSink() { return m_codeGenContext->getSink();} /// Get the code gen target CodeGenTarget getTarget() { return m_target; } @@ -217,7 +206,14 @@ public: void noteInternalErrorLoc(SourceLoc loc) { return getSink()->noteInternalErrorLoc(loc); } - CapabilitySet getTargetCaps() { return m_targetCaps; } + CapabilitySet getTargetCaps() { return m_codeGenContext->getTargetCaps(); } + + CodeGenContext* getCodeGenContext() { return m_codeGenContext; } + TargetRequest* getTargetReq() { return m_codeGenContext->getTargetReq(); } + Session* getSession() { return m_codeGenContext->getSession(); } + Linkage* getLinkage() { return m_codeGenContext->getLinkage(); } + ComponentType* getProgram() { return m_codeGenContext->getProgram(); } + TargetProgram* getTargetProgram() { return m_codeGenContext->getTargetProgram(); } // // Types @@ -475,9 +471,8 @@ public: // Sort witnessTable entries according to the order defined in the witnessed interface type. List<IRWitnessTableEntry*> getSortedWitnessTableEntries(IRWitnessTable* witnessTable); - - BackEndCompileRequest* m_compileRequest = nullptr; - TargetRequest* m_targetRequest = nullptr; + + CodeGenContext* m_codeGenContext = nullptr; IRModule* m_irModule = nullptr; // The stage for which we are emitting code. @@ -492,9 +487,6 @@ public: // The target language we want to generate code for CodeGenTarget m_target; - /// The capabilities of the target - CapabilitySet m_targetCaps; - // Source language (based on the more nuanced m_target) SourceLanguage m_sourceLanguage; diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index e7b7af991..c56190f65 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -1643,7 +1643,7 @@ SlangResult CPPSourceEmitter::calcFuncName(const HLSLIntrinsic* specOp, StringBu CPPSourceEmitter::CPPSourceEmitter(const Desc& desc): Super(desc), m_slicePool(StringSlicePool::Style::Default), - m_typeSet(desc.compileRequest->getSession()), + m_typeSet(desc.codeGenContext->getSession()), m_opLookup(new HLSLIntrinsicOpLookup), m_intrinsicSet(&m_typeSet, m_opLookup) { diff --git a/source/slang/slang-emit-cuda.h b/source/slang/slang-emit-cuda.h index ad2f8ed0a..8bd2d33c4 100644 --- a/source/slang/slang-emit-cuda.h +++ b/source/slang/slang-emit-cuda.h @@ -56,7 +56,7 @@ public: CUDASourceEmitter(const Desc& desc) : Super(desc) { - m_extensionTracker = dynamicCast<CUDAExtensionTracker>(desc.extensionTracker); + m_extensionTracker = dynamicCast<CUDAExtensionTracker>(desc.codeGenContext->getExtensionTracker()); SLANG_ASSERT(m_extensionTracker); } diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 044f93569..3b39c1cb1 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -15,7 +15,7 @@ namespace Slang { GLSLSourceEmitter::GLSLSourceEmitter(const Desc& desc) : Super(desc) { - m_glslExtensionTracker = dynamicCast<GLSLExtensionTracker>(desc.extensionTracker); + m_glslExtensionTracker = dynamicCast<GLSLExtensionTracker>(desc.codeGenContext->getExtensionTracker()); SLANG_ASSERT(m_glslExtensionTracker); } @@ -40,7 +40,7 @@ SlangResult GLSLSourceEmitter::init() default: break; } - if (m_targetRequest->getForceGLSLScalarBufferLayout()) + if (getTargetReq()->getForceGLSLScalarBufferLayout()) { m_glslExtensionTracker->requireExtension( UnownedStringSlice::fromLiteral("GL_EXT_scalar_block_layout")); @@ -121,7 +121,7 @@ void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSL _requireGLSLVersion(430); m_writer->emit("layout("); - m_writer->emit(m_targetRequest->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); + m_writer->emit(getTargetReq()->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); auto layout = getVarLayout(varDecl); if (layout) @@ -196,7 +196,7 @@ void GLSLSourceEmitter::_emitGLSLByteAddressBuffer(IRGlobalParam* varDecl, IRByt _requireGLSLVersion(430); m_writer->emit("layout("); - m_writer->emit(m_targetRequest->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); + m_writer->emit(getTargetReq()->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); auto layout = getVarLayout(varDecl); if (layout) @@ -292,7 +292,7 @@ void GLSLSourceEmitter::_emitGLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor { // Is writable m_writer->emit("layout("); - m_writer->emit(m_targetRequest->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); + m_writer->emit(getTargetReq()->getForceGLSLScalarBufferLayout() ? "scalar" : "std430"); m_writer->emit(") buffer "); } // TODO: what to do with HLSL `tbuffer` style buffers? @@ -300,7 +300,7 @@ void GLSLSourceEmitter::_emitGLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor { // uniform is implicitly read only m_writer->emit("layout("); - m_writer->emit(m_targetRequest->getForceGLSLScalarBufferLayout() ? "scalar" : "std140"); + m_writer->emit(getTargetReq()->getForceGLSLScalarBufferLayout() ? "scalar" : "std140"); m_writer->emit(") uniform "); } @@ -379,7 +379,7 @@ void GLSLSourceEmitter::_emitGLSLImageFormatModifier(IRInst* var, IRTextureType* // treating images without explicit formats as having // unknown format. // - if (m_compileRequest->useUnknownImageFormatAsDefault) + if (getCodeGenContext()->getUseUnknownImageFormatAsDefault()) { _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_EXT_shader_image_load_formatted")); return; diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 8995b4911..a2211578d 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1,5 +1,4 @@ // slang-emit-spirv.cpp -#include "slang-emit.h" #include "slang-compiler.h" #include "slang-emit-base.h" @@ -2860,16 +2859,18 @@ struct SPIRVEmitContext }; SlangResult emitSPIRVFromIR( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* irModule, const List<IRFunc*>& irEntryPoints, List<uint8_t>& spirvOut) { spirvOut.clear(); - SPIRVEmitContext context(irModule, targetRequest, compileRequest->getSink()); - legalizeIRForSPIRV(&context, irModule, irEntryPoints, compileRequest->getSink()); + auto targetRequest = codeGenContext->getTargetReq(); + auto sink = codeGenContext->getSink(); + + SPIRVEmitContext context(irModule, targetRequest, sink); + legalizeIRForSPIRV(&context, irModule, irEntryPoints, sink); context.emitFrontMatter(); for (auto irEntryPoint : irEntryPoints) diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 23f06e8e9..067d0a99a 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -1,5 +1,4 @@ // slang-emit.cpp -#include "slang-emit.h" #include "../core/slang-writer.h" #include "../core/slang-type-text-util.h" @@ -139,17 +138,17 @@ StructTypeLayout* getGlobalStructLayout( } static void dumpIRIfEnabled( - BackEndCompileRequest* compileRequest, + CodeGenContext* codeGenContext, IRModule* irModule, char const* label = nullptr) { - if(compileRequest->shouldDumpIR) + if(codeGenContext->shouldDumpIR()) { - DiagnosticSinkWriter writer(compileRequest->getSink()); + DiagnosticSinkWriter writer(codeGenContext->getSink()); //FILE* f = nullptr; //fopen_s(&f, (String("dump-") + label + ".txt").getBuffer(), "wt"); //FileWriter writer(f, 0); - dumpIR(irModule, compileRequest->m_irDumpOptions, label, compileRequest->getSourceManager(), &writer); + dumpIR(irModule, codeGenContext->getIRDumpOptions(), label, codeGenContext->getSourceManager(), &writer); //fclose(f); } } @@ -161,18 +160,15 @@ struct LinkingAndOptimizationOptions }; Result linkAndOptimizeIR( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - CodeGenTarget target, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, LinkingAndOptimizationOptions const& options, LinkedIR& outLinkedIR) { - auto sink = compileRequest->getSink(); - auto program = compileRequest->getProgram(); - auto targetProgram = program->getTargetProgram(targetRequest); + auto session = codeGenContext->getSession(); + auto sink = codeGenContext->getSink(); + auto target = codeGenContext->getTargetFormat(); + auto targetRequest = codeGenContext->getTargetReq(); - auto session = targetRequest->getSession(); // We start out by performing "linking" at the level of the IR. // This step will create a fresh IR module to be used for @@ -182,32 +178,28 @@ Result linkAndOptimizeIR( // modules, and also select between the definitions of // any "profile-overloaded" symbols. // - outLinkedIR = linkIR( - compileRequest, - entryPointIndices, - target, - targetProgram); + outLinkedIR = linkIR(codeGenContext); auto irModule = outLinkedIR.module; auto irEntryPoints = outLinkedIR.entryPoints; #if 0 - dumpIRIfEnabled(compileRequest, irModule, "LINKED"); + dumpIRIfEnabled(codeGenContext, irModule, "LINKED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // If the user specified the flag that they want us to dump // IR, then do it here, for the target-specific, but // un-specialized IR. - dumpIRIfEnabled(compileRequest, irModule); + dumpIRIfEnabled(codeGenContext, irModule); // Replace any global constants with their values. // replaceGlobalConstants(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "GLOBAL CONSTANTS REPLACED"); + dumpIRIfEnabled(codeGenContext, irModule, "GLOBAL CONSTANTS REPLACED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // When there are top-level existential-type parameters @@ -219,9 +211,9 @@ Result linkAndOptimizeIR( // bindExistentialSlots(irModule, sink); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "EXISTENTIALS BOUND"); + dumpIRIfEnabled(codeGenContext, irModule, "EXISTENTIALS BOUND"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Now that we've linked the IR code, any layout/binding // information has been attached to shader parameters @@ -243,9 +235,9 @@ Result linkAndOptimizeIR( // collectGlobalUniformParameters(irModule, outLinkedIR.globalScopeVarLayout); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "GLOBAL UNIFORMS COLLECTED"); + dumpIRIfEnabled(codeGenContext, irModule, "GLOBAL UNIFORMS COLLECTED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Another transformation that needed to wait until we // had layout information on parameters is to take uniform @@ -264,9 +256,9 @@ Result linkAndOptimizeIR( case CodeGenTarget::CUDASource: collectOptiXEntryPointUniformParams(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "OPTIX ENTRY POINT UNIFORMS COLLECTED"); + dumpIRIfEnabled(codeGenContext, irModule, "OPTIX ENTRY POINT UNIFORMS COLLECTED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); break; case CodeGenTarget::CPPSource: @@ -274,9 +266,9 @@ Result linkAndOptimizeIR( default: collectEntryPointUniformParams(irModule, passOptions); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "ENTRY POINT UNIFORMS COLLECTED"); + dumpIRIfEnabled(codeGenContext, irModule, "ENTRY POINT UNIFORMS COLLECTED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); break; } } @@ -286,9 +278,9 @@ Result linkAndOptimizeIR( default: moveEntryPointUniformParamsToGlobalScope(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "ENTRY POINT UNIFORMS MOVED"); + dumpIRIfEnabled(codeGenContext, irModule, "ENTRY POINT UNIFORMS MOVED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); break; case CodeGenTarget::HostCPPSource: case CodeGenTarget::CPPSource: @@ -302,9 +294,9 @@ Result linkAndOptimizeIR( // desugarUnionTypes(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "UNIONS DESUGARED"); + dumpIRIfEnabled(codeGenContext, irModule, "UNIONS DESUGARED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Next, we need to ensure that the code we emit for // the target doesn't contain any operations that would @@ -325,24 +317,24 @@ Result linkAndOptimizeIR( // perform specialization of functions based on parameter // values that need to be compile-time constants. // - dumpIRIfEnabled(compileRequest, irModule, "BEFORE-SPECIALIZE"); - if (!compileRequest->disableSpecialization) + dumpIRIfEnabled(codeGenContext, irModule, "BEFORE-SPECIALIZE"); + if (!codeGenContext->isSpecializationDisabled()) specializeModule(irModule); - dumpIRIfEnabled(compileRequest, irModule, "AFTER-SPECIALIZE"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER-SPECIALIZE"); applySparseConditionalConstantPropagation(irModule); eliminateDeadCode(irModule); lowerReinterpret(targetRequest, irModule, sink); - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // For targets that supports dynamic dispatch, we need to lower the // generics / interface types to ordinary functions and types using // function pointers. - dumpIRIfEnabled(compileRequest, irModule, "BEFORE-LOWER-GENERICS"); + dumpIRIfEnabled(codeGenContext, irModule, "BEFORE-LOWER-GENERICS"); lowerGenerics(targetRequest, irModule, sink); - dumpIRIfEnabled(compileRequest, irModule, "AFTER-LOWER-GENERICS"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER-LOWER-GENERICS"); if (sink->getErrorCount() != 0) return SLANG_FAIL; @@ -355,9 +347,9 @@ Result linkAndOptimizeIR( // so that they don't just throw out any non-entry point code // Debugging code for IR transformations... #if 0 - dumpIRIfEnabled(compileRequest, irModule, "SPECIALIZED"); + dumpIRIfEnabled(codeGenContext, irModule, "SPECIALIZED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Inline calls to any functions marked with [__unsafeInlineEarly] again, // since we may be missing out cases prevented by the generic constructs @@ -370,9 +362,9 @@ Result linkAndOptimizeIR( // simplifyIR(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER DCE"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER DCE"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // We don't need the legalize pass for C/C++ based types if(options.shouldLegalizeExistentialAndResourceTypes ) @@ -409,9 +401,9 @@ Result linkAndOptimizeIR( eliminateDeadCode(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "EXISTENTIALS LEGALIZED"); + dumpIRIfEnabled(codeGenContext, irModule, "EXISTENTIALS LEGALIZED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Many of our target languages and/or downstream compilers // don't support `struct` types that have resource-type fields. @@ -431,9 +423,9 @@ Result linkAndOptimizeIR( // Debugging output of legalization #if 0 - dumpIRIfEnabled(compileRequest, irModule, "LEGALIZED"); + dumpIRIfEnabled(codeGenContext, irModule, "LEGALIZED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); } // Once specialization and type legalization have been performed, @@ -444,9 +436,9 @@ Result linkAndOptimizeIR( simplifyIR(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER SSA"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER SSA"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // After type legalization and subsequent SSA cleanup we expect // that any resource types passed to functions are exposed @@ -457,8 +449,8 @@ Result linkAndOptimizeIR( // resource types can be used, so that having them as // function parameters, reults, etc. is invalid. // We clean up the usages of resource values here. - specializeResourceUsage(compileRequest, targetRequest, irModule); - specializeFuncsForBufferLoadArgs(compileRequest, targetRequest, irModule); + specializeResourceUsage(codeGenContext, irModule); + specializeFuncsForBufferLoadArgs(codeGenContext, irModule); // simplifyIR(irModule); @@ -468,15 +460,15 @@ Result linkAndOptimizeIR( // those platforms. if (isKhronosTarget(targetRequest)) { - specializeArrayParameters(compileRequest, targetRequest, irModule); + specializeArrayParameters(codeGenContext, irModule); simplifyIR(irModule); } #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER RESOURCE SPECIALIZATION"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER RESOURCE SPECIALIZATION"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // For HLSL (and fxc/dxc) only, we need to "wrap" any // structured buffers defined over matrix types so @@ -491,9 +483,9 @@ Result linkAndOptimizeIR( { wrapStructuredBuffersOfMatrices(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "STRUCTURED BUFFERS WRAPPED"); + dumpIRIfEnabled(codeGenContext, irModule, "STRUCTURED BUFFERS WRAPPED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); } break; @@ -600,12 +592,12 @@ Result linkAndOptimizeIR( { synthesizeActiveMask( irModule, - compileRequest->getSink()); + codeGenContext->getSink()); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER synthesizeActiveMask"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER synthesizeActiveMask"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); } break; @@ -631,26 +623,26 @@ Result linkAndOptimizeIR( session, irModule, irEntryPoints, - compileRequest->getSink(), + codeGenContext->getSink(), glslExtensionTracker); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "GLSL LEGALIZED"); + dumpIRIfEnabled(codeGenContext, irModule, "GLSL LEGALIZED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); } break; case CodeGenTarget::CSource: case CodeGenTarget::CPPSource: { - legalizeEntryPointVaryingParamsForCPU(irModule, compileRequest->getSink()); + legalizeEntryPointVaryingParamsForCPU(irModule, codeGenContext->getSink()); } break; case CodeGenTarget::CUDASource: { - legalizeEntryPointVaryingParamsForCUDA(irModule, compileRequest->getSink()); + legalizeEntryPointVaryingParamsForCUDA(irModule, codeGenContext->getSink()); } break; @@ -684,9 +676,9 @@ Result linkAndOptimizeIR( convertEntryPointPtrParamsToRawPtrs(irModule); } #if 0 - dumpIRIfEnabled(compileRequest, irModule, "EXPLICIT GLOBAL CONTEXT INTRODUCED"); + dumpIRIfEnabled(codeGenContext, irModule, "EXPLICIT GLOBAL CONTEXT INTRODUCED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); break; } @@ -696,9 +688,9 @@ Result linkAndOptimizeIR( stripWitnessTables(irModule); #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER STRIP WITNESS TABLES"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER STRIP WITNESS TABLES"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // The resource-based specialization pass above // may create specialized versions of functions, but @@ -717,9 +709,9 @@ Result linkAndOptimizeIR( performGLSLResourceReturnFunctionInlining(irModule); } #if 0 - dumpIRIfEnabled(compileRequest, irModule, "AFTER DCE"); + dumpIRIfEnabled(codeGenContext, irModule, "AFTER DCE"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); // Lower all bit_cast operations on complex types into leaf-level // bit_cast on basic types. @@ -731,9 +723,9 @@ Result linkAndOptimizeIR( // reflect the IR that code is generated from as closely as possible. // #if 0 - dumpIRIfEnabled(compileRequest, irModule, "OPTIMIZED"); + dumpIRIfEnabled(codeGenContext, irModule, "OPTIMIZED"); #endif - validateIRModuleIfEnabled(compileRequest, irModule); + validateIRModuleIfEnabled(codeGenContext, irModule); return SLANG_OK; } @@ -742,18 +734,17 @@ void trackGLSLTargetCaps( GLSLExtensionTracker* extensionTracker, CapabilitySet const& caps); -SlangResult emitEntryPointsSourceFromIR( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - CodeGenTarget target, - TargetRequest* targetRequest, - ExtensionTracker* extensionTracker, +SlangResult CodeGenContext::emitEntryPointsSourceFromIR( String& outSource) { outSource = String(); - auto sink = compileRequest->getSink(); - auto program = compileRequest->getProgram(); + auto extensionTracker = getExtensionTracker(); + auto session = getSession(); + auto sink = getSink(); + auto sourceManager = getSourceManager(); + auto target = getTargetFormat(); + auto targetRequest = getTargetReq(); auto lineDirectiveMode = targetRequest->getLineDirectiveMode(); // To try to make the default behavior reasonable, we will @@ -767,17 +758,15 @@ SlangResult emitEntryPointsSourceFromIR( lineDirectiveMode = LineDirectiveMode::GLSL; } - SourceWriter sourceWriter(compileRequest->getSourceManager(), lineDirectiveMode ); + SourceWriter sourceWriter(sourceManager, lineDirectiveMode ); CLikeSourceEmitter::Desc desc; - desc.compileRequest = compileRequest; - desc.targetRequest = targetRequest; - desc.target = target; - // TODO(DG): Can't assume a single entry point stage for multiple entry points - if (entryPointIndices.getCount() == 1) + desc.codeGenContext = this; + + if (getEntryPointCount() == 1) { - auto entryPoint = program->getEntryPoint(entryPointIndices[0]); + auto entryPoint = getEntryPoint(getSingleEntryPointIndex()); desc.entryPointStage = entryPoint->getStage(); desc.effectiveProfile = getEffectiveProfile(entryPoint, targetRequest); } @@ -786,9 +775,7 @@ SlangResult emitEntryPointsSourceFromIR( desc.entryPointStage = Stage::Unknown; desc.effectiveProfile = targetRequest->getTargetProfile(); } - desc.targetCaps = targetRequest->getTargetCaps(); desc.sourceWriter = &sourceWriter; - desc.extensionTracker = extensionTracker; // Define here, because must be in scope longer than the sourceEmitter, as sourceEmitter might reference // items in the linkedIR module @@ -848,10 +835,7 @@ SlangResult emitEntryPointsSourceFromIR( } SLANG_RETURN_ON_FAIL(linkAndOptimizeIR( - compileRequest, - entryPointIndices, - target, - targetRequest, + this, linkingAndOptimizationOptions, linkedIR)); @@ -884,7 +868,7 @@ SlangResult emitEntryPointsSourceFromIR( else { // If there is a prelude emit it - const auto& prelude = compileRequest->getSession()->getPreludeForLanguage(sourceLanguage); + const auto& prelude = session->getPreludeForLanguage(sourceLanguage); if (prelude.getLength() > 0) { sourceWriter.emit(prelude.getUnownedSlice()); @@ -924,40 +908,27 @@ SlangResult emitEntryPointsSourceFromIR( } SlangResult emitSPIRVFromIR( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* irModule, const List<IRFunc*>& irEntryPoints, List<uint8_t>& spirvOut); SlangResult emitSPIRVForEntryPointsDirectly( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - TargetRequest* targetRequest, - List<uint8_t>& spirvOut) + CodeGenContext* codeGenContext, + List<uint8_t>& spirvOut) { - auto sink = compileRequest->getSink(); - auto program = compileRequest->getProgram(); - auto targetProgram = program->getTargetProgram(targetRequest); - auto programLayout = targetProgram->getOrCreateLayout(sink); - - RefPtr<EntryPointLayout> entryPointLayout = programLayout->entryPoints[entryPointIndices[0]]; - // Outside because we want to keep IR in scope whilst we are processing emits LinkedIR linkedIR; LinkingAndOptimizationOptions linkingAndOptimizationOptions; SLANG_RETURN_ON_FAIL(linkAndOptimizeIR( - compileRequest, - entryPointIndices, - targetRequest->getTarget(), - targetRequest, + codeGenContext, linkingAndOptimizationOptions, linkedIR)); auto irModule = linkedIR.module; auto irEntryPoints = linkedIR.entryPoints; - emitSPIRVFromIR(compileRequest, targetRequest, irModule, irEntryPoints, spirvOut); + emitSPIRVFromIR(codeGenContext, irModule, irEntryPoints, spirvOut); return SLANG_OK; } diff --git a/source/slang/slang-emit.h b/source/slang/slang-emit.h deleted file mode 100644 index 1467a9bcd..000000000 --- a/source/slang/slang-emit.h +++ /dev/null @@ -1,47 +0,0 @@ -// slang-emit.h -#ifndef SLANG_EMIT_H_INCLUDED -#define SLANG_EMIT_H_INCLUDED - -#include "../core/slang-basic.h" - -#include "slang-compiler.h" - -namespace Slang -{ - class EntryPoint; - class ProgramLayout; - class TranslationUnitRequest; - - - - /// Emit source code for a single entry point. - /// - /// This function generates source code for the - /// entry point with index `entryPointIndex` - /// inside the program being compiled in `compileRequest`. - /// - /// The code is generated for the language specified - /// as `target` (e.g., HLSL or GLSL). - /// - /// The `targetRequest` gives further information about - /// the compilation target and its options. - /// - /// Note: it is possible that `target` and `targetRequest` - /// do not store the same target format. For example - /// `target` might be HLSL, while `targetRequest` is - /// a DXIL target. The split information here tells us - /// both the immediate target language (HLSL) as well - /// as the eventual destination format (DXIL) in case - /// we need to customize the output (e.g., we might - /// generate different HLSL output if we know it - /// will be used to generate SPIR-V). - /// - SlangResult emitEntryPointsSourceFromIR( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - CodeGenTarget target, - TargetRequest* targetRequest, - ExtensionTracker* extensionTracker, - String& outSource); -} -#endif diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 385b536dc..45b9a842f 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -1345,12 +1345,14 @@ struct IRSpecializationState }; LinkedIR linkIR( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - CodeGenTarget target, - TargetProgram* targetProgram) + CodeGenContext* codeGenContext) { - auto targetReq = targetProgram->getTargetReq(); + auto linkage = codeGenContext->getLinkage(); + auto program = codeGenContext->getProgram(); + auto session = codeGenContext->getSession(); + auto target = codeGenContext->getTargetFormat(); + auto targetProgram = codeGenContext->getTargetProgram(); + auto targetReq = codeGenContext->getTargetReq(); // TODO: We need to make sure that the program we are being asked // to compile has been "resolved" so that it has no outstanding @@ -1362,19 +1364,17 @@ LinkedIR linkIR( state->target = target; state->targetReq = targetReq; - auto program = compileRequest->getProgram(); auto sharedContext = state->getSharedContext(); initializeSharedSpecContext( sharedContext, - compileRequest->getSession(), + session, nullptr, target, targetReq); state->irModule = sharedContext->module; - auto linkage = compileRequest->getLinkage(); // We need to be able to look up IR definitions for any symbols in // modules that the program depends on (transitively). To @@ -1437,7 +1437,7 @@ LinkedIR linkIR( // List<IRFunc*> irEntryPoints; - for (auto entryPointIndex : entryPointIndices) + for (auto entryPointIndex : codeGenContext->getEntryPointIndices()) { auto entryPointMangledName = program->getEntryPointMangledName(entryPointIndex); auto nameOverride = program->getEntryPointNameOverride(entryPointIndex); diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h index 92a301c5a..6c81ae734 100644 --- a/source/slang/slang-ir-link.h +++ b/source/slang/slang-ir-link.h @@ -22,10 +22,7 @@ namespace Slang // target will be used. // LinkedIR linkIR( - BackEndCompileRequest* compileRequest, - const List<Int>& entryPointIndices, - CodeGenTarget target, - TargetProgram* targetProgram); + CodeGenContext* codeGenContext); // Replace any global constants in the IR module with their // definitions, if possible. diff --git a/source/slang/slang-ir-specialize-arrays.cpp b/source/slang/slang-ir-specialize-arrays.cpp index 2ed3da479..5b9a7b1c2 100644 --- a/source/slang/slang-ir-specialize-arrays.cpp +++ b/source/slang/slang-ir-specialize-arrays.cpp @@ -43,12 +43,11 @@ struct ArrayParameterSpecializationCondition : FunctionCallSpecializeCondition }; void specializeArrayParameters( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module) { ArrayParameterSpecializationCondition condition; - specializeFunctionCalls(compileRequest, targetRequest, module, &condition); + specializeFunctionCalls(codeGenContext, module, &condition); } } // namesapce Slang diff --git a/source/slang/slang-ir-specialize-arrays.h b/source/slang/slang-ir-specialize-arrays.h index 6373abb1d..1bbc2b783 100644 --- a/source/slang/slang-ir-specialize-arrays.h +++ b/source/slang/slang-ir-specialize-arrays.h @@ -3,8 +3,7 @@ namespace Slang { - class BackEndCompileRequest; - class TargetRequest; + struct CodeGenContext; struct IRModule; /// Specialize calls to functions that take parameters of @@ -19,7 +18,6 @@ namespace Slang /// This is an optimization for GL/VK backend since the downstream /// compiler doesn't seem to optimize such code well. void specializeArrayParameters( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, - IRModule* module); + CodeGenContext* codeGenContext, + IRModule* module); } diff --git a/source/slang/slang-ir-specialize-buffer-load-arg.cpp b/source/slang/slang-ir-specialize-buffer-load-arg.cpp index 353c6a104..891872582 100644 --- a/source/slang/slang-ir-specialize-buffer-load-arg.cpp +++ b/source/slang/slang-ir-specialize-buffer-load-arg.cpp @@ -85,12 +85,11 @@ struct FuncBufferLoadSpecializationCondition : FunctionCallSpecializeCondition }; void specializeFuncsForBufferLoadArgs( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codegenContext, IRModule* module) { FuncBufferLoadSpecializationCondition condition; - specializeFunctionCalls(compileRequest, targetRequest, module, &condition); + specializeFunctionCalls(codegenContext, module, &condition); } } diff --git a/source/slang/slang-ir-specialize-buffer-load-arg.h b/source/slang/slang-ir-specialize-buffer-load-arg.h index 9d79a870e..4a0f3bbc4 100644 --- a/source/slang/slang-ir-specialize-buffer-load-arg.h +++ b/source/slang/slang-ir-specialize-buffer-load-arg.h @@ -3,8 +3,7 @@ namespace Slang { -class BackEndCompileRequest; -class TargetRequest; +struct CodeGenContext; struct IRModule; @@ -38,7 +37,6 @@ struct IRModule; /// of the contents of `gParams`. /// void specializeFuncsForBufferLoadArgs( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, - IRModule* module); + CodeGenContext* codeGenContext, + IRModule* module); } diff --git a/source/slang/slang-ir-specialize-function-call.cpp b/source/slang/slang-ir-specialize-function-call.cpp index 1e63be890..12d89f70c 100644 --- a/source/slang/slang-ir-specialize-function-call.cpp +++ b/source/slang/slang-ir-specialize-function-call.cpp @@ -74,7 +74,7 @@ struct FunctionParameterSpecializationContext // the parameters that were passed to the top-level // `specializeFunctionParameters` function. // - BackEndCompileRequest* compileRequest; + CodeGenContext* codeGenContext; TargetRequest* targetRequest; IRModule* module; @@ -883,14 +883,13 @@ struct FunctionParameterSpecializationContext // and then defer to it for the real work. // bool specializeFunctionCalls( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module, FunctionCallSpecializeCondition* condition) { FunctionParameterSpecializationContext context; - context.compileRequest = compileRequest; - context.targetRequest = targetRequest; + context.codeGenContext = codeGenContext; + context.targetRequest = codeGenContext->getTargetReq(); context.module = module; context.condition = condition; diff --git a/source/slang/slang-ir-specialize-function-call.h b/source/slang/slang-ir-specialize-function-call.h index 4afb0526f..8fe113a98 100644 --- a/source/slang/slang-ir-specialize-function-call.h +++ b/source/slang/slang-ir-specialize-function-call.h @@ -3,11 +3,11 @@ namespace Slang { - class BackEndCompileRequest; - class TargetRequest; + struct CodeGenContext; struct IRInst; struct IRModule; struct IRParam; + class Module; class FunctionCallSpecializeCondition { @@ -28,8 +28,7 @@ namespace Slang /// global shader parameters directly). /// Returns true if any changes are made. bool specializeFunctionCalls( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module, FunctionCallSpecializeCondition* condition); } diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp index 01e1c396c..05a7c23de 100644 --- a/source/slang/slang-ir-specialize-resources.cpp +++ b/source/slang/slang-ir-specialize-resources.cpp @@ -85,17 +85,16 @@ struct ResourceParameterSpecializationCondition : FunctionCallSpecializeConditio }; bool specializeResourceParameters( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module) { bool result = false; ResourceParameterSpecializationCondition condition; - condition.targetRequest = targetRequest; + condition.targetRequest = codeGenContext->getTargetReq(); bool changed = true; while (changed) { - changed = specializeFunctionCalls(compileRequest, targetRequest, module, &condition); + changed = specializeFunctionCalls(codeGenContext, module, &condition); simplifyIR(module); result |= changed; } @@ -112,7 +111,7 @@ struct ResourceOutputSpecializationPass // via `return` or `out`/`inout` parmeters), and then specializes the // *call sites* for those functions based on the values that are output. - BackEndCompileRequest* compileRequest; + CodeGenContext* codeGenContext; TargetRequest* targetRequest; IRModule* module; @@ -1116,11 +1115,11 @@ struct ResourceOutputSpecializationPass }; bool specializeResourceOutputs( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module, List<IRFunc*>& unspecializableFuncs) { + auto targetRequest = codeGenContext->getTargetReq(); if(isD3DTarget(targetRequest) || isKhronosTarget(targetRequest)) {} else @@ -1136,7 +1135,7 @@ bool specializeResourceOutputs( } ResourceOutputSpecializationPass pass; - pass.compileRequest = compileRequest; + pass.codeGenContext = codeGenContext; pass.targetRequest = targetRequest; pass.module = module; pass.unspecializableFuncs = &unspecializableFuncs; @@ -1144,7 +1143,8 @@ bool specializeResourceOutputs( } bool specializeResourceUsage( - BackEndCompileRequest* compileRequest, TargetRequest* targetRequest, IRModule* irModule) + CodeGenContext* codeGenContext, + IRModule* irModule) { bool result = false; // We apply two kinds of specialization to clean up resource value usage: @@ -1173,8 +1173,8 @@ bool specializeResourceUsage( // pass down the target request along with the IR. // changed |= specializeResourceOutputs( - compileRequest, targetRequest, irModule, unspecializableFuncs); - changed |= specializeResourceParameters(compileRequest, targetRequest, irModule); + codeGenContext, irModule, unspecializableFuncs); + changed |= specializeResourceParameters(codeGenContext, irModule); // After specialization of function outputs, we may find that there // are cases where opaque-typed local variables can now be eliminated diff --git a/source/slang/slang-ir-specialize-resources.h b/source/slang/slang-ir-specialize-resources.h index 0f2fdc99e..ec831ac24 100644 --- a/source/slang/slang-ir-specialize-resources.h +++ b/source/slang/slang-ir-specialize-resources.h @@ -3,8 +3,7 @@ namespace Slang { - class BackEndCompileRequest; - class TargetRequest; + struct CodeGenContext; struct IRModule; struct IRType; @@ -19,18 +18,17 @@ namespace Slang /// global shader parameters directly). /// bool specializeResourceParameters( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, + CodeGenContext* codeGenContext, IRModule* module); bool specializeResourceOutputs( - BackEndCompileRequest* compileRequest, - TargetRequest* targetRequest, - IRModule* module); + CodeGenContext* codeGenContext, + IRModule* module); /// Combined iterative passes of `specializeResourceParameters` and `specializeResourceOutputs`. bool specializeResourceUsage( - BackEndCompileRequest* compileRequest, TargetRequest* targetRequest, IRModule* irModule); + CodeGenContext* codeGenContext, + IRModule* irModule); bool isIllegalGLSLParameterType(IRType* type); diff --git a/source/slang/slang-ir-validate.cpp b/source/slang/slang-ir-validate.cpp index e8da87187..46817e212 100644 --- a/source/slang/slang-ir-validate.cpp +++ b/source/slang/slang-ir-validate.cpp @@ -285,4 +285,15 @@ namespace Slang auto sink = compileRequest->getSink(); validateIRModule(module, sink); } + + void validateIRModuleIfEnabled( + CodeGenContext* codeGenContext, + IRModule* module) + { + if (!codeGenContext->shouldValidateIR()) + return; + + auto sink = codeGenContext->getSink(); + validateIRModule(module, sink); + } } diff --git a/source/slang/slang-ir-validate.h b/source/slang/slang-ir-validate.h index c9b0016f4..3e8e8dc92 100644 --- a/source/slang/slang-ir-validate.h +++ b/source/slang/slang-ir-validate.h @@ -3,6 +3,7 @@ namespace Slang { + struct CodeGenContext; class CompileRequestBase; class DiagnosticSink; struct IRModule; @@ -32,4 +33,8 @@ namespace Slang void validateIRModuleIfEnabled( CompileRequestBase* compileRequest, IRModule* module); + + void validateIRModuleIfEnabled( + CodeGenContext* codeGenContext, + IRModule* module); } diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 2d5e1aeea..982066a33 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -840,13 +840,12 @@ struct OptionsParser else if (argValue == "-dump-ir-ids") { requestImpl->getFrontEndReq()->m_irDumpOptions.flags |= IRDumpOptions::Flag::DumpDebugIds; - requestImpl->getBackEndReq()->m_irDumpOptions.flags |= IRDumpOptions::Flag::DumpDebugIds; } else if (argValue == "-dump-intermediate-prefix") { CommandLineArg prefix; SLANG_RETURN_ON_FAIL(reader.expectArg(prefix)); - requestImpl->getBackEndReq()->m_dumpIntermediatePrefix = prefix.value; + requestImpl->m_dumpIntermediatePrefix = prefix.value; } else if (argValue == "-output-includes") { @@ -855,7 +854,6 @@ struct OptionsParser else if(argValue == "-dump-ir" ) { requestImpl->getFrontEndReq()->shouldDumpIR = true; - requestImpl->getBackEndReq()->shouldDumpIR = true; } else if (argValue == "-E" || argValue == "-output-preprocessor") { @@ -993,11 +991,11 @@ struct OptionsParser } else if (argValue == "-disable-specialization") { - requestImpl->getBackEndReq()->disableSpecialization = true; + requestImpl->disableSpecialization = true; } else if (argValue == "-disable-dynamic-dispatch") { - requestImpl->getBackEndReq()->disableDynamicDispatch = true; + requestImpl->disableDynamicDispatch = true; } else if (argValue == "-verbose-paths") { @@ -1010,7 +1008,6 @@ struct OptionsParser else if(argValue == "-validate-ir" ) { requestImpl->getFrontEndReq()->shouldValidateIR = true; - requestImpl->getBackEndReq()->shouldValidateIR = true; } else if(argValue == "-skip-codegen" ) { @@ -1365,7 +1362,7 @@ struct OptionsParser } else if( argValue == "-default-image-format-unknown" ) { - requestImpl->getBackEndReq()->useUnknownImageFormatAsDefault = true; + requestImpl->useUnknownImageFormatAsDefault = true; } else if (argValue == "-obfuscate") { diff --git a/source/slang/slang-repro.cpp b/source/slang/slang-repro.cpp index a5591e68b..ad275ee7b 100644 --- a/source/slang/slang-repro.cpp +++ b/source/slang/slang-repro.cpp @@ -362,7 +362,7 @@ static String _scrubName(const String& in) RequestState* dst = base[requestState]; dst->compileFlags = request->getFrontEndReq()->compileFlags; - dst->shouldDumpIntermediates = request->getBackEndReq()->shouldDumpIntermediates; + dst->shouldDumpIntermediates = request->shouldDumpIntermediates; dst->debugInfoLevel = linkage->debugInfoLevel; dst->optimizationLevel = linkage->optimizationLevel; @@ -370,7 +370,7 @@ static String _scrubName(const String& in) dst->passThroughMode = request->m_passThrough; - dst->useUnknownImageFormatAsDefault = request->getBackEndReq()->useUnknownImageFormatAsDefault; + dst->useUnknownImageFormatAsDefault = request->useUnknownImageFormatAsDefault; dst->obfuscateCode = linkage->m_obfuscateCode; dst->defaultMatrixLayoutMode = linkage->defaultMatrixLayoutMode; @@ -909,7 +909,7 @@ struct LoadContext externalRequest->setOutputContainerFormat(SlangContainerFormat(requestState->containerFormat)); externalRequest->setPassThrough(SlangPassThrough(request->m_passThrough)); - request->getBackEndReq()->useUnknownImageFormatAsDefault = requestState->useUnknownImageFormatAsDefault; + request->useUnknownImageFormatAsDefault = requestState->useUnknownImageFormatAsDefault; linkage->m_obfuscateCode = requestState->obfuscateCode; linkage->setMatrixLayoutMode(requestState->defaultMatrixLayoutMode); diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index e83ab2da3..2d992ef36 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2202,17 +2202,6 @@ SlangResult FrontEndCompileRequest::executeActionsInner() return SLANG_OK; } -BackEndCompileRequest::BackEndCompileRequest( - Linkage* linkage, - DiagnosticSink* sink, - ComponentType* program) - : CompileRequestBase(linkage, sink) - , m_program(program) - , m_dumpIntermediatePrefix("slang-dump-") - -{ -} - EndToEndCompileRequest::EndToEndCompileRequest( Session* session) : m_session(session) @@ -2265,8 +2254,6 @@ void EndToEndCompileRequest::init() } m_frontEndReq = new FrontEndCompileRequest(getLinkage(), m_writers, getSink()); - - m_backEndReq = new BackEndCompileRequest(getLinkage(), getSink()); } SlangResult EndToEndCompileRequest::executeActionsInner() @@ -2382,8 +2369,7 @@ SlangResult EndToEndCompileRequest::executeActionsInner() } // Generate output code, in whatever format was requested - getBackEndReq()->setProgram(getSpecializedGlobalAndEntryPointsComponentType()); - generateOutput(this); + generateOutput(); if (getSink()->getErrorCount() != 0) return SLANG_FAIL; @@ -4129,7 +4115,7 @@ void EndToEndCompileRequest::setCompileFlags(SlangCompileFlags flags) void EndToEndCompileRequest::setDumpIntermediates(int enable) { - getBackEndReq()->shouldDumpIntermediates = (enable != 0); + shouldDumpIntermediates = (enable != 0); // Change all existing targets to use the new setting. auto linkage = getLinkage(); @@ -4141,7 +4127,7 @@ void EndToEndCompileRequest::setDumpIntermediates(int enable) void EndToEndCompileRequest::setDumpIntermediatePrefix(const char* prefix) { - getBackEndReq()->m_dumpIntermediatePrefix = prefix; + m_dumpIntermediatePrefix = prefix; } void EndToEndCompileRequest::setLineDirectiveMode(SlangLineDirectiveMode mode) |
