diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-08-16 16:12:45 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-16 13:12:45 -0700 |
| commit | 42de00db3ffe07599fff6d47d0d7228181ee3082 (patch) | |
| tree | 84367b359cd2701212214379d4d604488c4fac91 /source | |
| parent | ac71724c03392b429e44641a3641b2bcf7cc55fc (diff) | |
Move metadata/diagnostics to associated types (#2358)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP with hierarchical enums.
* Some small fixes and improvements around artifact desc related types.
* Improvements around hierarchical enum.
* Fixes to get Artifact types refactor to be able to execute tests.
* Attempt to better categorize PTX.
* Work around for potentially unused function warning.
* Typo fix.
* Simplify Artifact header.
* Small improvements around Artifact kind/payload/style.
* Added IDestroyable/ICastable
* Add IArtifactList.
* First impl of IArtifactUtil.
* Use the ICastable interface for IArtifactRepresentation.
* Added IArtifactRepresentation & IArtifactAssociated.
* Add SLANG_OVERRIDE to avoid gcc/clang warning.
* Fix calling convention issue on win32.
* Fix missing SLANG_OVERRIDE.
* First attempt at file abstraction around Artifact.
* Added creation of lock file.
* Move functionality for determining file paths to the IArtifactUtil.
Add casting to ICastable.
* Added some casting/finding mechanisms.
* Simplify IArtifact interface, and use Items for file reps.
* Fix problem with libraries on DXIL.
* Split out ArtifactRepresentation.
* Move ArtifactDesc functionality to ArtifactDescUtil. ArtifactInfoUtil becomes ArtifactDescUtil.
* Split implementations from the interfaces for Artifact.
* Use TypeTextUtil for target name outputting.
* Add artifact impls.
* Add ICastableList
* Added UnknownCastableAdapter
* Make ISlangSharedLibrary derive from ICastable, and remain backwards compatible with slang-llvm.
* Refactor Representation on Artifact.
* Make our ISlangBlobs also derive from ICastable.
Make ISlangBlob atomic ref counted.
* Split out CastableList and related types, and placed in core.
* Small fixes around IArtifact.
Improve IArtifact docs.
First impl of getChildren for IArtifact.
* Documentation improvements for Artifact related types.
* Fix typo.
* Special case adding a ICastableList to a LazyCastableList.
* Small simplification of LazyCastableList, by adding State member.
* Removed the ILockFile interface because IFileArtifactRepresentation can be used.
* Implement DiagnosticsArtifactRepresentation.
* Added PostEmitMetadataArtifactRepresentation
* Add searching by predicate.
Added handling of accessing Artifact as ISharedLibrary
* Fix typo.
* Add find to IArtifacgtList.
Fix some missing SLANG_NO_THROW.
* Small improvements around ArtifactDesc types.
* Another small change around ArtifactKind.
* Some more shuffling of ArtifactDesc.
* Make IArtifact castable
Remove IArtifactList
Made IArtifactContainer derive from IArtifact
Made ModuleLibrary atomic ref counted/given IModuleLibrary interface.
* Must call _requireChildren before any children access.
* Fix missing SLANG_MCALL on castAs.
* Fix missing SLANG_OVERRIDE.
* Added IArtifactHandler
* Use ICastable for basis of scope/lookup.
* WIP first attempt to remove CompileResult.
* Fix support for for downstream compiler shared library adapter.
* Fix issues found when replacing CompileResult.
* Fix typo.
* Fix getting items form 'significant' member of an Artifact.
* Split out ArtifactUtil & ArtifactHandler.
* Work around for problem on Visual studio.
* Improve searching.
* Add missing files.
* Split out Artifact associated types.
Don't produce a container by default - use associated for 'metadata'.
* Remove no longer used ArtifactPayload type.
* Generalized converting representations.
Small improvements to artifacts.
* Fix intermediate dumping issue.
* Removed #if 0 out CompileResult.
Remove DownstreamCompileResult maybeDumpIntermediate.
* Pull out functionality for dumping artifact output into ArtifactOutputUtil
Fixed a bug in naming files based on ArtifactDesc.
* std::atomic issue.
* Fix outputting as text bug.
Some small improvements.
* Add fix around prefix for dumping.
Improved how handling for extensions work form ArtifactDesc.
* Dump assembly if available.
Diffstat (limited to 'source')
31 files changed, 1002 insertions, 1129 deletions
diff --git a/source/compiler-core/slang-artifact-associated-impl.cpp b/source/compiler-core/slang-artifact-associated-impl.cpp new file mode 100644 index 000000000..17ede975e --- /dev/null +++ b/source/compiler-core/slang-artifact-associated-impl.cpp @@ -0,0 +1,99 @@ +// slang-artifact-associated-impl.cpp +#include "slang-artifact-associated-impl.h" + +#include "../core/slang-file-system.h" + +#include "../core/slang-type-text-util.h" +#include "../core/slang-io.h" +#include "../core/slang-array-view.h" + +#include "slang-artifact-util.h" + +namespace Slang { + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnostics !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* ArtifactDiagnostics::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IDiagnostics::getTypeGuid()) + { + return static_cast<IDiagnostics*>(this); + } + return nullptr; +} + +void* ArtifactDiagnostics::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +void* ArtifactDiagnostics::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + return getObject(guid); +} + +ZeroTerminatedCharSlice ArtifactDiagnostics::_allocateSlice(const Slice<char>& in) +{ + if (in.count == 0) + { + return ZeroTerminatedCharSlice("", 0); + } + const char* dst = m_arena.allocateString(in.data, in.count); + return ZeroTerminatedCharSlice(dst, in.count); +} + +void ArtifactDiagnostics::add(const Diagnostic& inDiagnostic) +{ + Diagnostic diagnostic(inDiagnostic); + + diagnostic.text = _allocateSlice(inDiagnostic.text); + diagnostic.code = _allocateSlice(inDiagnostic.code); + diagnostic.filePath = _allocateSlice(inDiagnostic.filePath); + + m_diagnostics.add(diagnostic); +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadata !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* PostEmitMetadata::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IPostEmitMetadata::getTypeGuid()) + { + return static_cast<IPostEmitMetadata*>(this); + } + return nullptr; +} + +void* PostEmitMetadata::getObject(const Guid& uuid) +{ + if (uuid == getTypeGuid()) + { + return this; + } + return nullptr; +} + +void* PostEmitMetadata::castAs(const Guid& guid) +{ + if (auto ptr = getInterface(guid)) + { + return ptr; + } + return getObject(guid); +} + +Slice<ShaderBindingRange> PostEmitMetadata::getBindingRanges() +{ + return Slice<ShaderBindingRange>(m_usedBindings.getBuffer(), m_usedBindings.getCount()); +} + +} // namespace Slang diff --git a/source/compiler-core/slang-artifact-associated-impl.h b/source/compiler-core/slang-artifact-associated-impl.h new file mode 100644 index 000000000..dcd796c1e --- /dev/null +++ b/source/compiler-core/slang-artifact-associated-impl.h @@ -0,0 +1,144 @@ +// slang-artifact-associated-impl.h +#ifndef SLANG_ARTIFACT_ASSOCIATED_IMPL_H +#define SLANG_ARTIFACT_ASSOCIATED_IMPL_H + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +#include "../core/slang-com-object.h" +#include "../core/slang-memory-arena.h" + +#include "slang-artifact-associated.h" + +namespace Slang +{ + +class ArtifactDiagnostics : public ComBaseObject, public IDiagnostics +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + // IDiagnostic + SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return &m_diagnostics[i]; } + SLANG_NO_THROW virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_diagnostics.getCount(); } + SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE { m_diagnostics.removeAt(i); } + SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() SLANG_OVERRIDE { return m_result; } + SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE { m_result = res; } + + ArtifactDiagnostics(): + m_arena(1024) + { + } + +protected: + void* getInterface(const Guid& uuid); + void* getObject(const Guid& uuid); + + ZeroTerminatedCharSlice _allocateSlice(const Slice<char>& in); + + // We could consider storing paths, codes in StringSlicePool, but for now we just allocate all 'string type things' + // in the arena. + MemoryArena m_arena; + + List<Diagnostic> m_diagnostics; + SlangResult m_result = SLANG_OK; + + ZeroTerminatedCharSlice m_raw; +}; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadata !!!!!!!!!!!!!!!!!!!!!!!!!! */ + +struct ShaderBindingRange +{ + slang::ParameterCategory category = slang::ParameterCategory::None; + UInt spaceIndex = 0; + UInt registerIndex = 0; + UInt registerCount = 0; // 0 for unsized + + bool isInfinite() const + { + return registerCount == 0; + } + + bool containsBinding(slang::ParameterCategory _category, UInt _spaceIndex, UInt _registerIndex) const + { + return category == _category + && spaceIndex == _spaceIndex + && registerIndex <= _registerIndex + && (isInfinite() || registerCount + registerIndex > _registerIndex); + } + + bool intersectsWith(const ShaderBindingRange& other) const + { + if (category != other.category || spaceIndex != other.spaceIndex) + return false; + + const bool leftIntersection = (registerIndex < other.registerIndex + other.registerCount) || other.isInfinite(); + const bool rightIntersection = (other.registerIndex < registerIndex + registerCount) || isInfinite(); + + return leftIntersection && rightIntersection; + } + + bool adjacentTo(const ShaderBindingRange& other) const + { + if (category != other.category || spaceIndex != other.spaceIndex) + return false; + + const bool leftIntersection = (registerIndex <= other.registerIndex + other.registerCount) || other.isInfinite(); + const bool rightIntersection = (other.registerIndex <= registerIndex + registerCount) || isInfinite(); + + return leftIntersection && rightIntersection; + } + + void mergeWith(const ShaderBindingRange other) + { + UInt newRegisterIndex = Math::Min(registerIndex, other.registerIndex); + + if (other.isInfinite()) + registerCount = 0; + else if (!isInfinite()) + registerCount = Math::Max(registerIndex + registerCount, other.registerIndex + other.registerCount) - newRegisterIndex; + + registerIndex = newRegisterIndex; + } + + static bool isUsageTracked(slang::ParameterCategory category) + { + switch (category) + { + case slang::ConstantBuffer: + case slang::ShaderResource: + case slang::UnorderedAccess: + case slang::SamplerState: + return true; + default: + return false; + } + } +}; + +class PostEmitMetadata : public ComBaseObject, public IPostEmitMetadata +{ +public: + SLANG_CLASS_GUID(0x6f82509f, 0xe48b, 0x4b83, { 0xa3, 0x84, 0x5d, 0x70, 0x83, 0x19, 0x83, 0xcc }) + + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // IPostEmitMetadata + SLANG_NO_THROW virtual Slice<ShaderBindingRange> SLANG_MCALL getBindingRanges() SLANG_OVERRIDE; + + void* getInterface(const Guid& uuid); + void* getObject(const Guid& uuid); + + List<ShaderBindingRange> m_usedBindings; +}; + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-associated.h b/source/compiler-core/slang-artifact-associated.h new file mode 100644 index 000000000..af47d2e59 --- /dev/null +++ b/source/compiler-core/slang-artifact-associated.h @@ -0,0 +1,79 @@ +// slang-artifact-associated.h +#ifndef SLANG_ARTIFACT_ASSOCIATED_H +#define SLANG_ARTIFACT_ASSOCIATED_H + +#include "slang-artifact.h" + +namespace Slang +{ + +/* Diagnostics. + +If there are raw diagnostics they can be associated to an artifact as (Kind::Text, Payload::Diagnostics) artifact */ +class IDiagnostics : public ICastable +{ +public: + SLANG_COM_INTERFACE(0x91f9b857, 0xcd6b, 0x45ca, { 0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a }); + + enum class Severity + { + Unknown, + Info, + Warning, + Error, + CountOf, + }; + enum class Stage + { + Compile, + Link, + }; + + struct Location + { + Int line = 0; ///< One indexed line number. 0 if not defined + Int column = 0; ///< One indexed *character (not byte)* column number. 0 if not defined + }; + + struct Diagnostic + { + Severity severity = Severity::Unknown; ///< The severity of error + Stage stage = Stage::Compile; ///< The stage the error came from + ZeroTerminatedCharSlice text; ///< The text of the error + ZeroTerminatedCharSlice code; ///< The compiler specific error code + ZeroTerminatedCharSlice filePath; ///< The path the error originated from + Location location; + }; + + /// Get the diagnostic at the index + SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) = 0; + /// Get the amount of diangostics + SLANG_NO_THROW virtual Count SLANG_MCALL getCount() = 0; + /// Add a diagnostic + SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) = 0; + /// Remove the diagnostic at the index + SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) = 0; + + /// Get raw diagnostics information + SLANG_NO_THROW virtual ZeroTerminatedCharSlice SLANG_MCALL getRaw() = 0; + + /// Get the result for a compilation + SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() = 0; + /// Set the result + SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) = 0; +}; + +struct ShaderBindingRange; + +class IPostEmitMetadata : public ICastable +{ +public: + SLANG_COM_INTERFACE(0x5d03bce9, 0xafb1, 0x4fc8, { 0xa4, 0x6f, 0x3c, 0xe0, 0x7b, 0x6, 0x1b, 0x1b }); + + /// Get the binding ranges + SLANG_NO_THROW virtual Slice<ShaderBindingRange> SLANG_MCALL getBindingRanges() = 0; +}; + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index 2c2b177c2..490020a27 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -215,7 +215,6 @@ SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_E x(SlangAST, AST) \ x(CompileResults, Base) \ x(MetaData, Base) \ - x(PostEmitMetadata, MetaData) \ x(DebugInfo, MetaData) \ x(Diagnostics, MetaData) @@ -466,66 +465,28 @@ static const KindExtension g_cpuKindExts[] = return getDescFromExtension(extension); } -/* static*/ UnownedStringSlice ArtifactDescUtil::getCpuExtensionForKind(Kind kind) +/* static*/ SlangResult ArtifactDescUtil::appendCpuExtensionForKind(Kind kind, StringBuilder& out) { for (const auto& kindExt : g_cpuKindExts) { if (kind == kindExt.kind) { - return kindExt.ext; + out << kindExt.ext; + return SLANG_OK; } } - return UnownedStringSlice(); + return SLANG_E_NOT_FOUND; } -UnownedStringSlice ArtifactDescUtil::getAssemblyExtensionForPayload(ArtifactPayload payload) +static UnownedStringSlice _getPayloadExtension(ArtifactPayload payload) { + typedef ArtifactPayload Payload; switch (payload) { - case ArtifactPayload::DXIL: return toSlice("dxil-asm"); - case ArtifactPayload::DXBC: return toSlice("dxbc-asm"); - case ArtifactPayload::SPIRV: return toSlice("spv-asm"); - case ArtifactPayload::PTX: return toSlice("ptx"); - - // TODO(JS): - // Not sure what to do for metal - does it have an assembly name? - - default: break; - } - - // We'll just use asm for all CPU assembly type - if (isDerivedFrom(payload, ArtifactPayload::CPULike)) - { - return toSlice("asm"); - } - - if (isDerivedFrom(payload, ArtifactPayload::GeneralIR)) - { - switch (payload) - { - case ArtifactPayload::SlangIR: return toSlice("slang-ir-asm"); - case ArtifactPayload::LLVMIR: return toSlice("llvm-ir-asm"); - break; - } - } - - return UnownedStringSlice(); -} + /* Misc */ + case Payload::Unknown: return toSlice("unknown"); -UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& desc) -{ - switch (desc.kind) - { - case ArtifactKind::Zip: return toSlice("zip"); - case ArtifactKind::Riff: return toSlice("riff"); - case ArtifactKind::Assembly: - { - return getAssemblyExtensionForPayload(desc.payload); - } - case ArtifactKind::Source: - { - switch (desc.payload) - { + /* Source types */ case Payload::HLSL: return toSlice("hlsl"); case Payload::GLSL: return toSlice("glsl"); @@ -537,24 +498,8 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des case Payload::CUDA: return toSlice("cu"); case Payload::Slang: return toSlice("slang"); - default: break; - } - } - default: break; - } - - if (ArtifactDescUtil::isCpuLikeTarget(desc)) - { - return getCpuExtensionForKind(desc.kind); - } - - if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) - { - switch (desc.payload) - { - case Payload::None: return UnownedStringSlice(); - case Payload::Unknown: return toSlice("unknown"); + /* Binary types */ case Payload::DXIL: return toSlice("dxil"); case Payload::DXBC: return toSlice("dxbc"); case Payload::SPIRV: return toSlice("spv"); @@ -563,20 +508,90 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des case Payload::LLVMIR: return toSlice("llvm-ir"); - case Payload::SlangIR: + case Payload::SlangIR: return toSlice("slang-ir"); + + case Payload::MetalAIR: return toSlice("air"); + + default: break; + } + return UnownedStringSlice(); +} + +SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, StringBuilder& out) +{ + switch (desc.kind) + { + case ArtifactKind::Library: { - return (desc.kind == ArtifactKind::Library) ? toSlice("slang-module") : toSlice("slang-ir"); + // Special cases + if (desc.payload == Payload::SlangIR) + { + out << toSlice("slang-module"); + return SLANG_OK; + } + else if (desc.payload == Payload::MetalAIR) + { + // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools + out << toSlice("metallib"); + return SLANG_OK; + } + + break; } - case Payload::MetalAIR: + case ArtifactKind::Zip: { - // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools - return (desc.kind == ArtifactKind::Library) ? toSlice("metallib") : toSlice("air"); + out << toSlice("zip"); + return SLANG_OK; + } + case ArtifactKind::Riff: + { + out << toSlice("riff"); + return SLANG_OK; + } + case ArtifactKind::Assembly: + { + // Special case PTX, because it is assembly + if (desc.payload == Payload::PTX) + { + out << _getPayloadExtension(desc.payload); + return SLANG_OK; + } + + // We'll just use asm for all CPU assembly type + if (isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) + { + out << toSlice("asm"); + return SLANG_OK; + } + + // Use the payload extension "-asm" + out << _getPayloadExtension(desc.payload); + out << toSlice("-asm"); + return SLANG_OK; + } + case ArtifactKind::Source: + { + out << _getPayloadExtension(desc.payload); + return SLANG_OK; } default: break; + } + + if (ArtifactDescUtil::isCpuLikeTarget(desc) && !isDerivedFrom(desc.payload, ArtifactPayload::Source)) + { + return appendCpuExtensionForKind(desc.kind, out); + } + else + { + auto slice = _getPayloadExtension(desc.payload); + if (slice.getLength()) + { + out << slice; + return SLANG_OK; } } - return UnownedStringSlice(); + return SLANG_E_NOT_FOUND; } /* static */String ArtifactDescUtil::getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path) @@ -602,7 +617,10 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des // Strip any extension { - auto descExt = getDefaultExtension(desc); + StringBuilder descExt; + + appendDefaultExtension(desc, descExt); + // Strip the extension if it's a match if (descExt.getLength() && Path::getPathExt(name) == descExt) @@ -620,27 +638,17 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des return getBaseNameFromPath(desc, path); } -/* static */SlangResult ArtifactDescUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath) +/* static */SlangResult ArtifactDescUtil::calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& inBaseName, StringBuilder& outName) { - outPath.Clear(); - - UnownedStringSlice baseName; - - // Append the directory - Index pos = Path::findLastSeparatorIndex(basePath); - if (pos >= 0) - { - // Keep the stem including the delimiter - outPath.append(basePath.head(pos + 1)); - // Get the baseName - baseName = basePath.tail(pos + 1); - } + UnownedStringSlice baseName(inBaseName); + // If there is no basename, set one if (baseName.getLength() == 0) { baseName = toSlice("unknown"); } + // Prefix if (isCpuBinary(desc) && (desc.kind == ArtifactKind::SharedLibrary || desc.kind == ArtifactKind::Library)) @@ -648,21 +656,47 @@ UnownedStringSlice ArtifactDescUtil::getDefaultExtension(const ArtifactDesc& des const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; if (isSharedLibraryPrefixPlatform) { - outPath << "lib"; - outPath << baseName; + outName << "lib"; } } - // If there is an extension append it - const UnownedStringSlice ext = getDefaultExtension(desc); + // Output the basename + outName << baseName; - if (ext.getLength()) + // If there is an extension append it + StringBuilder ext; + if (SLANG_SUCCEEDED(appendDefaultExtension(desc, ext)) && ext.getLength() > 0) { - outPath.appendChar('.'); - outPath.append(ext); + outName.appendChar('.'); + outName.append(ext); } return SLANG_OK; } +/* static */SlangResult ArtifactDescUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath) +{ + outPath.Clear(); + + // Append the directory + Index pos = Path::findLastSeparatorIndex(basePath); + if (pos >= 0) + { + // Keep the stem including the delimiter + outPath.append(basePath.head(pos + 1)); + + StringBuilder buf; + const auto baseName = basePath.tail(pos + 1); + + SLANG_RETURN_ON_FAIL(calcNameForDesc(desc, baseName, buf)); + outPath.append(buf); + + return SLANG_OK; + } + else + { + return calcNameForDesc(desc, basePath, outPath); + } +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-desc-util.h b/source/compiler-core/slang-artifact-desc-util.h index e3d1e6478..6f35cb500 100644 --- a/source/compiler-core/slang-artifact-desc-util.h +++ b/source/compiler-core/slang-artifact-desc-util.h @@ -50,9 +50,6 @@ struct ArtifactDescUtil /// True if the desc holds textual information static bool isText(const ArtifactDesc& desc); - /// Given an assembly type returns it's extension from the payload type - static UnownedStringSlice getAssemblyExtensionForPayload(ArtifactPayload payload); - /// True if artifact appears to be linkable static bool isLinkable(const ArtifactDesc& desc); @@ -62,11 +59,11 @@ struct ArtifactDescUtil /// Try to determine the desc from a path static ArtifactDesc getDescFromPath(const UnownedStringSlice& slice); - /// Gets the default file extension for the artifact type. Returns empty slice if not known - static UnownedStringSlice getDefaultExtension(const ArtifactDesc& desc); + /// Appends the default file extension for the artifact type. + static SlangResult appendDefaultExtension(const ArtifactDesc& desc, StringBuilder& out); /// Get the extension for CPU/Host for a kind - static UnownedStringSlice getCpuExtensionForKind(Kind kind); + static SlangResult appendCpuExtensionForKind(Kind kind, StringBuilder& out); /// Given a desc and a path returns the base name (stripped of prefix and extension) static String getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path); @@ -78,9 +75,12 @@ struct ArtifactDescUtil static String getBaseName(const ArtifactDesc& desc, IFileArtifactRepresentation* fileRep); - /// Given a desc, and a basePath returns a suitable path for a entity of specified desc + /// Given a desc and a basePath returns a suitable path for a entity of specified desc static SlangResult calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath); + /// Given a desc and a baseName works out the the output file name + static SlangResult calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& baseName, StringBuilder& outName); + /// Given a target returns the ArtifactDesc static ArtifactDesc makeDescFromCompileTarget(SlangCompileTarget target); diff --git a/source/compiler-core/slang-artifact-handler-impl.cpp b/source/compiler-core/slang-artifact-handler-impl.cpp index c93a4907b..f324a1d43 100644 --- a/source/compiler-core/slang-artifact-handler-impl.cpp +++ b/source/compiler-core/slang-artifact-handler-impl.cpp @@ -182,23 +182,21 @@ SlangResult DefaultArtifactHandler::expandChildren(IArtifactContainer* container return SLANG_E_NOT_IMPLEMENTED; } - - SlangResult DefaultArtifactHandler::getOrCreateRepresentation(IArtifact* artifact, const Guid& guid, ArtifactKeep keep, ICastable** outCastable) { + const auto reps = artifact->getRepresentations(); + // See if we already have a rep of this type + for (ICastable* rep : reps) { - for (ICastable* rep : artifact->getRepresentations()) + if (rep->castAs(guid)) { - if (rep->castAs(guid)) - { - rep->addRef(); - *outCastable = rep; - return SLANG_OK; - } + rep->addRef(); + *outCastable = rep; + return SLANG_OK; } } - + // TODO(JS): Temporary whilst DownstreamCompileResult is // Special handling for DownstreamCompileResult if (auto downstreamResult = findRepresentation<DownstreamCompileResult>(artifact)) @@ -217,14 +215,23 @@ SlangResult DefaultArtifactHandler::getOrCreateRepresentation(IArtifact* artifac } } - // Normal construction - if (guid == ISlangBlob::getTypeGuid()) + // We can ask each representation if they can do the conversion to the type, if they can we just use that + for (ICastable* castable : reps) { - ComPtr<ISlangBlob> blob; - SLANG_RETURN_ON_FAIL(_loadBlob(artifact, keep, blob.writeRef())); - return _addRepresentation(artifact, keep, blob, outCastable); + if (auto rep = as<IArtifactRepresentation>(castable)) + { + ComPtr<ICastable> created; + if (SLANG_SUCCEEDED(rep->createRepresentation(guid, created.writeRef()))) + { + SLANG_ASSERT(created); + // Add the rep + return _addRepresentation(artifact, keep, created, outCastable); + } + } } - else if (guid == ISlangSharedLibrary::getTypeGuid()) + + // Special case shared library + if (guid == ISlangSharedLibrary::getTypeGuid()) { ComPtr<ISlangSharedLibrary> sharedLib; SLANG_RETURN_ON_FAIL(_loadSharedLibrary(artifact, keep, sharedLib.writeRef())); @@ -348,33 +355,4 @@ SlangResult DefaultArtifactHandler::_loadSharedLibrary(IArtifact* artifact, Arti return SLANG_FAIL; } -SlangResult DefaultArtifactHandler::_loadBlob(IArtifact* artifact, ArtifactKeep keep, ISlangBlob** outBlob) -{ - SLANG_UNUSED(keep); - - ComPtr<ISlangBlob> blob; - - // Look for a representation that we can serialize into a blob - for (auto rep : artifact->getRepresentations()) - { - if (auto artifactRep = as<IArtifactRepresentation>(rep)) - { - SlangResult res = artifactRep->writeToBlob(blob.writeRef()); - if (SLANG_SUCCEEDED(res) && blob) - { - break; - } - } - } - - // Wasn't able to construct - if (!blob) - { - return SLANG_E_NOT_FOUND; - } - - *outBlob = blob.detach(); - return SLANG_OK; -} - } // namespace Slang diff --git a/source/compiler-core/slang-artifact-handler-impl.h b/source/compiler-core/slang-artifact-handler-impl.h index c7861b598..f49fa4230 100644 --- a/source/compiler-core/slang-artifact-handler-impl.h +++ b/source/compiler-core/slang-artifact-handler-impl.h @@ -29,8 +29,7 @@ public: protected: SlangResult _loadSharedLibrary(IArtifact* artifact, ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary); - SlangResult _loadBlob(IArtifact* artifact, ArtifactKeep keep, ISlangBlob** outBlob); - + void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); diff --git a/source/compiler-core/slang-artifact-helper.cpp b/source/compiler-core/slang-artifact-helper.cpp index ce6fab7d9..39e81b668 100644 --- a/source/compiler-core/slang-artifact-helper.cpp +++ b/source/compiler-core/slang-artifact-helper.cpp @@ -5,6 +5,7 @@ #include "slang-artifact-representation-impl.h" #include "slang-artifact-desc-util.h" +#include "slang-artifact-util.h" #include "../core/slang-castable-list-impl.h" @@ -14,7 +15,6 @@ namespace Slang { - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DefaultArtifactHelper !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ /* static */DefaultArtifactHelper DefaultArtifactHelper::g_singleton; @@ -121,4 +121,9 @@ ArtifactDesc DefaultArtifactHelper::makeDescFromCompileTarget(SlangCompileTarget return ArtifactDescUtil::makeDescFromCompileTarget(target); } +void DefaultArtifactHelper::getCastable(ISlangUnknown* unk, ICastable** outCastable) +{ + *outCastable = CastableUtil::getCastable(unk).detach(); +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-helper.h b/source/compiler-core/slang-artifact-helper.h index 41bf0f2c9..6a07c16ee 100644 --- a/source/compiler-core/slang-artifact-helper.h +++ b/source/compiler-core/slang-artifact-helper.h @@ -14,27 +14,43 @@ class IArtifactHelper : public ICastable { SLANG_COM_INTERFACE(0x882b25d7, 0xe300, 0x4b20, { 0xbe, 0xb, 0x26, 0xd2, 0x52, 0x3e, 0x70, 0x20 }) + /// Create an artifact virtual SLANG_NO_THROW SlangResult SLANG_MCALL createArtifact(const ArtifactDesc& desc, const char* name, IArtifact** outArtifact) = 0; + /// Create a container with desc, and specified name. name can be passed as nullptr for no name virtual SLANG_NO_THROW SlangResult SLANG_MCALL createArtifactContainer(const ArtifactDesc& desc, const char* name, IArtifactContainer** outArtifactContainer) = 0; + /// Get the parent to a kind virtual SLANG_NO_THROW ArtifactKind SLANG_MCALL getKindParent(ArtifactKind kind) = 0; + /// Get the name of a kind virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getKindName(ArtifactKind kind) = 0; + /// Returns true if kind is derived from base virtual SLANG_NO_THROW bool SLANG_MCALL isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) = 0; + /// Get the parent payload for payload virtual SLANG_NO_THROW ArtifactPayload SLANG_MCALL getPayloadParent(ArtifactPayload payload) = 0; + /// Get the payload name text virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getPayloadName(ArtifactPayload payload) = 0; + /// Returns true if payload is derived from base virtual SLANG_NO_THROW bool SLANG_MCALL isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) = 0; + /// Get the parent type of a style virtual SLANG_NO_THROW ArtifactStyle SLANG_MCALL getStyleParent(ArtifactStyle style) = 0; + /// Get text name for a style virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) = 0; + /// Returns true if style is derived from base virtual SLANG_NO_THROW bool SLANG_MCALL isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) = 0; + /// Create a lock file, the path of which can be used to generate other temporary files virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const char* nameBase, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outLockFile) = 0; /// Given a desc and a basePath returns a suitable name virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; + /// Given a compile target return the equivalent desc virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) = 0; + + /// Given an interface returns as a castable interface. This might just cast unk into ICastable, or wrap it such that it uses the castable interface + virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) = 0; }; class DefaultArtifactHelper : public IArtifactHelper @@ -70,6 +86,8 @@ public: virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) SLANG_OVERRIDE; + static IArtifactHelper* getSingleton() { return &g_singleton; } protected: diff --git a/source/compiler-core/slang-artifact-impl.h b/source/compiler-core/slang-artifact-impl.h index e0a976929..a6e99a4f7 100644 --- a/source/compiler-core/slang-artifact-impl.h +++ b/source/compiler-core/slang-artifact-impl.h @@ -47,7 +47,8 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary) SLANG_OVERRIDE; virtual SLANG_NO_THROW const char* SLANG_MCALL getName() SLANG_OVERRIDE { return m_name.getBuffer(); } - + virtual SLANG_NO_THROW void SLANG_MCALL setName(const char* name) SLANG_OVERRIDE { m_name = name; } + virtual SLANG_NO_THROW void SLANG_MCALL addAssociated(ICastable* castable) SLANG_OVERRIDE; virtual SLANG_NO_THROW void* SLANG_MCALL findAssociated(const Guid& unk) SLANG_OVERRIDE; virtual SLANG_NO_THROW ICastableList* SLANG_MCALL getAssociated() SLANG_OVERRIDE; diff --git a/source/compiler-core/slang-artifact-representation-impl.cpp b/source/compiler-core/slang-artifact-representation-impl.cpp index 32ec055d8..802f2c1dd 100644 --- a/source/compiler-core/slang-artifact-representation-impl.cpp +++ b/source/compiler-core/slang-artifact-representation-impl.cpp @@ -9,6 +9,8 @@ #include "slang-artifact-util.h" +#include "../core/slang-castable-list-impl.h" + namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -45,16 +47,23 @@ void* FileArtifactRepresentation::castAs(const Guid& guid) return getObject(guid); } -SlangResult FileArtifactRepresentation::writeToBlob(ISlangBlob** blob) +SlangResult FileArtifactRepresentation::createRepresentation(const Guid& typeGuid, ICastable** outCastable) { - if (m_kind == Kind::NameOnly) + // We can convert into a blob only, and only if we have a path + // If it's referenced by a name only, it's a file that *can't* be loaded as a blob in general. + if (typeGuid != ISlangBlob::getTypeGuid() || + m_kind == Kind::NameOnly) { - // If it's referenced by a name only, it's a file that *can't* be loaded as a blob in general. return SLANG_E_NOT_AVAILABLE; } + ComPtr<ISlangBlob> blob; + auto fileSystem = _getFileSystem(); - return fileSystem->loadFile(m_path.getBuffer(), blob); + SLANG_RETURN_ON_FAIL(fileSystem->loadFile(m_path.getBuffer(), blob.writeRef())); + + *outCastable = CastableUtil::getCastable(blob).detach(); + return SLANG_OK; } bool FileArtifactRepresentation::exists() @@ -94,105 +103,6 @@ FileArtifactRepresentation::~FileArtifactRepresentation() } } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DiagnosticsArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* DiagnosticsArtifactRepresentation::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == IArtifactRepresentation::getTypeGuid() || - guid == IDiagnosticsArtifactRepresentation::getTypeGuid()) - { - return static_cast<DiagnosticsArtifactRepresentation*>(this); - } - return nullptr; -} - -void* DiagnosticsArtifactRepresentation::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; -} - -void* DiagnosticsArtifactRepresentation::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -SlangResult DiagnosticsArtifactRepresentation::writeToBlob(ISlangBlob** outBlob) -{ - *outBlob = nullptr; - return SLANG_E_NOT_IMPLEMENTED; -} - -bool DiagnosticsArtifactRepresentation::exists() -{ - return true; -} - -ZeroTerminatedCharSlice DiagnosticsArtifactRepresentation::_allocateSlice(const Slice<char>& in) -{ - if (in.count == 0) - { - return ZeroTerminatedCharSlice("", 0); - } - const char* dst = m_arena.allocateString(in.data, in.count); - return ZeroTerminatedCharSlice(dst, in.count); -} - -void DiagnosticsArtifactRepresentation::add(const Diagnostic& inDiagnostic) -{ - Diagnostic diagnostic(inDiagnostic); - - diagnostic.text = _allocateSlice(inDiagnostic.text); - diagnostic.code = _allocateSlice(inDiagnostic.code); - diagnostic.filePath = _allocateSlice(inDiagnostic.filePath); - - m_diagnostics.add(diagnostic); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* PostEmitMetadataArtifactRepresentation::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == IArtifactRepresentation::getTypeGuid() || - guid == IPostEmitMetadataArtifactRepresentation::getTypeGuid()) - { - return static_cast<IPostEmitMetadataArtifactRepresentation*>(this); - } - return nullptr; -} - -void* PostEmitMetadataArtifactRepresentation::getObject(const Guid& uuid) -{ - if (uuid == getTypeGuid()) - { - return this; - } - return nullptr; -} - -void* PostEmitMetadataArtifactRepresentation::castAs(const Guid& guid) -{ - if (auto ptr = getInterface(guid)) - { - return ptr; - } - return getObject(guid); -} - - -Slice<ShaderBindingRange> PostEmitMetadataArtifactRepresentation::getBindingRanges() -{ - return Slice<ShaderBindingRange>(m_metadata.usedBindings.getBuffer(), m_metadata.usedBindings.getCount()); -} - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ void* ObjectArtifactRepresentation::castAs(const Guid& guid) diff --git a/source/compiler-core/slang-artifact-representation-impl.h b/source/compiler-core/slang-artifact-representation-impl.h index fb2e37c76..5e6716641 100644 --- a/source/compiler-core/slang-artifact-representation-impl.h +++ b/source/compiler-core/slang-artifact-representation-impl.h @@ -25,7 +25,7 @@ public: SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; // IFileArtifactRepresentation @@ -60,142 +60,6 @@ protected: ComPtr<ISlangMutableFileSystem> m_fileSystem; }; -class DiagnosticsArtifactRepresentation : public ComBaseObject, public IDiagnosticsArtifactRepresentation -{ -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) SLANG_OVERRIDE; - SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; - // IDiagnosticArtifactRepresentation - SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return &m_diagnostics[i]; } - SLANG_NO_THROW virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_diagnostics.getCount(); } - SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE { m_diagnostics.removeAt(i); } - SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() SLANG_OVERRIDE { return m_result; } - SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE { m_result = res; } - - DiagnosticsArtifactRepresentation(): - m_arena(1024) - { - } - -protected: - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); - - ZeroTerminatedCharSlice _allocateSlice(const Slice<char>& in); - - // We could consider storing paths, codes in StringSlicePool, but for now we just allocate all 'string type things' - // in the arena. - MemoryArena m_arena; - - List<Diagnostic> m_diagnostics; - SlangResult m_result = SLANG_OK; - - ZeroTerminatedCharSlice m_raw; -}; - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!! */ - -struct ShaderBindingRange -{ - slang::ParameterCategory category = slang::ParameterCategory::None; - UInt spaceIndex = 0; - UInt registerIndex = 0; - UInt registerCount = 0; // 0 for unsized - - bool isInfinite() const - { - return registerCount == 0; - } - - bool containsBinding(slang::ParameterCategory _category, UInt _spaceIndex, UInt _registerIndex) const - { - return category == _category - && spaceIndex == _spaceIndex - && registerIndex <= _registerIndex - && (isInfinite() || registerCount + registerIndex > _registerIndex); - } - - bool intersectsWith(const ShaderBindingRange& other) const - { - if (category != other.category || spaceIndex != other.spaceIndex) - return false; - - const bool leftIntersection = (registerIndex < other.registerIndex + other.registerCount) || other.isInfinite(); - const bool rightIntersection = (other.registerIndex < registerIndex + registerCount) || isInfinite(); - - return leftIntersection && rightIntersection; - } - - bool adjacentTo(const ShaderBindingRange& other) const - { - if (category != other.category || spaceIndex != other.spaceIndex) - return false; - - const bool leftIntersection = (registerIndex <= other.registerIndex + other.registerCount) || other.isInfinite(); - const bool rightIntersection = (other.registerIndex <= registerIndex + registerCount) || isInfinite(); - - return leftIntersection && rightIntersection; - } - - void mergeWith(const ShaderBindingRange other) - { - UInt newRegisterIndex = Math::Min(registerIndex, other.registerIndex); - - if (other.isInfinite()) - registerCount = 0; - else if (!isInfinite()) - registerCount = Math::Max(registerIndex + registerCount, other.registerIndex + other.registerCount) - newRegisterIndex; - - registerIndex = newRegisterIndex; - } - - static bool isUsageTracked(slang::ParameterCategory category) - { - switch (category) - { - case slang::ConstantBuffer: - case slang::ShaderResource: - case slang::UnorderedAccess: - case slang::SamplerState: - return true; - default: - return false; - } - } -}; - -struct PostEmitMetadata -{ - List<ShaderBindingRange> usedBindings; -}; - -class PostEmitMetadataArtifactRepresentation : public ComBaseObject, public IPostEmitMetadataArtifactRepresentation -{ -public: - SLANG_CLASS_GUID(0x6f82509f, 0xe48b, 0x4b83, { 0xa3, 0x84, 0x5d, 0x70, 0x83, 0x19, 0x83, 0xcc }) - - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** outBlob) SLANG_OVERRIDE { SLANG_UNUSED(outBlob); return SLANG_E_NOT_AVAILABLE; } - SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return true; } - // IPostEmitMetadataArtifactRepresentation - SLANG_NO_THROW virtual Slice<ShaderBindingRange> SLANG_MCALL getBindingRanges() SLANG_OVERRIDE; - - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); - - PostEmitMetadata m_metadata; -}; - /* This allows wrapping any object to be an artifact representation. NOTE! Only allows casting from a single guid. Passing a RefObject across an ABI bounday remains risky! @@ -210,7 +74,7 @@ public: // ICastable SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** outBlob) SLANG_OVERRIDE { SLANG_UNUSED(outBlob); return SLANG_E_NOT_AVAILABLE; } + SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& guid, ICastable** outCastable) SLANG_OVERRIDE { SLANG_UNUSED(guid); SLANG_UNUSED(outCastable); return SLANG_E_NOT_AVAILABLE; } SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return m_object; } ObjectArtifactRepresentation(const Guid& typeGuid, RefObject* obj): diff --git a/source/compiler-core/slang-artifact-representation.h b/source/compiler-core/slang-artifact-representation.h index 43a975d3c..466494052 100644 --- a/source/compiler-core/slang-artifact-representation.h +++ b/source/compiler-core/slang-artifact-representation.h @@ -40,71 +40,6 @@ public: virtual SLANG_NO_THROW IFileArtifactRepresentation* SLANG_MCALL getLockFile() = 0; }; -/* Diagnostics. - -If there are raw diagnostics they can be associated to an artifact as (Kind::Text, Payload::Diagnostics) artifact */ -class IDiagnosticsArtifactRepresentation : public IArtifactRepresentation -{ -public: - SLANG_COM_INTERFACE(0x91f9b857, 0xcd6b, 0x45ca, { 0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a }); - - enum class Severity - { - Unknown, - Info, - Warning, - Error, - CountOf, - }; - enum class Stage - { - Compile, - Link, - }; - - struct Location - { - Int line = 0; ///< One indexed line number. 0 if not defined - Int column = 0; ///< One indexed *character (not byte)* column number. 0 if not defined - }; - - struct Diagnostic - { - Severity severity = Severity::Unknown; ///< The severity of error - Stage stage = Stage::Compile; ///< The stage the error came from - ZeroTerminatedCharSlice text; ///< The text of the error - ZeroTerminatedCharSlice code; ///< The compiler specific error code - ZeroTerminatedCharSlice filePath; ///< The path the error originated from - Location location; - }; - - /// Get the diagnostic at the index - SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) = 0; - /// Get the amount of diangostics - SLANG_NO_THROW virtual Count SLANG_MCALL getCount() = 0; - /// Add a diagnostic - SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) = 0; - /// Remove the diagnostic at the index - SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) = 0; - - /// Get the result for a compilation - SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() = 0; - /// Set the result - SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) = 0; -}; - -struct ShaderBindingRange; - -class IPostEmitMetadataArtifactRepresentation : public IArtifactRepresentation -{ -public: - SLANG_COM_INTERFACE(0x5d03bce9, 0xafb1, 0x4fc8, { 0xa4, 0x6f, 0x3c, 0xe0, 0x7b, 0x6, 0x1b, 0x1b }); - - /// Get the binding ranges - SLANG_NO_THROW virtual Slice<ShaderBindingRange> SLANG_MCALL getBindingRanges() = 0; -}; - - } // namespace Slang #endif diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index f93924afb..fb3157522 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -23,10 +23,15 @@ namespace Slang { return ArtifactContainer::create(ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::CompileResults)); } -/* static */ComPtr<IArtifact> ArtifactUtil::createArtifactForCompileTarget(SlangCompileTarget target) +/* static */ComPtr<IArtifact> ArtifactUtil::createArtifact(const ArtifactDesc& desc, const char* name) { - auto desc = ArtifactDescUtil::makeDescFromCompileTarget(target); + auto artifact = createArtifact(desc); + artifact->setName(name); + return artifact; +} +/* static */ComPtr<IArtifact> ArtifactUtil::createArtifact(const ArtifactDesc& desc) +{ if (isDerivedFrom(desc.kind, ArtifactKind::Container)) { auto container = ArtifactContainer::create(desc); @@ -41,6 +46,12 @@ namespace Slang { } } +/* static */ComPtr<IArtifact> ArtifactUtil::createArtifactForCompileTarget(SlangCompileTarget target) +{ + auto desc = ArtifactDescUtil::makeDescFromCompileTarget(target); + return createArtifact(desc); +} + /* static */bool ArtifactUtil::isSignificant(IArtifact* artifact, void* data) { SLANG_UNUSED(data); @@ -79,6 +90,11 @@ namespace Slang { return true; } +/* static */IArtifact* ArtifactUtil::findSignificant(IArtifact* artifact) +{ + return artifact->findArtifactByPredicate(IArtifact::FindStyle::SelfOrChildren, &ArtifactUtil::isSignificant, nullptr); +} + /* static */String ArtifactUtil::getBaseName(IArtifact* artifact) { if (auto fileRep = findRepresentation<IFileArtifactRepresentation>(artifact)) diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index 541a1f058..c4768a7b8 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -30,10 +30,14 @@ struct ArtifactUtil /// Creates an empty artifact for a type static ComPtr<IArtifact> createArtifactForCompileTarget(SlangCompileTarget target); + /// Create an artifact + static ComPtr<IArtifact> createArtifact(const ArtifactDesc& desc, const char* name); + static ComPtr<IArtifact> createArtifact(const ArtifactDesc& desc); + /// Returns true if an artifact is 'significant' static bool isSignificant(IArtifact* artifact, void* data = nullptr); /// Find a significant artifact - static IArtifact* findSignificant(IArtifact* artifact) { return artifact->findArtifactByPredicate(IArtifact::FindStyle::SelfOrChildren, &isSignificant, nullptr); } + static IArtifact* findSignificant(IArtifact* artifact); }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index bde7f9a08..c54282c09 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -140,7 +140,6 @@ enum class ArtifactPayload : uint8_t DebugInfo, ///< Debugging information Diagnostics, ///< Diagnostics information - PostEmitMetadata, ///< Post emit meta data CountOf, }; @@ -343,6 +342,8 @@ public: /// Get the name of the artifact. This can be empty. virtual SLANG_NO_THROW const char* SLANG_MCALL getName() = 0; + /// Set the name associated with the artifact + virtual SLANG_NO_THROW void SLANG_MCALL setName(const char* name) = 0; /// Add data associated with this artifact virtual SLANG_NO_THROW void SLANG_MCALL addAssociated(ICastable* castable) = 0; @@ -411,6 +412,12 @@ SLANG_FORCE_INLINE T* findRepresentation(IArtifact* artifact) return reinterpret_cast<T*>(artifact->findRepresentation(T::getTypeGuid())); } +template <typename T> +SLANG_FORCE_INLINE T* findAssociated(IArtifact* artifact) +{ + return reinterpret_cast<T*>(artifact->findAssociated(T::getTypeGuid())); +} + /* The IArtifactRepresentation interface represents a single representation that can be part of an artifact. It's special in so far as @@ -421,9 +428,10 @@ class IArtifactRepresentation : public ICastable { SLANG_COM_INTERFACE(0x311457a8, 0x1796, 0x4ebb, { 0x9a, 0xfc, 0x46, 0xa5, 0x44, 0xc7, 0x6e, 0xa9 }) - /// Convert the instance into a serializable blob. + /// Create a representation of the specified typeGuid interface. + /// Calling castAs on the castable will return the specific type /// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement - virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) = 0; /// Returns true if this representation exists and is available for use. virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; diff --git a/source/core/slang-castable-list-impl.cpp b/source/core/slang-castable-list-impl.cpp index 56f8c7cae..dcc58e37b 100644 --- a/source/core/slang-castable-list-impl.cpp +++ b/source/core/slang-castable-list-impl.cpp @@ -3,7 +3,24 @@ namespace Slang { - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnknownCastableAdapter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CastableUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */ComPtr<ICastable> CastableUtil::getCastable(ISlangUnknown* unk) +{ + SLANG_ASSERT(unk); + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(unk->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef()))) + { + SLANG_ASSERT(castable); + } + else + { + castable = new UnknownCastableAdapter(unk); + } + return castable; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnknownCastableAdapter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ void* UnknownCastableAdapter::castAs(const Guid& guid) { diff --git a/source/core/slang-castable-list-impl.h b/source/core/slang-castable-list-impl.h index b578e8de4..2ce124ce7 100644 --- a/source/core/slang-castable-list-impl.h +++ b/source/core/slang-castable-list-impl.h @@ -79,6 +79,12 @@ protected: List<ICastable*> m_list; }; +struct CastableUtil +{ + /// Given an unk return as an unk + static ComPtr<ICastable> getCastable(ISlangUnknown* unk); +}; + } // namespace Slang #endif diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index 17cd60160..a6e97057b 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -1,3 +1,5 @@ +#define _CRT_SECURE_NO_WARNINGS 1 + #include "slang-io.h" #include "slang-exception.h" @@ -925,6 +927,20 @@ namespace Slang return SLANG_OK; } + /* static */SlangResult File::writeNativeText(const String& path, const void* data, size_t size) + { + FILE* file = fopen(path.getBuffer(), "w"); + if (!file) + { + return SLANG_FAIL; + } + + const auto count = fwrite(data, size, 1, file); + fclose(file); + + return (count == 1) ? SLANG_OK : SLANG_FAIL; + } + String URI::getPath() const { Index startIndex = uri.indexOf("://"); diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 4de246289..aa4ccae42 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -21,6 +21,9 @@ namespace Slang static SlangResult writeAllText(const String& fileName, const String& text); + /// Write as text in native form for the target (so typically may change line endings ) + static SlangResult writeNativeText(const String& filename, const void* data, size_t size); + static SlangResult writeAllBytes(const String& fileName, const void* data, size_t size); static SlangResult remove(const String& fileName); diff --git a/source/slang/slang-artifact-output-util.cpp b/source/slang/slang-artifact-output-util.cpp new file mode 100644 index 000000000..2694fcb10 --- /dev/null +++ b/source/slang/slang-artifact-output-util.cpp @@ -0,0 +1,237 @@ +#include "slang-artifact-output-util.h" + +#include "../core/slang-platform.h" + +#include "../core/slang-io.h" +#include "../core/slang-string-util.h" +#include "../core/slang-hex-dump-util.h" + +#include "../core/slang-type-text-util.h" + +// Artifact +#include "../compiler-core/slang-artifact-desc-util.h" +#include "../compiler-core/slang-artifact-util.h" + +#include "slang-compiler.h" + +namespace Slang +{ + +// Given a desc returns a codegen target if it can be used for disassembly +// Returns Unknown if cannot be used for generating disassembly +// +// NOTE! This returns the code gen target for the input binary, *not* the dissassembly output +static CodeGenTarget _getDisassemblyCodeGenTarget(const ArtifactDesc& desc) +{ + switch (desc.payload) + { + case ArtifactPayload::DXIL: return CodeGenTarget::DXIL; + case ArtifactPayload::DXBC: return CodeGenTarget::DXBytecode; + case ArtifactPayload::SPIRV: return CodeGenTarget::SPIRV; + default: break; + } + return CodeGenTarget::Unknown; +} + +/* static */SlangResult ArtifactOutputUtil::dissassembleWithDownstream(Session* session, IArtifact* artifact, DiagnosticSink* sink, IArtifact** outArtifact) +{ + auto desc = artifact->getDesc(); + + // 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. + + const CodeGenTarget target = _getDisassemblyCodeGenTarget(desc); + if (target == CodeGenTarget::Unknown) + { + return SLANG_FAIL; + } + + auto downstreamCompiler = getDownstreamCompilerRequiredForTarget(target); + + // Get the required downstream compiler + DownstreamCompiler* compiler = session->getOrLoadDownstreamCompiler(downstreamCompiler, sink); + + if (!compiler) + { + if (sink) + { + auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)downstreamCompiler); + sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); + } + return SLANG_FAIL; + } + + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef())); + + const auto data = blob->getBufferPointer(); + const auto dataSizeInBytes = blob->getBufferSize(); + + ComPtr<ISlangBlob> dissassemblyBlob; + SLANG_RETURN_ON_FAIL(compiler->disassemble(SlangCompileTarget(target), data, dataSizeInBytes, dissassemblyBlob.writeRef())); + + ArtifactDesc disassemblyDesc(desc); + disassemblyDesc.kind = ArtifactKind::Assembly; + + auto disassemblyArtifact = ArtifactUtil::createArtifact(disassemblyDesc); + disassemblyArtifact->addRepresentationUnknown(dissassemblyBlob); + + *outArtifact = disassemblyArtifact.detach(); + return SLANG_OK; +} + +SlangResult ArtifactOutputUtil::maybeDisassemble(Session* session, IArtifact* artifact, DiagnosticSink* sink, ComPtr<IArtifact>& outArtifact) +{ + const auto desc = artifact->getDesc(); + if (ArtifactDescUtil::isText(artifact->getDesc())) + { + // Nothing to convert + return SLANG_OK; + } + + if (_getDisassemblyCodeGenTarget(desc) != CodeGenTarget::Unknown) + { + // Get the blob + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef())); + + ComPtr<IArtifact> disassemblyArtifact; + + if (SLANG_SUCCEEDED(dissassembleWithDownstream(session, artifact, sink, disassemblyArtifact.writeRef()))) + { + // Check it is now text + SLANG_ASSERT(ArtifactDescUtil::isText(disassemblyArtifact->getDesc())); + + outArtifact.swap(disassemblyArtifact); + return SLANG_OK; + } + } + + return SLANG_OK; +} + +/* static */SlangResult ArtifactOutputUtil::write(const ArtifactDesc& desc, ISlangBlob* blob, ISlangWriter* writer) +{ + // If is text, we can just output + if (ArtifactDescUtil::isText(desc)) + { + return writer->write((const char*)blob->getBufferPointer(), blob->getBufferSize()); + } + else + { + if (writer->isConsole()) + { + // Else just dump as text + return HexDumpUtil::dumpWithMarkers((const uint8_t*)blob->getBufferPointer(), blob->getBufferSize(), 24, writer); + } + else + { + // Redirecting stdout to a file, so do the usual thing + writer->setMode(SLANG_WRITER_MODE_BINARY); + return writer->write((const char*)blob->getBufferPointer(), blob->getBufferSize()); + } + } +} + +/* static */SlangResult ArtifactOutputUtil::write(IArtifact* artifact, ISlangWriter* writer) +{ + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef())); + return write(artifact->getDesc(), blob, writer); +} + +static SlangResult _requireBlob(IArtifact* artifact, DiagnosticSink* sink, ComPtr<ISlangBlob>& outBlob) +{ + const auto res = artifact->loadBlob(ArtifactKeep::No, outBlob.writeRef()); + if (SLANG_FAILED(res)) + { + sink->diagnose(SourceLoc(), Diagnostics::cannotAccessAsBlob); + return res; + } + return SLANG_OK; +} + +/* static */SlangResult ArtifactOutputUtil::write(IArtifact* artifact, DiagnosticSink* sink, const UnownedStringSlice& writerName, ISlangWriter* writer) +{ + if (sink == nullptr) + { + return write(artifact, writer); + } + + // Make sure we can access as a blob + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(_requireBlob(artifact, sink, blob)); + + const auto res = write(artifact->getDesc(), blob, writer); + if (SLANG_FAILED(res)) + { + sink->diagnose(SourceLoc(), Diagnostics::cannotWriteOutputFile, writerName); + } + return res; +} + +/* static */SlangResult ArtifactOutputUtil::maybeConvertAndWrite(Session* session, IArtifact* artifact, DiagnosticSink* sink, const UnownedStringSlice& writerName, ISlangWriter* writer) +{ + // If the output is console we will try and turn into disassembly + if (writer->isConsole()) + { + ComPtr<IArtifact> disassemblyArtifact; + maybeDisassemble(session, artifact, sink, disassemblyArtifact); + + if (disassemblyArtifact) + { + return write(disassemblyArtifact, sink, writerName, writer); + } + } + + return write(artifact, sink, writerName, writer); +} + +/* static */SlangResult ArtifactOutputUtil::writeToFile(const ArtifactDesc& desc, const void* data, size_t size, const String& path) +{ + if (ArtifactDescUtil::isText(desc)) + { + return File::writeNativeText(path, data, size); + } + else + { + return File::writeAllBytes(path, data, size); + } +} + +/* static */SlangResult ArtifactOutputUtil::writeToFile(const ArtifactDesc& desc, ISlangBlob* blob, const String& path) +{ + SLANG_RETURN_ON_FAIL(writeToFile(desc, blob->getBufferPointer(), blob->getBufferSize(), path)); + return SLANG_OK; +} + +/* static */SlangResult ArtifactOutputUtil::writeToFile(IArtifact* artifact, const String& path) +{ + // Get the blob + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef())); + return writeToFile(artifact->getDesc(), blob, path); +} + +/* static */SlangResult ArtifactOutputUtil::writeToFile(IArtifact* artifact, DiagnosticSink* sink, const String& path) +{ + if (!sink) + { + return writeToFile(artifact, path); + } + + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(_requireBlob(artifact, sink, blob)); + + const auto res = writeToFile(artifact, path); + if (SLANG_FAILED(res) && sink) + { + sink->diagnose(SourceLoc(), Diagnostics::cannotWriteOutputFile, path); + } + + return res; +} + +} diff --git a/source/slang/slang-artifact-output-util.h b/source/slang/slang-artifact-output-util.h new file mode 100644 index 000000000..948b3ce7a --- /dev/null +++ b/source/slang/slang-artifact-output-util.h @@ -0,0 +1,46 @@ +#ifndef SLANG_ARTIFACT_OUTPUT_UTIL_H +#define SLANG_ARTIFACT_OUTPUT_UTIL_H + +#include "../core/slang-basic.h" + +#include "../compiler-core/slang-artifact.h" +#include "../compiler-core/slang-diagnostic-sink.h" + +#include "../../slang-com-ptr.h" + +namespace Slang +{ + +class Session; + +struct ArtifactOutputUtil +{ + /// Attempts to disassembly artifact into outArtifact. + /// Errors are output to sink if set. If not desired pass nullptr + static SlangResult dissassembleWithDownstream(Session* session, IArtifact* artifact, DiagnosticSink* sink, IArtifact** outArtifact); + + /// Disassembles if that is plausible + /// Errors are output to sink if set. If not desired pass nullptr + static SlangResult maybeDisassemble(Session* session, IArtifact* artifact, DiagnosticSink* sink, ComPtr<IArtifact>& outArtifact); + + /// Writes output to writer, will convert into disassembly if that is possible and appropriate (if outputting to console for example). + /// Errors are output to sink if set. If not desired pass nullptr + static SlangResult maybeConvertAndWrite(Session* session, IArtifact* artifact, DiagnosticSink* sink, const UnownedStringSlice& writerName, ISlangWriter* writer); + + /// Write (without any diagnostics) + static SlangResult write(IArtifact* artifact, ISlangWriter* writer); + static SlangResult write(const ArtifactDesc& desc, ISlangBlob* blob, ISlangWriter* writer); + + /// Writes the artifact with diagnostics + static SlangResult write(IArtifact* artifact, DiagnosticSink* sink, const UnownedStringSlice& writerName, ISlangWriter* writer); + + /// Write to the specified path + static SlangResult writeToFile(const ArtifactDesc& desc, const void* data, size_t size, const String& path); + static SlangResult writeToFile(const ArtifactDesc& desc, ISlangBlob* blob, const String& path); + static SlangResult writeToFile(IArtifact* artifact, const String& path); + static SlangResult writeToFile(IArtifact* artifact, DiagnosticSink* sink, const String& path); +}; + +} + +#endif diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index e49b67af2..02d312b61 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -19,6 +19,10 @@ #include "../compiler-core/slang-artifact-representation-impl.h" #include "../compiler-core/slang-artifact-impl.h" #include "../compiler-core/slang-artifact-util.h" +#include "../compiler-core/slang-artifact-associated.h" + +// Artifact output +#include "slang-artifact-output-util.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" @@ -31,33 +35,10 @@ #include "slang-emit-cuda.h" #include "slang-serialize-container.h" -// - -// Includes to allow us to control console -// output when writing assembly dumps. -#include <fcntl.h> -#ifdef _WIN32 -#include <io.h> -#else -#include <unistd.h> -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include <Windows.h> -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX -#endif - -#ifdef _MSC_VER -#pragma warning(disable: 4996) -#endif namespace Slang { - // !!!!!!!!!!!!!!!!!!!!!! free functions for DiagnosicSink !!!!!!!!!!!!!!!!!!!!!!!!!!!!! bool isHeterogeneousTarget(CodeGenTarget target) @@ -77,77 +58,6 @@ namespace Slang sb << TypeTextUtil::getPassThroughName(SlangPassThrough(val)); } - // !!!!!!!!!!!!!!!!!!!!!!!!!!!! CompileResult !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -#if 0 - SlangResult CompileResult::getSharedLibrary(ComPtr<ISlangSharedLibrary>& outSharedLibrary) - { - if (downstreamResult) - { - // TODO(JS): Work around for not knowing actual interface this is returning, - // and needing to support deps interface - - ComPtr<ISlangSharedLibrary> lib; - SLANG_RETURN_ON_FAIL(downstreamResult->getHostCallableSharedLibrary(lib)); - - if (SLANG_SUCCEEDED(lib->queryInterface(ISlangSharedLibrary::getTypeGuid(), (void**)outSharedLibrary.writeRef()))) - { - return SLANG_OK; - } - - ComPtr<ISlangSharedLibrary_Dep1> libDep1; - if (SLANG_SUCCEEDED(lib->queryInterface(ISlangSharedLibrary_Dep1::getTypeGuid(), (void**)libDep1.writeRef()))) - { - // Okay, we need to adapt for now - outSharedLibrary = new SharedLibraryDep1Adapter(libDep1); - return SLANG_OK; - } - } - return SLANG_FAIL; - } - - SlangResult CompileResult::getBlob(ComPtr<ISlangBlob>& outBlob) const - { - if(!blob) - { - switch(format) - { - default: - case ResultFormat::None: - { - // If no blob is returned, it's an error - return SLANG_FAIL; - } - case ResultFormat::Text: - { - blob = StringUtil::createStringBlob(outputString); - break; - } - case ResultFormat::Binary: - { - if (downstreamResult) - { - // TODO(JS): - // This seems a little questionable. As it stands downstreamResult, if it doesn't have a blob - // can try and read a file. How this currently works is that every getBlob will potentially try to read that file. - // Setting result to None would stop this, but is that reasonable as the state. - // Perhaps downstreamResult should hold some state that the read failed. - // For now we don't worry though. - - SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(blob)); - } - break; - } - } - } - - outBlob = blob; - return SLANG_OK; - } - - -#endif - // // FrontEndEntryPointRequest // @@ -1072,7 +982,7 @@ namespace Slang } } - ComPtr<IArtifact> sourceContainerArtifact; + ComPtr<IArtifact> sourceArtifact; /* 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 @@ -1141,9 +1051,9 @@ namespace Slang CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); - SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceContainerArtifact)); + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); - sourceCodeGenContext.maybeDumpIntermediate(sourceContainerArtifact); + sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); } else { @@ -1161,25 +1071,17 @@ namespace Slang { CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); - SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceContainerArtifact)); - sourceCodeGenContext.maybeDumpIntermediate(sourceContainerArtifact); + SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact)); + sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact); sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget); } - ComPtr<IArtifact> metadata; - if (sourceContainerArtifact) + ComPtr<IPostEmitMetadata> metadata; + if (sourceArtifact) { - auto sourceArtifact = sourceContainerArtifact->findArtifactByDerivedDesc(IArtifact::FindStyle::SelfOrChildren, - ArtifactDesc::make(ArtifactKind::Source, ArtifactPayload::Base, ArtifactStyle::Base)); - if (!sourceArtifact) - { - return SLANG_FAIL; - } - - metadata = sourceContainerArtifact->findArtifactByDerivedDesc(IArtifact::FindStyle::SelfOrChildren, - ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::PostEmitMetadata, ArtifactStyle::Base)); - + metadata = findAssociated<IPostEmitMetadata>(sourceArtifact); + ComPtr<ISlangBlob> blob; SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::No, blob.writeRef())); @@ -1513,13 +1415,6 @@ namespace Slang return SLANG_FAIL; } - auto artifactContainer = ArtifactUtil::createResultsContainer(); - - if (metadata) - { - artifactContainer->addChild(metadata); - } - // Create the artifact that encapsulates the result auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(target)); @@ -1527,54 +1422,16 @@ namespace Slang auto objRep = new ObjectArtifactRepresentation(DownstreamCompileResult::getTypeGuid(), downstreamCompileResult); artifact->addRepresentation(objRep); - // Set the artifact - outArtifact.swap(artifact); - return SLANG_OK; - } - - SlangResult CodeGenContext::dissassembleWithDownstream( - const void* data, - size_t dataSizeInBytes, - ISlangBlob** outBlob) - { - auto session = getSession(); - auto sink = getSink(); - auto target = getTargetFormat(); - - // 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) + if (metadata) { - auto compilerName = TypeTextUtil::getPassThroughAsHumanText((SlangPassThrough)downstreamCompiler); - sink->diagnose(SourceLoc(), Diagnostics::passThroughCompilerNotFound, compilerName); - return SLANG_FAIL; + artifact->addAssociated(metadata); } - ComPtr<ISlangBlob> dissassemblyBlob; - SLANG_RETURN_ON_FAIL(compiler->disassemble(SlangCompileTarget(target), data, dataSizeInBytes, dissassemblyBlob.writeRef())); - - *outBlob = dissassemblyBlob.detach(); + // Set the artifact + outArtifact.swap(artifact); return SLANG_OK; } - SlangResult CodeGenContext::dissassembleWithDownstream( - DownstreamCompileResult* downstreamResult, - ISlangBlob** outBlob) - { - - ComPtr<ISlangBlob> codeBlob; - SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(codeBlob)); - return dissassembleWithDownstream(codeBlob->getBufferPointer(), codeBlob->getBufferSize(), outBlob); - } - SlangResult emitSPIRVForEntryPointsDirectly( CodeGenContext* codeGenContext, ComPtr<IArtifact>& outArtifact); @@ -1609,26 +1466,12 @@ namespace Slang SLANG_RETURN_ON_FAIL(intermediateContext._emitEntryPoints(intermediateArtifact)); intermediateContext.maybeDumpIntermediate(intermediateArtifact); - IArtifact* binaryArtifact = intermediateArtifact->findArtifactByDerivedDesc(IArtifact::FindStyle::SelfOrChildren, - ArtifactDesc::make(ArtifactKind::BinaryLike, ArtifactPayload::Base, ArtifactStyle::Base)); - if (!binaryArtifact) - { - return SLANG_FAIL; - } - - ComPtr<ISlangBlob> binaryBlob; - SLANG_RETURN_ON_FAIL(binaryArtifact->loadBlob(ArtifactKeep::No, binaryBlob.writeRef())); - // Then disassemble the intermediate binary result to get the desired output - // Output the disassembly - ComPtr<ISlangBlob> disassemblyBlob; - SLANG_RETURN_ON_FAIL(intermediateContext.dissassembleWithDownstream(binaryBlob->getBufferPointer(), binaryBlob->getBufferSize(), disassemblyBlob.writeRef())); - - auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(target)); - artifact->addRepresentationUnknown(disassemblyBlob); - - outArtifact.swap(artifact); + // Output the disassemble + ComPtr<IArtifact> disassemblyArtifact; + SLANG_RETURN_ON_FAIL(ArtifactOutputUtil::dissassembleWithDownstream(getSession(), intermediateArtifact, getSink(), disassemblyArtifact.writeRef())); + outArtifact.swap(disassemblyArtifact); return SLANG_OK; } case CodeGenTarget::SPIRV: @@ -1714,168 +1557,16 @@ namespace Slang } } - enum class OutputFileKind - { - Text, - Binary, - }; - - static void writeOutputFile( - CodeGenContext* context, - FILE* file, - String const& path, - void const* data, - size_t size) - { - size_t count = fwrite(data, size, 1, file); - if (count != 1) - { - context->getSink()->diagnose( - SourceLoc(), - Diagnostics::cannotWriteOutputFile, - path); - } - } - - static void writeOutputFile( - CodeGenContext* context, - ISlangWriter* writer, - String const& path, - void const* data, - size_t size) + void EndToEndCompileRequest::writeArtifactToStandardOutput(IArtifact* artifact, DiagnosticSink* sink) { - - if (SLANG_FAILED(writer->write((const char*)data, size))) - { - context->getSink()->diagnose( - SourceLoc(), - Diagnostics::cannotWriteOutputFile, - path); - } - } - - static void writeOutputFile( - CodeGenContext* context, - String const& path, - void const* data, - size_t size, - OutputFileKind kind) - { - FILE* file = fopen( - path.getBuffer(), - kind == OutputFileKind::Binary ? "wb" : "w"); - if (!file) - { - context->getSink()->diagnose( - SourceLoc(), - Diagnostics::cannotWriteOutputFile, - path); - return; - } - - writeOutputFile(context, file, path, data, size); - fclose(file); - } - - static void writeCompileResultToFile( - CodeGenContext* context, - String const& outputPath, - IArtifact* inArtifact) - { - // The artifact can contain multiple things, we want to find something like 'source' or binary like - IArtifact* artifact = ArtifactUtil::findSignificant(inArtifact); - if (!artifact) - { - return; - } - - ComPtr<ISlangBlob> blob; - if (SLANG_FAILED(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()))) - { - // Unable to get blob - return; - } - - const auto outputKind = ArtifactDescUtil::isText(artifact->getDesc()) ? - OutputFileKind::Text : - OutputFileKind::Binary; - - writeOutputFile(context, - outputPath, - (const char*)blob->getBufferPointer(), - blob->getBufferSize(), - outputKind); - } - - static void writeOutputToConsole( - ISlangWriter* writer, - String const& text) - { - writer->write(text.getBuffer(), text.getLength()); - } - - static void writeCompileResultToStandardOutput( - CodeGenContext* codeGenContext, - EndToEndCompileRequest* endToEndReq, - IArtifact* inArtifact) - { - ISlangWriter* writer = endToEndReq->getWriter(WriterChannel::StdOutput); - - // The artifact can contain multiple things, we want to find something like 'source' or binary like - IArtifact* artifact = ArtifactUtil::findSignificant(inArtifact); - if (!artifact) + // If it's host callable it's not available to write to output + if (isDerivedFrom(artifact->getDesc().kind, ArtifactKind::HostCallable)) { return; } - ComPtr<ISlangBlob> blob; - if (SLANG_FAILED(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()))) - { - // Unable to get blob - return; - } - - // If is text, we can just output - if (ArtifactDescUtil::isText(artifact->getDesc())) - { - writer->write((const char*)blob->getBufferPointer(), blob->getBufferSize()); - return; - } - - if (writer->isConsole()) - { - switch (artifact->getDesc().payload) - { - case ArtifactPayload::SPIRV: - case ArtifactPayload::DXIL: - case ArtifactPayload::DXBC: - { - ComPtr<ISlangBlob> disassemblyBlob; - - if (SLANG_SUCCEEDED(codeGenContext->dissassembleWithDownstream(blob->getBufferPointer(), blob->getBufferSize(), disassemblyBlob.writeRef()))) - { - const UnownedStringSlice disassembly = StringUtil::getSlice(disassemblyBlob); - writeOutputToConsole(writer, disassembly); - } - return; - } - } - - // Else just dump as text - HexDumpUtil::dumpWithMarkers((const uint8_t*)blob->getBufferPointer(), blob->getBufferSize(), 24, writer); - } - else - { - // Redirecting stdout to a file, so do the usual thing - writer->setMode(SLANG_WRITER_MODE_BINARY); - - writeOutputFile( - codeGenContext, - writer, - "stdout", - blob->getBufferPointer(), - blob->getBufferSize()); - } + auto session = getSession(); + ArtifactOutputUtil::maybeConvertAndWrite(session, artifact, sink, toSlice("stdout"), getWriter(WriterChannel::StdOutput)); } void EndToEndCompileRequest::writeWholeProgramResult( @@ -1907,12 +1598,11 @@ namespace Slang String outputPath = targetInfo->wholeTargetOutputPath; if (outputPath != "") { - writeCompileResultToFile(&codeGenContext, outputPath, artifact); + ArtifactOutputUtil::writeToFile(artifact, codeGenContext.getSink(), outputPath); return; } } - - writeCompileResultToStandardOutput(&codeGenContext, this, artifact); + writeArtifactToStandardOutput(artifact, codeGenContext.getSink()); } void EndToEndCompileRequest::writeEntryPointResult( @@ -1946,12 +1636,12 @@ namespace Slang String outputPath; if(targetInfo->entryPointOutputPaths.TryGetValue(entryPointIndex, outputPath)) { - writeCompileResultToFile(&codeGenContext, outputPath, artifact); + ArtifactOutputUtil::writeToFile(artifact, codeGenContext.getSink(), outputPath); return; } } - writeCompileResultToStandardOutput(&codeGenContext, this, artifact); + writeArtifactToStandardOutput(artifact, codeGenContext.getSink()); } IArtifact* TargetProgram::_createWholeProgramResult( @@ -2336,219 +2026,77 @@ namespace Slang // Debug logic for dumping intermediate outputs - // - - void CodeGenContext::dumpIntermediate( - void const* data, - size_t size, - char const* ext, - bool isBinary) - { - // Try to generate a unique ID for the file to dump, - // even in cases where there might be multiple threads - // doing compilation. - // - // This is primarily a debugging aid, so we don't - // really need/want to do anything too elaborate - - static uint32_t counter = 0; -#ifdef _WIN32 - uint32_t id = InterlockedIncrement(&counter); -#else - // TODO: actually implement the case for other platforms - uint32_t id = counter++; -#endif - - String path; - path.append(getIntermediateDumpPrefix()); - path.append(id); - path.append(ext); - - FILE* file = fopen(path.getBuffer(), isBinary ? "wb" : "w"); - if (!file) return; - - fwrite(data, size, 1, file); - fclose(file); - } - - void CodeGenContext::dumpIntermediateText( - void const* data, - size_t size, - char const* ext) - { - dumpIntermediate(data, size, ext, false); - } - - void CodeGenContext::dumpIntermediateBinary( - void const* data, - size_t size, - char const* ext) - { - dumpIntermediate(data, size, ext, true); - } - - void CodeGenContext::maybeDumpIntermediate( - DownstreamCompileResult* compileResult) + + void CodeGenContext::_dumpIntermediateMaybeWithAssembly(IArtifact* artifact) { - if (!shouldDumpIntermediates()) - return; + _dumpIntermediate(artifact); - ComPtr<ISlangBlob> blob; - if (SLANG_SUCCEEDED(compileResult->getBinary(blob))) - { - maybeDumpIntermediate(blob->getBufferPointer(), blob->getBufferSize()); - } - } + ComPtr<IArtifact> assembly; + ArtifactOutputUtil::maybeDisassemble(getSession(), artifact, nullptr, assembly); - static const char* _getTargetExtension(CodeGenTarget target) - { - switch (target) + if (assembly) { - case CodeGenTarget::HLSL: return ".hlsl"; - case CodeGenTarget::GLSL: return ".glsl"; - case CodeGenTarget::SPIRV: return ".spv"; - case CodeGenTarget::DXBytecode: return ".dxbc"; - case CodeGenTarget::DXIL: return ".dxil"; - case CodeGenTarget::SPIRVAssembly: return ".spv.asm"; - case CodeGenTarget::DXBytecodeAssembly: return ".dxbc.asm"; - case CodeGenTarget::DXILAssembly: return ".dxil.asm"; - case CodeGenTarget::CSource: return ".c"; - case CodeGenTarget::CUDASource: return ".cu"; - case CodeGenTarget::CPPSource: return ".cpp"; - case CodeGenTarget::HostCPPSource: return ".cpp"; - - // What these should be called is target specific, but just use these exts to make clear for now - // for now - case CodeGenTarget::HostExecutable: - { - return ".exe"; - } - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - { - return ".shared-lib"; - } - default: break; + _dumpIntermediate(assembly); } - return nullptr; } - void CodeGenContext::maybeDumpIntermediate(IArtifact* inArtifact) + void CodeGenContext::_dumpIntermediate(IArtifact* artifact) { - if (!shouldDumpIntermediates()) - return; - - IArtifact* artifact = ArtifactUtil::findSignificant(inArtifact); - if (!artifact) - { - return; - } - ComPtr<ISlangBlob> blob; if (SLANG_FAILED(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()))) { return; } + _dumpIntermediate(artifact->getDesc(), blob->getBufferPointer(), blob->getBufferSize()); + } - const auto desc = artifact->getDesc(); - String ext = ArtifactDescUtil::getDefaultExtension(desc); + void CodeGenContext::_dumpIntermediate( + const ArtifactDesc& desc, + void const* data, + size_t size) + { + // Try to generate a unique ID for the file to dump, + // even in cases where there might be multiple threads + // doing compilation. + // + // This is primarily a debugging aid, so we don't + // really need/want to do anything too elaborate + static std::atomic<uint32_t> counter(0); - if (ArtifactDescUtil::isText(artifact->getDesc())) - { - dumpIntermediateText(blob->getBufferPointer(), blob->getBufferSize(), ext.getBuffer()); - } - else - { - switch (artifact->getDesc().payload) - { - case ArtifactPayload::SPIRV: - case ArtifactPayload::DXIL: - case ArtifactPayload::DXBC: - { - ComPtr<ISlangBlob> disassemblyBlob; + const uint32_t id = ++counter; - if (SLANG_SUCCEEDED(dissassembleWithDownstream(blob->getBufferPointer(), blob->getBufferSize(), disassemblyBlob.writeRef()))) - { - ArtifactDesc assemblyDesc(desc); - assemblyDesc.kind = ArtifactKind::Assembly; + // Just use the counter for the 'base name' + StringBuilder basename; - ext = ArtifactDescUtil::getDefaultExtension(assemblyDesc); + // Add the prefix + basename << getIntermediateDumpPrefix(); - dumpIntermediateText(disassemblyBlob->getBufferPointer(), disassemblyBlob->getBufferSize(), ext.getBuffer()); - return; - } - } - default: break; - } + // Add the id + basename << int(id); - dumpIntermediateBinary(blob->getBufferPointer(), blob->getBufferSize(), ext.getBuffer()); - } - } + // Work out the filename based on the desc and the basename + StringBuilder filename; + ArtifactDescUtil::calcNameForDesc(desc, basename.getUnownedSlice(), filename); - void CodeGenContext::maybeDumpIntermediate( - void const* data, - size_t size) - { - if (!shouldDumpIntermediates()) - return; - - auto target = getTargetFormat(); - const auto desc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)); - - if (desc.kind == ArtifactKind::Text) + // If didn't produce a filename, use basename with .unknown extension + if (filename.getLength() == 0) { - dumpIntermediateText(data, size, _getTargetExtension(target)); - return; + filename = basename; + filename << ".unknown"; } - switch (target) - { -#if 0 - case CodeGenTarget::SlangIRAssembly: - { - dumpIntermediateText(compileRequest, data, size, ".slang-ir.asm"); - break; - } -#endif - case CodeGenTarget::DXIL: - case CodeGenTarget::DXBytecode: - case CodeGenTarget::SPIRV: - { - const char* ext = _getTargetExtension(target); - SLANG_ASSERT(ext); - - dumpIntermediateBinary(data, size, ext); - ComPtr<ISlangBlob> disassemblyBlob; - if (SLANG_SUCCEEDED(dissassembleWithDownstream(data, size, disassemblyBlob.writeRef()))) - { - StringBuilder buf; - buf << ext << ".asm"; - dumpIntermediateText(disassemblyBlob->getBufferPointer(), disassemblyBlob->getBufferSize(), buf.getBuffer()); - } - break; - } - - case CodeGenTarget::HostHostCallable: - case CodeGenTarget::ShaderHostCallable: - case CodeGenTarget::ShaderSharedLibrary: - case CodeGenTarget::HostExecutable: - { - dumpIntermediateBinary(data, size, _getTargetExtension(target)); - break; - } - default: break; - } + // Write to a file + ArtifactOutputUtil::writeToFile(desc, data, size, filename); } - void CodeGenContext::maybeDumpIntermediate( - char const* text) + void CodeGenContext::maybeDumpIntermediate(IArtifact* artifact) { if (!shouldDumpIntermediates()) return; - maybeDumpIntermediate(text, strlen(text)); + + _dumpIntermediateMaybeWithAssembly(artifact); } IRDumpOptions CodeGenContext::getIRDumpOptions() diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 9f75d94d3..6b79b2679 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -144,47 +144,6 @@ namespace Slang class Module; class TranslationUnitRequest; -#if 0 - // Result of compiling an entry point. - // Should only ever be string, binary or shared library - class CompileResult - { - public: - CompileResult() = default; - explicit CompileResult(String const& str, RefPtr<PostEmitMetadata> metadata) - : format(ResultFormat::Text) - , outputString(str) - , postEmitMetadata(metadata) {} - - explicit CompileResult(ISlangBlob* inBlob) - : format(ResultFormat::Binary) - , blob(inBlob) {} - - explicit CompileResult(DownstreamCompileResult* inDownstreamResult, RefPtr<PostEmitMetadata> metadata) - : format(ResultFormat::Binary) - , downstreamResult(inDownstreamResult) - , postEmitMetadata(metadata) {} - - explicit CompileResult(const UnownedStringSlice& slice ) - : format(ResultFormat::Text) - , outputString(slice) {} - - SlangResult getBlob(ComPtr<ISlangBlob>& outBlob) const; - SlangResult getSharedLibrary(ComPtr<ISlangSharedLibrary>& outSharedLibrary); - - SlangResult isParameterLocationUsed(SlangParameterCategory category, UInt spaceIndex, UInt registerIndex, bool& outUsed); - - ResultFormat format = ResultFormat::None; - String outputString; ///< Only set if result type is ResultFormat::Text - - mutable ComPtr<ISlangBlob> blob; - - RefPtr<DownstreamCompileResult> downstreamResult; - - RefPtr<PostEmitMetadata> postEmitMetadata; - }; -#endif - /// Information collected about global or entry-point shader parameters struct ShaderParamInfo { @@ -2414,46 +2373,21 @@ namespace Slang SlangResult emitEntryPoints(ComPtr<IArtifact>& outArtifact); - SlangResult dissassembleWithDownstream( - const void* data, - size_t dataSizeInBytes, - ISlangBlob** outBlob); - - SlangResult dissassembleWithDownstream( - DownstreamCompileResult* downstreamResult, - ISlangBlob** outBlob); + void maybeDumpIntermediate(IArtifact* artifact); protected: CodeGenTarget m_targetFormat = CodeGenTarget::Unknown; ExtensionTracker* m_extensionTracker = nullptr; - void maybeDumpIntermediate(IArtifact* artifact); + /// Will output assembly as well as the artifact if appropriate for the artifact type for assembly output + /// and conversion is possible + void _dumpIntermediateMaybeWithAssembly(IArtifact* artifact); - // Helper to dump intermediate output when debugging - void maybeDumpIntermediate( + void _dumpIntermediate(IArtifact* artifact); + void _dumpIntermediate( + const ArtifactDesc& desc, void const* data, size_t size); - void maybeDumpIntermediate( - char const* text); - - void maybeDumpIntermediate( - DownstreamCompileResult* compileResult); - - void dumpIntermediate( - void const* data, - size_t size, - char const* ext, - bool isBinary); - - void dumpIntermediateText( - void const* data, - size_t size, - char const* ext); - - void dumpIntermediateBinary( - void const* data, - size_t size, - char const* ext); /* Emits entry point source taking into account if a pass-through or not. Uses 'targetFormat' to determine the target (not targetReq) */ @@ -2687,6 +2621,7 @@ namespace Slang return m_specializedEntryPoints[index]; } + void writeArtifactToStandardOutput(IArtifact* artifact, DiagnosticSink* sink); void generateOutput(); @@ -2865,7 +2800,7 @@ namespace Slang { return m_downstreamCompileTime; } - + /// Get the downstream compiler for a transition DownstreamCompiler* getDownstreamCompiler(CodeGenTarget source, CodeGenTarget target); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index cbbb284cb..6acd27e40 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -129,6 +129,7 @@ DIAGNOSTIC( 94, Error, unableToReadRiff, "unable to read as 'riff'/not a 'rif DIAGNOSTIC( 95, Error, unknownLibraryKind, "unknown library kind '$0'") DIAGNOSTIC( 96, Error, kindNotLinkable, "not a known linkable kind '$0'") DIAGNOSTIC( 97, Error, libraryDoesNotExist, "library '$0' does not exist") +DIAGNOSTIC( 98, Error, cannotAccessAsBlob, "cannot access as a blob") // // 001xx - Downstream Compilers diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 43f9da3df..2a1b78833 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -71,6 +71,7 @@ #include "../compiler-core/slang-artifact-desc-util.h" #include "../compiler-core/slang-artifact-util.h" #include "../compiler-core/slang-artifact-impl.h" +#include "../compiler-core/slang-artifact-associated-impl.h" #include <assert.h> @@ -836,11 +837,10 @@ Result linkAndOptimizeIR( #endif validateIRModuleIfEnabled(codeGenContext, irModule); - auto metadata = Artifact::create(ArtifactDesc::make(ArtifactKind::Instance, ArtifactPayload::PostEmitMetadata, artifactDesc.style)); - auto postEmitMetaRep = new PostEmitMetadataArtifactRepresentation; - metadata->addRepresentation(postEmitMetaRep); + auto metadata = new PostEmitMetadata; + outLinkedIR.metadata = metadata; - collectMetadata(irModule, postEmitMetaRep->m_metadata); + collectMetadata(irModule, *metadata); outLinkedIR.metadata = metadata; @@ -857,8 +857,6 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr auto target = getTargetFormat(); auto targetRequest = getTargetReq(); - auto artifactContainer = ArtifactUtil::createResultsContainer(); - auto lineDirectiveMode = targetRequest->getLineDirectiveMode(); // To try to make the default behavior reasonable, we will // always use C-style line directives (to give the user @@ -930,7 +928,7 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr SLANG_RETURN_ON_FAIL(sourceEmitter->init()); - + ComPtr<IPostEmitMetadata> metadata; { LinkingAndOptimizationOptions linkingAndOptimizationOptions; @@ -955,11 +953,8 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr auto irModule = linkedIR.module; - if (linkedIR.metadata) - { - artifactContainer->addChild(linkedIR.metadata); - } - + metadata = linkedIR.metadata; + // After all of the required optimization and legalization // passes have been performed, we can emit target code from // the IR module. @@ -1029,12 +1024,15 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr // Write out the result - auto targetArtifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(target)); - targetArtifact->addRepresentationUnknown(StringBlob::moveCreate(finalResult)); + auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(target)); + artifact->addRepresentationUnknown(StringBlob::moveCreate(finalResult)); - artifactContainer->addChild(targetArtifact); + if (metadata) + { + artifact->addAssociated(metadata); + } - outArtifact = artifactContainer; + outArtifact.swap(artifact); return SLANG_OK; } @@ -1048,8 +1046,6 @@ SlangResult emitSPIRVForEntryPointsDirectly( CodeGenContext* codeGenContext, ComPtr<IArtifact>& outArtifact) { - auto artifactContainer = ArtifactUtil::createResultsContainer(); - // Outside because we want to keep IR in scope whilst we are processing emits LinkedIR linkedIR; LinkingAndOptimizationOptions linkingAndOptimizationOptions; @@ -1064,17 +1060,15 @@ SlangResult emitSPIRVForEntryPointsDirectly( List<uint8_t> spirv; emitSPIRVFromIR(codeGenContext, irModule, irEntryPoints, spirv); - auto targetArtifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(codeGenContext->getTargetFormat())); - targetArtifact->addRepresentationUnknown(ListBlob::moveCreate(spirv)); - - artifactContainer->addChild(targetArtifact); + auto artifact = ArtifactUtil::createArtifactForCompileTarget(asExternal(codeGenContext->getTargetFormat())); + artifact->addRepresentationUnknown(ListBlob::moveCreate(spirv)); if (linkedIR.metadata) { - artifactContainer->addChild(linkedIR.metadata); + artifact->addAssociated(linkedIR.metadata); } - outArtifact = artifactContainer; + outArtifact.swap(artifact); return SLANG_OK; } diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h index dcfb642da..5fac8dde2 100644 --- a/source/slang/slang-ir-link.h +++ b/source/slang/slang-ir-link.h @@ -3,16 +3,18 @@ #include "slang-compiler.h" +#include "../compiler-core/slang-artifact-associated.h" + namespace Slang { struct IRVarLayout; struct LinkedIR { - RefPtr<IRModule> module; - IRVarLayout* globalScopeVarLayout; - List<IRFunc*> entryPoints; - ComPtr<IArtifact> metadata; + RefPtr<IRModule> module; + IRVarLayout* globalScopeVarLayout; + List<IRFunc*> entryPoints; + ComPtr<IPostEmitMetadata> metadata; }; diff --git a/source/slang/slang-ir-metadata.cpp b/source/slang/slang-ir-metadata.cpp index 396c40837..7d4694ec5 100644 --- a/source/slang/slang-ir-metadata.cpp +++ b/source/slang/slang-ir-metadata.cpp @@ -4,7 +4,7 @@ #include "slang-ir.h" #include "slang-ir-insts.h" -#include "../compiler-core/slang-artifact-representation-impl.h" +#include "../compiler-core/slang-artifact-associated-impl.h" namespace Slang { @@ -69,11 +69,10 @@ void collectMetadata(const IRModule* irModule, PostEmitMetadata& outMetadata) auto registerIndex = offsetAttr->getOffset(); auto size = sizeAttr->getSize(); auto count = size.isFinite() ? size.getFiniteValue() : 0; - _insertBinding(outMetadata.usedBindings, kind, spaceIndex, registerIndex, count); + _insertBinding(outMetadata.m_usedBindings, kind, spaceIndex, registerIndex, count); } } } } - } diff --git a/source/slang/slang-ir-metadata.h b/source/slang/slang-ir-metadata.h index b7fcd1e2b..e72e10a94 100644 --- a/source/slang/slang-ir-metadata.h +++ b/source/slang/slang-ir-metadata.h @@ -4,7 +4,7 @@ namespace Slang { -struct PostEmitMetadata; +class PostEmitMetadata; struct IRModule; void collectMetadata(const IRModule* irModule, PostEmitMetadata& outMetadata); diff --git a/source/slang/slang-module-library.h b/source/slang/slang-module-library.h index dd74193a4..698e4e014 100644 --- a/source/slang/slang-module-library.h +++ b/source/slang/slang-module-library.h @@ -26,7 +26,7 @@ public: virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) SLANG_OVERRIDE { SLANG_UNUSED(blob); return SLANG_E_NOT_IMPLEMENTED; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE { SLANG_UNUSED(typeGuid); SLANG_UNUSED(outCastable); return SLANG_E_NOT_IMPLEMENTED; } virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return true; } List<FrontEndCompileRequest::ExtraEntryPointInfo> m_entryPoints; diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 6515dc35d..4f135d144 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -11,6 +11,7 @@ #include "../compiler-core/slang-artifact-impl.h" #include "../compiler-core/slang-artifact-desc-util.h" #include "../compiler-core/slang-artifact-util.h" +#include "../compiler-core/slang-artifact-associated-impl.h" #include "slang-module-library.h" @@ -3153,19 +3154,13 @@ SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointCode( DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); - IArtifact* entryPointResult = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); + IArtifact* artifact = targetProgram->getOrCreateEntryPointResult(entryPointIndex, &sink); sink.getBlobIfNeeded(outDiagnostics); - if(entryPointResult == nullptr) - return SLANG_FAIL; - - IArtifact* significantBlob = ArtifactUtil::findSignificant(entryPointResult); - if (!significantBlob) - { + if(artifact == nullptr) return SLANG_FAIL; - } - return significantBlob->loadBlob(ArtifactKeep::Yes, outCode); + return artifact->loadBlob(ArtifactKeep::Yes, outCode); } SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::getEntryPointHostCallable( @@ -4838,11 +4833,8 @@ SlangResult EndToEndCompileRequest::getEntryPointCodeBlob(int entryPointIndex, i if (!outBlob) return SLANG_E_INVALID_ARG; ComPtr<IArtifact> artifact; SLANG_RETURN_ON_FAIL(_getEntryPointResult(this, entryPointIndex, targetIndex, artifact)); - if (auto significant = ArtifactUtil::findSignificant(artifact)) - { - SLANG_RETURN_ON_FAIL(significant->loadBlob(ArtifactKeep::Yes, outBlob)); - return SLANG_OK; - } + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, outBlob)); + return SLANG_E_NOT_AVAILABLE; } @@ -4851,11 +4843,7 @@ SlangResult EndToEndCompileRequest::getEntryPointHostCallable(int entryPointInde if (!outSharedLibrary) return SLANG_E_INVALID_ARG; ComPtr<IArtifact> artifact; SLANG_RETURN_ON_FAIL(_getEntryPointResult(this, entryPointIndex, targetIndex, artifact)); - if (auto significant = ArtifactUtil::findSignificant(artifact)) - { - SLANG_RETURN_ON_FAIL(significant->loadSharedLibrary(ArtifactKeep::Yes, outSharedLibrary)); - return SLANG_OK; - } + SLANG_RETURN_ON_FAIL(artifact->loadSharedLibrary(ArtifactKeep::Yes, outSharedLibrary)); return SLANG_E_NOT_AVAILABLE; } @@ -4866,13 +4854,8 @@ SlangResult EndToEndCompileRequest::getTargetCodeBlob(int targetIndex, ISlangBlo ComPtr<IArtifact> artifact; SLANG_RETURN_ON_FAIL(_getWholeProgramResult(this, targetIndex, artifact)); - - if (auto significant = ArtifactUtil::findSignificant(artifact)) - { - SLANG_RETURN_ON_FAIL(significant->loadBlob(ArtifactKeep::Yes, outBlob)); - return SLANG_OK; - } - return SLANG_E_NOT_AVAILABLE; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, outBlob)); + return SLANG_OK; } SlangResult EndToEndCompileRequest::getTargetHostCallable(int targetIndex,ISlangSharedLibrary** outSharedLibrary) @@ -5030,22 +5013,14 @@ SlangResult EndToEndCompileRequest::isParameterLocationUsed(Int entryPointIndex, if (SLANG_FAILED(_getEntryPointResult(this, static_cast<int>(entryPointIndex), static_cast<int>(targetIndex), artifact))) return SLANG_E_INVALID_ARG; - // We need to find the meta data - IArtifact* metadataArtifact = artifact->findArtifactByDerivedDesc(IArtifact::FindStyle::SelfOrChildren, - ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::PostEmitMetadata, ArtifactStyle::Base)); - if (!metadataArtifact) - { - return SLANG_E_NOT_AVAILABLE; - } - // Find a rep - auto metadataRep = findRepresentation<IPostEmitMetadataArtifactRepresentation>(metadataArtifact); - if (!metadataRep) + auto metadata = findAssociated<IPostEmitMetadata>(artifact); + if (!metadata) return SLANG_E_NOT_AVAILABLE; // TODO: optimize this with a binary search through a sorted list - for (const auto& range : metadataRep->getBindingRanges()) + for (const auto& range : metadata->getBindingRanges()) { if (range.containsBinding((slang::ParameterCategory)category, spaceIndex, registerIndex)) { |
