diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2021-05-14 17:50:00 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-14 17:50:00 -0400 |
| commit | d4316c88457a32f1169b2d7d82053ccbc05fa7ed (patch) | |
| tree | cbc87350b9ef2f5be31ebc20783e08b895767779 /source | |
| parent | 79d106fac18f5792fcac448a0b037aa834fa6042 (diff) | |
FXC as DownstreamCompiler (#1844)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP Fxc as downstream compiler.
* First pass FXC downstream compiler working.
* GCC compile fix.
* Fix FXC parsing issue.
* Special case filesystem access.
* Use StringUtil getSlice.
* Fix isses with not emitting source for FXC.
* Small fixes for DXBC handling.
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-downstream-compiler.cpp | 93 | ||||
| -rw-r--r-- | source/compiler-core/slang-downstream-compiler.h | 35 | ||||
| -rw-r--r-- | source/compiler-core/slang-fxc-compiler.cpp | 417 | ||||
| -rw-r--r-- | source/compiler-core/slang-fxc-compiler.h | 18 | ||||
| -rw-r--r-- | source/compiler-core/slang-gcc-compiler-util.cpp | 14 | ||||
| -rw-r--r-- | source/compiler-core/slang-include-system.cpp (renamed from source/slang/slang-include-system.cpp) | 0 | ||||
| -rw-r--r-- | source/compiler-core/slang-include-system.h (renamed from source/slang/slang-include-system.h) | 0 | ||||
| -rw-r--r-- | source/compiler-core/slang-nvrtc-compiler.cpp | 1 | ||||
| -rw-r--r-- | source/compiler-core/slang-visual-studio-compiler-util.cpp | 12 | ||||
| -rw-r--r-- | source/core/slang-string-util.cpp | 13 | ||||
| -rw-r--r-- | source/core/slang-string-util.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-check.cpp | 2 | ||||
| -rwxr-xr-x | source/slang/slang-compiler.cpp | 598 | ||||
| -rwxr-xr-x | source/slang/slang-compiler.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-preprocessor.h | 3 |
15 files changed, 776 insertions, 436 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 696376b49..d89434896 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -18,6 +18,7 @@ #include "slang-visual-studio-compiler-util.h" #include "slang-gcc-compiler-util.h" #include "slang-nvrtc-compiler.h" +#include "slang-fxc-compiler.h" namespace Slang { @@ -74,8 +75,56 @@ void DownstreamCompiler::Desc::appendAsText(StringBuilder& out) const } } +/* static */SlangResult DownstreamDiagnostic::splitPathLocation(const UnownedStringSlice& pathLocation, DownstreamDiagnostic& outDiagnostic) +{ + const Index lineStartIndex = pathLocation.lastIndexOf('('); + if (lineStartIndex >= 0) + { + outDiagnostic.filePath = UnownedStringSlice(pathLocation.head(lineStartIndex).trim()); + + const UnownedStringSlice tail = pathLocation.tail(lineStartIndex + 1); + const Index lineEndIndex = tail.indexOf(')'); + + if (lineEndIndex >= 0) + { + // Extract the location info + UnownedStringSlice locationSlice(tail.begin(), tail.begin() + lineEndIndex); + + UnownedStringSlice slices[2]; + const Index numSlices = StringUtil::split(locationSlice, ',', 2, slices); + + // NOTE! FXC actually outputs a range of columns in the form of START-END in the column position + // We don't need to parse here, because we only care about the line number + + Int lineNumber = 0; + if (numSlices > 0) + { + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(slices[0], lineNumber)); + } + + // Store the line + outDiagnostic.fileLine = lineNumber; + } + } + else + { + outDiagnostic.filePath = pathLocation; + } + return SLANG_OK; +} + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ +SlangResult DownstreamCompiler::dissassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) +{ + SLANG_UNUSED(sourceBlobTarget); + SLANG_UNUSED(blob); + SLANG_UNUSED(blobSize); + SLANG_UNUSED(out); + + return SLANG_E_NOT_AVAILABLE; +} + /* static */bool DownstreamCompiler::canCompile(SlangPassThrough compiler, SlangSourceLanguage sourceLanguage) { @@ -92,6 +141,7 @@ void DownstreamCompiler::Desc::appendAsText(StringBuilder& out) const case SLANG_SOURCE_LANGUAGE_C: return SLANG_C_SOURCE; case SLANG_SOURCE_LANGUAGE_CPP: return SLANG_CPP_SOURCE; case SLANG_SOURCE_LANGUAGE_CUDA: return SLANG_CUDA_SOURCE; + default: return SLANG_TARGET_UNKNOWN; } } @@ -196,6 +246,34 @@ void DownstreamDiagnostics::removeBySeverity(Diagnostic::Severity severity) } } +/* static */void DownstreamDiagnostics::addNote(const UnownedStringSlice& in, List<DownstreamDiagnostic>& ioDiagnostics) +{ + // Don't bother adding an empty line + if (in.trim().getLength() == 0) + { + return; + } + + // If there's nothing previous, we'll ignore too, as note should be in addition to + // a pre-existing error/warning + if (ioDiagnostics.getCount() == 0) + { + return; + } + + // Make it a note on the output + DownstreamDiagnostic diagnostic; + diagnostic.reset(); + diagnostic.severity = DownstreamDiagnostic::Severity::Info; + diagnostic.text = in; + ioDiagnostics.add(diagnostic); +} + +void DownstreamDiagnostics::addNote(const UnownedStringSlice& in) +{ + addNote(in, diagnostics); +} + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompileResult !!!!!!!!!!!!!!!!!!!!!!*/ SlangResult CommandLineDownstreamCompileResult::getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) @@ -595,19 +673,6 @@ static SlangResult _locateDXCCompilers(const String& path, ISlangSharedLibraryLo return SLANG_OK; } -static SlangResult _locateFXCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) -{ - ComPtr<ISlangSharedLibrary> sharedLibrary; - if (SLANG_SUCCEEDED(DefaultSharedLibraryLoader::load(loader, path, "d3dcompiler_47", sharedLibrary.writeRef()))) - { - // Can we determine the version? - DownstreamCompiler::Desc desc(SLANG_PASS_THROUGH_FXC); - RefPtr<DownstreamCompiler> compiler(new SharedLibraryDownstreamCompiler(desc, sharedLibrary)); - set->addCompiler(compiler); - } - return SLANG_OK; -} - static SlangResult _locateGlslangCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) { #if SLANG_UNIX_FAMILY @@ -633,7 +698,7 @@ static SlangResult _locateGlslangCompilers(const String& path, ISlangSharedLibra outFuncs[int(SLANG_PASS_THROUGH_GCC)] = &GCCDownstreamCompilerUtil::locateGCCCompilers; outFuncs[int(SLANG_PASS_THROUGH_NVRTC)] = &NVRTCDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_DXC)] = &_locateDXCCompilers; - outFuncs[int(SLANG_PASS_THROUGH_FXC)] = &_locateFXCCompilers; + outFuncs[int(SLANG_PASS_THROUGH_FXC)] = &FXCDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_GLSLANG)] = &_locateGlslangCompilers; } diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index def13993e..b7f7b0cde 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -16,6 +16,8 @@ namespace Slang { +struct SourceManager; + struct DownstreamDiagnostic { typedef DownstreamDiagnostic ThisType; @@ -54,6 +56,9 @@ struct DownstreamDiagnostic static UnownedStringSlice getSeverityText(Severity severity); + /// Given a path, that holds line number and potentially column number in () after path, writes result into outDiagnostic + static SlangResult splitPathLocation(const UnownedStringSlice& pathLocation, DownstreamDiagnostic& outDiagnostic); + Severity severity; ///< The severity of error Stage stage; ///< The stage the error came from String text; ///< The text of the error @@ -85,6 +90,11 @@ struct DownstreamDiagnostics /// Remove all diagnostics of the type void removeBySeverity(Diagnostic::Severity severity); + /// Add a note + void addNote(const UnownedStringSlice& in); + + static void addNote(const UnownedStringSlice& in, List<DownstreamDiagnostic>& ioDiagnostics); + String rawDiagnostics; SlangResult result; @@ -209,12 +219,14 @@ public: Precise, }; +#if 0 enum TargetType { Executable, ///< Produce an executable SharedLibrary, ///< Produce a shared library object/dll Object, ///< Produce an object file }; +#endif enum PipelineType { @@ -256,7 +268,7 @@ public: OptimizationLevel optimizationLevel = OptimizationLevel::Default; DebugInfoType debugInfoType = DebugInfoType::Standard; - TargetType targetType = TargetType::Executable; + SlangCompileTarget targetType = SLANG_EXECUTABLE; SlangSourceLanguage sourceLanguage = SLANG_SOURCE_LANGUAGE_CPP; FloatingPointMode floatingPointMode = FloatingPointMode::Default; PipelineType pipelineType = PipelineType::Unknown; @@ -284,6 +296,16 @@ public: List<String> libraryPaths; List<CapabilityVersion> requiredCapabilityVersions; + + /// For compilers/compiles that require an entry point name, else can be empty + String entryPointName; + /// Profile name to use, only required for compiles that need to compile against a a specific profiles. + /// Profile names are tied to compilers and targets. + String profileName; + + /// NOTE! Not all downstream compilers can use the fileSystemExt/sourceManager. This option will be ignored in those scenarios. + ISlangFileSystemExt* fileSystemExt = nullptr; + SourceManager* sourceManager = nullptr; }; typedef uint32_t ProductFlags; @@ -317,6 +339,12 @@ public: /// Some downstream compilers are backed by a shared library. This allows access to the shared library to access internal functions. virtual ISlangSharedLibrary* getSharedLibrary() { return nullptr; } + /// Some compilers have support converting a binary blob into disassembly. Output disassembly is held in the output blob + virtual SlangResult dissassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out); + + /// True if underlying compiler uses file system to pass source + virtual bool isFileBased() = 0; + /// Get info for a compiler type static const Info& getInfo(SlangPassThrough compiler) { return s_infos.infos[int(compiler)]; } /// True if this compiler can compile the specified language @@ -369,7 +397,8 @@ public: // DownstreamCompiler virtual SlangResult compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; - + virtual bool isFileBased() SLANG_OVERRIDE { return true; } + // Functions to be implemented for a specific CommandLine /// Given the compilation options and the module name, determines the actual file name used for output @@ -405,6 +434,7 @@ public: // DownstreamCompiler virtual SlangResult compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE { SLANG_UNUSED(options); SLANG_UNUSED(outResult); return SLANG_E_NOT_IMPLEMENTED; } + virtual bool isFileBased() SLANG_OVERRIDE { return true; } virtual ISlangSharedLibrary* getSharedLibrary() SLANG_OVERRIDE { return m_library; } SharedLibraryDownstreamCompiler(const Desc& desc, ISlangSharedLibrary* library): @@ -461,7 +491,6 @@ struct DownstreamCompilerBaseUtil { typedef DownstreamCompiler::CompileOptions CompileOptions; typedef DownstreamCompiler::OptimizationLevel OptimizationLevel; - typedef DownstreamCompiler::TargetType TargetType; typedef DownstreamCompiler::DebugInfoType DebugInfoType; typedef DownstreamDiagnostics::Diagnostic Diagnostic; diff --git a/source/compiler-core/slang-fxc-compiler.cpp b/source/compiler-core/slang-fxc-compiler.cpp new file mode 100644 index 000000000..8e190bbca --- /dev/null +++ b/source/compiler-core/slang-fxc-compiler.cpp @@ -0,0 +1,417 @@ +// slang-fxc-compiler.cpp +#include "slang-fxc-compiler.h" + +#include "../core/slang-common.h" +#include "../../slang-com-helper.h" + +#include "../core/slang-blob.h" + +#include "../core/slang-string-util.h" +#include "../core/slang-string-slice-pool.h" + +#include "../core/slang-io.h" +#include "../core/slang-shared-library.h" +#include "../core/slang-semantic-version.h" +#include "../core/slang-char-util.h" + +#include "slang-include-system.h" +#include "slang-source-loc.h" + +#include "../core/slang-shared-library.h" + +// Enable calling through to `fxc` or `dxc` to +// generate code on Windows. +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include <Windows.h> +# undef WIN32_LEAN_AND_MEAN +# undef NOMINMAX +# include <d3dcompiler.h> + +# ifndef SLANG_ENABLE_DXBC_SUPPORT +# define SLANG_ENABLE_DXBC_SUPPORT 1 +# endif +#endif + +#ifndef SLANG_ENABLE_DXBC_SUPPORT +# define SLANG_ENABLE_DXBC_SUPPORT 0 +#endif + +#if SLANG_ENABLE_DXBC_SUPPORT + // Some of the `D3DCOMPILE_*` constants aren't available in all + // versions of `d3dcompiler.h`, so we define them here just in case +# ifndef D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES +# define D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES (1 << 20) +# endif + +# ifndef D3DCOMPILE_ALL_RESOURCES_BOUND +# define D3DCOMPILE_ALL_RESOURCES_BOUND (1 << 21) +# endif +#endif + +namespace Slang +{ + +#if SLANG_ENABLE_DXBC_SUPPORT + +static UnownedStringSlice _getSlice(ID3DBlob* blob) { return StringUtil::getSlice((ISlangBlob*)blob); } + +struct FxcIncludeHandler : ID3DInclude +{ + + STDMETHOD(Open)(D3D_INCLUDE_TYPE includeType, LPCSTR fileName, LPCVOID parentData, LPCVOID* outData, UINT* outSize) override + { + SLANG_UNUSED(includeType); + // NOTE! The pParentData means the *text* of any previous include. + // In order to work out what *path* that came from, we need to seach which source file it came from, and + // use it's path + + // Assume the root pathInfo initially + PathInfo includedFromPathInfo = m_rootPathInfo; + + // Lets try and find the parent source if there is any + if (parentData) + { + SourceFile* foundSourceFile = m_system.getSourceManager()->findSourceFileByContentRecursively((const char*)parentData); + if (foundSourceFile) + { + includedFromPathInfo = foundSourceFile->getPathInfo(); + } + } + + String path(fileName); + PathInfo pathInfo; + ComPtr<ISlangBlob> blob; + + SLANG_RETURN_ON_FAIL(m_system.findAndLoadFile(path, includedFromPathInfo.foundPath, pathInfo, blob)); + + // Return the data + *outData = blob->getBufferPointer(); + *outSize = (UINT)blob->getBufferSize(); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) override + { + SLANG_UNUSED(pData); + return S_OK; + } + FxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager) : + m_system(searchDirectories, fileSystemExt, sourceManager) + { + } + + PathInfo m_rootPathInfo; + IncludeSystem m_system; +}; + +class FXCDownstreamCompiler : public DownstreamCompiler +{ +public: + typedef DownstreamCompiler Super; + + // DownstreamCompiler + virtual SlangResult compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + virtual ISlangSharedLibrary* getSharedLibrary() SLANG_OVERRIDE { return m_sharedLibrary; } + virtual SlangResult dissassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) SLANG_OVERRIDE; + virtual bool isFileBased() SLANG_OVERRIDE { return false; } + + /// Must be called before use + SlangResult init(ISlangSharedLibrary* library); + + FXCDownstreamCompiler() {} + +protected: + + pD3DCompile m_compile = nullptr; + pD3DDisassemble m_disassemble = nullptr; + + ComPtr<ISlangSharedLibrary> m_sharedLibrary; +}; + +SlangResult FXCDownstreamCompiler::init(ISlangSharedLibrary* library) +{ + m_compile = (pD3DCompile)library->findFuncByName("D3DCompile"); + m_disassemble = (pD3DDisassemble)library->findFuncByName("D3DDisassemble"); + + if (!m_compile || !m_disassemble) + { + return SLANG_FAIL; + } + + m_sharedLibrary = library; + + // It's not clear how to query for a version, but we can get a version number from the header + m_desc = Desc(SLANG_PASS_THROUGH_FXC, D3D_COMPILER_VERSION); + + return SLANG_OK; +} + +static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +{ + /* tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@' */ + if (lineSlices.getCount() < 3) + { + return SLANG_FAIL; + } + + SLANG_RETURN_ON_FAIL(DownstreamDiagnostic::splitPathLocation(lineSlices[0], outDiagnostic)); + + { + const UnownedStringSlice severityAndCodeSlice = lineSlices[1].trim(); + const UnownedStringSlice severitySlice = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 0); + + outDiagnostic.code = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1); + + outDiagnostic.severity = DownstreamDiagnostic::Severity::Error; + if (severitySlice == "warning") + { + outDiagnostic.severity = DownstreamDiagnostic::Severity::Warning; + } + } + + outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); + return SLANG_OK; +} + +static SlangResult _splitDiagnosticLine(const UnownedStringSlice& line, List<UnownedStringSlice>& outSlices) +{ + StringUtil::split(line, ':', outSlices); + + /* + tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@' + */ + + const Int pathIndex = 0; + + // Now we want to fix up a path as might have drive letter, and therefore : + // If this is the situation then we need to have a slice after the one at the index + if (outSlices.getCount() > pathIndex + 1) + { + const UnownedStringSlice pathStart = outSlices[pathIndex].trim(); + if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0])) + { + // Splice back together + outSlices[pathIndex] = UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end()); + outSlices.removeAt(pathIndex + 1); + } + } + + return SLANG_OK; +} + +static SlangResult _parseDiagnostics(const UnownedStringSlice& inText, List<DownstreamDiagnostic>& outDiagnostics) +{ + List<UnownedStringSlice> splitLine; + + UnownedStringSlice text(inText), line; + while (StringUtil::extractLine(text, line)) + { + SLANG_RETURN_ON_FAIL(_splitDiagnosticLine(line, splitLine)); + + DownstreamDiagnostic diagnostic; + diagnostic.severity = DownstreamDiagnostic::Severity::Error; + diagnostic.stage = DownstreamDiagnostic::Stage::Compile; + diagnostic.fileLine = 0; + + if (SLANG_SUCCEEDED(_parseDiagnosticLine(line, splitLine, diagnostic))) + { + outDiagnostics.add(diagnostic); + } + else + { + // If couldn't parse, just add as a note + DownstreamDiagnostics::addNote(line, outDiagnostics); + } + } + + return SLANG_OK; +} + +SlangResult FXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) +{ + // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath + if (options.sourceFiles.getCount() > 0) + { + return SLANG_FAIL; + } + + if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXBC) + { + SLANG_ASSERT(!"Can only compile HLSL to DXBC"); + return SLANG_FAIL; + } + + // If we have been invoked in a pass-through mode, then we need to make sure + // that the downstream compiler sees whatever options were passed to Slang + // via the command line or API. + // + // TODO: more pieces of information should be added here as needed. + // + + SearchDirectoryList searchDirectories; + for (const auto& includePath : options.includePaths) + { + searchDirectories.searchDirectories.add(includePath); + } + + // Use the default fileSystemExt is not set + ID3DInclude* includeHandler = nullptr; + + FxcIncludeHandler fxcIncludeHandlerStorage(&searchDirectories, options.fileSystemExt, options.sourceManager); + if (options.fileSystemExt) + { + if (options.sourceContentsPath.getLength() > 0) + { + fxcIncludeHandlerStorage.m_rootPathInfo = PathInfo::makePath(options.sourceContentsPath); + } + includeHandler = &fxcIncludeHandlerStorage; + } + + List<D3D_SHADER_MACRO> dxMacrosStorage; + D3D_SHADER_MACRO const* dxMacros = nullptr; + + if (options.defines.getCount() > 0) + { + for (const auto& define : options.defines) + { + D3D_SHADER_MACRO dxMacro; + dxMacro.Name = define.nameWithSig.getBuffer(); + dxMacro.Definition = define.value.getBuffer(); + dxMacrosStorage.add(dxMacro); + } + D3D_SHADER_MACRO nullTerminator = { 0, 0 }; + dxMacrosStorage.add(nullTerminator); + + dxMacros = dxMacrosStorage.getBuffer(); + } + + DWORD flags = 0; + + switch (options.floatingPointMode) + { + default: + break; + + case FloatingPointMode::Precise: + flags |= D3DCOMPILE_IEEE_STRICTNESS; + break; + } + + flags |= D3DCOMPILE_ENABLE_STRICTNESS; + flags |= D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES; + + switch (options.optimizationLevel) + { + default: + break; + + case OptimizationLevel::None: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0; break; + case OptimizationLevel::Default: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL1; break; + case OptimizationLevel::High: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL2; break; + case OptimizationLevel::Maximal: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; break; + } + + switch (options.debugInfoType) + { + case DebugInfoType::None: + break; + + default: + flags |= D3DCOMPILE_DEBUG; + break; + } + + ComPtr<ID3DBlob> codeBlob; + ComPtr<ID3DBlob> diagnosticsBlob; + HRESULT hr = m_compile( + options.sourceContents.begin(), + options.sourceContents.getLength(), + options.sourceContentsPath.getBuffer(), + dxMacros, + includeHandler, + options.entryPointName.getBuffer(), + options.profileName.getBuffer(), + flags, + 0, // unused: effect flags + codeBlob.writeRef(), + diagnosticsBlob.writeRef()); + + DownstreamDiagnostics diagnostics; + + // HRESULT is compatible with SlangResult + diagnostics.result = hr; + + if (diagnosticsBlob) + { + UnownedStringSlice diagnosticText = _getSlice(diagnosticsBlob); + diagnostics.rawDiagnostics = diagnosticText; + _parseDiagnostics(diagnosticText, diagnostics.diagnostics); + } + + // ID3DBlob is compatible with ISlangBlob, so just cast away... + ISlangBlob* slangCodeBlob = (ISlangBlob*)codeBlob.get(); + + outResult = new BlobDownstreamCompileResult(diagnostics, slangCodeBlob); + return SLANG_OK; +} + +SlangResult FXCDownstreamCompiler::dissassemble(SlangCompileTarget sourceBlobTarget, const void* blob, size_t blobSize, ISlangBlob** out) +{ + // Can only disassemble blobs that are DXBC + if (sourceBlobTarget != SLANG_DXBC) + { + return SLANG_FAIL; + } + + ComPtr<ID3DBlob> codeBlob; + SLANG_RETURN_ON_FAIL(m_disassemble(blob, blobSize, 0, nullptr, codeBlob.writeRef())); + + // ISlangBlob is compatible with ID3DBlob + *out = (ISlangBlob*)codeBlob.detach(); + return SLANG_OK; +} + +/* static */SlangResult FXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + ComPtr<ISlangSharedLibrary> library; + + // If the user supplies a path to their preferred version of FXC, + // we just use this. + if (path.getLength() != 0) + { + SLANG_RETURN_ON_FAIL(loader->loadSharedLibrary(path.getBuffer(), library.writeRef())); + } + else + { + SLANG_RETURN_ON_FAIL(loader->loadSharedLibrary("d3dcompiler_47", library.writeRef())); + } + + SLANG_ASSERT(library); + if (!library) + { + return SLANG_FAIL; + } + + RefPtr<FXCDownstreamCompiler> compiler(new FXCDownstreamCompiler); + SLANG_RETURN_ON_FAIL(compiler->init(library)); + + set->addCompiler(compiler); + return SLANG_OK; +} + +#else // SLANG_ENABLE_DXBC_SUPPORT + +/* static */SlangResult FXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + SLANG_UNUSED(path); + SLANG_UNUSED(loader); + SLANG_UNUSED(set); + return SLANG_E_NOT_AVAILABLE; +} + +#endif // SLANG_ENABLE_DXBC_SUPPORT + +} diff --git a/source/compiler-core/slang-fxc-compiler.h b/source/compiler-core/slang-fxc-compiler.h new file mode 100644 index 000000000..0718f6db4 --- /dev/null +++ b/source/compiler-core/slang-fxc-compiler.h @@ -0,0 +1,18 @@ +#ifndef SLANG_FXC_COMPILER_UTIL_H +#define SLANG_FXC_COMPILER_UTIL_H + +#include "slang-downstream-compiler.h" + +#include "../core/slang-platform.h" + +namespace Slang +{ + +struct FXCDownstreamCompilerUtil +{ + static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); +}; + +} + +#endif diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index a51d5735f..971416ddb 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -377,18 +377,18 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse switch (options.targetType) { - case TargetType::SharedLibrary: + case SLANG_SHARED_LIBRARY: { outPath << SharedLibrary::calcPlatformPath(options.modulePath.getUnownedSlice()); return SLANG_OK; } - case TargetType::Executable: + case SLANG_EXECUTABLE: { outPath << options.modulePath; outPath << ProcessUtil::getExecutableSuffix(); return SLANG_OK; } - case TargetType::Object: + case SLANG_OBJECT_CODE: { #if __CYGWIN__ outPath << options.modulePath << ".obj"; @@ -509,7 +509,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse switch (options.targetType) { - case TargetType::SharedLibrary: + case SLANG_SHARED_LIBRARY: { // Shared library cmdLine.addArg("-shared"); @@ -521,11 +521,11 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse } break; } - case TargetType::Executable: + case SLANG_EXECUTABLE: { break; } - case TargetType::Object: + case SLANG_OBJECT_CODE: { // Don't link, just produce object file cmdLine.addArg("-c"); @@ -563,7 +563,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse //cmdLine.addArg(linkOptions); } - if (options.targetType == TargetType::SharedLibrary) + if (options.targetType == SLANG_SHARED_LIBRARY) { if (!PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) { diff --git a/source/slang/slang-include-system.cpp b/source/compiler-core/slang-include-system.cpp index 891d376f6..891d376f6 100644 --- a/source/slang/slang-include-system.cpp +++ b/source/compiler-core/slang-include-system.cpp diff --git a/source/slang/slang-include-system.h b/source/compiler-core/slang-include-system.h index 70f6dd81e..70f6dd81e 100644 --- a/source/slang/slang-include-system.h +++ b/source/compiler-core/slang-include-system.h diff --git a/source/compiler-core/slang-nvrtc-compiler.cpp b/source/compiler-core/slang-nvrtc-compiler.cpp index 79280e033..029f3c71b 100644 --- a/source/compiler-core/slang-nvrtc-compiler.cpp +++ b/source/compiler-core/slang-nvrtc-compiler.cpp @@ -100,6 +100,7 @@ public: // DownstreamCompiler virtual SlangResult compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; virtual ISlangSharedLibrary* getSharedLibrary() SLANG_OVERRIDE { return m_sharedLibrary; } + virtual bool isFileBased() SLANG_OVERRIDE { return false; } /// Must be called before use SlangResult init(ISlangSharedLibrary* library); diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index fd879e63f..e2c488ee9 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -23,17 +23,17 @@ namespace Slang switch (options.targetType) { - case TargetType::SharedLibrary: + case SLANG_SHARED_LIBRARY: { outPath << options.modulePath << ".dll"; return SLANG_OK; } - case TargetType::Executable: + case SLANG_EXECUTABLE: { outPath << options.modulePath << ".exe"; return SLANG_OK; } - case TargetType::Object: + case SLANG_OBJECT_CODE: { outPath << options.modulePath << ".obj"; return SLANG_OK; @@ -60,7 +60,7 @@ namespace Slang { outPaths.add(options.modulePath + ".ilk"); - if (options.targetType == TargetType::SharedLibrary) + if (options.targetType == SLANG_SHARED_LIBRARY) { outPaths.add(options.modulePath + ".exp"); outPaths.add(options.modulePath + ".lib"); @@ -190,7 +190,7 @@ namespace Slang switch (options.targetType) { - case TargetType::SharedLibrary: + case SLANG_SHARED_LIBRARY: { // Create dynamic link library if (options.debugInfoType == DebugInfoType::None) @@ -205,7 +205,7 @@ namespace Slang cmdLine.addPrefixPathArg("/Fe", options.modulePath, ".dll"); break; } - case TargetType::Executable: + case SLANG_EXECUTABLE: { cmdLine.addPrefixPathArg("/Fe", options.modulePath, ".exe"); break; diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp index cddee4bc4..7a142f643 100644 --- a/source/core/slang-string-util.cpp +++ b/source/core/slang-string-util.cpp @@ -293,7 +293,7 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s return builder; } -/* static */String StringUtil::getString(ISlangBlob* blob) +/* static */UnownedStringSlice StringUtil::getSlice(ISlangBlob* blob) { if (blob) { @@ -301,15 +301,20 @@ UnownedStringSlice StringUtil::getAtInSplit(const UnownedStringSlice& in, char s if (size > 0) { const char* contents = (const char*)blob->getBufferPointer(); - // Check it has terminating 0, if not we must construct as if it does + // Check it has terminating 0, if it has we skip it, because slices do not need zero termination if (contents[size - 1] == 0) { size--; } - return String(contents, contents + size); + return UnownedStringSlice(contents, contents + size); } } - return String(); + return UnownedStringSlice(); +} + +/* static */String StringUtil::getString(ISlangBlob* blob) +{ + return getSlice(blob); } ComPtr<ISlangBlob> StringUtil::createStringBlob(const String& string) diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index 5b375a09e..2b30120b7 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -69,6 +69,7 @@ struct StringUtil /// Given a string held in a blob, returns as a String /// Returns an empty string if blob is nullptr static String getString(ISlangBlob* blob); + static UnownedStringSlice getSlice(ISlangBlob* blob); /// Given a string or slice, replaces all instances of fromChar with toChar static String calcCharReplaced(const UnownedStringSlice& slice, char fromChar, char toChar); diff --git a/source/slang/slang-check.cpp b/source/slang/slang-check.cpp index 600578297..a5701aa90 100644 --- a/source/slang/slang-check.cpp +++ b/source/slang/slang-check.cpp @@ -70,8 +70,6 @@ namespace Slang { case FuncType::Glslang_Compile_1_0: return { "glslang_compile", PassThroughMode::Glslang} ; case FuncType::Glslang_Compile_1_1: return { "glslang_compile_1_1", PassThroughMode::Glslang} ; - case FuncType::Fxc_D3DCompile: return { "D3DCompile", PassThroughMode::Fxc}; - case FuncType::Fxc_D3DDisassemble: return { "D3DDisassemble", PassThroughMode::Fxc }; case FuncType::Dxc_DxcCreateInstance: return { "DxcCreateInstance", PassThroughMode::Dxc }; default: return { nullptr, PassThroughMode::None }; } diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 736250219..22e5bb61e 100755 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -35,18 +35,12 @@ #undef WIN32_LEAN_AND_MEAN #undef NOMINMAX #include <d3dcompiler.h> - #ifndef SLANG_ENABLE_DXBC_SUPPORT - #define SLANG_ENABLE_DXBC_SUPPORT 1 - #endif #ifndef SLANG_ENABLE_DXIL_SUPPORT #define SLANG_ENABLE_DXIL_SUPPORT 1 #endif #endif // -// Otherwise, don't enable DXBC/DXIL by default: -#ifndef SLANG_ENABLE_DXBC_SUPPORT - #define SLANG_ENABLE_DXBC_SUPPORT 0 -#endif +// Otherwise, don't enable DXIL by default: #ifndef SLANG_ENABLE_DXIL_SUPPORT #define SLANG_ENABLE_DXIL_SUPPORT 0 #endif @@ -415,9 +409,6 @@ namespace Slang #if !SLANG_ENABLE_DXIL_SUPPORT case PassThroughMode::Dxc: return SLANG_E_NOT_IMPLEMENTED; #endif -#if !SLANG_ENABLE_DXBC_SUPPORT - case PassThroughMode::Fxc: return SLANG_E_NOT_IMPLEMENTED; -#endif #if !SLANG_ENABLE_GLSLANG_SUPPORT case PassThroughMode::Glslang: return SLANG_E_NOT_IMPLEMENTED; #endif @@ -522,7 +513,8 @@ namespace Slang bool isPassThroughEnabled( EndToEndCompileRequest* endToEndReq) - { // If there isn't an end-to-end compile going on, + { + // If there isn't an end-to-end compile going on, // there can be no pass-through. // if (!endToEndReq) return false; @@ -556,23 +548,11 @@ namespace Slang return nullptr; } - static void _appendEscapedPath(const UnownedStringSlice& path, StringBuilder& outBuilder) - { - for (auto c : path) - { - // TODO(JS): Probably want more sophisticated handling... - if (c == '\\') - { - outBuilder.appendChar(c); - } - outBuilder.appendChar(c); - } - } - static void _appendCodeWithPath(const UnownedStringSlice& filePath, const UnownedStringSlice& fileContent, StringBuilder& outCodeBuilder) { outCodeBuilder << "#line 1 \""; - _appendEscapedPath(filePath, outCodeBuilder); + auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); + handler->appendEscaped(filePath, outCodeBuilder); outCodeBuilder << "\"\n"; outCodeBuilder << fileContent << "\n"; } @@ -883,276 +863,6 @@ namespace Slang return *entryPointIndices.begin(); } -#if SLANG_ENABLE_DXBC_SUPPORT - - static UnownedStringSlice _getSlice(ID3DBlob* blob) - { - if (blob) - { - const char* chars = (const char*)blob->GetBufferPointer(); - size_t len = blob->GetBufferSize(); - len -= size_t(len > 0 && chars[len - 1] == 0); - return UnownedStringSlice(chars, len); - } - return UnownedStringSlice(); - } - - struct FxcIncludeHandler : ID3DInclude - { - - STDMETHOD(Open)(D3D_INCLUDE_TYPE includeType, LPCSTR fileName, LPCVOID parentData, LPCVOID* outData, UINT* outSize) override - { - SLANG_UNUSED(includeType); - // NOTE! The pParentData means the *text* of any previous include. - // In order to work out what *path* that came from, we need to seach which source file it came from, and - // use it's path - - // Assume the root pathInfo initially - PathInfo includedFromPathInfo = m_rootPathInfo; - - // Lets try and find the parent source if there is any - if (parentData) - { - SourceFile* foundSourceFile = m_system.getSourceManager()->findSourceFileByContentRecursively((const char*)parentData); - if (foundSourceFile) - { - includedFromPathInfo = foundSourceFile->getPathInfo(); - } - } - - String path(fileName); - PathInfo pathInfo; - ComPtr<ISlangBlob> blob; - - SLANG_RETURN_ON_FAIL(m_system.findAndLoadFile(path, includedFromPathInfo.foundPath, pathInfo, blob)); - - // Return the data - *outData = blob->getBufferPointer(); - *outSize = (UINT) blob->getBufferSize(); - - return S_OK; - } - - STDMETHOD(Close)(LPCVOID pData) override - { - SLANG_UNUSED(pData); - return S_OK; - } - FxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager): - m_system(searchDirectories, fileSystemExt, sourceManager) - { - } - - PathInfo m_rootPathInfo; - IncludeSystem m_system; - }; - - SlangResult emitDXBytecodeForEntryPoint( - ComponentType* program, - BackEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq, - List<uint8_t>& byteCodeOut) - { - byteCodeOut.clear(); - - auto session = compileRequest->getSession(); - auto sink = compileRequest->getSink(); - - auto compileFunc = (pD3DCompile)session->getSharedLibraryFunc(Session::SharedLibraryFuncType::Fxc_D3DCompile, sink); - if (!compileFunc) - { - return SLANG_FAIL; - } - - SourceResult source; - SLANG_RETURN_ON_FAIL(emitEntryPointSource(compileRequest, entryPointIndex, targetReq, CodeGenTarget::HLSL, endToEndReq, source)); - - const auto& hlslCode = source.source; - maybeDumpIntermediate(compileRequest, hlslCode.getBuffer(), CodeGenTarget::HLSL); - - auto entryPoint = program->getEntryPoint(entryPointIndex); - auto profile = getEffectiveProfile(entryPoint, targetReq); - - auto linkage = compileRequest->getLinkage(); - - // If we have been invoked in a pass-through mode, then we need to make sure - // that the downstream compiler sees whatever options were passed to Slang - // via the command line or API. - // - // TODO: more pieces of information should be added here as needed. - // - List<D3D_SHADER_MACRO> dxMacrosStorage; - D3D_SHADER_MACRO const* dxMacros = nullptr; - - FxcIncludeHandler fxcIncludeHandlerStorage(&linkage->searchDirectories, linkage->getFileSystemExt(), sink->getSourceManager()); - FxcIncludeHandler* fxcIncludeHandler = &fxcIncludeHandlerStorage; - - if(auto translationUnit = findPassThroughTranslationUnit(endToEndReq, entryPointIndex)) - { - for( auto& define : translationUnit->compileRequest->preprocessorDefinitions ) - { - D3D_SHADER_MACRO dxMacro; - dxMacro.Name = define.Key.getBuffer(); - dxMacro.Definition = define.Value.getBuffer(); - dxMacrosStorage.add(dxMacro); - } - for( auto& define : translationUnit->preprocessorDefinitions ) - { - D3D_SHADER_MACRO dxMacro; - dxMacro.Name = define.Key.getBuffer(); - dxMacro.Definition = define.Value.getBuffer(); - dxMacrosStorage.add(dxMacro); - } - D3D_SHADER_MACRO nullTerminator = { 0, 0 }; - dxMacrosStorage.add(nullTerminator); - - dxMacros = dxMacrosStorage.getBuffer(); - - fxcIncludeHandler = &fxcIncludeHandlerStorage; - fxcIncludeHandlerStorage.m_rootPathInfo = translationUnit->m_sourceFiles[0]->getPathInfo(); - } - - DWORD flags = 0; - - switch( targetReq->getFloatingPointMode() ) - { - default: - break; - - case FloatingPointMode::Precise: - flags |= D3DCOMPILE_IEEE_STRICTNESS; - break; - } - - // Some of the `D3DCOMPILE_*` constants aren't available in all - // versions of `d3dcompiler.h`, so we define them here just in case - #ifndef D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES - #define D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES (1 << 20) - #endif - - #ifndef D3DCOMPILE_ALL_RESOURCES_BOUND - #define D3DCOMPILE_ALL_RESOURCES_BOUND (1 << 21) - #endif - - flags |= D3DCOMPILE_ENABLE_STRICTNESS; - flags |= D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES; - - switch( linkage->optimizationLevel ) - { - default: - break; - - case OptimizationLevel::None: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0; break; - case OptimizationLevel::Default: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL1; break; - case OptimizationLevel::High: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL2; break; - case OptimizationLevel::Maximal: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; break; - } - - switch( linkage->debugInfoLevel ) - { - case DebugInfoLevel::None: - break; - - default: - flags |= D3DCOMPILE_DEBUG; - break; - } - - const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); - - ComPtr<ID3DBlob> codeBlob; - ComPtr<ID3DBlob> diagnosticsBlob; - HRESULT hr = compileFunc( - hlslCode.begin(), - hlslCode.getLength(), - sourcePath.getBuffer(), - dxMacros, - fxcIncludeHandler, - getText(entryPoint->getName()).begin(), - GetHLSLProfileName(profile).getBuffer(), - flags, - 0, // unused: effect flags - codeBlob.writeRef(), - diagnosticsBlob.writeRef()); - - if (codeBlob && SLANG_SUCCEEDED(hr)) - { - byteCodeOut.addRange((uint8_t const*)codeBlob->GetBufferPointer(), (int)codeBlob->GetBufferSize()); - } - - if (FAILED(hr)) - { - reportExternalCompileError("fxc", hr, _getSlice(diagnosticsBlob), sink); - } - - return hr; - } - - SlangResult dissassembleDXBC( - BackEndCompileRequest* compileRequest, - void const* data, - size_t size, - String& assemOut) - { - assemOut = String(); - - auto session = compileRequest->getSession(); - auto sink = compileRequest->getSink(); - - auto disassembleFunc = (pD3DDisassemble)session->getSharedLibraryFunc(Session::SharedLibraryFuncType::Fxc_D3DDisassemble, sink); - if (!disassembleFunc) - { - return SLANG_E_NOT_FOUND; - } - - if (!data || !size) - { - return SLANG_FAIL; - } - - ComPtr<ID3DBlob> codeBlob; - SlangResult res = disassembleFunc(data, size, 0, nullptr, codeBlob.writeRef()); - - if (codeBlob) - { - assemOut = _getSlice(codeBlob); - } - if (FAILED(res)) - { - // TODO(tfoley): need to figure out what to diagnose here... - reportExternalCompileError("fxc", res, UnownedStringSlice(), sink); - } - - return res; - } - - SlangResult emitDXBytecodeAssemblyForEntryPoint( - ComponentType* program, - BackEndCompileRequest* compileRequest, - Int entryPointIndex, - TargetRequest* targetReq, - EndToEndCompileRequest* endToEndReq, - String& assemOut) - { - - List<uint8_t> dxbc; - SLANG_RETURN_ON_FAIL(emitDXBytecodeForEntryPoint( - program, - compileRequest, - entryPointIndex, - targetReq, - endToEndReq, - dxbc)); - if (!dxbc.getCount()) - { - return SLANG_FAIL; - } - return dissassembleDXBC(compileRequest, dxbc.getBuffer(), dxbc.getCount(), assemOut); - } -#endif - #if SLANG_ENABLE_DXIL_SUPPORT // Implementations in `dxc-support.cpp` @@ -1262,10 +972,42 @@ SlangResult dissassembleDXILUsingDXC( return SLANG_OK; } + // True if the downstream compiler will need to emit source to make compilation work + // That it may be desirable to not emit source if it is available as is on the file system + // and the downstream compiler accesses files through the file system. + static bool _isEmittedSourceRequired(DownstreamCompiler* compiler, TranslationUnitRequest* translationUnit) + { + // We only bother if it's a file based compiler. + if (compiler->isFileBased()) + { + // It can only have *one* source file as otherwise we have to combine to make a new source file anyway + const auto& sourceFiles = translationUnit->getSourceFiles(); + + // The *assumption* here is that if it's file based that assuming it can find the file with the same contents + // it can compile directly without having to save off as a file + if (sourceFiles.getCount() == 1) + { + const SourceFile* sourceFile = sourceFiles[0]; + // We need the path to be found and set + // + // NOTE! That the downstream compiler can determine if the path and contents match such that it can be used + // without writing file + const PathInfo& pathInfo = sourceFile->getPathInfo(); + if ((pathInfo.type == PathInfo::Type::FoundPath || pathInfo.type == PathInfo::Type::Normal) && pathInfo.foundPath.getLength()) + { + return false; + } + } + } + return true; + } + SlangResult emitWithDownstreamForEntryPoints( + ComponentType* program, BackEndCompileRequest* slangRequest, const List<Int>& entryPointIndices, TargetRequest* targetReq, + CodeGenTarget target, EndToEndCompileRequest* endToEndReq, RefPtr<DownstreamCompileResult>& outResult) { @@ -1275,8 +1017,6 @@ SlangResult dissassembleDXILUsingDXC( auto session = slangRequest->getSession(); - const String originalSourcePath = calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); - CodeGenTarget sourceTarget = CodeGenTarget::None; SourceLanguage sourceLanguage = SourceLanguage::Unknown; @@ -1285,7 +1025,6 @@ SlangResult dissassembleDXILUsingDXC( // If we are not in pass through, lookup the default compiler for the emitted source type if (downstreamCompiler == PassThroughMode::None) { - auto target = targetReq->getTarget(); switch (target) { case CodeGenTarget::PTX: @@ -1302,26 +1041,34 @@ SlangResult dissassembleDXILUsingDXC( sourceLanguage = SourceLanguage::CPP; break; } + case CodeGenTarget::DXBytecode: + { + sourceTarget = CodeGenTarget::HLSL; + sourceLanguage = SourceLanguage::HLSL; + downstreamCompiler = PassThroughMode::Fxc; + break; + } default: break; } - downstreamCompiler = PassThroughMode(session->getDefaultDownstreamCompiler(SlangSourceLanguage(sourceLanguage))); + // Try looking up based on the language if one isn't set + if (downstreamCompiler == PassThroughMode::None) + { + downstreamCompiler = PassThroughMode(session->getDefaultDownstreamCompiler(SlangSourceLanguage(sourceLanguage))); + } } + + // We should have a downstream compiler set at this point + SLANG_ASSERT(downstreamCompiler != PassThroughMode::None); + // Get the required downstream compiler DownstreamCompiler* compiler = session->getOrLoadDownstreamCompiler(downstreamCompiler, sink); if (!compiler) { auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)downstreamCompiler); - if (downstreamCompiler != PassThroughMode::None) - { - sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); - } - else - { - sink->diagnose(SourceLoc(), Diagnostics::cppCompilerNotFound, compilerName); - } + sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); return SLANG_FAIL; } @@ -1383,27 +1130,40 @@ SlangResult dissassembleDXILUsingDXC( // We are just passing thru, so it's whatever it originally was sourceLanguage = translationUnit->sourceLanguage; - sourceTarget = CodeGenTarget(DownstreamCompiler::getCompileTarget(SlangSourceLanguage(sourceLanguage))); - // Special case if we have a single file, so that we pass the path, and the contents - const auto& sourceFiles = translationUnit->getSourceFiles(); - if (sourceFiles.getCount() == 1) + // TODO(JS): This seems like a bit of a hack + // That if a pass-through is being performed and the source language is Slang + // no downstream compiler knows how to deal with that, so probably means 'HLSL' + if (sourceLanguage == SourceLanguage::Slang) { - const SourceFile* sourceFile = sourceFiles[0]; - const PathInfo& pathInfo = sourceFile->getPathInfo(); - if (pathInfo.type == PathInfo::Type::FoundPath || pathInfo.type == PathInfo::Type::Normal) - { - options.sourceContentsPath = pathInfo.foundPath; - } - options.sourceContents = sourceFile->getContent(); + sourceLanguage = SourceLanguage::HLSL; } - else + + sourceTarget = CodeGenTarget(DownstreamCompiler::getCompileTarget(SlangSourceLanguage(sourceLanguage))); + + // If emitted source is required, emit and set the path + if (_isEmittedSourceRequired(compiler, translationUnit)) { + // 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 + const String originalSourcePath = calcSourcePathForEntryPoints(endToEndReq, entryPointIndices); + options.sourceContentsPath = originalSourcePath; + SourceResult source; SLANG_RETURN_ON_FAIL(emitEntryPointsSource(slangRequest, entryPointIndices, targetReq, sourceTarget, endToEndReq, source)); - options.sourceContents = source.source; } + else + { + // Special case if we have a single file, so that we pass the path, and the contents + const auto& sourceFiles = translationUnit->getSourceFiles(); + SLANG_ASSERT(sourceFiles.getCount() == 1); + + const SourceFile* sourceFile = sourceFiles[0]; + + options.sourceContentsPath = sourceFile->getPathInfo().foundPath; + options.sourceContents = sourceFile->getContent(); + } } else { @@ -1435,36 +1195,44 @@ SlangResult dissassembleDXILUsingDXC( maybeDumpIntermediate(slangRequest, options.sourceContents.getBuffer(), sourceTarget); } + // Set the file sytem and source manager, as *may* be used by downstream compiler + options.fileSystemExt = slangRequest->getFileSystemExt(); + options.sourceManager = slangRequest->getSourceManager(); + // Set the source type options.sourceLanguage = SlangSourceLanguage(sourceLanguage); - + // Disable exceptions and security checks options.flags &= ~(CompileOptions::Flag::EnableExceptionHandling | CompileOptions::Flag::EnableSecurityChecks); - // Set what kind of target we should build - switch (targetReq->getTarget()) + if (downstreamCompiler == PassThroughMode::Fxc) { - case CodeGenTarget::HostCallable: - case CodeGenTarget::SharedLibrary: - { - options.targetType = DownstreamCompiler::TargetType::SharedLibrary; - break; - } - case CodeGenTarget::Executable: - { - options.targetType = DownstreamCompiler::TargetType::Executable; - break; - } - case CodeGenTarget::PTX: + if (entryPointIndices.getCount() != 1) { - // TODO(JS): Not clear what to do here. - // For example should 'Kernel' be distinct from 'Executable'. For now just use executable. - options.targetType = DownstreamCompiler::TargetType::Executable; - break; + // 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; } - default: break; + + const Index entryPointIndex = entryPointIndices[0]; + + auto entryPoint = program->getEntryPoint(entryPointIndex); + auto profile = getEffectiveProfile(entryPoint, targetReq); + + // Set the profile + options.profileName = GetHLSLProfileName(profile); + + options.entryPointName = getText(entryPoint->getName()); } + // For host callable we want downstream compile to produce a shared library + if (target == CodeGenTarget::HostCallable) + { + target = CodeGenTarget::SharedLibrary; + } + + options.targetType = (SlangCompileTarget)target; + // Need to configure for the compilation { @@ -1543,8 +1311,7 @@ SlangResult dissassembleDXILUsingDXC( options.pipelineType = DownstreamCompiler::PipelineType::RayTracing; break; } - } - + } } // Add all the search paths (as calculated earlier - they will only be set if this is a pass through else will be empty) @@ -1569,6 +1336,7 @@ SlangResult dissassembleDXILUsingDXC( const auto& diagnostics = downstreamCompileResult->getDiagnostics(); + if (diagnostics.diagnostics.getCount()) { StringBuilder compilerText; compiler->getDesc().appendAsText(compilerText); @@ -1631,6 +1399,52 @@ SlangResult dissassembleDXILUsingDXC( return SLANG_OK; } + SlangResult dissassembleWithDownstream( + BackEndCompileRequest* slangRequest, + CodeGenTarget target, + const void* data, + size_t dataSizeInBytes, + ISlangBlob** outBlob) + { + auto session = slangRequest->getSession(); + auto sink = slangRequest->getSink(); + + // Get the downstream compiler that can be used for this target + + // TODO(JS): + // This could perhaps be performed in some other manner if there was more than one way to produce + // disassembly from a binary. + auto downstreamCompiler = getDownstreamCompilerRequiredForTarget(target); + + // Get the required downstream compiler + DownstreamCompiler* compiler = session->getOrLoadDownstreamCompiler(downstreamCompiler, sink); + + if (!compiler) + { + auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)downstreamCompiler); + sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); + return SLANG_FAIL; + } + + ComPtr<ISlangBlob> dissassemblyBlob; + SLANG_RETURN_ON_FAIL(compiler->dissassemble(SlangCompileTarget(target), data, dataSizeInBytes, dissassemblyBlob.writeRef())); + + *outBlob = dissassemblyBlob.detach(); + return SLANG_OK; + } + + SlangResult dissassembleWithDownstream( + BackEndCompileRequest* slangRequest, + CodeGenTarget target, + DownstreamCompileResult* downstreamResult, + ISlangBlob** outBlob) + { + + ComPtr<ISlangBlob> codeBlob; + SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(codeBlob)); + return dissassembleWithDownstream(slangRequest, target, codeBlob->getBufferPointer(), codeBlob->getBufferSize(), outBlob); + } + SlangResult emitSPIRVForEntryPointsDirectly( BackEndCompileRequest* compileRequest, const List<Int>& entryPointIndices, @@ -1757,6 +1571,32 @@ SlangResult dissassembleDXILUsingDXC( switch (target) { + case CodeGenTarget::DXBytecodeAssembly: + { + RefPtr<DownstreamCompileResult> downstreamResult; + const CodeGenTarget intermediateTarget = CodeGenTarget::DXBytecode; + + if (SLANG_SUCCEEDED(emitWithDownstreamForEntryPoints( + program, + compileRequest, + entryPointIndices, + targetReq, + intermediateTarget, + endToEndReq, + downstreamResult))) + { + maybeDumpIntermediate(compileRequest, downstreamResult, target); + + ComPtr<ISlangBlob> disassemblyBlob; + if (SLANG_SUCCEEDED(dissassembleWithDownstream(compileRequest, intermediateTarget, downstreamResult, disassemblyBlob.writeRef()))) + { + // Return the disassembly blob + result = CompileResult(disassemblyBlob); + } + } + } + break; + case CodeGenTarget::DXBytecode: case CodeGenTarget::PTX: case CodeGenTarget::HostCallable: case CodeGenTarget::SharedLibrary: @@ -1765,14 +1605,15 @@ SlangResult dissassembleDXILUsingDXC( RefPtr<DownstreamCompileResult> downstreamResult; if (SLANG_SUCCEEDED(emitWithDownstreamForEntryPoints( + program, compileRequest, entryPointIndices, targetReq, + target, endToEndReq, downstreamResult))) { maybeDumpIntermediate(compileRequest, downstreamResult, target); - result = CompileResult(downstreamResult); } } @@ -1796,47 +1637,6 @@ SlangResult dissassembleDXILUsingDXC( } break; -#if SLANG_ENABLE_DXBC_SUPPORT - case CodeGenTarget::DXBytecode: - { - // Assert only one entry point case -- move out of this function - List<uint8_t> code; - auto entryPointIndex = assertSingleEntryPoint(entryPointIndices); - if (SLANG_SUCCEEDED(emitDXBytecodeForEntryPoint( - program, - compileRequest, - entryPointIndex, - targetReq, - endToEndReq, - code))) - { - maybeDumpIntermediate(compileRequest, code.getBuffer(), code.getCount(), target); - - result = CompileResult(ListBlob::moveCreate(code)); - } - } - break; - - case CodeGenTarget::DXBytecodeAssembly: - { - // Assert only one entry point case - String code; - auto entryPointIndex = assertSingleEntryPoint(entryPointIndices); - if (SLANG_SUCCEEDED(emitDXBytecodeAssemblyForEntryPoint( - program, - compileRequest, - entryPointIndex, - targetReq, - endToEndReq, - code))) - { - maybeDumpIntermediate(compileRequest, code.getBuffer(), target); - result = CompileResult(code); - } - } - break; -#endif - #if SLANG_ENABLE_DXIL_SUPPORT case CodeGenTarget::DXIL: { @@ -2098,16 +1898,24 @@ SlangResult dissassembleDXILUsingDXC( switch (targetReq->getTarget()) { - #if SLANG_ENABLE_DXBC_SUPPORT - case CodeGenTarget::DXBytecode: + case CodeGenTarget::DXBytecodeAssembly: { - String assembly; - dissassembleDXBC(backEndReq, blobData, blobSize, assembly); - writeOutputToConsole(writer, assembly); + const UnownedStringSlice disassembly = StringUtil::getSlice(blob); + writeOutputToConsole(writer, disassembly); } break; - #endif + case CodeGenTarget::DXBytecode: + { + ComPtr<ISlangBlob> disassemblyBlob; + if (SLANG_SUCCEEDED(dissassembleWithDownstream(backEndReq, targetReq->getTarget(), blobData, blobSize, disassemblyBlob.writeRef()))) + { + const UnownedStringSlice disassembly = StringUtil::getSlice(disassemblyBlob); + writeOutputToConsole(writer, disassembly); + } + } + break; + #if SLANG_ENABLE_DXIL_SUPPORT case CodeGenTarget::DXIL: { @@ -2675,7 +2483,6 @@ SlangResult dissassembleDXILUsingDXC( } break; - #if SLANG_ENABLE_DXBC_SUPPORT case CodeGenTarget::DXBytecodeAssembly: dumpIntermediateText(compileRequest, data, size, ".dxbc.asm"); break; @@ -2683,12 +2490,13 @@ SlangResult dissassembleDXILUsingDXC( case CodeGenTarget::DXBytecode: dumpIntermediateBinary(compileRequest, data, size, ".dxbc"); { - String dxbcAssembly; - dissassembleDXBC(compileRequest, data, size, dxbcAssembly); - dumpIntermediateText(compileRequest, dxbcAssembly.begin(), dxbcAssembly.getLength(), ".dxbc.asm"); + ComPtr<ISlangBlob> disassemblyBlob; + if (SLANG_SUCCEEDED(dissassembleWithDownstream(compileRequest, target, data, size, disassemblyBlob.writeRef()))) + { + dumpIntermediateText(compileRequest, disassemblyBlob->getBufferPointer(), disassemblyBlob->getBufferSize(), ".dxbc.asm"); + } } break; - #endif #if SLANG_ENABLE_DXIL_SUPPORT case CodeGenTarget::DXILAssembly: diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index e57c1683a..52f3b9465 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -8,6 +8,7 @@ #include "../compiler-core/slang-downstream-compiler.h" #include "../compiler-core/slang-name.h" +#include "../compiler-core/slang-include-system.h" #include "../core/slang-std-writers.h" @@ -21,7 +22,6 @@ #include "slang-syntax.h" -#include "slang-include-system.h" #include "slang-serialize-ir-types.h" @@ -76,6 +76,7 @@ namespace Slang HostCallable = SLANG_HOST_CALLABLE, CUDASource = SLANG_CUDA_SOURCE, PTX = SLANG_PTX, + ObjectCode = SLANG_OBJECT_CODE, CountOf = SLANG_TARGET_COUNT_OF, }; @@ -2229,8 +2230,6 @@ namespace Slang { Glslang_Compile_1_0, Glslang_Compile_1_1, - Fxc_D3DCompile, - Fxc_D3DDisassemble, Dxc_DxcCreateInstance, CountOf, }; diff --git a/source/slang/slang-preprocessor.h b/source/slang/slang-preprocessor.h index 9de82b9f2..9f3940d29 100644 --- a/source/slang/slang-preprocessor.h +++ b/source/slang/slang-preprocessor.h @@ -5,8 +5,7 @@ #include "../core/slang-basic.h" #include "../compiler-core/slang-lexer.h" - -#include "slang-include-system.h" +#include "../compiler-core/slang-include-system.h" namespace Slang { |
