diff options
| -rw-r--r-- | source/slang/slang-compiler.cpp | 560 | ||||
| -rw-r--r-- | source/slang/slang-compiler.h | 23 | ||||
| -rw-r--r-- | source/slang/slang-dxc-support.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-emit.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-link.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-ir-link.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 8 |
8 files changed, 447 insertions, 195 deletions
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index fe0f7d69c..ca7e5fb83 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -508,29 +508,42 @@ namespace Slang SLANG_OK; } - // - - /// If there is a pass-through compile going on, find the translation unit for the given entry point. - TranslationUnitRequest* findPassThroughTranslationUnit( - EndToEndCompileRequest* endToEndReq, - Int entryPointIndex) - { - // If there isn't an end-to-end compile going on, + bool isPassThroughEnabled( + EndToEndCompileRequest* endToEndReq) + { // If there isn't an end-to-end compile going on, // there can be no pass-through. // - if(!endToEndReq) return nullptr; + if (!endToEndReq) return false; // And if pass-through isn't set, we don't need // access to the translation unit. // - if(endToEndReq->passThrough == PassThroughMode::None) return nullptr; - + if(endToEndReq->passThrough == PassThroughMode::None) return false; + return true; + } + /// 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( + EndToEndCompileRequest* endToEndReq, + Int entryPointIndex) + { + SLANG_ASSERT(endToEndReq); + SLANG_ASSERT(endToEndReq->passThrough != PassThroughMode::None); auto frontEndReq = endToEndReq->getFrontEndReq(); auto entryPointReq = frontEndReq->getEntryPointReq(entryPointIndex); auto translationUnit = entryPointReq->getTranslationUnit(); return translationUnit; } + TranslationUnitRequest* findPassThroughTranslationUnit( + EndToEndCompileRequest* endToEndReq, + Int entryPointIndex) + { + if (isPassThroughEnabled(endToEndReq)) + return getPassThroughTranslationUnit(endToEndReq, entryPointIndex); + return nullptr; + } + static void _appendEscapedPath(const UnownedStringSlice& path, StringBuilder& outBuilder) { for (auto c : path) @@ -552,67 +565,86 @@ namespace Slang outCodeBuilder << fileContent << "\n"; } - SlangResult emitEntryPointSource( + SlangResult emitEntryPointsSource( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, TargetRequest* targetReq, CodeGenTarget target, EndToEndCompileRequest* endToEndReq, - SourceResult& outSource) + SourceResult& outSource) { outSource.reset(); - if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex)) + if(isPassThroughEnabled(endToEndReq)) { - // Generate a string that includes the content of - // the source file(s), along with a line directive - // to ensure that we get reasonable messages - // from the downstream compiler when in pass-through - // mode. - - StringBuilder codeBuilder; - if (target == CodeGenTarget::GLSL) + for (auto entryPointIndex = entryPointIndices.begin(); entryPointIndex != entryPointIndices.end(); entryPointIndex++) { - // Special case GLSL - int translationUnitCounter = 0; - for (auto sourceFile : translationUnit->getSourceFiles()) + auto translationUnit = getPassThroughTranslationUnit(endToEndReq, *entryPointIndex); + SLANG_ASSERT(translationUnit); + // Generate a string that includes the content of + // the source file(s), along with a line directive + // to ensure that we get reasonable messages + // from the downstream compiler when in pass-through + // mode. + + StringBuilder codeBuilder; + if (target == CodeGenTarget::GLSL) { - int translationUnitIndex = translationUnitCounter++; - - // We want to output `#line` directives, but we need - // to skip this for the first file, since otherwise - // some GLSL implementations will get tripped up by - // not having the `#version` directive be the first - // thing in the file. - if (translationUnitIndex != 0) + // Special case GLSL + int translationUnitCounter = 0; + for (auto sourceFile : translationUnit->getSourceFiles()) { - codeBuilder << "#line 1 " << translationUnitIndex << "\n"; + int translationUnitIndex = translationUnitCounter++; + + // We want to output `#line` directives, but we need + // to skip this for the first file, since otherwise + // some GLSL implementations will get tripped up by + // not having the `#version` directive be the first + // thing in the file. + if (translationUnitIndex != 0) + { + codeBuilder << "#line 1 " << translationUnitIndex << "\n"; + } + codeBuilder << sourceFile->getContent() << "\n"; } - codeBuilder << sourceFile->getContent() << "\n"; } - } - else - { - for(auto sourceFile : translationUnit->getSourceFiles()) + else { - _appendCodeWithPath(sourceFile->getPathInfo().foundPath.getUnownedSlice(), sourceFile->getContent(), codeBuilder); + for (auto sourceFile : translationUnit->getSourceFiles()) + { + _appendCodeWithPath(sourceFile->getPathInfo().foundPath.getUnownedSlice(), sourceFile->getContent(), codeBuilder); + } } - } - outSource.source = codeBuilder.ProduceString(); + outSource.source = codeBuilder.ProduceString(); + } return SLANG_OK; } else { return emitEntryPointSourceFromIR( compileRequest, - entryPointIndex, + entryPointIndices, target, targetReq, outSource); } } + SlangResult emitEntryPointSource( + BackEndCompileRequest* compileRequest, + Int entryPointIndex, + TargetRequest* targetReq, + CodeGenTarget target, + EndToEndCompileRequest* endToEndReq, + SourceResult& outSource) + { + List<Int> entryPointIndices; + entryPointIndices.add(entryPointIndex); + return emitEntryPointsSource(compileRequest, entryPointIndices, targetReq, + target, endToEndReq, outSource); + } + String GetHLSLProfileName(Profile profile) { switch( profile.getFamily() ) @@ -745,13 +777,17 @@ namespace Slang } } - String calcSourcePathForEntryPoint( + String calcSourcePathForEntryPoints( EndToEndCompileRequest* endToEndReq, - UInt entryPointIndex) + List<Int> entryPointIndices) { + String failureMode = "slang-generated"; + if (entryPointIndices.getCount() != 1) + return failureMode; + auto entryPointIndex = entryPointIndices[0]; auto translationUnitRequest = findPassThroughTranslationUnit(endToEndReq, entryPointIndex); - if(!translationUnitRequest) - return "slang-generated"; + if (!translationUnitRequest) + return failureMode; const auto& sourceFiles = translationUnitRequest->getSourceFiles(); @@ -776,6 +812,49 @@ namespace Slang } } + String calcSourcePathForEntryPoint( + EndToEndCompileRequest* endToEndReq, + Int entryPointIndex) + { + List<Int> entryPointIndices; + entryPointIndices.add(entryPointIndex); + return calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); + } + + struct EntryPointAndIndex { + EntryPoint* entryPoint; + Int index; + EntryPointAndIndex(); + EntryPointAndIndex(EntryPoint* entryPoint, Int index); + }; + + EntryPointAndIndex::EntryPointAndIndex() + { + entryPoint = NULL; + index = -1; + } + + EntryPointAndIndex::EntryPointAndIndex(EntryPoint* ep, Int i) + { + entryPoint = ep; + index = i; + } + + // Helper function for recovering the entry point code indices from a list of entry points + List<Int> getEntryPointIndices(List<EntryPointAndIndex> const& entryPoints) { + List<Int> result; + for (auto entryPoint = entryPoints.begin(); entryPoint != entryPoints.end(); entryPoint++) { + result.add(entryPoint->index); + } + return result; + } + + // Helper function for cases where we can assume a single entry point + EntryPointAndIndex assertSingleEntryPoint(List<EntryPointAndIndex> const& entryPoints) { + SLANG_ASSERT(entryPoints.getCount() == 1); + return *entryPoints.begin(); + } + #if SLANG_ENABLE_DXBC_SUPPORT static UnownedStringSlice _getSlice(ID3DBlob* blob) @@ -879,8 +958,7 @@ namespace Slang SlangResult emitDXBytecodeForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - Int entryPointIndex, + EntryPointAndIndex entryPoint, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq, List<uint8_t>& byteCodeOut) @@ -897,12 +975,12 @@ namespace Slang } SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(compileRequest, entryPointIndex, targetReq, CodeGenTarget::HLSL, endToEndReq, source)); + SLANG_RETURN_ON_FAIL(emitEntryPointSource(compileRequest, entryPoint.index, targetReq, CodeGenTarget::HLSL, endToEndReq, source)); const auto& hlslCode = source.source; maybeDumpIntermediate(compileRequest, hlslCode.getBuffer(), CodeGenTarget::HLSL); - auto profile = getEffectiveProfile(entryPoint, targetReq); + auto profile = getEffectiveProfile(entryPoint.entryPoint, targetReq); auto linkage = compileRequest->getLinkage(); @@ -922,7 +1000,7 @@ namespace Slang FxcIncludeHandler fxcIncludeHandlerStorage; FxcIncludeHandler* fxcIncludeHandler = nullptr; - if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex)) + if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPoint.index)) { for( auto& define : translationUnit->compileRequest->preprocessorDefinitions ) { @@ -990,13 +1068,13 @@ namespace Slang { case DebugInfoLevel::None: break; - + default: flags |= D3DCOMPILE_DEBUG; break; } - const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); + const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPoint.index); ComPtr<ID3DBlob> codeBlob; ComPtr<ID3DBlob> diagnosticsBlob; @@ -1006,7 +1084,7 @@ namespace Slang sourcePath.getBuffer(), dxMacros, fxcIncludeHandler, - getText(entryPoint->getName()).begin(), + getText(entryPoint.entryPoint->getName()).begin(), GetHLSLProfileName(profile).getBuffer(), flags, 0, // unused: effect flags @@ -1066,8 +1144,7 @@ namespace Slang SlangResult emitDXBytecodeAssemblyForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - Int entryPointIndex, + EntryPointAndIndex entryPoint, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq, String& assemOut) @@ -1077,7 +1154,6 @@ namespace Slang SLANG_RETURN_ON_FAIL(emitDXBytecodeForEntryPoint( compileRequest, entryPoint, - entryPointIndex, targetReq, endToEndReq, dxbc)); @@ -1198,9 +1274,9 @@ SlangResult dissassembleDXILUsingDXC( return SLANG_OK; } - SlangResult emitWithDownstreamForEntryPoint( + SlangResult emitWithDownstreamForEntryPoints( BackEndCompileRequest* slangRequest, - Int entryPointIndex, + List<Int> entryPointIndices, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq, RefPtr<DownstreamCompileResult>& outResult) @@ -1211,7 +1287,7 @@ SlangResult dissassembleDXILUsingDXC( auto session = slangRequest->getSession(); - const String originalSourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); + const String originalSourcePath = calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); CodeGenTarget sourceTarget = CodeGenTarget::None; SourceLanguage sourceLanguage = SourceLanguage::Unknown; @@ -1270,8 +1346,11 @@ SlangResult dissassembleDXILUsingDXC( /* 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 (auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex)) + // Note also that we require there to be only one entry point to use a translation unit + // TODO(DG): Review this assertion later + if (isPassThroughEnabled(endToEndReq) && entryPointIndices.getCount() == 1) { + auto translationUnit = getPassThroughTranslationUnit(endToEndReq, entryPointIndices[0]); // If it's pass through we accumulate the preprocessor definitions. for (auto& define : translationUnit->compileRequest->preprocessorDefinitions) { @@ -1333,7 +1412,7 @@ SlangResult dissassembleDXILUsingDXC( else { SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(slangRequest, entryPointIndex, targetReq, sourceTarget, endToEndReq, source)); + SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, entryPointIndices, targetReq, sourceTarget, endToEndReq, source)); options.sourceContents = source.source; } @@ -1341,7 +1420,7 @@ SlangResult dissassembleDXILUsingDXC( else { SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(slangRequest, entryPointIndex, targetReq, sourceTarget, endToEndReq, source)); + SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, entryPointIndices, targetReq, sourceTarget, endToEndReq, source)); // Look for the version if (auto cudaTracker = as<CUDAExtensionTracker>(source.extensionTracker)) @@ -1557,25 +1636,24 @@ SlangResult dissassembleDXILUsingDXC( return SLANG_OK; } - SlangResult emitSPIRVForEntryPointDirectly( + SlangResult emitSPIRVForEntryPointsDirectly( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, TargetRequest* targetReq, List<uint8_t>& spirvOut); - SlangResult emitSPIRVForEntryPointViaGLSL( - BackEndCompileRequest* slangRequest, - EntryPoint* entryPoint, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq, - List<uint8_t>& spirvOut) + SlangResult emitSPIRVForEntryPointsViaGLSL( + BackEndCompileRequest* slangRequest, + List<EntryPointAndIndex> const& entryPoints, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq, + List<uint8_t>& spirvOut) { spirvOut.clear(); SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(slangRequest, entryPointIndex, targetReq, CodeGenTarget::GLSL, endToEndReq, source)); + SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, getEntryPointIndices(entryPoints), targetReq, CodeGenTarget::GLSL, endToEndReq, source)); const auto& rawGLSL = source.source; @@ -1586,7 +1664,9 @@ SlangResult dissassembleDXILUsingDXC( ((List<uint8_t>*)userData)->addRange((uint8_t*)data, size); }; - const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); + SLANG_ASSERT(entryPoints.getCount() == 1); + auto entryPoint = entryPoints[0]; + const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPoint.index); glslang_CompileRequest_1_1 request; memset(&request, 0, sizeof(request)); @@ -1594,10 +1674,10 @@ SlangResult dissassembleDXILUsingDXC( request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV; request.sourcePath = sourcePath.getBuffer(); - request.slangStage = (SlangStage)entryPoint->getStage(); + request.slangStage = (SlangStage)entryPoint.entryPoint->getStage(); - request.inputBegin = rawGLSL.begin(); - request.inputEnd = rawGLSL.end(); + request.inputBegin = rawGLSL.begin(); + request.inputEnd = rawGLSL.end(); if (GLSLExtensionTracker* tracker = as<GLSLExtensionTracker>(source.extensionTracker.Ptr())) { @@ -1616,47 +1696,43 @@ SlangResult dissassembleDXILUsingDXC( return SLANG_OK; } - SlangResult emitSPIRVForEntryPoint( - BackEndCompileRequest* slangRequest, - EntryPoint* entryPoint, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq, - List<uint8_t>& spirvOut) + SlangResult emitSPIRVForEntryPoints( + BackEndCompileRequest* slangRequest, + List<EntryPointAndIndex> const& entryPoints, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq, + List<uint8_t>& spirvOut) { if( slangRequest->shouldEmitSPIRVDirectly ) { - return emitSPIRVForEntryPointDirectly( + return emitSPIRVForEntryPointsDirectly( slangRequest, - entryPointIndex, + getEntryPointIndices(entryPoints), targetReq, spirvOut); } else { - return emitSPIRVForEntryPointViaGLSL( + return emitSPIRVForEntryPointsViaGLSL( slangRequest, - entryPoint, - entryPointIndex, + entryPoints, targetReq, endToEndReq, spirvOut); } } - SlangResult emitSPIRVAssemblyForEntryPoint( - BackEndCompileRequest* slangRequest, - EntryPoint* entryPoint, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq, - String& assemblyOut) + SlangResult emitSPIRVAssemblyForEntryPoints( + BackEndCompileRequest* slangRequest, + List<EntryPointAndIndex> const& entryPoints, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq, + String& assemblyOut) { List<uint8_t> spirv; - SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPoint( + SLANG_RETURN_ON_FAIL(emitSPIRVForEntryPoints( slangRequest, - entryPoint, - entryPointIndex, + entryPoints, targetReq, endToEndReq, spirv)); @@ -1668,13 +1744,12 @@ SlangResult dissassembleDXILUsingDXC( } #endif - // Do emit logic for a single entry point - CompileResult emitEntryPoint( - BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq) + // Do emit logic for a zero or more entry points + CompileResult emitEntryPoints( + BackEndCompileRequest* compileRequest, + List<EntryPointAndIndex> const& entryPoints, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq) { CompileResult result; @@ -1689,9 +1764,9 @@ SlangResult dissassembleDXILUsingDXC( { RefPtr<DownstreamCompileResult> downstreamResult; - if (SLANG_SUCCEEDED(emitWithDownstreamForEntryPoint( + if (SLANG_SUCCEEDED(emitWithDownstreamForEntryPoints( compileRequest, - entryPointIndex, + getEntryPointIndices(entryPoints), targetReq, endToEndReq, downstreamResult))) @@ -1709,7 +1784,8 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::CSource: { SourceResult source; - if (SLANG_FAILED(emitEntryPointSource(compileRequest, entryPointIndex, targetReq, target, endToEndReq, source))) + if (SLANG_FAILED(emitEntryPointsSource(compileRequest, getEntryPointIndices(entryPoints), + targetReq, target, endToEndReq, source))) { return result; } @@ -1723,11 +1799,11 @@ SlangResult dissassembleDXILUsingDXC( #if SLANG_ENABLE_DXBC_SUPPORT case CodeGenTarget::DXBytecode: { + // Assert only one entry point case -- move out of this function List<uint8_t> code; if (SLANG_SUCCEEDED(emitDXBytecodeForEntryPoint( compileRequest, - entryPoint, - entryPointIndex, + assertSingleEntryPoint(entryPoints), targetReq, endToEndReq, code))) @@ -1741,11 +1817,11 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::DXBytecodeAssembly: { + // Assert only one entry point case String code; if (SLANG_SUCCEEDED(emitDXBytecodeAssemblyForEntryPoint( compileRequest, - entryPoint, - entryPointIndex, + assertSingleEntryPoint(entryPoints), targetReq, endToEndReq, code))) @@ -1761,10 +1837,11 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::DXIL: { List<uint8_t> code; + EntryPointAndIndex entryPoint = assertSingleEntryPoint(entryPoints); if (SLANG_SUCCEEDED(emitDXILForEntryPointUsingDXC( compileRequest, - entryPoint, - entryPointIndex, + entryPoint.entryPoint, + entryPoint.index, targetReq, endToEndReq, code))) @@ -1778,19 +1855,20 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::DXILAssembly: { List<uint8_t> code; + EntryPointAndIndex entryPoint = assertSingleEntryPoint(entryPoints); if (SLANG_SUCCEEDED(emitDXILForEntryPointUsingDXC( compileRequest, - entryPoint, - entryPointIndex, + entryPoint.entryPoint, + entryPoint.index, targetReq, endToEndReq, code))) { - String assembly; + String assembly; dissassembleDXILUsingDXC( compileRequest, code.getBuffer(), - code.getCount(), + code.getCount(), assembly); maybeDumpIntermediate(compileRequest, assembly.getBuffer(), target); @@ -1803,10 +1881,9 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::SPIRV: { List<uint8_t> code; - if (SLANG_SUCCEEDED(emitSPIRVForEntryPoint( + if (SLANG_SUCCEEDED(emitSPIRVForEntryPoints( compileRequest, - entryPoint, - entryPointIndex, + entryPoints, targetReq, endToEndReq, code))) @@ -1820,10 +1897,9 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::SPIRVAssembly: { String code; - if (SLANG_SUCCEEDED(emitSPIRVAssemblyForEntryPoint( + if (SLANG_SUCCEEDED(emitSPIRVAssemblyForEntryPoints( compileRequest, - entryPoint, - entryPointIndex, + entryPoints, targetReq, endToEndReq, code))) @@ -1838,7 +1914,7 @@ SlangResult dissassembleDXILUsingDXC( // The user requested no output break; - // Note(tfoley): We currently hit this case when compiling the stdlib + // Note(tfoley): We currently hit this case when compiling the stdlib case CodeGenTarget::Unknown: break; @@ -1850,6 +1926,18 @@ SlangResult dissassembleDXILUsingDXC( return result; } + // Do emit logic for a single entry point + CompileResult emitEntryPoint( + BackEndCompileRequest* compileRequest, + EntryPointAndIndex entryPoint, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq) + { + List<EntryPointAndIndex> entryPoints; + entryPoints.add(entryPoint); + return emitEntryPoints(compileRequest, entryPoints, targetReq, endToEndReq); + } + enum class OutputFileKind { Text, @@ -1913,14 +2001,11 @@ SlangResult dissassembleDXILUsingDXC( fclose(file); } - static void writeEntryPointResultToFile( - BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - String const& outputPath, - CompileResult const& result) + static void writeCompileResultToFile( + BackEndCompileRequest* compileRequest, + String const& outputPath, + CompileResult const& result) { - SLANG_UNUSED(entryPoint); - switch (result.format) { case ResultFormat::Text: @@ -1953,6 +2038,16 @@ SlangResult dissassembleDXILUsingDXC( } + 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) @@ -1960,14 +2055,11 @@ SlangResult dissassembleDXILUsingDXC( writer->write(text.getBuffer(), text.getLength()); } - static void writeEntryPointResultToStandardOutput( - EndToEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - TargetRequest* targetReq, - CompileResult const& result) + static void writeCompileRequestToStandardOutput( + EndToEndCompileRequest* compileRequest, + TargetRequest* targetReq, + CompileResult const& result) { - SLANG_UNUSED(entryPoint); - ISlangWriter* writer = compileRequest->getWriter(WriterChannel::StdOutput); auto backEndReq = compileRequest->getBackEndReq(); @@ -2007,7 +2099,7 @@ SlangResult dissassembleDXILUsingDXC( #if SLANG_ENABLE_DXIL_SUPPORT case CodeGenTarget::DXIL: { - String assembly; + String assembly; dissassembleDXILUsingDXC(backEndReq, blobData, blobSize, assembly); writeOutputToConsole(writer, assembly); } @@ -2035,22 +2127,22 @@ SlangResult dissassembleDXILUsingDXC( default: SLANG_UNEXPECTED("unhandled output format"); return; - } - } - else - { - // Redirecting stdout to a file, so do the usual thing - writer->setMode(SLANG_WRITER_MODE_BINARY); - - writeOutputFile( - backEndReq, - writer, - "stdout", - blobData, - blobSize); + } } + else + { + // Redirecting stdout to a file, so do the usual thing + writer->setMode(SLANG_WRITER_MODE_BINARY); + + writeOutputFile( + backEndReq, + writer, + "stdout", + blobData, + blobSize); } - break; + } + break; default: SLANG_UNEXPECTED("unhandled output format"); @@ -2059,17 +2151,59 @@ SlangResult dissassembleDXILUsingDXC( } + static void writeEntryPointResultToStandardOutput( + EndToEndCompileRequest* compileRequest, + EntryPoint* entryPoint, + TargetRequest* targetReq, + CompileResult const& result) + { + SLANG_UNUSED(entryPoint); + writeCompileRequestToStandardOutput(compileRequest, targetReq, result); + } + + static void writeWholeProgramResult( + EndToEndCompileRequest* compileRequest, + TargetRequest* targetReq) + { + auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); + auto targetProgram = program->getTargetProgram(targetReq); + auto backEndReq = compileRequest->getBackEndReq(); + + auto& result = targetProgram->getExistingWholeProgramResult(); + + // Skip the case with no output + if (result.format == ResultFormat::None) + return; + + // 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->targetInfos.TryGetValue(targetReq, targetInfo)) + { + String outputPath = targetInfo->wholeTargetOutputPath; + if (outputPath != "") + { + writeCompileResultToFile(backEndReq, outputPath, result); + return; + } + } + + writeCompileRequestToStandardOutput(compileRequest, targetReq, result); + } + static void writeEntryPointResult( EndToEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - TargetRequest* targetReq, - Int entryPointIndex) + EntryPointAndIndex entryPoint, + TargetRequest* targetReq) { auto program = compileRequest->getSpecializedGlobalAndEntryPointsComponentType(); auto targetProgram = program->getTargetProgram(targetReq); auto backEndReq = compileRequest->getBackEndReq(); - auto& result = targetProgram->getExistingEntryPointResult(entryPointIndex); + auto& result = targetProgram->getExistingEntryPointResult(entryPoint.index); // Skip the case with no output if (result.format == ResultFormat::None) @@ -2084,14 +2218,46 @@ SlangResult dissassembleDXILUsingDXC( if(compileRequest->targetInfos.TryGetValue(targetReq, targetInfo)) { String outputPath; - if(targetInfo->entryPointOutputPaths.TryGetValue(entryPointIndex, outputPath)) + if(targetInfo->entryPointOutputPaths.TryGetValue(entryPoint.index, outputPath)) { - writeEntryPointResultToFile(backEndReq, entryPoint, outputPath, result); + writeEntryPointResultToFile(backEndReq, entryPoint.entryPoint, outputPath, result); return; } } - writeEntryPointResultToStandardOutput(compileRequest, entryPoint, targetReq, result); + writeEntryPointResultToStandardOutput(compileRequest, entryPoint.entryPoint, targetReq, result); + } + + CompileResult& TargetProgram::_createWholeProgramResult( + List<Int> entryPointIndices, + BackEndCompileRequest* backEndRequest, + EndToEndCompileRequest* endToEndRequest) + { + List<EntryPointAndIndex> entryPoints; + for (auto entryPointIndex = entryPointIndices.begin(); entryPointIndex != entryPointIndices.end(); entryPointIndex++) { + if (*entryPointIndex >= m_entryPointResults.getCount()) + m_entryPointResults.setCount(*entryPointIndex + 1); + + // It is possible that entry points goot added to the `Program` + // *after* we created this `TargetProgram`, so there might be + // a request for an entry point that we didn't allocate space for. + // + // TODO: Change the construction logic so that a `Program` is + // constructed all at once rather than incrementally, to avoid + // this problem. + // + auto entryPoint = m_program->getEntryPoint(*entryPointIndex); + entryPoints.add(EntryPointAndIndex(entryPoint, *entryPointIndex)); + } + auto& result = m_wholeProgramResult; + result = emitEntryPoints( + backEndRequest, + entryPoints, + m_targetReq, + endToEndRequest); + + return result; + } CompileResult& TargetProgram::_createEntryPointResult( @@ -2115,8 +2281,7 @@ SlangResult dissassembleDXILUsingDXC( auto& result = m_entryPointResults[entryPointIndex]; result = emitEntryPoint( backEndRequest, - entryPoint, - entryPointIndex, + EntryPointAndIndex(entryPoint, entryPointIndex), m_targetReq, endToEndRequest); @@ -2124,6 +2289,34 @@ SlangResult dissassembleDXILUsingDXC( } + CompileResult& TargetProgram::getOrCreateWholeProgramResult( + List<Int> entryPointIndices, + DiagnosticSink* sink) + { + auto& result = m_wholeProgramResult; + if (result.format != ResultFormat::None) + return result; + + // If we haven't yet computed a layout for this target + // program, we need to make sure that is done before + // code generation. + // + if (!getOrCreateIRModuleForLayout(sink)) + { + return result; + } + + RefPtr<BackEndCompileRequest> backEndRequest = new BackEndCompileRequest( + m_program->getLinkage(), + sink, + m_program); + + return _createWholeProgramResult( + entryPointIndices, + backEndRequest, + nullptr); + } + CompileResult& TargetProgram::getOrCreateEntryPointResult( Int entryPointIndex, DiagnosticSink* sink) @@ -2166,13 +2359,23 @@ SlangResult dissassembleDXILUsingDXC( // Generate target code any entry points that // have been requested for compilation. auto entryPointCount = program->getEntryPointCount(); - for(Index ii = 0; ii < entryPointCount; ++ii) + if (targetReq->isWholeProgramRequest) { - targetProgram->_createEntryPointResult( - ii, + targetProgram->_createWholeProgramResult( + List<Int>(), compileReq, endToEndReq); } + else + { + for (Index ii = 0; ii < entryPointCount; ++ii) + { + targetProgram->_createEntryPointResult( + ii, + compileReq, + endToEndReq); + } + } } @@ -2377,13 +2580,19 @@ SlangResult dissassembleDXILUsingDXC( for (auto targetReq : linkage->targets) { Index entryPointCount = program->getEntryPointCount(); - for (Index ee = 0; ee < entryPointCount; ++ee) - { - writeEntryPointResult( + if (targetReq->isWholeProgramRequest) { + writeWholeProgramResult( compileRequest, - program->getEntryPoint(ee), - targetReq, - ee); + targetReq); + } + else { + for (Index ee = 0; ee < entryPointCount; ++ee) + { + writeEntryPointResult( + compileRequest, + EntryPointAndIndex(program->getEntryPoint(ee), ee), + targetReq); + } } } @@ -2563,5 +2772,4 @@ SlangResult dissassembleDXILUsingDXC( maybeDumpIntermediate(compileRequest, text, strlen(text), target); } - } diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index e4b537e19..72c40a497 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1129,6 +1129,7 @@ namespace Slang SlangTargetFlags targetFlags = 0; Slang::Profile targetProfile = Slang::Profile(); FloatingPointMode floatingPointMode = FloatingPointMode::Default; + bool isWholeProgramRequest = false; Linkage* getLinkage() { return linkage; } CodeGenTarget getTarget() { return target; } @@ -1681,7 +1682,13 @@ namespace Slang /// code generation to the given `sink`. /// CompileResult& getOrCreateEntryPointResult(Int entryPointIndex, DiagnosticSink* sink); + CompileResult& getOrCreateWholeProgramResult(List<Int> entryPointIndices, DiagnosticSink* sink); + + CompileResult& getExistingWholeProgramResult() + { + return m_wholeProgramResult; + } /// Get the compiled code for an entry point on the target. /// /// This routine assumes that `getOrCreateEntryPointResult` @@ -1692,7 +1699,10 @@ namespace Slang return m_entryPointResults[entryPointIndex]; } - + CompileResult& _createWholeProgramResult( + List<Int> entryPointIndices, + BackEndCompileRequest* backEndRequest, + EndToEndCompileRequest* endToEndRequest); /// Internal helper for `getOrCreateEntryPointResult`. /// /// This is used so that command-line and API-based @@ -1727,6 +1737,7 @@ namespace Slang // Generated compile results for each entry point // in the parent `Program` (indexing matches // the order they are given in the `Program`) + CompileResult m_wholeProgramResult; List<CompileResult> m_entryPointResults; RefPtr<IRModule> m_irModuleForLayout; @@ -1839,6 +1850,7 @@ namespace Slang // An empty string indices no output desired for // the given entry point. Dictionary<Int, String> entryPointOutputPaths; + String wholeTargetOutputPath; }; Dictionary<TargetRequest*, RefPtr<TargetInfo>> targetInfos; @@ -1944,7 +1956,10 @@ namespace Slang @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, UInt entryPointIndex); + // TODO(DG): Note to reviewer; this was changed from UInt to List<Int> -- let me know if that's a problem + // and I can work out the appropriate casts + String calcSourcePathForEntryPoint(EndToEndCompileRequest* endToEndReq, Int entryPointIndex); + String calcSourcePathForEntryPoints(EndToEndCompileRequest* endToEndReq, List<Int> entryPointIndices); struct SourceResult { @@ -1961,9 +1976,9 @@ namespace Slang /* Emits entry point source taking into account if a pass-through or not. Uses 'target' to determine the target (not targetReq) */ - SlangResult emitEntryPointSource( + SlangResult emitEntryPointsSource( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, TargetRequest* targetReq, CodeGenTarget target, EndToEndCompileRequest* endToEndReq, diff --git a/source/slang/slang-dxc-support.cpp b/source/slang/slang-dxc-support.cpp index ffcc405c8..4fdb55e29 100644 --- a/source/slang/slang-dxc-support.cpp +++ b/source/slang/slang-dxc-support.cpp @@ -82,7 +82,10 @@ namespace Slang // Now let's go ahead and generate HLSL for the entry // point, since we'll need that to feed into dxc. SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(compileRequest, entryPointIndex, targetReq, CodeGenTarget::HLSL, endToEndReq, source)); + List<Int> entryPointIndices; + entryPointIndices.add(entryPointIndex); + SLANG_RETURN_ON_FAIL(emitEntryPointsSource(compileRequest, entryPointIndices, + targetReq, CodeGenTarget::HLSL, endToEndReq, source)); const auto& hlslCode = source.source; @@ -190,7 +193,9 @@ namespace Slang args[argCount++] = L"-enable-16bit-types"; } - const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); + List<Int> entryPointIndices2; + entryPointIndices.add(entryPointIndex); + const String sourcePath = calcSourcePathForEntryPoints(endToEndReq, entryPointIndices2); ComPtr<IDxcOperationResult> dxcResult; SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob, diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 59b059e91..e59cfae37 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -160,9 +160,10 @@ struct LinkingAndOptimizationOptions CLikeSourceEmitter* sourceEmitter = nullptr; }; +// TODO(DG): A bit tricky; this needs to be generalized to multiple entry points Result linkAndOptimizeIR( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, CodeGenTarget target, TargetRequest* targetRequest, LinkingAndOptimizationOptions const& options, @@ -184,7 +185,7 @@ Result linkAndOptimizeIR( // outLinkedIR = linkIR( compileRequest, - entryPointIndex, + entryPointIndices, target, targetProgram); auto irModule = outLinkedIR.module; @@ -287,6 +288,9 @@ Result linkAndOptimizeIR( break; } + // TODO(DG): There are multiple DCE steps here, which need to be changed + // CHECK: how to these modules work? + // so that they don't just throw out any non-entry point code // Debugging code for IR transformations... #if 0 dumpIRIfEnabled(compileRequest, irModule, "SPECIALIZED"); @@ -605,19 +609,23 @@ Result linkAndOptimizeIR( return SLANG_OK; } +// TODO(DG): This probably needs to be generalized to a list SlangResult emitEntryPointSourceFromIR( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, CodeGenTarget target, TargetRequest* targetRequest, SourceResult& outSource) { + // Temporary assertion for checkpoint + SLANG_ASSERT(entryPointIndices.getCount() == 1); outSource.reset(); auto sink = compileRequest->getSink(); auto program = compileRequest->getProgram(); - auto entryPoint = program->getEntryPoint(entryPointIndex); + // TODO(DG): Update from assertion + auto entryPoint = program->getEntryPoint(entryPointIndices[0]); auto lineDirectiveMode = compileRequest->getLineDirectiveMode(); // To try to make the default behavior reasonable, we will @@ -637,6 +645,7 @@ SlangResult emitEntryPointSourceFromIR( desc.compileRequest = compileRequest; desc.target = target; + // TODO(DG): Can't assume a single entry point stage for multiple entry points desc.entryPointStage = entryPoint->getStage(); desc.effectiveProfile = getEffectiveProfile(entryPoint, targetRequest); desc.sourceWriter = &sourceWriter; @@ -700,7 +709,7 @@ SlangResult emitEntryPointSourceFromIR( linkAndOptimizeIR( compileRequest, - entryPointIndex, + entryPointIndices, target, targetRequest, linkingAndOptimizationOptions, @@ -769,25 +778,27 @@ SlangResult emitSPIRVFromIR( IRFunc* irEntryPoint, List<uint8_t>& spirvOut); -SlangResult emitSPIRVForEntryPointDirectly( +SlangResult emitSPIRVForEntryPointsDirectly( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, TargetRequest* targetRequest, List<uint8_t>& spirvOut) { + // TODO(DG): Temporary assertion for checkpoint + SLANG_ASSERT(entryPointIndices.getCount() == 1); auto sink = compileRequest->getSink(); auto program = compileRequest->getProgram(); auto targetProgram = program->getTargetProgram(targetRequest); auto programLayout = targetProgram->getOrCreateLayout(sink); - RefPtr<EntryPointLayout> entryPointLayout = programLayout->entryPoints[entryPointIndex]; + 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; linkAndOptimizeIR( compileRequest, - entryPointIndex, + entryPointIndices, targetRequest->getTarget(), targetRequest, linkingAndOptimizationOptions, diff --git a/source/slang/slang-emit.h b/source/slang/slang-emit.h index e18ba6f01..09da4c2ba 100644 --- a/source/slang/slang-emit.h +++ b/source/slang/slang-emit.h @@ -38,7 +38,7 @@ namespace Slang /// SlangResult emitEntryPointSourceFromIR( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, CodeGenTarget target, TargetRequest* targetRequest, SourceResult& outSource); diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index f80f97aff..f1f6d4cd4 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -1346,9 +1346,10 @@ struct IRSpecializationState } }; +// TODO(DG): Generalize to multiple entry points LinkedIR linkIR( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, CodeGenTarget target, TargetProgram* targetProgram) { @@ -1446,7 +1447,11 @@ LinkedIR linkIR( // arguments which might end up affecting the mangled // entry point name. // - auto entryPointMangledName = program->getEntryPointMangledName(entryPointIndex); + // TODO(DG): spot to generalize to multiple entry points + // Note that only stuff referenced by an entry point gets linked here + // Temporary assertion for checkpoint + SLANG_ASSERT(entryPointIndices.getCount() == 1); + auto entryPointMangledName = program->getEntryPointMangledName(entryPointIndices[0]); auto irEntryPoint = specializeIRForEntryPoint(context, entryPointMangledName); // Bindings for global generic parameters are currently represented diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h index 9fc9cb975..e244f29e6 100644 --- a/source/slang/slang-ir-link.h +++ b/source/slang/slang-ir-link.h @@ -20,7 +20,7 @@ namespace Slang // LinkedIR linkIR( BackEndCompileRequest* compileRequest, - Int entryPointIndex, + List<Int> entryPointIndices, CodeGenTarget target, TargetProgram* targetProgram); diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index f3c702c26..3f1adeb13 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -1421,6 +1421,9 @@ struct OptionsParser // for(auto& rawOutput : rawOutputs) { + // TODO(DG): As noted below, change support for output formats + // with multiple entry points + // For now, all output formats need to be tightly bound to // both a target and an entry point (down the road we will // need to support output formats that can store multiple @@ -1457,6 +1460,10 @@ struct OptionsParser // point was handled above, and the user is expected to // follow the ordering rules when using multiple entry points. // + // TODO(DG): check if output format is left unassociated + // If (known format for that output && that format supports whole program) { + // set isWholeProgram bit on the TargetRequest } + // else { diagnose what happened } if( rawOutput.entryPointIndex == -1 ) { sink->diagnose(SourceLoc(), Diagnostics::cannotMatchOutputFileToEntryPoint, rawOutput.path); @@ -1472,6 +1479,7 @@ struct OptionsParser for(auto& rawOutput : rawOutputs) { if(rawOutput.targetIndex == -1) continue; + // TODO(DG): probably needs updating if(rawOutput.entryPointIndex == -1) continue; auto targetID = rawTargets[rawOutput.targetIndex].targetID; |
