diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-04-26 12:09:32 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-26 12:09:32 -0400 |
| commit | 79dd12c21e8f5c5ce01051a280679cf6ac8ffe97 (patch) | |
| tree | 705df0ab9047e4418a6218993cd0ddb2a46dffbc /source | |
| parent | 66ad0072821b58318c6dc5d2d64c966e312951dd (diff) | |
Linking in DXC (#2190)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Compile to a dxil library.
* Added CompileProduct.
* Support handling of ModuleLibrary.
* CacheBehavior -> Cache
* Use CompileProduct for -r references.
* CompileProduct -> Artifact.
* Determining an artifact type on binding.
* Determine binary linkability.
* Added Artifact::exists.
* Added ArtifactKeep.
* Small fixes.
* Small improvements to Artifact.
* Add zip extension.
* Fix some comments.
* Fix multiple adding of PublicDecoration.
Make public output export for DXIL/lib.
Add checking for simpleDecorations such that only added once.
* Use 'whole program' to identify library build.
* Move slang-artifact into compiler-core.
* Split out Keep free functions.
* Artifact::Keep -> ArtifactKeep.
* Handle libraries as artifacts.
* Add -target dxil so test infrastructure knows it needs DXC.
* Linking working in DXC.
* Improve handling around emit for 'export'.
* Add comment around Artifact name.
* Render test working with linking.
Co-authored-by: Theresa Foley <10618364+tangent-vector@users.noreply.github.com>
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-artifact.cpp (renamed from source/slang/slang-artifact.cpp) | 135 | ||||
| -rw-r--r-- | source/compiler-core/slang-artifact.h (renamed from source/slang/slang-artifact.h) | 64 | ||||
| -rw-r--r-- | source/compiler-core/slang-downstream-compiler.h | 4 | ||||
| -rw-r--r-- | source/compiler-core/slang-dxc-compiler.cpp | 236 | ||||
| -rw-r--r-- | source/compiler-core/slang-gcc-compiler-util.cpp | 51 | ||||
| -rw-r--r-- | source/compiler-core/slang-visual-studio-compiler-util.cpp | 14 | ||||
| -rw-r--r-- | source/core/slang-command-line.cpp | 11 | ||||
| -rw-r--r-- | source/slang/slang-compiler.cpp | 11 | ||||
| -rw-r--r-- | source/slang/slang-emit-hlsl.cpp | 13 | ||||
| -rw-r--r-- | source/slang/slang-ir-link.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-module-library.cpp | 95 | ||||
| -rw-r--r-- | source/slang/slang-module-library.h | 28 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 6 |
14 files changed, 481 insertions, 195 deletions
diff --git a/source/slang/slang-artifact.cpp b/source/compiler-core/slang-artifact.cpp index 770f2202a..5d9f8692c 100644 --- a/source/slang/slang-artifact.cpp +++ b/source/compiler-core/slang-artifact.cpp @@ -1,15 +1,8 @@ // slang-artifact.cpp #include "slang-artifact.h" -#include <assert.h> - -#include "../core/slang-blob.h" -#include "../core/slang-riff.h" #include "../core/slang-type-text-util.h" - -// Serialization -#include "slang-serialize-ir.h" -#include "slang-serialize-container.h" +#include "../core/slang-io.h" namespace Slang { @@ -70,41 +63,41 @@ static const KindExtension g_cpuKindExts[] = } } - const auto target = (CodeGenTarget)TypeTextUtil::findCompileTargetFromExtension(slice); + const auto target = TypeTextUtil::findCompileTargetFromExtension(slice); - return make(target); + return makeFromCompileTarget(target); } -/* static */ArtifactDesc ArtifactDesc::make(CodeGenTarget target) +/* static */ArtifactDesc ArtifactDesc::makeFromCompileTarget(SlangCompileTarget target) { switch (target) { - case CodeGenTarget::Unknown: return make(Kind::Unknown, Payload::None, Style::Unknown, 0); - case CodeGenTarget::None: return make(Kind::None, Payload::None, Style::Unknown, 0); - case CodeGenTarget::GLSL_Vulkan: - case CodeGenTarget::GLSL_Vulkan_OneDesc: - case CodeGenTarget::GLSL: + case SLANG_TARGET_UNKNOWN: return make(Kind::Unknown, Payload::None, Style::Unknown, 0); + case SLANG_TARGET_NONE: return make(Kind::None, Payload::None, Style::Unknown, 0); + case SLANG_GLSL_VULKAN: + case SLANG_GLSL_VULKAN_ONE_DESC: + case SLANG_GLSL: { // For the moment we make all just map to GLSL, but we could use flags // or some other mechanism to distinguish the types return make(Kind::Text, Payload::GLSL, Style::Kernel, 0); } - case CodeGenTarget::HLSL: return make(Kind::Text, Payload::HLSL, Style::Kernel, 0); - case CodeGenTarget::SPIRV: return make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); - case CodeGenTarget::SPIRVAssembly: return make(Kind::Text, Payload::SPIRVAssembly, Style::Kernel, 0); - case CodeGenTarget::DXBytecode: return make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); - case CodeGenTarget::DXBytecodeAssembly: return make(Kind::Text, Payload::DXBCAssembly, Style::Kernel, 0); - case CodeGenTarget::DXIL: return make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); - case CodeGenTarget::DXILAssembly: return make(Kind::Text, Payload::DXILAssembly, Style::Kernel, 0); - case CodeGenTarget::CSource: return make(Kind::Text, Payload::C, Style::Kernel, 0); - case CodeGenTarget::CPPSource: return make(Kind::Text, Payload::CPP, Style::Kernel, 0); - case CodeGenTarget::HostCPPSource: return make(Kind::Text, Payload::CPP, Style::Host, 0); - case CodeGenTarget::HostExecutable: return make(Kind::Executable, Payload::HostCPU, Style::Host, 0); - case CodeGenTarget::ShaderSharedLibrary: return make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); - case CodeGenTarget::ShaderHostCallable: return make(Kind::Callable, Payload::HostCPU, Style::Kernel, 0); - case CodeGenTarget::CUDASource: return make(Kind::Text, Payload::CUDA, Style::Kernel, 0); - case CodeGenTarget::PTX: return make(Kind::Executable, Payload::PTX, Style::Kernel, 0); - case CodeGenTarget::ObjectCode: return make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); + case SLANG_HLSL: return make(Kind::Text, Payload::HLSL, Style::Kernel, 0); + case SLANG_SPIRV: return make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); + case SLANG_SPIRV_ASM: return make(Kind::Text, Payload::SPIRVAssembly, Style::Kernel, 0); + case SLANG_DXBC: return make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); + case SLANG_DXBC_ASM: return make(Kind::Text, Payload::DXBCAssembly, Style::Kernel, 0); + case SLANG_DXIL: return make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); + case SLANG_DXIL_ASM: return make(Kind::Text, Payload::DXILAssembly, Style::Kernel, 0); + case SLANG_C_SOURCE: return make(Kind::Text, Payload::C, Style::Kernel, 0); + case SLANG_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Kernel, 0); + case SLANG_HOST_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Host, 0); + case SLANG_HOST_EXECUTABLE: return make(Kind::Executable, Payload::HostCPU, Style::Host, 0); + case SLANG_SHADER_SHARED_LIBRARY: return make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); + case SLANG_SHADER_HOST_CALLABLE: return make(Kind::Callable, Payload::HostCPU, Style::Kernel, 0); + case SLANG_CUDA_SOURCE: return make(Kind::Text, Payload::CUDA, Style::Kernel, 0); + case SLANG_PTX: return make(Kind::Executable, Payload::PTX, Style::Kernel, 0); + case SLANG_OBJECT_CODE: return make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); default: break; } @@ -463,82 +456,4 @@ SlangResult Artifact::loadBlob(Keep keep, ComPtr<ISlangBlob>& outBlob) return SLANG_OK; } -SlangResult loadModuleLibrary(const Byte* inBytes, size_t bytesCount, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& outLibrary) -{ - RefPtr<ModuleLibrary> library = new ModuleLibrary; - - // Load up the module - MemoryStreamBase memoryStream(FileAccess::Read, inBytes, bytesCount); - - RiffContainer riffContainer; - SLANG_RETURN_ON_FAIL(RiffUtil::read(&memoryStream, riffContainer)); - - auto linkage = req->getLinkage(); - - // TODO(JS): May be better to have a ITypeComponent that encapsulates a collection of modules - // For now just add to the linkage - - { - SerialContainerData containerData; - - SerialContainerUtil::ReadOptions options; - options.namePool = req->getNamePool(); - options.session = req->getSession(); - options.sharedASTBuilder = linkage->getASTBuilder()->getSharedASTBuilder(); - options.sourceManager = linkage->getSourceManager(); - options.linkage = req->getLinkage(); - options.sink = req->getSink(); - - SLANG_RETURN_ON_FAIL(SerialContainerUtil::read(&riffContainer, options, containerData)); - - for (const auto& module : containerData.modules) - { - // If the irModule is set, add it - if (module.irModule) - { - library->m_modules.add(module.irModule); - } - } - - for (const auto& entryPoint : containerData.entryPoints) - { - FrontEndCompileRequest::ExtraEntryPointInfo dst; - dst.mangledName = entryPoint.mangledName; - dst.name = entryPoint.name; - dst.profile = entryPoint.profile; - - // Add entry point - library->m_entryPoints.add(dst); - } - } - - outLibrary = library; - return SLANG_OK; -} - -SlangResult loadModuleLibrary(Artifact::Keep keep, Artifact* product, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& outLibrary) -{ - if (auto foundLibrary = product->findObjectInstance<ModuleLibrary>()) - { - outLibrary = foundLibrary; - return SLANG_OK; - } - - // Load the blob - ComPtr<ISlangBlob> blob; - SLANG_RETURN_ON_FAIL(product->loadBlob(Artifact::getIntermediateKeep(keep), blob)); - - // Load the module - RefPtr<ModuleLibrary> library; - SLANG_RETURN_ON_FAIL(loadModuleLibrary((const Byte*)blob->getBufferPointer(), blob->getBufferSize(), req, library)); - - if (Artifact::canKeep(keep)) - { - product->add(Artifact::Entry::Style::Artifact, library); - } - - outLibrary = library; - return SLANG_OK; -} - } // namespace Slang diff --git a/source/slang/slang-artifact.h b/source/compiler-core/slang-artifact.h index 0e009e990..232e9a8eb 100644 --- a/source/slang/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -2,7 +2,10 @@ #ifndef SLANG_ARTIFACT_H #define SLANG_ARTIFACT_H -#include "slang-compiler.h" +#include "../core/slang-basic.h" + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" namespace Slang { @@ -88,6 +91,14 @@ struct ArtifactFlag }; }; +// Controls what items can be kept. +enum class ArtifactKeep +{ + No, ///< Don't keep the item + Yes, ///< Yes keep the final item + All, ///< Keep the final item and any intermediataries +}; + /** A value type to describe aspects of the contents of an Artifact. @@ -143,7 +154,7 @@ public: bool operator!=(const This& rhs) const { return !(*this == rhs); } /// Given a code gen target, get the equivalent ArtifactDesc - static This make(CodeGenTarget target); + static This makeFromCompileTarget(SlangCompileTarget target); /// Construct from the elements static This make(Kind inKind, Payload inPayload, Style inStyle = Style::Kernel, Flags flags = 0) @@ -211,7 +222,15 @@ A more long term goal would be to * Make Artifact an interface (such that it can work long term over binary boundaries) * Make Diagnostics into an interface (such it can be added to a Artifact result) -* Use Artifact and related types for downstream compiler +* Use Artifact and related types for downstream compiler + +TODO(JS): There is an issue here around libraries in that downstream compilers can use +named libraries, but the name doesn't directly relate to a file. If it is a file it may +not be easily possible to determine it's location. So there is a desire to indicate the +`name` as opposed to the path. + +As a second related issue. Lets say we have a blob (and not a file). + */ class Artifact : public RefObject { @@ -223,15 +242,8 @@ public: typedef ArtifactPayload Payload; typedef ArtifactStyle Style; typedef ArtifactFlags Flags; - - // Controls what items can be kept. - enum class Keep - { - No, ///< Don't keep the item - Yes, ///< Yes keep the final item - All, ///< Keep the final item and any intermediataries - }; - + typedef ArtifactKeep Keep; + enum PathType { None, @@ -304,14 +316,6 @@ public: const List<Entry>& getEntries() const { return m_entries; } - /// True if can keep an intermediate item - static bool canKeepIntermediate(Keep keep) { return keep == Keep::All; } - /// True if can keep - static bool canKeep(Keep keep) { return Index(keep) >= Index(Keep::Yes); } - - /// Returns the keep type for an intermediate - static Keep getIntermediateKeep(Keep keep) { return (keep == Keep::All) ? Keep::All : Keep::No; } - /// Ctor Artifact(const Desc& desc) :m_desc(desc) {} /// Dtor @@ -350,20 +354,12 @@ T* Artifact::findObjectInstance() return nullptr; } - -// Class to hold information serialized in from a -r slang-lib/slang-module -class ModuleLibrary : public RefObject -{ -public: - - List<FrontEndCompileRequest::ExtraEntryPointInfo> m_entryPoints; - List<RefPtr<IRModule>> m_modules; -}; - -SlangResult loadModuleLibrary(const Byte* inBytes, size_t bytesCount, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& module); - -// Given a product make available as a module -SlangResult loadModuleLibrary(Artifact::Keep keep, Artifact* artifact, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& module); +/// True if can keep an intermediate item +SLANG_INLINE bool canKeepIntermediate(ArtifactKeep keep) { return keep == ArtifactKeep::All; } + /// True if can keep +SLANG_INLINE bool canKeep(ArtifactKeep keep) { return Index(keep) >= Index(ArtifactKeep::Yes); } + /// Returns the keep type for an intermediate +SLANG_INLINE ArtifactKeep getIntermediateKeep(ArtifactKeep keep) { return (keep == ArtifactKeep::All) ? ArtifactKeep::All : ArtifactKeep::No; } } // namespace Slang diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index e40ffc13a..e6c1f7a40 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -13,6 +13,8 @@ #include "../../slang-com-ptr.h" +#include "slang-artifact.h" + namespace Slang { @@ -303,7 +305,7 @@ public: List<String> libraryPaths; /// Libraries to link against. - List<String> libraries; + List<RefPtr<Artifact>> libraries; List<CapabilityVersion> requiredCapabilityVersions; diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp index f5db290b1..eb26dd3cc 100644 --- a/source/compiler-core/slang-dxc-compiler.cpp +++ b/source/compiler-core/slang-dxc-compiler.cpp @@ -50,6 +50,52 @@ static UnownedStringSlice _getSlice(IDxcBlob* blob) { return StringUtil::getSlic // 7f61fc7d-950d-467f-b3e3-3c02fb49187c static const Guid IID_IDxcIncludeHandler = { 0x7f61fc7d, 0x950d, 0x467f, { 0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c } }; +namespace { // anonymous + +class LibraryNameList +{ +public: + void addName(Artifact* library) + { + String name; + if (library->getPathType() == Artifact::Existing) + { + name = Path::getFileNameWithoutExt(library->getPath()); + } + addName(name); + } + void addName(const String& inName) + { + String name(inName); + if (name.getLength() == 0) + { + name = "unnamed"; + } + + if (m_names.indexOf(name) >= 0) + { + StringBuilder buf; + for (Index i = 1; ; ++i) + { + buf.Clear(); + buf << name << "_" << i; + + if (m_names.indexOf(buf) < 0) + { + name = buf; + break; + } + } + } + + m_names.add(name); + } + + List<String> m_names; +}; + +} // anonymous + class DxcIncludeHandler : public IDxcIncludeHandler { public: @@ -137,6 +183,8 @@ public: protected: DxcCreateInstanceProc m_createInstance = nullptr; + + ComPtr<ISlangSharedLibrary> m_sharedLibrary; }; @@ -183,6 +231,60 @@ static SlangResult _parseDiagnosticLine(const UnownedStringSlice& line, List<Uno return SLANG_OK; } +static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, DownstreamDiagnostics& ioDiagnostics, ComPtr<IDxcBlob>& outBlob) +{ + // Retrieve result. + HRESULT resultCode = S_OK; + SLANG_RETURN_ON_FAIL(dxcResult->GetStatus(&resultCode)); + + // Note: it seems like the dxcompiler interface + // doesn't support querying diagnostic output + // *unless* the compile failed (no way to get + // warnings out!?). + + if (SLANG_SUCCEEDED(ioDiagnostics.result)) + { + ioDiagnostics.result = resultCode; + } + + // Try getting the error/diagnostics blob + ComPtr<IDxcBlobEncoding> dxcErrorBlob; + dxcResult->GetErrorBuffer(dxcErrorBlob.writeRef()); + + if (dxcErrorBlob) + { + const UnownedStringSlice diagnosticsSlice = _getSlice(dxcErrorBlob); + if (diagnosticsSlice.getLength()) + { + if (ioDiagnostics.rawDiagnostics.getLength() > 0) + { + ioDiagnostics.rawDiagnostics.append("\n"); + } + ioDiagnostics.rawDiagnostics.append(diagnosticsSlice); + + SlangResult diagnosticParseRes = DownstreamDiagnostic::parseColonDelimitedDiagnostics(diagnosticsSlice, 0, _parseDiagnosticLine, ioDiagnostics.diagnostics); + + SLANG_UNUSED(diagnosticParseRes); + SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); + } + } + + // If it failed, make sure we have an error in the diagnostics + if (SLANG_FAILED(resultCode)) + { + // In case the parsing failed, we still have an error -> so require there is one in the diagnostics + ioDiagnostics.requireErrorDiagnostic(); + } + else + { + // Okay, the compile supposedly succeeded, so we + // just need to grab the buffer with the output DXIL. + SLANG_RETURN_ON_FAIL(dxcResult->GetResult(outBlob.writeRef())); + } + + return SLANG_OK; +} + SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) { // This compiler doesn't read files, they should be read externally and stored in sourceContents/sourceContentsPath @@ -197,6 +299,22 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr return SLANG_FAIL; } + // Find all of the libraries + List<Artifact*> libraries; + for (Artifact* library : options.libraries) + { + const auto desc = library->getDesc(); + + if (desc.kind == ArtifactKind::Library && desc.payload == ArtifactPayload::DXIL) + { + // Make sure they all have blobs + ComPtr<ISlangBlob> libraryBlob; + SLANG_RETURN_ON_FAIL(library->loadBlob(ArtifactKeep::Yes, libraryBlob)); + + libraries.add(library); + } + } + ComPtr<IDxcCompiler> dxcCompiler; SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef())); ComPtr<IDxcLibrary> dxcLibrary; @@ -289,8 +407,28 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr // args.add(L"-no-warnings"); + String profileName = options.profileName; + // If we are going to link we have to compile in the lib profile style + if (libraries.getCount()) + { + if (!profileName.startsWith("lib")) + { + const Index index = profileName.indexOf('_'); + if (index < 0) + { + profileName = "lib_6_3"; + } + else + { + StringBuilder buf; + buf << "lib" << profileName.getUnownedSlice().tail(index); + profileName = buf; + } + } + } + OSString wideEntryPointName = options.entryPointName.toWString(); - OSString wideProfileName = options.profileName.toWString(); + OSString wideProfileName = profileName.toWString(); if (options.flags & CompileOptions::Flag::EnableFloat16) { @@ -319,50 +457,80 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, RefPtr &includeHandler, // `#include` handler dxcResult.writeRef())); - // Retrieve result. - HRESULT resultCode = S_OK; - SLANG_RETURN_ON_FAIL(dxcResult->GetStatus(&resultCode)); - - // Note: it seems like the dxcompiler interface - // doesn't support querying diagnostic output - // *unless* the compile failed (no way to get - // warnings out!?). - DownstreamDiagnostics diagnostics; - diagnostics.result = resultCode; - // Try getting the error/diagnostics blob - ComPtr<IDxcBlobEncoding> dxcErrorBlob; - dxcResult->GetErrorBuffer(dxcErrorBlob.writeRef()); + ComPtr<IDxcBlob> dxcResultBlob; - if (dxcErrorBlob) + SLANG_RETURN_ON_FAIL(_handleOperationResult(dxcResult, diagnostics, dxcResultBlob)); + + // If we have libraries then we need to link... + if (libraries.getCount()) { - const UnownedStringSlice diagnosticsSlice = _getSlice(dxcErrorBlob); - if (diagnosticsSlice.getLength()) + ComPtr<IDxcLinker> linker; + SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLinker, __uuidof(linker), (void**)linker.writeRef())); + + List<ComPtr<ISlangBlob>> libraryBlobs; + + LibraryNameList libraryNames; + + for (Artifact* library : libraries) { - diagnostics.rawDiagnostics = String(diagnosticsSlice); + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(library->loadBlob(ArtifactKeep::Yes, blob)); - SlangResult diagnosticParseRes = DownstreamDiagnostic::parseColonDelimitedDiagnostics(diagnosticsSlice, 0, _parseDiagnosticLine, diagnostics.diagnostics); + libraryBlobs.add(blob); + libraryNames.addName(library); + } - SLANG_UNUSED(diagnosticParseRes); - SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); + // Add the compiled blob name + + { + auto blob = (ISlangBlob*)dxcResultBlob.get(); + libraryBlobs.add(ComPtr<ISlangBlob>(blob)); } - } - ComPtr<IDxcBlob> dxcResultBlob; + if (options.modulePath.getLength()) + { + libraryNames.addName(Path::getFileNameWithoutExt(options.modulePath)); + } + else if (options.sourceContentsPath.getLength()) + { + libraryNames.addName(Path::getFileNameWithoutExt(options.sourceContentsPath)); + } + else + { + libraryNames.addName(""); + } - // If it failed, make sure we have an error in the diagnostics - if (SLANG_FAILED(resultCode)) - { - // In case the parsing failed, we still have an error -> so require there is one in the diagnostics - diagnostics.requireErrorDiagnostic(); + const Index librariesCount = libraryNames.m_names.getCount(); + SLANG_ASSERT(libraryBlobs.getCount() == librariesCount); + + List<const wchar_t*> linkLibraryNames; + List<OSString> wideLibraryNames; + + linkLibraryNames.setCount(librariesCount); + wideLibraryNames.setCount(librariesCount); + + for (Index i = 0; i < librariesCount; ++i) + { + wideLibraryNames[i] = libraryNames.m_names[i].toWString(); + linkLibraryNames[i] = wideLibraryNames[i].begin(); + + // Register the library + SLANG_RETURN_ON_FAIL(linker->RegisterLibrary(linkLibraryNames[i], (IDxcBlob*)libraryBlobs[i].get())); + } + + // Use the original profile name + wideProfileName = options.profileName.toWString(); + + ComPtr<IDxcOperationResult> linkDxcResult; + SLANG_RETURN_ON_FAIL(linker->Link(wideEntryPointName.begin(), wideProfileName.begin(), linkLibraryNames.getBuffer(), UINT32(librariesCount), nullptr, 0, linkDxcResult.writeRef())); + + ComPtr<IDxcBlob> linkedBlob; + SLANG_RETURN_ON_FAIL(_handleOperationResult(linkDxcResult, diagnostics, linkedBlob)); + + dxcResultBlob = linkedBlob; } - else - { - // Okay, the compile supposedly succeeded, so we - // just need to grab the buffer with the output DXIL. - SLANG_RETURN_ON_FAIL(dxcResult->GetResult(dxcResultBlob.writeRef())); - } outResult = new BlobDownstreamCompileResult(diagnostics, (ISlangBlob*)dxcResultBlob.get()); return SLANG_OK; diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 8d1b87b68..7d1b7b86a 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -619,6 +619,56 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse cmdLine.addArg(sourceFile); } + // Add the library paths + List<String> libraryPaths; + libraryPaths.addRange(options.libraryPaths.getBuffer(), options.libraryPaths.getCount()); + + // Artifacts might add library paths + for (Artifact* artifact : options.libraries) + { + const auto desc = artifact->getDesc(); + // If it's a library for CPU types, try and use it + if (desc.isCpuBinary()) + { + if (desc.kind == ArtifactKind::Library) + { + String path; + SLANG_RETURN_ON_FAIL(artifact->requireFilePath(ArtifactKeep::No, path)); + + String parentDir = Path::getParentDirectory(parentDir); + if (parentDir.getLength()) + { + // Check if we already have the library path, only add it if it's not found + if (libraryPaths.indexOf(parentDir) < 0) + { + libraryPaths.add(parentDir); + } + path = Path::getFileName(path); + } + + // If it starts with lib strip it + if (path.startsWith("lib")) + { + const String stripLib = path.getUnownedSlice().tail(3); + path = stripLib; + } + + // Strip the extension if it's a match + auto extension = Path::getPathExt(path); + if (extension.getLength()) + { + auto libExt = ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::HostCPU).getDefaultExtension(); + if (extension == libExt) + { + path = Path::getFileNameWithoutExt(path); + } + } + + cmdLine.addPrefixPathArg("-l", path); + } + } + } + for (const auto& libPath : options.libraryPaths) { // Note that any escaping of the path is handled in the ProcessUtil:: @@ -628,6 +678,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse cmdLine.addArg(libPath); } + if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind)) { // Make STD libs available diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index 2ba69c1ce..df64ed821 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -257,9 +257,19 @@ namespace Slang } // Link libraries. - for (const auto& lib : options.libraries) + for (Artifact* artifact : options.libraries) { - cmdLine.addPrefixPathArg("", lib, ".lib"); + if (artifact->getDesc().isCpuBinary()) + { + String path; + SLANG_RETURN_ON_FAIL(artifact->requireFilePath(ArtifactKeep::No, path)); + + if (Path::getPathExt(path).getLength() == 0) + { + path.append(".lib"); + } + cmdLine.addArg(path); + } } return SLANG_OK; diff --git a/source/core/slang-command-line.cpp b/source/core/slang-command-line.cpp index 973bb46d0..f8b5ff10f 100644 --- a/source/core/slang-command-line.cpp +++ b/source/core/slang-command-line.cpp @@ -71,7 +71,16 @@ void ExecutableLocation::append(StringBuilder& out) const void CommandLine::addPrefixPathArg(const char* prefix, const String& path, const char* pathPostfix) { StringBuilder builder; - builder << prefix << path; + builder << prefix; + + // TODO(JS): The assumption here is that quoting will be added as necessary and + // -prefixSomething Else + // is okay as + // "-prefixSomething Else" rather than + // -prefix"Something Else" + + builder << path; + if (pathPostfix) { // Work out the path with the postfix diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 881194bcb..789103ff8 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -1285,7 +1285,13 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) if (_isCPUHostTarget(target)) { options.libraryPaths.add(Path::getParentDirectory(Path::getExecutablePath())); - options.libraries.add("slang-rt"); + + // Set up the library artifact + const ArtifactDesc desc = ArtifactDesc::make(ArtifactKind::Library, Artifact::Payload::HostCPU, ArtifactStyle::Unknown); + RefPtr<Artifact> artifact = new Artifact(desc); + artifact->setPath(Artifact::PathType::Existing, "slang-rt"); + + options.libraries.add(artifact); } } @@ -1386,6 +1392,9 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) options.defines.add(define); } } + + // Add all of the module libraries + options.libraries.addRange(linkage->m_libModules.getBuffer(), linkage->m_libModules.getCount()); } // Compile diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 059a3f641..03566f9df 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -739,14 +739,11 @@ void HLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) const auto stage = profile.getStage(); const auto version = profile.getVersion(); - // I would perhaps ideally know that this was being compiled for 'library' stage. - // Stage::Unknown is currently also used for lib profiles. - - // TODO(JS): Potentially can do export for fxc too, but for now we don't add. - - if (family == ProfileFamily::DX && - version >= ProfileVersion::DX_6_1 && - stage == Stage::Unknown) + // If it's whole program and it's for a late enough version of shader model + // output with 'export' + if (getTargetReq()->isWholeProgramRequest() && + family == ProfileFamily::DX && + version >= ProfileVersion::DX_6_1) { m_writer->emit("export\n"); } diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index b03d48764..fd91d81bb 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -6,7 +6,10 @@ #include "slang-ir-insts.h" #include "slang-mangle.h" #include "slang-ir-string-hash.h" -#include "slang-artifact.h" + +#include "slang-module-library.h" + +#include "../compiler-core/slang-artifact.h" namespace Slang { diff --git a/source/slang/slang-module-library.cpp b/source/slang/slang-module-library.cpp new file mode 100644 index 000000000..76bb85ebb --- /dev/null +++ b/source/slang/slang-module-library.cpp @@ -0,0 +1,95 @@ +// slang-module-library.cpp +#include "slang-module-library.h" +#include <assert.h> + +#include "../core/slang-blob.h" +#include "../core/slang-riff.h" + +#include "../core/slang-type-text-util.h" + +// Serialization +#include "slang-serialize-ir.h" +#include "slang-serialize-container.h" + +namespace Slang { + + +SlangResult loadModuleLibrary(const Byte* inBytes, size_t bytesCount, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& outLibrary) +{ + RefPtr<ModuleLibrary> library = new ModuleLibrary; + + // Load up the module + MemoryStreamBase memoryStream(FileAccess::Read, inBytes, bytesCount); + + RiffContainer riffContainer; + SLANG_RETURN_ON_FAIL(RiffUtil::read(&memoryStream, riffContainer)); + + auto linkage = req->getLinkage(); + + // TODO(JS): May be better to have a ITypeComponent that encapsulates a collection of modules + // For now just add to the linkage + + { + SerialContainerData containerData; + + SerialContainerUtil::ReadOptions options; + options.namePool = req->getNamePool(); + options.session = req->getSession(); + options.sharedASTBuilder = linkage->getASTBuilder()->getSharedASTBuilder(); + options.sourceManager = linkage->getSourceManager(); + options.linkage = req->getLinkage(); + options.sink = req->getSink(); + + SLANG_RETURN_ON_FAIL(SerialContainerUtil::read(&riffContainer, options, containerData)); + + for (const auto& module : containerData.modules) + { + // If the irModule is set, add it + if (module.irModule) + { + library->m_modules.add(module.irModule); + } + } + + for (const auto& entryPoint : containerData.entryPoints) + { + FrontEndCompileRequest::ExtraEntryPointInfo dst; + dst.mangledName = entryPoint.mangledName; + dst.name = entryPoint.name; + dst.profile = entryPoint.profile; + + // Add entry point + library->m_entryPoints.add(dst); + } + } + + outLibrary = library; + return SLANG_OK; +} + +SlangResult loadModuleLibrary(ArtifactKeep keep, Artifact* product, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& outLibrary) +{ + if (auto foundLibrary = product->findObjectInstance<ModuleLibrary>()) + { + outLibrary = foundLibrary; + return SLANG_OK; + } + + // Load the blob + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(product->loadBlob(getIntermediateKeep(keep), blob)); + + // Load the module + RefPtr<ModuleLibrary> library; + SLANG_RETURN_ON_FAIL(loadModuleLibrary((const Byte*)blob->getBufferPointer(), blob->getBufferSize(), req, library)); + + if (canKeep(keep)) + { + product->add(Artifact::Entry::Style::Artifact, library); + } + + outLibrary = library; + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/slang/slang-module-library.h b/source/slang/slang-module-library.h new file mode 100644 index 000000000..dc709a684 --- /dev/null +++ b/source/slang/slang-module-library.h @@ -0,0 +1,28 @@ +// slang-module-library.h +#ifndef SLANG_MODULE_LIBRARY_H +#define SLANG_MODULE_LIBRARY_H + +#include "../compiler-core/slang-artifact.h" + +#include "slang-compiler.h" + +namespace Slang +{ + +// Class to hold information serialized in from a -r slang-lib/slang-module +class ModuleLibrary : public RefObject +{ +public: + + List<FrontEndCompileRequest::ExtraEntryPointInfo> m_entryPoints; + List<RefPtr<IRModule>> m_modules; +}; + +SlangResult loadModuleLibrary(const Byte* inBytes, size_t bytesCount, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& module); + +// Given a product make available as a module +SlangResult loadModuleLibrary(ArtifactKeep keep, Artifact* artifact, EndToEndCompileRequest* req, RefPtr<ModuleLibrary>& module); + +} // namespace Slang + +#endif diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index d4199154f..4c7234753 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -9,7 +9,8 @@ #include "slang-compiler.h" #include "slang-profile.h" -#include "slang-artifact.h" + +#include "../compiler-core/slang-artifact.h" #include "slang-repro.h" #include "slang-serialize-ir.h" diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 5d4e61cc0..5b65cd15a 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -7,7 +7,9 @@ #include "../core/slang-type-text-util.h" #include "../core/slang-type-convert-util.h" -#include "slang-artifact.h" +#include "../compiler-core/slang-artifact.h" + +#include "slang-module-library.h" #include "slang-check.h" #include "slang-parameter-binding.h" @@ -4335,7 +4337,7 @@ SlangResult _addLibraryReference(EndToEndCompileRequest* req, Artifact* artifact { RefPtr<ModuleLibrary> library; - SLANG_RETURN_ON_FAIL(loadModuleLibrary(Artifact::Keep::Yes, artifact, req, library)); + SLANG_RETURN_ON_FAIL(loadModuleLibrary(ArtifactKeep::Yes, artifact, req, library)); FrontEndCompileRequest* frontEndRequest = req->getFrontEndReq(); frontEndRequest->m_extraEntryPoints.addRange(library->m_entryPoints.getBuffer(), library->m_entryPoints.getCount()); |
