diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-08-09 11:23:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-09 11:23:40 -0400 |
| commit | 9df7fcb023bd5a22f35ecd609b7a50cc6634976c (patch) | |
| tree | 69692c36e664eafa2a37b5fa13ca7142f62b1844 /source | |
| parent | c0733be56dc24ef0eb67b26fe0c49d3419e75773 (diff) | |
Artifact split interface and implementation (#2349)
* #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.
Diffstat (limited to 'source')
23 files changed, 1441 insertions, 1380 deletions
diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp new file mode 100644 index 000000000..e382ca08c --- /dev/null +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -0,0 +1,689 @@ +// slang-artifact-desc-util.cpp +#include "slang-artifact-desc-util.h" + +#include "slang-artifact-representation.h" + +#include "../core/slang-type-text-util.h" +#include "../core/slang-io.h" + +namespace Slang { + +namespace { // anonymous + +struct HierarchicalEnumEntry +{ + Index value; + Index parent; + const char* name; +}; + +static bool _isHierarchicalEnumOk(ConstArrayView<HierarchicalEnumEntry> entries, Count countOf) +{ + // All values should be set + if (entries.getCount() != countOf) + { + return false; + } + + List<uint8_t> isUsed; + isUsed.setCount(countOf); + ::memset(isUsed.getBuffer(), 0, countOf); + + for (const auto& entry : entries) + { + const auto value = entry.value; + // Must be in range + if (value < 0 || value >= countOf) + { + return false; + } + + if (isUsed[value] != 0) + { + return false; + } + // Mark as used + isUsed[value]++; + } + + // There can't be any gaps + for (auto v : isUsed) + { + if (v == 0) + { + return false; + } + } + + // Okay, looks reasonable.. + return true; +} + +template <typename T> +struct HierarchicalEnumTable +{ + HierarchicalEnumTable(ConstArrayView<HierarchicalEnumEntry> entries) + { + // Remove warnings around this not being used. + { + const auto unused = _isHierarchicalEnumOk; + SLANG_UNUSED(unused); + } + + SLANG_COMPILE_TIME_ASSERT(Index(T::Invalid) < Index(T::Base)); + SLANG_ASSERT(entries.getCount() == Count(T::CountOf)); + + SLANG_ASSERT(_isHierarchicalEnumOk(entries, Count(T::CountOf))); + + ::memset(&m_parents, 0, sizeof(m_parents)); + + for (const auto& entry : entries) + { + const auto value = entry.value; + m_parents[value] = T(entry.parent); + m_names[value] = UnownedStringSlice(entry.name); + } + + // TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid* + // we would want the Parent of Base to be Base. + // + // Base parent should be invalid + SLANG_ASSERT(getParent(T::Base) == T::Invalid); + // Invalids parent should be invalid + SLANG_ASSERT(getParent(T::Invalid) == T::Invalid); + } + + T getParent(T kind) const + { + return (kind >= T::CountOf) ? + T::Invalid : + m_parents[Index(kind)]; + } + UnownedStringSlice getName(T kind) const + { + return (kind >= T::CountOf) ? + UnownedStringSlice() : + m_names[Index(kind)]; + } + + bool isDerivedFrom(T type, T base) const + { + if (Index(type) >= Index(T::CountOf)) + { + return false; + } + + do + { + if (type == base) + { + return true; + } + type = m_parents[Index(type)]; + } while (Index(type) > Index(T::Base)); + + return false; + } + +protected: + T m_parents[Count(T::CountOf)]; + UnownedStringSlice m_names[Count(T::CountOf)]; +}; + +} // anonymous + +// Macro utils to create "enum hierarchy" tables + +#define SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_ENTRY_MACRO) \ +static ConstArrayView<HierarchicalEnumEntry> _getEntries##ENUM_TYPE() \ +{ \ + static const HierarchicalEnumEntry values[] = { ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO) }; \ + return makeConstArrayView(values); \ +} + +#define SLANG_HIERARCHICAL_ENUM(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ +SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ +\ +static const HierarchicalEnumTable<ENUM_TYPE> g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \ +\ +ENUM_TYPE getParent(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getParent(kind); } \ +UnownedStringSlice getName(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getName(kind); } \ +bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) { return g_table##ENUM_TYPE.isDerivedFrom(kind, base); } + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactKind !!!!!!!!!!!!!!!!!!!!!!! */ + +#define SLANG_ARTIFACT_KIND(x) \ + x(Invalid, Invalid) \ + x(Base, Invalid) \ + x(None, Base) \ + x(Unknown, Base) \ + x(Container, Base) \ + x(Zip, Container) \ + x(Riff, Container) \ + x(Text, Base) \ + x(HumanText, Text) \ + x(Source, Text) \ + x(Assembly, Text) \ + x(BinaryLike, Base) \ + x(ObjectCode, BinaryLike) \ + x(Library, BinaryLike) \ + x(Executable, BinaryLike) \ + x(SharedLibrary, BinaryLike) \ + x(HostCallable, BinaryLike) \ + \ + x(DebugInfo, Base) \ + x(Diagnostics, Base) + +#define SLANG_ARTIFACT_KIND_ENTRY(TYPE, PARENT) { Index(ArtifactKind::TYPE), Index(ArtifactKind::PARENT), #TYPE }, + +SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_ENTRY) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPayload !!!!!!!!!!!!!!!!!!!!!!! */ + +#define SLANG_ARTIFACT_PAYLOAD(x) \ + x(Invalid, Invalid) \ + x(Base, Invalid) \ + x(None, Base) \ + x(Unknown, Base) \ + x(Source, Base) \ + x(C, Source) \ + x(Cpp, Source) \ + x(HLSL, Source) \ + x(GLSL, Source) \ + x(CUDA, Source) \ + x(Metal, Source) \ + x(Slang, Source) \ + x(KernelLike, Base) \ + x(DXIL, KernelLike) \ + x(DXBC, KernelLike) \ + x(SPIRV, KernelLike) \ + x(PTX, KernelLike) \ + x(CuBin, KernelLike) \ + x(MetalAIR, KernelLike) \ + x(CPULike, Base) \ + x(UnknownCPU, CPULike) \ + x(X86, CPULike) \ + x(X86_64, CPULike) \ + x(Aarch, CPULike) \ + x(Aarch64, CPULike) \ + x(HostCPU, CPULike) \ + x(UniversalCPU, CPULike) \ + x(GeneralIR, Base) \ + x(SlangIR, GeneralIR) \ + x(LLVMIR, GeneralIR) \ + x(AST, Base) \ + x(SlangAST, AST) + +#define SLANG_ARTIFACT_PAYLOAD_ENTRY(TYPE, PARENT) { Index(ArtifactPayload::TYPE), Index(ArtifactPayload::PARENT), #TYPE }, + +SLANG_HIERARCHICAL_ENUM(ArtifactPayload, SLANG_ARTIFACT_PAYLOAD, SLANG_ARTIFACT_PAYLOAD_ENTRY) + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactStyle !!!!!!!!!!!!!!!!!!!!!!! */ + +#define SLANG_ARTIFACT_STYLE(x) \ + x(Invalid, Invalid) \ + x(Base, Invalid) \ + x(Unknown, Base) \ + x(Kernel, Base) \ + x(Host, Base) + +#define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) { Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE }, + +SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYLE_ENTRY) + + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDescUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */ArtifactDesc ArtifactDescUtil::makeDescFromCompileTarget(SlangCompileTarget target) +{ + switch (target) + { + case SLANG_TARGET_UNKNOWN: return Desc::make(Kind::Unknown, Payload::None, Style::Unknown, 0); + case SLANG_TARGET_NONE: return Desc::make(Kind::None, Payload::None, Style::Unknown, 0); + case SLANG_GLSL_VULKAN: + case SLANG_GLSL_VULKAN_ONE_DESC: + case SLANG_GLSL: + { + // For the moment we Desc::make all just map to GLSL, but we could use flags + // or some other mechanism to distinguish the types + return Desc::make(Kind::Source, Payload::GLSL, Style::Kernel, 0); + } + case SLANG_HLSL: return Desc::make(Kind::Source, Payload::HLSL, Style::Kernel, 0); + case SLANG_SPIRV: return Desc::make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); + case SLANG_SPIRV_ASM: return Desc::make(Kind::Assembly, Payload::SPIRV, Style::Kernel, 0); + case SLANG_DXBC: return Desc::make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); + case SLANG_DXBC_ASM: return Desc::make(Kind::Assembly, Payload::DXBC, Style::Kernel, 0); + case SLANG_DXIL: return Desc::make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); + case SLANG_DXIL_ASM: return Desc::make(Kind::Assembly, Payload::DXIL, Style::Kernel, 0); + case SLANG_C_SOURCE: return Desc::make(Kind::Source, Payload::C, Style::Kernel, 0); + case SLANG_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Kernel, 0); + case SLANG_HOST_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0); + case SLANG_HOST_EXECUTABLE: return Desc::make(Kind::Executable, Payload::HostCPU, Style::Host, 0); + case SLANG_SHADER_SHARED_LIBRARY: return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); + case SLANG_SHADER_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Kernel, 0); + case SLANG_CUDA_SOURCE: return Desc::make(Kind::Source, Payload::CUDA, Style::Kernel, 0); + // TODO(JS): + // Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. Saying it is + // 'Executable' implies it is Binary (which PTX isn't). Executable also implies 'complete for executation', + // irrespective of it being text. + case SLANG_PTX: return Desc::make(Kind::Executable, Payload::PTX, Style::Kernel, 0); + case SLANG_OBJECT_CODE: return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); + case SLANG_HOST_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); + default: break; + } + + SLANG_UNEXPECTED("Unhandled type"); +} + +namespace { // anonymous +struct KindExtension +{ + ArtifactKind kind; + UnownedStringSlice ext; +}; +} // anonymous + +#define SLANG_KIND_EXTENSION(kind, ext) \ + { ArtifactKind::kind, toSlice(ext) }, + +static const KindExtension g_cpuKindExts[] = +{ +#if SLANG_WINDOWS_FAMILY + SLANG_KIND_EXTENSION(Library, "lib") + SLANG_KIND_EXTENSION(ObjectCode, "obj") + SLANG_KIND_EXTENSION(Executable, "exe") + SLANG_KIND_EXTENSION(SharedLibrary, "dll") +#else + SLANG_KIND_EXTENSION(Library, "a") + SLANG_KIND_EXTENSION(ObjectCode, "o") + SLANG_KIND_EXTENSION(Executable, "") + +#if __CYGWIN__ + SLANG_KIND_EXTENSION(SharedLibrary, "dll") +#elif SLANG_APPLE_FAMILY + SLANG_KIND_EXTENSION(SharedLibrary, "dylib") +#else + SLANG_KIND_EXTENSION(SharedLibrary, "so") +#endif + +#endif +}; + + +/* static */ bool ArtifactDescUtil::isCpuBinary(const ArtifactDesc& desc) +{ + return isDerivedFrom(desc.kind, ArtifactKind::BinaryLike) && isDerivedFrom(desc.payload, ArtifactPayload::CPULike); +} + +/* static */bool ArtifactDescUtil::isText(const ArtifactDesc& desc) +{ + // If it's derived from text... + if (isDerivedFrom(desc.kind, ArtifactKind::Text)) + { + return true; + } + + // Special case PTX... + if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) + { + return desc.payload == ArtifactPayload::PTX; + } + + // Not text + return false; +} + +/* static */bool ArtifactDescUtil::isGpuUsable(const ArtifactDesc& desc) +{ + if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) + { + return isDerivedFrom(desc.payload, ArtifactPayload::KernelLike); + } + + // PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be passed + // to CUDA runtime + return desc.kind == ArtifactKind::Assembly && desc.payload == ArtifactPayload::PTX; +} + +/* static */bool ArtifactDescUtil::isKindBinaryLinkable(Kind kind) +{ + switch (kind) + { + case Kind::Library: + case Kind::ObjectCode: + { + return true; + } + default: break; + } + return false; +} + +/* static */bool ArtifactDescUtil::isLinkable(const ArtifactDesc& desc) +{ + if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) + { + if (isDerivedFrom(desc.payload, ArtifactPayload::KernelLike)) + { + // It seems as if DXBC is potentially linkable from + // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords#export + + // We can't *actually* link PTX or SPIR-V currently but it is in principal possible + // so let's say we accept for now + + return true; + } + else if (isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) + { + // If kind is exe or shared library, linking will arguably not work + if (desc.kind == ArtifactKind::SharedLibrary || + desc.kind == ArtifactKind::Executable) + { + return false; + } + + return true; + } + else if (isDerivedFrom(desc.payload, ArtifactPayload::GeneralIR)) + { + // We'll *assume* IR is linkable + return true; + } + } + return false; +} + +/* static */bool ArtifactDescUtil::isCpuLikeTarget(const ArtifactDesc& desc) +{ + if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) + { + return isDerivedFrom(desc.payload, ArtifactPayload::CPULike); + } + else if (isDerivedFrom(desc.kind, ArtifactKind::Source)) + { + // We'll assume C/C++ are targetting CPU, although that is perhaps somewhat arguable. + return desc.payload == Payload::C || desc.payload == Payload::Cpp; + } + + return false; +} + +/* static */ArtifactDesc ArtifactDescUtil::getDescFromExtension(const UnownedStringSlice& slice) +{ + if (slice == "slang-module" || + slice == "slang-lib") + { + return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::SlangIR); + } + + // Metal + // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools + if (slice == toSlice("air")) + { + return ArtifactDesc::make(ArtifactKind::ObjectCode, ArtifactPayload::MetalAIR); + } + else if (slice == toSlice("metallib") || slice == toSlice("metalar")) + { + return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::MetalAIR); + } + + if (slice == toSlice("zip")) + { + return ArtifactDesc::make(ArtifactKind::Zip, ArtifactPayload::Unknown); + } + else if (slice == toSlice("riff")) + { + return ArtifactDesc::make(ArtifactKind::Riff, ArtifactPayload::Unknown); + } + + if (slice == toSlice("asm")) + { + // We'll assume asm means current CPU assembler.. + return ArtifactDesc::make(ArtifactKind::Assembly, ArtifactPayload::HostCPU); + } + + for (const auto& kindExt : g_cpuKindExts) + { + if (slice == kindExt.ext) + { + // We'll assume it's for the host CPU for now.. + return ArtifactDesc::make(kindExt.kind, Payload::HostCPU); + } + } + + const auto target = TypeTextUtil::findCompileTargetFromExtension(slice); + + return makeDescFromCompileTarget(target); +} + +/* static */ArtifactDesc ArtifactDescUtil::getDescFromPath(const UnownedStringSlice& slice) +{ + auto extension = Path::getPathExt(slice); + return getDescFromExtension(extension); +} + +/* static*/ UnownedStringSlice ArtifactDescUtil::getCpuExtensionForKind(Kind kind) +{ + for (const auto& kindExt : g_cpuKindExts) + { + if (kind == kindExt.kind) + { + return kindExt.ext; + } + } + return UnownedStringSlice(); +} + +UnownedStringSlice ArtifactDescUtil::getAssemblyExtensionForPayload(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(); +} + +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) + { + case Payload::HLSL: return toSlice("hlsl"); + case Payload::GLSL: return toSlice("glsl"); + + case Payload::Cpp: return toSlice("cpp"); + case Payload::C: return toSlice("c"); + + case Payload::Metal: return toSlice("metal"); + + 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"); + + case Payload::DXIL: return toSlice("dxil"); + case Payload::DXBC: return toSlice("dxbc"); + case Payload::SPIRV: return toSlice("spv"); + + case Payload::PTX: return toSlice("ptx"); + + case Payload::LLVMIR: return toSlice("llvm-ir"); + + case Payload::SlangIR: + { + return (desc.kind == ArtifactKind::Library) ? toSlice("slang-module") : toSlice("slang-ir"); + } + case Payload::MetalAIR: + { + // 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"); + } + default: break; + } + } + + return UnownedStringSlice(); +} + +/* static */String ArtifactDescUtil::getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path) +{ + String name = Path::getFileName(path); + + const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; + if (isSharedLibraryPrefixPlatform) + { + // Strip lib prefix + if (isCpuBinary(desc) && + (desc.kind == ArtifactKind::Library || + desc.kind == ArtifactKind::SharedLibrary)) + { + // If it starts with lib strip it + if (name.startsWith("lib")) + { + const String stripLib = name.getUnownedSlice().tail(3); + name = stripLib; + } + } + } + + // Strip any extension + { + auto descExt = getDefaultExtension(desc); + // Strip the extension if it's a match + if (descExt.getLength() && + Path::getPathExt(name) == descExt) + { + name = Path::getFileNameWithoutExt(name); + } + } + + return name; +} + +/* static */String ArtifactDescUtil::getBaseName(const ArtifactDesc& desc, IFileArtifactRepresentation* fileRep) +{ + UnownedStringSlice path(fileRep->getPath()); + return getBaseNameFromPath(desc, path); +} + +/* static */String ArtifactDescUtil::getBaseName(IArtifact* artifact) +{ + if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact)) + { + return getBaseName(artifact->getDesc(), fileRep); + } + // Else use the name + return artifact->getName(); +} + +/* static */String ArtifactDescUtil::getParentPath(IFileArtifactRepresentation* fileRep) +{ + UnownedStringSlice path(fileRep->getPath()); + return Path::getParentDirectory(path); +} + +/* static */String ArtifactDescUtil::getParentPath(IArtifact* artifact) +{ + if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact)) + { + return getParentPath(fileRep); + } + return String(); +} + +/* static */SlangResult ArtifactDescUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath) +{ + outPath.Clear(); + + UnownedStringSlice baseName; + + // Append the directory + Index pos = Path::findLastSeparatorIndex(basePath); + if (pos >= 0) + { + outPath.append(basePath.head(pos)); + outPath.append(Path::kPathDelimiter); + + baseName = basePath.tail(pos + 1); + } + + if (baseName.getLength() == 0) + { + baseName = toSlice("unknown"); + } + + if (isCpuBinary(desc) && + (desc.kind == ArtifactKind::SharedLibrary || + desc.kind == ArtifactKind::Library)) + { + const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; + if (isSharedLibraryPrefixPlatform) + { + outPath << "lib"; + outPath << baseName; + } + } + + // If there is an extension append it + const UnownedStringSlice ext = getDefaultExtension(desc); + + if (ext.getLength()) + { + outPath.appendChar('.'); + outPath.append(ext); + } + + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/compiler-core/slang-artifact-info.h b/source/compiler-core/slang-artifact-desc-util.h index 9f741cbbe..ccd380892 100644 --- a/source/compiler-core/slang-artifact-info.h +++ b/source/compiler-core/slang-artifact-desc-util.h @@ -1,23 +1,47 @@ -// slang-artifact-info.h -#ifndef SLANG_ARTIFACT_INFO_H -#define SLANG_ARTIFACT_INFO_H +// slang-artifact-desc.h + +#ifndef SLANG_ARTIFACT_DESC_UTIL_H +#define SLANG_ARTIFACT_DESC_UTIL_H #include "slang-artifact.h" namespace Slang { -struct ArtifactInfoUtil + /// Get the parent kind +ArtifactKind getParent(ArtifactKind kind); + /// Returns true if kind is derived from base +bool isDerivedFrom(ArtifactKind kind, ArtifactKind base); + /// Get the name for the kind +UnownedStringSlice getName(ArtifactKind kind); + + /// Get the parent payload +ArtifactPayload getParent(ArtifactPayload payload); + /// Returns true if payload is derived from base +bool isDerivedFrom(ArtifactPayload payload, ArtifactPayload base); + /// Get the name for the payload +UnownedStringSlice getName(ArtifactPayload payload); + + /// Get the parent style +ArtifactStyle getParent(ArtifactStyle style); + /// Returns true if style is derived from base +bool isDerivedFrom(ArtifactStyle style, ArtifactStyle base); + /// Get the name for the style +UnownedStringSlice getName(ArtifactStyle style); + +struct ArtifactDescUtil { typedef ArtifactPayload Payload; typedef ArtifactKind Kind; - + typedef ArtifactStyle Style; + typedef ArtifactDesc Desc; + /// Returns true if the kind is binary linkable static bool isKindBinaryLinkable(Kind kind); /// True if is a CPU target - either static bool isCpuLikeTarget(const ArtifactDesc& desc); - + /// True if is a CPU binary static bool isCpuBinary(const ArtifactDesc& desc); /// True if is a GPU usable (can be passed to a driver/API and be used @@ -61,6 +85,8 @@ struct ArtifactInfoUtil /// 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); + /// Make ArtifactDesc from target + static ArtifactDesc makeDescFromCompileTarget(SlangCompileTarget target); }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-impl.cpp b/source/compiler-core/slang-artifact-impl.cpp new file mode 100644 index 000000000..8dbae063b --- /dev/null +++ b/source/compiler-core/slang-artifact-impl.cpp @@ -0,0 +1,224 @@ +// slang-artifact-impl.cpp +#include "slang-artifact-impl.h" + +#include "slang-artifact-representation.h" + +#include "slang-artifact-util.h" + +namespace Slang { + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* ArtifactList::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IArtifactList::getTypeGuid()) + { + return static_cast<IArtifactList*>(this); + } + return nullptr; +} + +void* ArtifactList::getObject(const Guid& guid) +{ + // For now we can't cast to an object + SLANG_UNUSED(guid); + return nullptr; +} + +void* ArtifactList::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + return getObject(guid); +} + +void ArtifactList::add(IArtifact* artifact) +{ + // Must be set + SLANG_ASSERT(artifact); + // Can't already be in the list + SLANG_ASSERT(m_artifacts.indexOf(artifact) < 0); + // Can't have another owner + SLANG_ASSERT(artifact->getParent() == nullptr); + + // Set the parent + artifact->setParent(m_parent); + + // Add + m_artifacts.add(ComPtr<IArtifact>(artifact)); +} + +void ArtifactList::removeAt(Index index) +{ + IArtifact* artifact = m_artifacts[index]; + artifact->setParent(nullptr); + m_artifacts.removeAt(index); +} + +void ArtifactList::clear() +{ + _setParent(nullptr); + m_artifacts.clear(); +} + +void ArtifactList::_setParent(IArtifact* parent) +{ + if (m_parent == parent) + { + return; + } + + for (IArtifact* artifact : m_artifacts) + { + artifact->setParent(artifact); + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Artifact !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* Artifact::getInterface(const Guid& uuid) +{ + if (uuid == ISlangUnknown::getTypeGuid() || uuid == IArtifact::getTypeGuid()) + { + return static_cast<IArtifact*>(this); + } + return nullptr; +} + +bool Artifact::exists() +{ + for (ISlangUnknown* item : m_items) + { + ComPtr<ICastable> castable; + + if (SLANG_SUCCEEDED(item->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + auto rep = as<IArtifactRepresentation>(castable); + if (rep) + { + // It is a rep and it exists + if (rep->exists()) + { + return true; + } + continue; + } + // Associated types don't encapsulate an artifact representation, so don't signal existance + if (as<IArtifactAssociated>(castable)) + { + continue; + } + } + + // It can't be IArtifactRepresentation or IArtifactAssociated, so we assume means it exists + return true; + } + + return false; +} + +void Artifact::addItem(ISlangUnknown* intf) +{ + SLANG_ASSERT(intf); + // Can't already be in there + SLANG_ASSERT(m_items.indexOf(intf) < 0); + // Add it + m_items.add(ComPtr<ISlangUnknown>(intf)); +} + +void Artifact::removeItemAt(Index i) +{ + m_items.removeAt(i); +} + +void* Artifact::findItemInterface(const Guid& guid) +{ + for (ISlangUnknown* intf : m_items) + { + ISlangUnknown* cast = nullptr; + if (SLANG_SUCCEEDED(intf->queryInterface(guid, (void**)&cast)) && cast) + { + // NOTE! This assumes we *DONT* need to ref count to keep an interface in scope + // (as strict COM requires so as to allow on demand interfaces). + cast->release(); + return cast; + } + } + return nullptr; +} + +void* Artifact::findItemObject(const Guid& classGuid) +{ + for (ISlangUnknown* intf : m_items) + { + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(intf->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + void* obj = castable->castAs(classGuid); + + // NOTE! This assumes we *DONT* need to ref count to keep an interface in scope + // (as strict COM requires so as to allow on demand interfaces). + + // If could cast return the result + if (obj) + { + return obj; + } + } + } + return nullptr; +} + +SlangResult Artifact::requireFile(Keep keep, IFileArtifactRepresentation** outFileRep) +{ + auto util = ArtifactUtilImpl::getSingleton(); + return util->requireFileDefaultImpl(this, keep, outFileRep); +} + +SlangResult Artifact::loadBlob(Keep keep, ISlangBlob** outBlob) +{ + // If we have a blob just return it + if (auto blob = findItem<ISlangBlob>(this)) + { + blob->addRef(); + *outBlob = blob; + return SLANG_OK; + } + + ComPtr<ISlangBlob> blob; + + // Look for a representation that we can serialize into a blob + for (ISlangUnknown* intf : m_items) + { + ComPtr<IArtifactRepresentation> rep; + if (SLANG_SUCCEEDED(intf->queryInterface(IArtifactRepresentation::getTypeGuid(), (void**)rep.writeRef())) && rep) + { + SlangResult res = rep->writeToBlob(blob.writeRef()); + if (SLANG_SUCCEEDED(res) && blob) + { + break; + } + } + } + + // Wasn't able to construct + if (!blob) + { + return SLANG_E_NOT_FOUND; + } + + // Put in cache + if (canKeep(keep)) + { + addItem(blob); + } + + *outBlob = blob.detach(); + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/compiler-core/slang-artifact-impl.h b/source/compiler-core/slang-artifact-impl.h new file mode 100644 index 000000000..35dbe5f98 --- /dev/null +++ b/source/compiler-core/slang-artifact-impl.h @@ -0,0 +1,116 @@ +// slang-artifact-impl.h +#ifndef SLANG_ARTIFACT_IMPL_H +#define SLANG_ARTIFACT_IMPL_H + +#include "slang-artifact.h" + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +#include "../core/slang-com-object.h" + +namespace Slang +{ + +class ArtifactList : public ComBaseObject, public IArtifactList +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // IArtifactList + SLANG_NO_THROW IArtifact* SLANG_MCALL getParent() SLANG_OVERRIDE { return m_parent; } + SLANG_NO_THROW void SLANG_MCALL setParent(IArtifact* parent) SLANG_OVERRIDE { _setParent(parent); } + + SLANG_NO_THROW IArtifact* SLANG_MCALL getAt(Index index) SLANG_OVERRIDE { return m_artifacts[index]; } + SLANG_NO_THROW Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_artifacts.getCount(); } + SLANG_NO_THROW void SLANG_MCALL add(IArtifact* artifact) SLANG_OVERRIDE; + SLANG_NO_THROW void SLANG_MCALL removeAt(Index index) SLANG_OVERRIDE; + SLANG_NO_THROW void SLANG_MCALL clear() SLANG_OVERRIDE; + + // NOTE! The parent is a weak reference. + ArtifactList(IArtifact* parent): + m_parent(parent) + { + } + + virtual ~ArtifactList() { _setParent(nullptr); } + +protected: + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); + + void _setParent(IArtifact* artifact); + + IArtifact* m_parent; + List<ComPtr<IArtifact>> m_artifacts; +}; + +/* +Discussion: + +It could make sense to remove the explicit variables of a ISlangBlob, and the file backing from this interface, as they could +all be implemented as element types presumably deriving from IArtifactInstance. Doing so would mean how a 'file' is turned into +a blob is abstracted. + +It may be helpful to be able to add temporary files to the artifact (such that they will be deleted when the artifact goes out of +scope). Using an implementation of the File backed IArtifactInstance, with a suitable desc would sort of work, but it breaks the idea +that any IArtifactInstance *represents* the contents of Artifact that contains it. Of course there could be types *not* deriving +from IArtifactInstance that handle temporary file existance. This is probably the simplest answer to the problem. + +Another issue occurs around wanting to hold multiple kernels within a container. The problem here is that although through the desc +we can identify what target a kernel is for, there is no way of telling what stage it is for. + +When discussing the idea of a shader cache, one idea was to use a ISlangFileSystem (which could actually be a zip, or directory or in memory rep) +as the main structure. Within this it can contain kernels, and then a json manifest can describe what each of these actually are. + +This all 'works', in that we can add an element of ISlangFileSystem with a desc of Container. Code that uses this can then go through the process +of finding, and getting the blob, and find from the manifest what it means. That does sound a little tedious though. Perhaps we just have an interface +that handles this detail, such that we search for that first. That interface is just attached to the artifact as an element. +*/ + +/* Implementation of the IArtifact interface */ +class Artifact : public ComBaseObject, public IArtifact +{ +public: + + SLANG_COM_BASE_IUNKNOWN_ALL + + /// IArtifact impl + virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc() SLANG_OVERRIDE { return m_desc; } + virtual SLANG_NO_THROW IArtifact* SLANG_MCALL getParent() SLANG_OVERRIDE { return m_parent; } + virtual SLANG_NO_THROW void SLANG_MCALL setParent(IArtifact* parent) SLANG_OVERRIDE { m_parent = parent; } + virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob(Keep keep, ISlangBlob** outBlob) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFile(Keep keep, IFileArtifactRepresentation** outFileRep) SLANG_OVERRIDE; + virtual SLANG_NO_THROW const char* SLANG_MCALL getName() SLANG_OVERRIDE { return m_name.getBuffer(); } + virtual SLANG_NO_THROW void* SLANG_MCALL findItemInterface(const Guid& uuid) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void* SLANG_MCALL findItemObject(const Guid& classGuid) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL addItem(ISlangUnknown* intf) SLANG_OVERRIDE; + virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getItemAt(Index i) SLANG_OVERRIDE { return m_items[i]; } + virtual SLANG_NO_THROW void SLANG_MCALL removeItemAt(Index i) SLANG_OVERRIDE; + virtual SLANG_NO_THROW Index SLANG_MCALL getItemCount() SLANG_OVERRIDE { return m_items.getCount(); } + + /// Ctor + Artifact(const Desc& desc, const String& name) : + m_desc(desc), + m_name(name), + m_parent(nullptr) + {} + +protected: + void* getInterface(const Guid& uuid); + + Desc m_desc; ///< Description of the artifact + IArtifact* m_parent; ///< Artifact this artifact belongs to + + String m_name; ///< Name of this artifact + + List<ComPtr<ISlangUnknown>> m_items; ///< Associated items +}; + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-info.cpp b/source/compiler-core/slang-artifact-info.cpp deleted file mode 100644 index 1d309e3c7..000000000 --- a/source/compiler-core/slang-artifact-info.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// slang-artifact-info.cpp -#include "slang-artifact-info.h" - -#include "../core/slang-type-text-util.h" -#include "../core/slang-io.h" - -namespace Slang { - -/* !!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactInfoUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -namespace { // anonymous -struct KindExtension -{ - ArtifactKind kind; - UnownedStringSlice ext; -}; -} // anonymous - -#define SLANG_KIND_EXTENSION(kind, ext) \ - { ArtifactKind::kind, toSlice(ext) }, - -static const KindExtension g_cpuKindExts[] = -{ -#if SLANG_WINDOWS_FAMILY - SLANG_KIND_EXTENSION(Library, "lib") - SLANG_KIND_EXTENSION(ObjectCode, "obj") - SLANG_KIND_EXTENSION(Executable, "exe") - SLANG_KIND_EXTENSION(SharedLibrary, "dll") -#else - SLANG_KIND_EXTENSION(Library, "a") - SLANG_KIND_EXTENSION(ObjectCode, "o") - SLANG_KIND_EXTENSION(Executable, "") - -#if __CYGWIN__ - SLANG_KIND_EXTENSION(SharedLibrary, "dll") -#elif SLANG_APPLE_FAMILY - SLANG_KIND_EXTENSION(SharedLibrary, "dylib") -#else - SLANG_KIND_EXTENSION(SharedLibrary, "so") -#endif - -#endif -}; - -/* static */ bool ArtifactInfoUtil::isCpuBinary(const ArtifactDesc& desc) -{ - return isDerivedFrom(desc.kind, ArtifactKind::BinaryLike) && isDerivedFrom(desc.payload, ArtifactPayload::CPULike); -} - -/* static */bool ArtifactInfoUtil::isText(const ArtifactDesc& desc) -{ - // If it's derived from text... - if (isDerivedFrom(desc.kind, ArtifactKind::Text)) - { - return true; - } - - // Special case PTX... - if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) - { - return desc.payload == ArtifactPayload::PTX; - } - - // Not text - return false; -} - -/* static */bool ArtifactInfoUtil::isGpuUsable(const ArtifactDesc& desc) -{ - if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) - { - return isDerivedFrom(desc.payload, ArtifactPayload::KernelLike); - } - - // PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be passed - // to CUDA runtime - return desc.kind == ArtifactKind::Assembly && desc.payload == ArtifactPayload::PTX; -} - -/* static */bool ArtifactInfoUtil::isKindBinaryLinkable(Kind kind) -{ - switch (kind) - { - case Kind::Library: - case Kind::ObjectCode: - { - return true; - } - default: break; - } - return false; -} - -/* static */bool ArtifactInfoUtil::isLinkable(const ArtifactDesc& desc) -{ - if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) - { - if (isDerivedFrom(desc.payload, ArtifactPayload::KernelLike)) - { - // It seems as if DXBC is potentially linkable from - // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords#export - - // We can't *actually* link PTX or SPIR-V currently but it is in principal possible - // so let's say we accept for now - - return true; - } - else if (isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) - { - // If kind is exe or shared library, linking will arguably not work - if (desc.kind == ArtifactKind::SharedLibrary || - desc.kind == ArtifactKind::Executable) - { - return false; - } - - return true; - } - else if (isDerivedFrom(desc.payload, ArtifactPayload::GeneralIR)) - { - // We'll *assume* IR is linkable - return true; - } - } - return false; -} - -/* static */bool ArtifactInfoUtil::isCpuLikeTarget(const ArtifactDesc& desc) -{ - if (isDerivedFrom(desc.kind, ArtifactKind::BinaryLike)) - { - return isDerivedFrom(desc.payload, ArtifactPayload::CPULike); - } - else if (isDerivedFrom(desc.kind, ArtifactKind::Source)) - { - // We'll assume C/C++ are targetting CPU, although that is perhaps somewhat arguable. - return desc.payload == Payload::C || desc.payload == Payload::Cpp; - } - - return false; -} - -/* static */ArtifactDesc ArtifactInfoUtil::getDescFromExtension(const UnownedStringSlice& slice) -{ - if (slice == "slang-module" || - slice == "slang-lib") - { - return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::SlangIR); - } - - // Metal - // https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools - if (slice == toSlice("air")) - { - return ArtifactDesc::make(ArtifactKind::ObjectCode, ArtifactPayload::MetalAIR); - } - else if (slice == toSlice("metallib") || slice == toSlice("metalar")) - { - return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::MetalAIR); - } - - if (slice == toSlice("zip")) - { - return ArtifactDesc::make(ArtifactKind::Zip, ArtifactPayload::Unknown); - } - else if (slice == toSlice("riff")) - { - return ArtifactDesc::make(ArtifactKind::Riff, ArtifactPayload::Unknown); - } - - if (slice == toSlice("asm")) - { - // We'll assume asm means current CPU assembler.. - return ArtifactDesc::make(ArtifactKind::Assembly, ArtifactPayload::HostCPU); - } - - for (const auto& kindExt : g_cpuKindExts) - { - if (slice == kindExt.ext) - { - // We'll assume it's for the host CPU for now.. - return ArtifactDesc::make(kindExt.kind, Payload::HostCPU); - } - } - - const auto target = TypeTextUtil::findCompileTargetFromExtension(slice); - - return ArtifactDesc::makeFromCompileTarget(target); -} - -/* static */ArtifactDesc ArtifactInfoUtil::getDescFromPath(const UnownedStringSlice& slice) -{ - auto extension = Path::getPathExt(slice); - return getDescFromExtension(extension); -} - -/* static*/ UnownedStringSlice ArtifactInfoUtil::getCpuExtensionForKind(Kind kind) -{ - for (const auto& kindExt : g_cpuKindExts) - { - if (kind == kindExt.kind) - { - return kindExt.ext; - } - } - return UnownedStringSlice(); -} - -UnownedStringSlice ArtifactInfoUtil::getAssemblyExtensionForPayload(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(); -} - -UnownedStringSlice ArtifactInfoUtil::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) - { - case Payload::HLSL: return toSlice("hlsl"); - case Payload::GLSL: return toSlice("glsl"); - - case Payload::Cpp: return toSlice("cpp"); - case Payload::C: return toSlice("c"); - - case Payload::Metal: return toSlice("metal"); - - case Payload::CUDA: return toSlice("cu"); - - case Payload::Slang: return toSlice("slang"); - default: break; - } - } - default: break; - } - - if (ArtifactInfoUtil::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"); - - case Payload::DXIL: return toSlice("dxil"); - case Payload::DXBC: return toSlice("dxbc"); - case Payload::SPIRV: return toSlice("spv"); - - case Payload::PTX: return toSlice("ptx"); - - case Payload::LLVMIR: return toSlice("llvm-ir"); - - case Payload::SlangIR: - { - return (desc.kind == ArtifactKind::Library) ? toSlice("slang-module") : toSlice("slang-ir"); - } - case Payload::MetalAIR: - { - // 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"); - } - default: break; - } - } - - return UnownedStringSlice(); -} - -/* static */String ArtifactInfoUtil::getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path) -{ - String name = Path::getFileName(path); - - const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; - if (isSharedLibraryPrefixPlatform) - { - // Strip lib prefix - if (ArtifactInfoUtil::isCpuBinary(desc) && - (desc.kind == ArtifactKind::Library || - desc.kind == ArtifactKind::SharedLibrary)) - { - // If it starts with lib strip it - if (name.startsWith("lib")) - { - const String stripLib = name.getUnownedSlice().tail(3); - name = stripLib; - } - } - } - - // Strip any extension - { - auto descExt = ArtifactInfoUtil::getDefaultExtension(desc); - // Strip the extension if it's a match - if (descExt.getLength() && - Path::getPathExt(name) == descExt) - { - name = Path::getFileNameWithoutExt(name); - } - } - - return name; -} - -/* static */String ArtifactInfoUtil::getBaseName(const ArtifactDesc& desc, IFileArtifactRepresentation* fileRep) -{ - UnownedStringSlice path(fileRep->getPath()); - return getBaseNameFromPath(desc, path); -} - -/* static */String ArtifactInfoUtil::getBaseName(IArtifact* artifact) -{ - if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact)) - { - return getBaseName(artifact->getDesc(), fileRep); - } - // Else use the name - return artifact->getName(); -} - -/* static */String ArtifactInfoUtil::getParentPath(IFileArtifactRepresentation* fileRep) -{ - UnownedStringSlice path(fileRep->getPath()); - return Path::getParentDirectory(path); -} - -/* static */String ArtifactInfoUtil::getParentPath(IArtifact* artifact) -{ - if (auto fileRep = findItem<IFileArtifactRepresentation>(artifact)) - { - return getParentPath(fileRep); - } - return String(); -} - -/* static */SlangResult ArtifactInfoUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath) -{ - outPath.Clear(); - - UnownedStringSlice baseName; - - // Append the directory - Index pos = Path::findLastSeparatorIndex(basePath); - if (pos >= 0) - { - outPath.append(basePath.head(pos)); - outPath.append(Path::kPathDelimiter); - - baseName = basePath.tail(pos + 1); - } - - if (baseName.getLength() == 0) - { - baseName = toSlice("unknown"); - } - - if (ArtifactInfoUtil::isCpuBinary(desc) && - (desc.kind == ArtifactKind::SharedLibrary || - desc.kind == ArtifactKind::Library)) - { - const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; - if (isSharedLibraryPrefixPlatform) - { - outPath << "lib"; - outPath << baseName; - } - } - - // If there is an extension append it - const UnownedStringSlice ext = ArtifactInfoUtil::getDefaultExtension(desc); - - if (ext.getLength()) - { - outPath.appendChar('.'); - outPath.append(ext); - } - - return SLANG_OK; -} - -} // namespace Slang diff --git a/source/compiler-core/slang-artifact-representation-impl.cpp b/source/compiler-core/slang-artifact-representation-impl.cpp new file mode 100644 index 000000000..20480ae07 --- /dev/null +++ b/source/compiler-core/slang-artifact-representation-impl.cpp @@ -0,0 +1,147 @@ +// slang-artifact-representation-impl.cpp +#include "slang-artifact-representation-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 { + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* FileArtifactRepresentation::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == IArtifactRepresentation::getTypeGuid() || + guid == IFileArtifactRepresentation::getTypeGuid()) + { + return static_cast<IFileArtifactRepresentation*>(this); + } + return nullptr; +} + +void* FileArtifactRepresentation::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +ISlangMutableFileSystem* FileArtifactRepresentation::_getFileSystem() +{ + return m_fileSystem ? m_fileSystem : OSFileSystem::getMutableSingleton(); +} + +void* FileArtifactRepresentation::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + return getObject(guid); +} + +SlangResult FileArtifactRepresentation::writeToBlob(ISlangBlob** blob) +{ + if (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; + } + + auto fileSystem = _getFileSystem(); + return fileSystem->loadFile(m_path.getBuffer(), blob); +} + +bool FileArtifactRepresentation::exists() +{ + // TODO(JS): + // If it's a name only it's hard to know what exists should do. It can't *check* because it relies on the 'system' doing + // the actual location. We could ask the IArtifactUtil, and that could change the behavior. + // For now we just assume it does. + if (m_kind == Kind::NameOnly) + { + return true; + } + + auto fileSystem = _getFileSystem(); + + SlangPathType pathType; + const auto res = fileSystem->getPathType(m_path.getBuffer(), &pathType); + + // It exists if it is a file + return SLANG_SUCCEEDED(res) && pathType == SLANG_PATH_TYPE_FILE; +} + +FileArtifactRepresentation::~FileArtifactRepresentation() +{ + if (m_kind == Kind::Owned) + { + auto fileSystem = _getFileSystem(); + fileSystem->remove(m_path.getBuffer()); + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LockFile !!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* LockFile::getInterface(const Guid& guid) +{ + if (guid == ISlangUnknown::getTypeGuid() || + guid == ICastable::getTypeGuid() || + guid == ILockFile::getTypeGuid()) + { + return static_cast<ILockFile*>(this); + } + return nullptr; +} + +void* LockFile::getObject(const Guid& guid) +{ + SLANG_UNUSED(guid); + return nullptr; +} + +ISlangMutableFileSystem* LockFile::_getFileSystem() +{ + return m_fileSystem ? m_fileSystem : OSFileSystem::getMutableSingleton(); +} + +void* LockFile::castAs(const Guid& guid) +{ + if (auto intf = getInterface(guid)) + { + return intf; + } + return getObject(guid); +} + +const char* LockFile::getPath() +{ + return (m_path.getLength() > 0) ? m_path.getBuffer() : nullptr; +} + +ISlangMutableFileSystem* LockFile::getFileSystem() +{ + return m_fileSystem; +} + +LockFile::~LockFile() +{ + if (m_path.getLength() > 0) + { + auto fileSystem = _getFileSystem(); + fileSystem->remove(m_path.getBuffer()); + } +} + +void LockFile::disown() +{ + m_path = String(); + m_fileSystem.setNull(); +} + +} // namespace Slang diff --git a/source/compiler-core/slang-artifact-representation-impl.h b/source/compiler-core/slang-artifact-representation-impl.h new file mode 100644 index 000000000..9c2066e55 --- /dev/null +++ b/source/compiler-core/slang-artifact-representation-impl.h @@ -0,0 +1,94 @@ +// slang-artifact-representation-impl.h +#ifndef SLANG_ARTIFACT_REPRESENTATION_IMPL_H +#define SLANG_ARTIFACT_REPRESENTATION_IMPL_H + +#include "slang-artifact-representation.h" + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +#include "../core/slang-com-object.h" + +namespace Slang +{ + +/* An implementation of ILockFile */ +class LockFile : public ComBaseObject, public ILockFile +{ +public: + SLANG_COM_BASE_IUNKNOWN_ALL + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // ILockFile + SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE; + SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE; + SLANG_NO_THROW void SLANG_MCALL disown() SLANG_OVERRIDE; + + /// Ctor + LockFile(String path, ISlangMutableFileSystem* fileSystem) : + m_path(path), + m_fileSystem(fileSystem) + { + } + + ~LockFile(); + +protected: + void* getInterface(const Guid& uuid); + void* getObject(const Guid& uuid); + + ISlangMutableFileSystem* _getFileSystem(); + + String m_path; + ComPtr<ISlangMutableFileSystem> m_fileSystem; +}; + +/* +A representation of an artifact that is held in a file */ +class FileArtifactRepresentation : public ComBaseObject, public IFileArtifactRepresentation +{ +public: + typedef IFileArtifactRepresentation::Kind Kind; + + 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; + + // IFileArtifactRepresentation + virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() SLANG_OVERRIDE { return m_kind; } + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_path.getBuffer(); } + virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() SLANG_OVERRIDE { return m_lockFile; } + virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE { return m_fileSystem; } + + FileArtifactRepresentation(Kind kind, String path, ILockFile* lockFile, ISlangMutableFileSystem* fileSystem): + m_kind(kind), + m_path(path), + m_lockFile(lockFile), + m_fileSystem(fileSystem) + { + } + + ~FileArtifactRepresentation(); + +protected: + void* getInterface(const Guid& uuid); + void* getObject(const Guid& uuid); + + ISlangMutableFileSystem* _getFileSystem(); + + Kind m_kind; + String m_path; + ComPtr<ILockFile> m_lockFile; + ComPtr<ISlangMutableFileSystem> m_fileSystem; +}; + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-representation.h b/source/compiler-core/slang-artifact-representation.h new file mode 100644 index 000000000..00a5c9e5b --- /dev/null +++ b/source/compiler-core/slang-artifact-representation.h @@ -0,0 +1,52 @@ +// slang-artifact-representation.h +#ifndef SLANG_ARTIFACT_REPRESENTATION_H +#define SLANG_ARTIFACT_REPRESENTATION_H + +#include "slang-artifact.h" + +namespace Slang +{ + +/* A lock file */ +class ILockFile : public ICastable +{ + SLANG_COM_INTERFACE(0x9177ea36, 0xa608, 0x4490, { 0x87, 0xf0, 0xf3, 0x93, 0x9, 0x7d, 0x36, 0xce }) + + /// The path to a lock file. + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; + /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. + virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; + + /// Makes the lock file no longer owned. Doing so will make the path nullptr, and getFileSystem nullptr. + virtual SLANG_NO_THROW void SLANG_MCALL disown() = 0; +}; + +/* +A representation as a file. If it is a temporary file, it will likely disappear. +A file representation does not have to be a representation of a file on the file system. +That is indicated by getFileSystem returning nullptr. Then the path is the path on the *actual* OS file system. +This distinction is important as it is sometimes necessary to have an artifact stored on the OS file system +to be usable. */ +class IFileArtifactRepresentation : public IArtifactRepresentation +{ +public: + enum class Kind + { + Reference, ///< References a file on the file system + Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope + NameOnly, ///< Typically used for items that can be found by the 'system'. The path is just a name, and cannot typically be loaded as a blob. + }; + + /// The the kind of file. + virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() = 0; + /// The path (on the file system) + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; + /// Get the lock file. Return nullptr if there is no lock file. + virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() = 0; + /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. + virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; +}; + +} // namespace Slang + +#endif diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index 5c1641f7f..9a8194969 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -1,7 +1,10 @@ // slang-artifact.cpp #include "slang-artifact-util.h" -#include "slang-artifact-info.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" + +#include "slang-artifact-desc-util.h" #include "../core/slang-file-system.h" #include "../core/slang-io.h" @@ -31,7 +34,6 @@ void* ArtifactUtilImpl::getInterface(const Guid& guid) return nullptr; } - SlangResult ArtifactUtilImpl::createArtifact(const ArtifactDesc& desc, const char* inName, IArtifact** outArtifact) { String name; @@ -93,7 +95,7 @@ SlangResult ArtifactUtilImpl::calcArtifactPath(const ArtifactDesc& desc, const c UnownedStringSlice basePath(inBasePath); StringBuilder path; - SLANG_RETURN_ON_FAIL(ArtifactInfoUtil::calcPathForDesc(desc, basePath, path)); + SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, basePath, path)); auto blob = new StringBlob(path); blob->addRef(); @@ -150,4 +152,9 @@ SlangResult ArtifactUtilImpl::requireFileDefaultImpl(IArtifact* artifact, Artifa return SLANG_OK; } +ArtifactDesc ArtifactUtilImpl::makeDescFromCompileTarget(SlangCompileTarget target) +{ + return ArtifactDescUtil::makeDescFromCompileTarget(target); +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index f60578d14..f9070a76e 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -3,6 +3,7 @@ #define SLANG_ARTIFACT_UTIL_H #include "slang-artifact.h" +#include "slang-artifact-representation.h" namespace Slang { @@ -34,6 +35,8 @@ class IArtifactUtil : public ISlangUnknown /// Default implementation of getting virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFileDefaultImpl(IArtifact* artifact, ArtifactKeep keep, IFileArtifactRepresentation** outFileRep) = 0; + + virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) = 0; }; class ArtifactUtilImpl : public IArtifactUtil @@ -67,6 +70,8 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFileDefaultImpl(IArtifact* artifact, ArtifactKeep keep, IFileArtifactRepresentation** outFileRep) SLANG_OVERRIDE; + virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescFromCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; + static IArtifactUtil* getSingleton() { return &g_singleton; } protected: diff --git a/source/compiler-core/slang-artifact.cpp b/source/compiler-core/slang-artifact.cpp deleted file mode 100644 index cefb8d753..000000000 --- a/source/compiler-core/slang-artifact.cpp +++ /dev/null @@ -1,630 +0,0 @@ -// slang-artifact.cpp -#include "slang-artifact.h" - -#include "slang-artifact-info.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 { - -namespace { // anonymous - -struct HierarchicalEnumEntry -{ - Index value; - Index parent; - const char* name; -}; - -static bool _isHierarchicalEnumOk(ConstArrayView<HierarchicalEnumEntry> entries, Count countOf) -{ - // All values should be set - if (entries.getCount() != countOf) - { - return false; - } - - List<uint8_t> isUsed; - isUsed.setCount(countOf); - ::memset(isUsed.getBuffer(), 0, countOf); - - for (const auto& entry : entries) - { - const auto value = entry.value; - // Must be in range - if (value < 0 || value >= countOf) - { - return false; - } - - if (isUsed[value] != 0) - { - return false; - } - // Mark as used - isUsed[value]++; - } - - // There can't be any gaps - for (auto v : isUsed) - { - if (v == 0) - { - return false; - } - } - - // Okay, looks reasonable.. - return true; -} - -template <typename T> -struct HierarchicalEnumTable -{ - HierarchicalEnumTable(ConstArrayView<HierarchicalEnumEntry> entries) - { - // Remove warnings around this not being used. - { - const auto unused = _isHierarchicalEnumOk; - SLANG_UNUSED(unused); - } - - SLANG_COMPILE_TIME_ASSERT(Index(T::Invalid) < Index(T::Base)); - SLANG_ASSERT(entries.getCount() == Count(T::CountOf)); - - SLANG_ASSERT(_isHierarchicalEnumOk(entries, Count(T::CountOf))); - - ::memset(&m_parents, 0, sizeof(m_parents)); - - for (const auto& entry : entries) - { - const auto value = entry.value; - m_parents[value] = T(entry.parent); - m_names[value] = UnownedStringSlice(entry.name); - } - - // TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid* - // we would want the Parent of Base to be Base. - // - // Base parent should be invalid - SLANG_ASSERT(getParent(T::Base) == T::Invalid); - // Invalids parent should be invalid - SLANG_ASSERT(getParent(T::Invalid) == T::Invalid); - } - - T getParent(T kind) const - { - return (kind >= T::CountOf) ? - T::Invalid : - m_parents[Index(kind)]; - } - UnownedStringSlice getName(T kind) const - { - return (kind >= T::CountOf) ? - UnownedStringSlice() : - m_names[Index(kind)]; - } - - bool isDerivedFrom(T type, T base) const - { - if (Index(type) >= Index(T::CountOf)) - { - return false; - } - - do - { - if (type == base) - { - return true; - } - type = m_parents[Index(type)]; - } while (Index(type) > Index(T::Base)); - - return false; - } - -protected: - T m_parents[Count(T::CountOf)]; - UnownedStringSlice m_names[Count(T::CountOf)]; -}; - -} // anonymous - -// Macro utils to create "enum hierarchy" tables - -#define SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_ENTRY_MACRO) \ -static ConstArrayView<HierarchicalEnumEntry> _getEntries##ENUM_TYPE() \ -{ \ - static const HierarchicalEnumEntry values[] = { ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO) }; \ - return makeConstArrayView(values); \ -} - -#define SLANG_HIERARCHICAL_ENUM(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ -SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ -\ -static const HierarchicalEnumTable<ENUM_TYPE> g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \ -\ -ENUM_TYPE getParent(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getParent(kind); } \ -UnownedStringSlice getName(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getName(kind); } \ -bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) { return g_table##ENUM_TYPE.isDerivedFrom(kind, base); } - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactKind !!!!!!!!!!!!!!!!!!!!!!! */ - -#define SLANG_ARTIFACT_KIND(x) \ - x(Invalid, Invalid) \ - x(Base, Invalid) \ - x(None, Base) \ - x(Unknown, Base) \ - x(Container, Base) \ - x(Zip, Container) \ - x(Riff, Container) \ - x(Text, Base) \ - x(HumanText, Text) \ - x(Source, Text) \ - x(Assembly, Text) \ - x(BinaryLike, Base) \ - x(ObjectCode, BinaryLike) \ - x(Library, BinaryLike) \ - x(Executable, BinaryLike) \ - x(SharedLibrary, BinaryLike) \ - x(HostCallable, BinaryLike) \ - \ - x(DebugInfo, Base) \ - x(Diagnostics, Base) - -#define SLANG_ARTIFACT_KIND_ENTRY(TYPE, PARENT) { Index(ArtifactKind::TYPE), Index(ArtifactKind::PARENT), #TYPE }, - -SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_ENTRY) - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPayload !!!!!!!!!!!!!!!!!!!!!!! */ - -#define SLANG_ARTIFACT_PAYLOAD(x) \ - x(Invalid, Invalid) \ - x(Base, Invalid) \ - x(None, Base) \ - x(Unknown, Base) \ - x(Source, Base) \ - x(C, Source) \ - x(Cpp, Source) \ - x(HLSL, Source) \ - x(GLSL, Source) \ - x(CUDA, Source) \ - x(Metal, Source) \ - x(Slang, Source) \ - x(KernelLike, Base) \ - x(DXIL, KernelLike) \ - x(DXBC, KernelLike) \ - x(SPIRV, KernelLike) \ - x(PTX, KernelLike) \ - x(CuBin, KernelLike) \ - x(MetalAIR, KernelLike) \ - x(CPULike, Base) \ - x(UnknownCPU, CPULike) \ - x(X86, CPULike) \ - x(X86_64, CPULike) \ - x(Aarch, CPULike) \ - x(Aarch64, CPULike) \ - x(HostCPU, CPULike) \ - x(UniversalCPU, CPULike) \ - x(GeneralIR, Base) \ - x(SlangIR, GeneralIR) \ - x(LLVMIR, GeneralIR) \ - x(AST, Base) \ - x(SlangAST, AST) - -#define SLANG_ARTIFACT_PAYLOAD_ENTRY(TYPE, PARENT) { Index(ArtifactPayload::TYPE), Index(ArtifactPayload::PARENT), #TYPE }, - -SLANG_HIERARCHICAL_ENUM(ArtifactPayload, SLANG_ARTIFACT_PAYLOAD, SLANG_ARTIFACT_PAYLOAD_ENTRY) - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactStyle !!!!!!!!!!!!!!!!!!!!!!! */ - -#define SLANG_ARTIFACT_STYLE(x) \ - x(Invalid, Invalid) \ - x(Base, Invalid) \ - x(Unknown, Base) \ - x(Kernel, Base) \ - x(Host, Base) - -#define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) { Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE }, - -SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYLE_ENTRY) - - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDesc !!!!!!!!!!!!!!!!!!!!!!! */ - -/* static */ArtifactDesc ArtifactDesc::makeFromCompileTarget(SlangCompileTarget target) -{ - switch (target) - { - case SLANG_TARGET_UNKNOWN: return make(Kind::Unknown, Payload::None, Style::Unknown, 0); - case SLANG_TARGET_NONE: return make(Kind::None, Payload::None, Style::Unknown, 0); - case SLANG_GLSL_VULKAN: - case SLANG_GLSL_VULKAN_ONE_DESC: - case SLANG_GLSL: - { - // For the moment we make all just map to GLSL, but we could use flags - // or some other mechanism to distinguish the types - return make(Kind::Source, Payload::GLSL, Style::Kernel, 0); - } - case SLANG_HLSL: return make(Kind::Source, Payload::HLSL, Style::Kernel, 0); - case SLANG_SPIRV: return make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); - case SLANG_SPIRV_ASM: return make(Kind::Assembly, Payload::SPIRV, Style::Kernel, 0); - case SLANG_DXBC: return make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); - case SLANG_DXBC_ASM: return make(Kind::Assembly, Payload::DXBC, Style::Kernel, 0); - case SLANG_DXIL: return make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); - case SLANG_DXIL_ASM: return make(Kind::Assembly, Payload::DXIL, Style::Kernel, 0); - case SLANG_C_SOURCE: return make(Kind::Source, Payload::C, Style::Kernel, 0); - case SLANG_CPP_SOURCE: return make(Kind::Source, Payload::Cpp, Style::Kernel, 0); - case SLANG_HOST_CPP_SOURCE: return make(Kind::Source, Payload::Cpp, Style::Host, 0); - case SLANG_HOST_EXECUTABLE: return make(Kind::Executable, Payload::HostCPU, Style::Host, 0); - case SLANG_SHADER_SHARED_LIBRARY: return make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); - case SLANG_SHADER_HOST_CALLABLE: return make(Kind::HostCallable, Payload::HostCPU, Style::Kernel, 0); - case SLANG_CUDA_SOURCE: return make(Kind::Source, Payload::CUDA, Style::Kernel, 0); - // TODO(JS): - // Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. Saying it is - // 'Executable' implies it is Binary (which PTX isn't). Executable also implies 'complete for executation', - // irrespective of it being text. - case SLANG_PTX: return make(Kind::Executable, Payload::PTX, Style::Kernel, 0); - case SLANG_OBJECT_CODE: return make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); - case SLANG_HOST_HOST_CALLABLE: return make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); - default: break; - } - - SLANG_UNEXPECTED("Unhandled type"); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! FileArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* FileArtifactRepresentation::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == IArtifactRepresentation::getTypeGuid() || - guid == IFileArtifactRepresentation::getTypeGuid()) - { - return static_cast<IFileArtifactRepresentation*>(this); - } - return nullptr; -} - -void* FileArtifactRepresentation::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; -} - -ISlangMutableFileSystem* FileArtifactRepresentation::_getFileSystem() -{ - return m_fileSystem ? m_fileSystem : OSFileSystem::getMutableSingleton(); -} - -void* FileArtifactRepresentation::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -SlangResult FileArtifactRepresentation::writeToBlob(ISlangBlob** blob) -{ - if (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; - } - - auto fileSystem = _getFileSystem(); - return fileSystem->loadFile(m_path.getBuffer(), blob); -} - -bool FileArtifactRepresentation::exists() -{ - // TODO(JS): - // If it's a name only it's hard to know what exists should do. It can't *check* because it relies on the 'system' doing - // the actual location. We could ask the IArtifactUtil, and that could change the behavior. - // For now we just assume it does. - if (m_kind == Kind::NameOnly) - { - return true; - } - - auto fileSystem = _getFileSystem(); - - SlangPathType pathType; - const auto res = fileSystem->getPathType(m_path.getBuffer(), &pathType); - - // It exists if it is a file - return SLANG_SUCCEEDED(res) && pathType == SLANG_PATH_TYPE_FILE; -} - -FileArtifactRepresentation::~FileArtifactRepresentation() -{ - if (m_kind == Kind::Owned) - { - auto fileSystem = _getFileSystem(); - fileSystem->remove(m_path.getBuffer()); - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LockFile !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* LockFile::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == ILockFile::getTypeGuid()) - { - return static_cast<ILockFile*>(this); - } - return nullptr; -} - -void* LockFile::getObject(const Guid& guid) -{ - SLANG_UNUSED(guid); - return nullptr; -} - -ISlangMutableFileSystem* LockFile::_getFileSystem() -{ - return m_fileSystem ? m_fileSystem : OSFileSystem::getMutableSingleton(); -} - -void* LockFile::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -const char* LockFile::getPath() -{ - return (m_path.getLength() > 0) ? m_path.getBuffer() : nullptr; -} - -ISlangMutableFileSystem* LockFile::getFileSystem() -{ - return m_fileSystem; -} - -LockFile::~LockFile() -{ - if (m_path.getLength() > 0) - { - auto fileSystem = _getFileSystem(); - fileSystem->remove(m_path.getBuffer()); - } -} - -void LockFile::disown() -{ - m_path = String(); - m_fileSystem.setNull(); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactList !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* ArtifactList::getInterface(const Guid& guid) -{ - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == IArtifactList::getTypeGuid()) - { - return static_cast<IArtifactList*>(this); - } - return nullptr; -} - -void* ArtifactList::getObject(const Guid& guid) -{ - // For now we can't cast to an object - SLANG_UNUSED(guid); - return nullptr; -} - -void* ArtifactList::castAs(const Guid& guid) -{ - if (auto intf = getInterface(guid)) - { - return intf; - } - return getObject(guid); -} - -void ArtifactList::add(IArtifact* artifact) -{ - // Must be set - SLANG_ASSERT(artifact); - // Can't already be in the list - SLANG_ASSERT(m_artifacts.indexOf(artifact) < 0); - // Can't have another owner - SLANG_ASSERT(artifact->getParent() == nullptr); - - // Set the parent - artifact->setParent(m_parent); - - // Add - m_artifacts.add(ComPtr<IArtifact>(artifact)); -} - -void ArtifactList::removeAt(Index index) -{ - IArtifact* artifact = m_artifacts[index]; - artifact->setParent(nullptr); - m_artifacts.removeAt(index); -} - -void ArtifactList::clear() -{ - _setParent(nullptr); - m_artifacts.clear(); -} - -void ArtifactList::_setParent(IArtifact* parent) -{ - if (m_parent == parent) - { - return; - } - - for (IArtifact* artifact : m_artifacts) - { - artifact->setParent(artifact); - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Artifact !!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* Artifact::getInterface(const Guid& uuid) -{ - if (uuid == ISlangUnknown::getTypeGuid() || uuid == IArtifact::getTypeGuid()) - { - return static_cast<IArtifact*>(this); - } - return nullptr; -} - -bool Artifact::exists() -{ - for (ISlangUnknown* item : m_items) - { - ComPtr<ICastable> castable; - - if (SLANG_SUCCEEDED(item->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) - { - auto rep = as<IArtifactRepresentation>(castable); - if (rep) - { - // It is a rep and it exists - if (rep->exists()) - { - return true; - } - continue; - } - // Associated types don't encapsulate an artifact representation, so don't signal existance - if (as<IArtifactAssociated>(castable)) - { - continue; - } - } - - // It can't be IArtifactRepresentation or IArtifactAssociated, so we assume means it exists - return true; - } - - return false; -} - -void Artifact::addItem(ISlangUnknown* intf) -{ - SLANG_ASSERT(intf); - // Can't already be in there - SLANG_ASSERT(m_items.indexOf(intf) < 0); - // Add it - m_items.add(ComPtr<ISlangUnknown>(intf)); -} - -void Artifact::removeItemAt(Index i) -{ - m_items.removeAt(i); -} - -void* Artifact::findItemInterface(const Guid& guid) -{ - for (ISlangUnknown* intf : m_items) - { - ISlangUnknown* cast = nullptr; - if (SLANG_SUCCEEDED(intf->queryInterface(guid, (void**)&cast)) && cast) - { - // NOTE! This assumes we *DONT* need to ref count to keep an interface in scope - // (as strict COM requires so as to allow on demand interfaces). - cast->release(); - return cast; - } - } - return nullptr; -} - -void* Artifact::findItemObject(const Guid& classGuid) -{ - for (ISlangUnknown* intf : m_items) - { - ComPtr<ICastable> castable; - if (SLANG_SUCCEEDED(intf->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) - { - void* obj = castable->castAs(classGuid); - - // NOTE! This assumes we *DONT* need to ref count to keep an interface in scope - // (as strict COM requires so as to allow on demand interfaces). - - // If could cast return the result - if (obj) - { - return obj; - } - } - } - return nullptr; -} - -SlangResult Artifact::requireFile(Keep keep, IFileArtifactRepresentation** outFileRep) -{ - auto util = ArtifactUtilImpl::getSingleton(); - return util->requireFileDefaultImpl(this, keep, outFileRep); -} - -SlangResult Artifact::loadBlob(Keep keep, ISlangBlob** outBlob) -{ - // If we have a blob just return it - if (auto blob = findItem<ISlangBlob>(this)) - { - blob->addRef(); - *outBlob = blob; - return SLANG_OK; - } - - ComPtr<ISlangBlob> blob; - - // Look for a representation that we can serialize into a blob - for (ISlangUnknown* intf : m_items) - { - ComPtr<IArtifactRepresentation> rep; - if (SLANG_SUCCEEDED(intf->queryInterface(IArtifactRepresentation::getTypeGuid(), (void**)rep.writeRef())) && rep) - { - SlangResult res = rep->writeToBlob(blob.writeRef()); - if (SLANG_SUCCEEDED(res) && blob) - { - break; - } - } - } - - // Wasn't able to construct - if (!blob) - { - return SLANG_E_NOT_FOUND; - } - - // Put in cache - if (canKeep(keep)) - { - addItem(blob); - } - - *outBlob = blob.detach(); - return SLANG_OK; -} - -} // namespace Slang diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index 88993773d..86b08dbb9 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -5,9 +5,7 @@ #include "../core/slang-basic.h" #include "../../slang-com-helper.h" -#include "../../slang-com-ptr.h" -#include "../core/slang-com-object.h" #include "../core/slang-destroyable.h" namespace Slang @@ -53,13 +51,6 @@ enum class ArtifactKind : uint8_t CountOf, }; - -/// Get the parent kind -ArtifactKind getParent(ArtifactKind kind); -/// Returns true if kind is derived from base -bool isDerivedFrom(ArtifactKind kind, ArtifactKind base); -/// Get the name for the kind -UnownedStringSlice getName(ArtifactKind kind); /* Payload. @@ -120,13 +111,6 @@ enum class ArtifactPayload : uint8_t CountOf, }; -/// Get the parent payload -ArtifactPayload getParent(ArtifactPayload payload); -/// Returns true if payload is derived from base -bool isDerivedFrom(ArtifactPayload payload, ArtifactPayload base); -/// Get the name for the payload -UnownedStringSlice getName(ArtifactPayload payload); - /* Style. NOTE! @@ -148,13 +132,6 @@ enum class ArtifactStyle : uint8_t CountOf, }; -/// Get the parent style -ArtifactStyle getParent(ArtifactStyle style); -/// Returns true if style is derived from base -bool isDerivedFrom(ArtifactStyle style, ArtifactStyle base); -/// Get the name for the style -UnownedStringSlice getName(ArtifactStyle style); - typedef uint8_t ArtifactFlags; struct ArtifactFlag { @@ -186,9 +163,6 @@ public: bool operator==(const This& rhs) const { return kind == rhs.kind && payload == rhs.payload && style == rhs.style && flags == rhs.flags; } bool operator!=(const This& rhs) const { return !(*this == rhs); } - /// Given a code gen target, get the equivalent ArtifactDesc - static This makeFromCompileTarget(SlangCompileTarget target); - /// Construct from the elements static This make(Kind inKind, Payload inPayload, Style inStyle = Style::Unknown, Flags flags = 0) { return This{ inKind, inPayload, inStyle, flags }; } @@ -225,6 +199,8 @@ inline /* static */ArtifactDesc ArtifactDesc::make(Packed inPacked) return r; } +// Forward declare +class IFileArtifactRepresentation; // Controls what items can be kept. enum class ArtifactKeep @@ -241,77 +217,6 @@ SLANG_INLINE bool canKeep(ArtifactKeep keep) { return Index(keep) >= Index(Artif /// Returns the keep type for an intermediate SLANG_INLINE ArtifactKeep getIntermediateKeep(ArtifactKeep keep) { return (keep == ArtifactKeep::All) ? ArtifactKeep::All : ArtifactKeep::No; } -enum ArtifactPathType -{ - None, - Temporary, ///< Is a temporary file - Existing, ///< Is an existing file -}; - -/* The IArtifactRepresentation interface represents a single representation that can be part of an artifact. It's special in so far -as - -* IArtifactRepresentation can be queried for it's underlying object class -* Can optionally serialize into a blob -*/ -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. - /// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement - virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) = 0; - - /// Returns true if this representation exists and is available for use. - virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; -}; - -/* A lock file */ -class ILockFile : public ICastable -{ - SLANG_COM_INTERFACE(0x9177ea36, 0xa608, 0x4490, { 0x87, 0xf0, 0xf3, 0x93, 0x9, 0x7d, 0x36, 0xce }) - - /// The path to a lock file. - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; - /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. - virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; - - /// Makes the lock file no longer owned. Doing so will make the path nullptr, and getFileSystem nullptr. - virtual SLANG_NO_THROW void SLANG_MCALL disown() = 0; -}; - -/* -A representation as a file. If it is a temporary file, it will likely disappear. -A file representation does not have to be a representation of a file on the file system. -That is indicated by getFileSystem returning nullptr. Then the path is the path on the *actual* OS file system. -This distinction is important as it is sometimes necessary to have an artifact stored on the OS file system -to be usable. */ -struct IFileArtifactRepresentation : public IArtifactRepresentation -{ - enum class Kind - { - Reference, ///< References a file on the file system - Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope - NameOnly, ///< Typically used for items that can be found by the 'system'. The path is just a name, and cannot typically be loaded as a blob. - }; - - /// The the kind of file. - virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() = 0; - /// The path (on the file system) - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; - /// Get the lock file. Return nullptr if there is no lock file. - virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() = 0; - /// Optional, the file system it's on. If nullptr its on 'regular' OS file system. - virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() = 0; -}; - -/* Interface for types that are associated with an artifact, but aren't a representation, or are -only part of a representation. */ -class IArtifactAssociated : public ICastable -{ - SLANG_COM_INTERFACE(0xafc0e4db, 0x16d4, 0x4d7a, { 0x93, 0x5f, 0x3e, 0x47, 0x7a, 0x23, 0x2a, 0x7f }) -}; - /* The IArtifact interface is designed to represent some Artifact of compilation. It could be input to or output from a compilation. An abstraction is desirable here, because depending on the compiler the artifact/s could be @@ -359,7 +264,6 @@ public: typedef ArtifactStyle Style; typedef ArtifactFlags Flags; typedef ArtifactKeep Keep; - typedef ArtifactPathType PathType; /// Get the Desc defining the contents of the artifact virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc() = 0; @@ -420,180 +324,32 @@ class IArtifactList : public ICastable virtual SLANG_NO_THROW void SLANG_MCALL clear() = 0; }; -class ArtifactList : public ComBaseObject, public IArtifactList -{ -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // IArtifactList - SLANG_NO_THROW IArtifact* SLANG_MCALL getParent() SLANG_OVERRIDE { return m_parent; } - SLANG_NO_THROW void SLANG_MCALL setParent(IArtifact* parent) SLANG_OVERRIDE { _setParent(parent); } - - SLANG_NO_THROW IArtifact* SLANG_MCALL getAt(Index index) SLANG_OVERRIDE { return m_artifacts[index]; } - SLANG_NO_THROW Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_artifacts.getCount(); } - SLANG_NO_THROW void SLANG_MCALL add(IArtifact* artifact) SLANG_OVERRIDE; - SLANG_NO_THROW void SLANG_MCALL removeAt(Index index) SLANG_OVERRIDE; - SLANG_NO_THROW void SLANG_MCALL clear() SLANG_OVERRIDE; - - // NOTE! The parent is a weak reference. - ArtifactList(IArtifact* parent): - m_parent(parent) - { - } - - virtual ~ArtifactList() { _setParent(nullptr); } - -protected: - void* getInterface(const Guid& guid); - void* getObject(const Guid& guid); - - void _setParent(IArtifact* artifact); - - IArtifact* m_parent; - List<ComPtr<IArtifact>> m_artifacts; -}; - -/* -Discussion: - -It could make sense to remove the explicit variables of a ISlangBlob, and the file backing from this interface, as they could -all be implemented as element types presumably deriving from IArtifactInstance. Doing so would mean how a 'file' is turned into -a blob is abstracted. - -It may be helpful to be able to add temporary files to the artifact (such that they will be deleted when the artifact goes out of -scope). Using an implementation of the File backed IArtifactInstance, with a suitable desc would sort of work, but it breaks the idea -that any IArtifactInstance *represents* the contents of Artifact that contains it. Of course there could be types *not* deriving -from IArtifactInstance that handle temporary file existance. This is probably the simplest answer to the problem. - -Another issue occurs around wanting to hold multiple kernels within a container. The problem here is that although through the desc -we can identify what target a kernel is for, there is no way of telling what stage it is for. +/* The IArtifactRepresentation interface represents a single representation that can be part of an artifact. It's special in so far +as -When discussing the idea of a shader cache, one idea was to use a ISlangFileSystem (which could actually be a zip, or directory or in memory rep) -as the main structure. Within this it can contain kernels, and then a json manifest can describe what each of these actually are. - -This all 'works', in that we can add an element of ISlangFileSystem with a desc of Container. Code that uses this can then go through the process -of finding, and getting the blob, and find from the manifest what it means. That does sound a little tedious though. Perhaps we just have an interface -that handles this detail, such that we search for that first. That interface is just attached to the artifact as an element. +* IArtifactRepresentation can be queried for it's underlying object class +* Can optionally serialize into a blob */ - -/* Implementation of the IArtifact interface */ -class Artifact : public ComBaseObject, public IArtifact -{ -public: - - SLANG_COM_BASE_IUNKNOWN_ALL - - /// IArtifact impl - virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc() SLANG_OVERRIDE { return m_desc; } - virtual SLANG_NO_THROW IArtifact* SLANG_MCALL getParent() SLANG_OVERRIDE { return m_parent; } - virtual SLANG_NO_THROW void SLANG_MCALL setParent(IArtifact* parent) SLANG_OVERRIDE { m_parent = parent; } - virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob(Keep keep, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFile(Keep keep, IFileArtifactRepresentation** outFileRep) SLANG_OVERRIDE; - virtual SLANG_NO_THROW const char* SLANG_MCALL getName() SLANG_OVERRIDE { return m_name.getBuffer(); } - virtual SLANG_NO_THROW void* SLANG_MCALL findItemInterface(const Guid& uuid) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void* SLANG_MCALL findItemObject(const Guid& classGuid) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void SLANG_MCALL addItem(ISlangUnknown* intf) SLANG_OVERRIDE; - virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getItemAt(Index i) SLANG_OVERRIDE { return m_items[i]; } - virtual SLANG_NO_THROW void SLANG_MCALL removeItemAt(Index i) SLANG_OVERRIDE; - virtual SLANG_NO_THROW Index SLANG_MCALL getItemCount() SLANG_OVERRIDE { return m_items.getCount(); } - - /// Ctor - Artifact(const Desc& desc, const String& name) : - m_desc(desc), - m_name(name), - m_parent(nullptr) - {} - -protected: - void* getInterface(const Guid& uuid); - - Desc m_desc; ///< Description of the artifact - IArtifact* m_parent; ///< Artifact this artifact belongs to - - String m_name; ///< Name of this artifact - - List<ComPtr<ISlangUnknown>> m_items; ///< Associated items -}; - -/* An implementation of ILockFile */ -class LockFile : public ComBaseObject, public ILockFile +class IArtifactRepresentation : public ICastable { -public: - SLANG_COM_BASE_IUNKNOWN_ALL - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // ILockFile - SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE; - SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE; - SLANG_NO_THROW void SLANG_MCALL disown() SLANG_OVERRIDE; - - /// Ctor - LockFile(String path, ISlangMutableFileSystem* fileSystem): - m_path(path), - m_fileSystem(fileSystem) - { - } - - ~LockFile(); - -protected: - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); + SLANG_COM_INTERFACE(0x311457a8, 0x1796, 0x4ebb, { 0x9a, 0xfc, 0x46, 0xa5, 0x44, 0xc7, 0x6e, 0xa9 }) - ISlangMutableFileSystem* _getFileSystem(); + /// Convert the instance into a serializable blob. + /// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement + virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToBlob(ISlangBlob** blob) = 0; - String m_path; - ComPtr<ISlangMutableFileSystem> m_fileSystem; + /// Returns true if this representation exists and is available for use. + virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; }; -/* -A representation of an artifact that is held in a file */ -class FileArtifactRepresentation : public ComBaseObject, public IFileArtifactRepresentation +/* Interface for types that are associated with an artifact, but aren't a representation, or are +only part of a representation. */ +class IArtifactAssociated : public ICastable { -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; - - // IFileArtifactRepresentation - virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() SLANG_OVERRIDE { return m_kind; } - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_path.getBuffer(); } - virtual SLANG_NO_THROW ILockFile* SLANG_MCALL getLockFile() SLANG_OVERRIDE { return m_lockFile; } - virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getFileSystem() SLANG_OVERRIDE { return m_fileSystem; } - - FileArtifactRepresentation(IFileArtifactRepresentation::Kind kind, String path, ILockFile* lockFile, ISlangMutableFileSystem* fileSystem): - m_kind(kind), - m_path(path), - m_lockFile(lockFile), - m_fileSystem(fileSystem) - { - } - - ~FileArtifactRepresentation(); - -protected: - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); - - ISlangMutableFileSystem* _getFileSystem(); - - IFileArtifactRepresentation::Kind m_kind; - String m_path; - ComPtr<ILockFile> m_lockFile; - ComPtr<ISlangMutableFileSystem> m_fileSystem; + SLANG_COM_INTERFACE(0xafc0e4db, 0x16d4, 0x4d7a, { 0x93, 0x5f, 0x3e, 0x47, 0x7a, 0x23, 0x2a, 0x7f }) }; + // Helper template to make finding an item more simple // There isn't a problem if we only have a forward declaration, because in that case T::getTypeGuid can't work. SLANG_FORCE_INLINE void* _findItemImpl(IArtifact* artifact, const Guid& guid, const ISlangUnknown* intf) diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp index 6375ba23a..8467cbbdc 100644 --- a/source/compiler-core/slang-dxc-compiler.cpp +++ b/source/compiler-core/slang-dxc-compiler.cpp @@ -19,7 +19,7 @@ #include "../core/slang-shared-library.h" -#include "../compiler-core/slang-artifact-info.h" +#include "../compiler-core/slang-artifact-desc-util.h" // Enable calling through to `dxc` to // generate code on Windows. @@ -83,7 +83,7 @@ static UnownedStringSlice _addName(const UnownedStringSlice& inSlice, StringSlic static UnownedStringSlice _addName(IArtifact* artifact, StringSlicePool& pool) { - return _addName(ArtifactInfoUtil::getBaseName(artifact).getUnownedSlice(), pool); + return _addName(ArtifactDescUtil::getBaseName(artifact).getUnownedSlice(), pool); } class DxcIncludeHandler : public IDxcIncludeHandler diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index bbf9eaf26..aee3b1bcc 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -10,7 +10,7 @@ #include "../core/slang-char-util.h" #include "../core/slang-string-slice-pool.h" -#include "slang-artifact-info.h" +#include "slang-artifact-desc-util.h" namespace Slang { @@ -635,15 +635,15 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse { const auto desc = artifact->getDesc(); // If it's a library for CPU types, try and use it - if (ArtifactInfoUtil::isCpuBinary(desc) && desc.kind == ArtifactKind::Library) + if (ArtifactDescUtil::isCpuBinary(desc) && desc.kind == ArtifactKind::Library) { ComPtr<IFileArtifactRepresentation> fileRep; // Get the name and path (can be empty) to the library SLANG_RETURN_ON_FAIL(artifact->requireFile(ArtifactKeep::No, fileRep.writeRef())); - libPathPool.add(ArtifactInfoUtil::getParentPath(fileRep)); - cmdLine.addPrefixPathArg("-l", ArtifactInfoUtil::getBaseName(artifact->getDesc(), fileRep)); + libPathPool.add(ArtifactDescUtil::getParentPath(fileRep)); + cmdLine.addPrefixPathArg("-l", ArtifactDescUtil::getBaseName(artifact->getDesc(), fileRep)); } } diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index a2e9c78d1..a4b4e7bc6 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -12,7 +12,7 @@ #endif #include "../core/slang-io.h" -#include "slang-artifact-info.h" +#include "slang-artifact-desc-util.h" namespace Slang { @@ -264,15 +264,15 @@ namespace Slang { auto desc = artifact->getDesc(); - if (ArtifactInfoUtil::isCpuBinary(desc) && desc.kind == ArtifactKind::Library) + if (ArtifactDescUtil::isCpuBinary(desc) && desc.kind == ArtifactKind::Library) { // Get the libray name and path ComPtr<IFileArtifactRepresentation> fileRep; SLANG_RETURN_ON_FAIL(artifact->requireFile(ArtifactKeep::No, fileRep.writeRef())); - libPathPool.add(ArtifactInfoUtil::getParentPath(fileRep)); + libPathPool.add(ArtifactDescUtil::getParentPath(fileRep)); // We need the extension for windows - cmdLine.addArg(ArtifactInfoUtil::getBaseName(artifact->getDesc(), fileRep) + ".lib"); + cmdLine.addArg(ArtifactDescUtil::getBaseName(artifact->getDesc(), fileRep) + ".lib"); } } diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 8205bcf36..361f92525 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -13,7 +13,11 @@ #include "slang-compiler.h" #include "../compiler-core/slang-lexer.h" -#include "../compiler-core/slang-artifact.h" + +// Artifact +#include "../compiler-core/slang-artifact-desc-util.h" +#include "../compiler-core/slang-artifact-representation-impl.h" +#include "../compiler-core/slang-artifact-impl.h" #include "slang-lower-to-ir.h" #include "slang-mangle.h" @@ -28,7 +32,6 @@ #include "slang-serialize-container.h" // - // Includes to allow us to control console // output when writing assembly dumps. #include <fcntl.h> @@ -53,32 +56,18 @@ namespace Slang { - // !!!!!!!!!!!!!!!!!!!!!! free functions for DiagnosicSink !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!! free functions for DiagnosicSink !!!!!!!!!!!!!!!!!!!!!!!!!!!!! -bool isHeterogeneousTarget(CodeGenTarget target) -{ - return ArtifactDesc::makeFromCompileTarget(asExternal(target)).style == ArtifactStyle::Host; -} - -void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) + bool isHeterogeneousTarget(CodeGenTarget target) { - switch (val) - { - default: - sb << "<unknown>"; - break; + return ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)).style == ArtifactStyle::Host; + } - #define CASE(TAG, STR) case CodeGenTarget::TAG: sb << STR; break - CASE(GLSL, "glsl"); - CASE(HLSL, "hlsl"); - CASE(SPIRV, "spirv"); - CASE(SPIRVAssembly, "spriv-assembly"); - CASE(DXBytecode, "dxbc"); - CASE(DXBytecodeAssembly, "dxbc-assembly"); - CASE(DXIL, "dxil"); - CASE(DXILAssembly, "dxil-assembly"); - #undef CASE - } + void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) + { + UnownedStringSlice name = TypeTextUtil::getCompileTargetName(asExternal(val)); + name = name.getLength() ? name : toSlice("<unknown>"); + sb << name; } void printDiagnosticArg(StringBuilder& sb, PassThroughMode val) @@ -86,7 +75,6 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) sb << TypeTextUtil::getPassThroughName(SlangPassThrough(val)); } - // !!!!!!!!!!!!!!!!!!!!!!!!!!!! CompileResult !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SlangResult CompileResult::getSharedLibrary(ComPtr<ISlangSharedLibrary>& outSharedLibrary) @@ -997,7 +985,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) static bool _isCPUHostTarget(CodeGenTarget target) { - auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + auto desc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)); return desc.style == ArtifactStyle::Host; } @@ -1303,7 +1291,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) // If we aren't using LLVM 'host callable', we want downstream compile to produce a shared library if (compilerType != PassThroughMode::LLVM && - ArtifactDesc::makeFromCompileTarget(asExternal(target)).kind == ArtifactKind::HostCallable) + ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)).kind == ArtifactKind::HostCallable) { target = CodeGenTarget::ShaderSharedLibrary; } @@ -1804,7 +1792,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) ComPtr<ISlangBlob> blob; if (SLANG_FAILED(result.getBlob(blob))) { - if (ArtifactDesc::makeFromCompileTarget(asExternal(targetReq->getTarget())).kind == ArtifactKind::HostCallable) + if (ArtifactDescUtil::makeDescFromCompileTarget(asExternal(targetReq->getTarget())).kind == ArtifactKind::HostCallable) { // Some HostCallable are not directly representable as a 'binary'. // So here, we just ignore if that appears the case, and don't output an unexpected error. @@ -2448,7 +2436,7 @@ void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val) return; auto target = getTargetFormat(); - const auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + const auto desc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)); if (desc.kind == ArtifactKind::Text) { diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index 5df13cbde..3cfe4d8d4 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -8,6 +8,8 @@ #include "slang-ir-clone.h" +#include "../compiler-core/slang-artifact-desc-util.h" + #include <assert.h> /* @@ -1653,7 +1655,7 @@ CPPSourceEmitter::CPPSourceEmitter(const Desc& desc): //m_semanticUsedFlags = SemanticUsedFlag::GroupID | SemanticUsedFlag::GroupThreadID | SemanticUsedFlag::DispatchThreadID; - const auto artifactDesc = ArtifactDesc::makeFromCompileTarget(asExternal(getTarget())); + const auto artifactDesc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(getTarget())); // If we have runtime library we can convert to a terminated string slice m_hasString = (artifactDesc.style == ArtifactStyle::Host); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 1ded8668f..21073f4c8 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -66,6 +66,8 @@ #include "slang-emit-cpp.h" #include "slang-emit-cuda.h" +#include "../compiler-core/slang-artifact-desc-util.h" + #include <assert.h> Slang::String get_slang_cpp_host_prelude(); @@ -180,7 +182,7 @@ Result linkAndOptimizeIR( auto targetRequest = codeGenContext->getTargetReq(); // Get the artifact desc for the target - const auto artifactDesc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); + const auto artifactDesc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)); // We start out by performing "linking" at the level of the IR. // This step will create a fresh IR module to be used for diff --git a/source/slang/slang-module-library.h b/source/slang/slang-module-library.h index 58d10bfc3..40e655e85 100644 --- a/source/slang/slang-module-library.h +++ b/source/slang/slang-module-library.h @@ -2,7 +2,7 @@ #ifndef SLANG_MODULE_LIBRARY_H #define SLANG_MODULE_LIBRARY_H -#include "../compiler-core/slang-artifact.h" +#include "../compiler-core/slang-artifact-representation.h" #include "slang-compiler.h" @@ -13,7 +13,6 @@ namespace Slang class ModuleLibrary : public ComObject, public IArtifactRepresentation { public: - SLANG_COM_OBJECT_IUNKNOWN_ALL SLANG_CLASS_GUID(0x2f7412bd, 0x6154, 0x40a9, { 0x89, 0xb3, 0x62, 0xe0, 0x24, 0x17, 0x24, 0xa1 }); diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index ab658fe18..5b14ca24f 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -10,7 +10,10 @@ #include "slang-compiler.h" #include "slang-profile.h" -#include "../compiler-core/slang-artifact.h" +#include "../compiler-core/slang-artifact-desc-util.h" + +#include "../compiler-core/slang-artifact-impl.h" +#include "../compiler-core/slang-artifact-representation-impl.h" #include "slang-repro.h" #include "slang-serialize-ir.h" @@ -20,7 +23,7 @@ #include "../core/slang-hex-dump-util.h" #include "../compiler-core/slang-command-line-args.h" -#include "../compiler-core/slang-artifact-info.h" +#include "../compiler-core/slang-artifact-desc-util.h" #include "../compiler-core/slang-core-diagnostics.h" #include <assert.h> @@ -1458,7 +1461,7 @@ struct OptionsParser const auto path = referenceModuleName.value; - auto desc = ArtifactInfoUtil::getDescFromPath(path.getUnownedSlice()); + auto desc = ArtifactDescUtil::getDescFromPath(path.getUnownedSlice()); if (desc.kind == ArtifactKind::Unknown) { @@ -1467,18 +1470,18 @@ struct OptionsParser } // If it's a GPU binary, then we'll assume it's a library - if (ArtifactInfoUtil::isGpuUsable(desc)) + if (ArtifactDescUtil::isGpuUsable(desc)) { desc.kind = ArtifactKind::Library; } - if (!ArtifactInfoUtil::isLinkable(desc)) + if (!ArtifactDescUtil::isLinkable(desc)) { sink->diagnose(referenceModuleName.loc, Diagnostics::kindNotLinkable, Path::getPathExt(path)); return SLANG_FAIL; } - const String name = ArtifactInfoUtil::getBaseNameFromPath(desc, path.getUnownedSlice()); + const String name = ArtifactDescUtil::getBaseNameFromPath(desc, path.getUnownedSlice()); // Create the artifact ComPtr<IArtifact> artifact(new Artifact(desc, name)); @@ -2042,7 +2045,7 @@ struct OptionsParser // and output type is callable, add an empty' rawOutput. if (rawOutputs.getCount() == 0 && rawTargets.getCount() == 1 && - ArtifactDesc::makeFromCompileTarget(asExternal(rawTargets[0].format)).kind == ArtifactKind::HostCallable) + ArtifactDescUtil::makeDescFromCompileTarget(asExternal(rawTargets[0].format)).kind == ArtifactKind::HostCallable) { RawOutput rawOutput; rawOutput.impliedFormat = rawTargets[0].format; diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 220cfb992..0a5df003a 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -5,7 +5,7 @@ #include "slang-compiler.h" #include "slang-type-layout.h" -#include "../compiler-core/slang-artifact-info.h" +#include "../compiler-core/slang-artifact-desc-util.h" #include "slang-ir-string-hash.h" @@ -3031,8 +3031,8 @@ static int _calcTotalNumUsedRegistersForLayoutResourceKind(ParameterBindingConte static bool _isCPUTarget(CodeGenTarget target) { - const auto desc = ArtifactDesc::makeFromCompileTarget(asExternal(target)); - return ArtifactInfoUtil::isCpuLikeTarget(desc); + const auto desc = ArtifactDescUtil::makeDescFromCompileTarget(asExternal(target)); + return ArtifactDescUtil::isCpuLikeTarget(desc); } static bool _isPTXTarget(CodeGenTarget target) diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index cde70d488..22af19271 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -4,7 +4,7 @@ #include "slang-syntax.h" #include "slang-ir-insts.h" -#include "../compiler-core/slang-artifact-info.h" +#include "../compiler-core/slang-artifact-desc-util.h" #include <assert.h> @@ -1606,7 +1606,7 @@ bool isKhronosTarget(TargetRequest* targetReq) bool isCPUTarget(TargetRequest* targetReq) { - return ArtifactInfoUtil::isCpuLikeTarget(ArtifactDesc::makeFromCompileTarget(asExternal(targetReq->getTarget()))); + return ArtifactDescUtil::isCpuLikeTarget(ArtifactDescUtil::makeDescFromCompileTarget(asExternal(targetReq->getTarget()))); } bool isCUDATarget(TargetRequest* targetReq) diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index dd53c98bf..f74a4a5d6 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -7,7 +7,9 @@ #include "../core/slang-type-text-util.h" #include "../core/slang-type-convert-util.h" -#include "../compiler-core/slang-artifact.h" +// Artifact +#include "../compiler-core/slang-artifact-impl.h" +#include "../compiler-core/slang-artifact-desc-util.h" #include "slang-module-library.h" @@ -729,7 +731,7 @@ SlangPassThrough Session::getDownstreamCompilerForTransition(SlangCompileTarget return (SlangPassThrough)m_codeGenTransitionMap.getTransition(source, target); } - const auto desc = ArtifactDesc::makeFromCompileTarget(inTarget); + const auto desc = ArtifactDescUtil::makeDescFromCompileTarget(inTarget); // Special case host-callable if ((desc.kind == ArtifactKind::HostCallable) && |
