diff options
Diffstat (limited to 'source/compiler-core/slang-artifact.cpp')
| -rw-r--r-- | source/compiler-core/slang-artifact.cpp | 425 |
1 files changed, 375 insertions, 50 deletions
diff --git a/source/compiler-core/slang-artifact.cpp b/source/compiler-core/slang-artifact.cpp index bf61763c8..cb77f5140 100644 --- a/source/compiler-core/slang-artifact.cpp +++ b/source/compiler-core/slang-artifact.cpp @@ -5,9 +5,236 @@ #include "../core/slang-type-text-util.h" #include "../core/slang-io.h" +#include "../core/slang-array-view.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) @@ -20,31 +247,106 @@ namespace Slang { { // For the moment we make all just map to GLSL, but we could use flags // or some other mechanism to distinguish the types - return make(Kind::Text, Payload::GLSL, Style::Kernel, 0); + return make(Kind::Source, Payload::GLSL, Style::Kernel, 0); } - case SLANG_HLSL: return make(Kind::Text, Payload::HLSL, 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::Text, Payload::SPIRVAssembly, 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::Text, Payload::DXBCAssembly, 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::Text, Payload::DXILAssembly, Style::Kernel, 0); - case SLANG_C_SOURCE: return make(Kind::Text, Payload::C, Style::Kernel, 0); - case SLANG_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Kernel, 0); - case SLANG_HOST_CPP_SOURCE: return make(Kind::Text, Payload::CPP, Style::Host, 0); + case SLANG_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::Callable, Payload::HostCPU, Style::Kernel, 0); - case SLANG_CUDA_SOURCE: return make(Kind::Text, Payload::CUDA, 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::Callable, Payload::HostCPU, Style::Host, 0); + case SLANG_HOST_HOST_CALLABLE: return make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); default: break; } SLANG_UNEXPECTED("Unhandled type"); } +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 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) @@ -78,9 +380,30 @@ bool Artifact::exists() return true; } - // If we have an associated entry that represents the artifact it exists - if (findElement(IArtifactInstance::getTypeGuid())) + for (ISlangUnknown* item : m_items) { + ComPtr<ICastable> castable; + + if (SLANG_SUCCEEDED(item->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) + { + auto rep = (IArtifactRepresentation*)castable->castAs(IArtifactRepresentation::getTypeGuid()); + 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 (castable->castAs(IArtifactAssociated::getTypeGuid())) + { + continue; + } + } + + // It can't be IArtifactRepresentation or IArtifactAssociated, so we assume means it exists return true; } @@ -94,54 +417,57 @@ bool Artifact::exists() return File::exists(m_path); } -ISlangUnknown* Artifact::findElement(const Guid& guid) + +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) { - for (auto const& element : m_elements) - { - ISlangUnknown* value = element.value; + m_items.removeAt(i); +} + - ISlangUnknown* intf = nullptr; - if (SLANG_SUCCEEDED(value->queryInterface(guid, (void**)&intf)) && intf) +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). - intf->release(); - return intf; + cast->release(); + return cast; } } - return nullptr; } -void Artifact::addElement(const Desc& desc, ISlangUnknown* intf) -{ - SLANG_ASSERT(intf); - Element element{ desc, ComPtr<ISlangUnknown>(intf) }; - m_elements.add(element); -} - -void Artifact::removeElementAt(Index i) +void* Artifact::findItemObject(const Guid& classGuid) { - m_elements.removeAt(i); -} - -void* Artifact::findElementObject(const Guid& classGuid) -{ - ComPtr<IArtifactInstance> instance; - for (const auto& element : m_elements) + for (ISlangUnknown* intf : m_items) { - ISlangUnknown* value = element.value; - - if (SLANG_SUCCEEDED(value->queryInterface(IArtifactInstance::getTypeGuid(), (void**)instance.writeRef())) && instance) + ComPtr<ICastable> castable; + if (SLANG_SUCCEEDED(intf->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable) { - void* classInstance = instance->queryObject(classGuid); - if (classInstance) + 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 classInstance; + return obj; } } } - return nullptr; } @@ -270,14 +596,13 @@ SlangResult Artifact::loadBlob(Keep keep, ISlangBlob** outBlob) else { // Look for a representation that we can serialize into a blob - for (const auto& element : m_elements) + for (ISlangUnknown* intf : m_items) { - ISlangUnknown* intf = element.value; - - ComPtr<IArtifactInstance> inst; - if (SLANG_SUCCEEDED(intf->queryInterface(IArtifactInstance::getTypeGuid(), (void**)inst.writeRef())) && inst) + + ComPtr<IArtifactRepresentation> rep; + if (SLANG_SUCCEEDED(intf->queryInterface(IArtifactRepresentation::getTypeGuid(), (void**)rep.writeRef())) && rep) { - SlangResult res = inst->writeToBlob(blob.writeRef()); + SlangResult res = rep->writeToBlob(blob.writeRef()); if (SLANG_SUCCEEDED(res) && blob) { break; |
