diff options
Diffstat (limited to 'source/slang/slang-serialize-ir.cpp')
| -rw-r--r-- | source/slang/slang-serialize-ir.cpp | 162 |
1 files changed, 147 insertions, 15 deletions
diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp index 52a0a6537..55ccca5fc 100644 --- a/source/slang/slang-serialize-ir.cpp +++ b/source/slang/slang-serialize-ir.cpp @@ -2,12 +2,19 @@ #include "slang-serialize-ir.h" #include "core/slang-blob-builder.h" +#include "slang-ir-insts-stable-names.h" #include "slang-ir-insts.h" #include "slang-ir-validate.h" #include "slang-serialize-fossil.h" #include "slang-serialize-source-loc.h" #include "slang-serialize.h" +#include "slang-tag-version.h" +#include "slang.h" +// +#include "slang-serialize-ir.cpp.fiddle" + +FIDDLE() namespace Slang { @@ -16,9 +23,20 @@ namespace Slang // we want to serialize some sidecar information to help with on-demand loading // or backwards compat // +FIDDLE() struct IRModuleInfo { - RefPtr<IRModule> module; + FIDDLE(...) + // Include the specific compiler version in serialized output, in case we + // ever need to do any version specific workarounds. + FIDDLE() String fullVersion = SLANG_TAG_VERSION; + // Include this here so that if we need to change the way we serialize + // things and maintain backwards compat we can increment this value, for + // example if we introduce more instructions with weird payloads like + // IRModuleInst or IRConstants. + const static UInt kSupportedSerializationVersion = 0; + FIDDLE() UInt serializationVersion = kSupportedSerializationVersion; + FIDDLE() RefPtr<IRModule> module; }; // @@ -68,19 +86,87 @@ struct IRSerialReadContext : IRSerialContext, RefObject RefPtr<IRModule> _module; }; -// IROps are serialized as integers -SLANG_DECLARE_FOSSILIZED_AS(IROp, FossilUInt); -void serialize(Serializer const& serializer, IROp& value) +SLANG_DECLARE_FOSSILIZED_AS(Name, String); + +/// Fossilized representation of a `IRModule` +struct Fossilized_IRModule; + +SLANG_DECLARE_FOSSILIZED_TYPE(IRModule, Fossilized_IRModule); + +struct Fossilized_IRModule : public FossilizedRecordVal +{ + Fossilized<decltype(IRModule::m_moduleInst)> m_moduleInst; + Fossilized<String> m_name; + Fossilized<decltype(IRModule::m_version)> m_version; +}; + +// +// This splice handles any aggregate types, a similar splice is well documented +// in slang-serialize-ast.cpp +// +#if 0 // FIDDLE TEMPLATE: +% irStructTypes = { +% Slang.IRModuleInfo, +% } +% +% for _,T in ipairs(irStructTypes) do + +/// Fossilized representation of a `$T` +struct Fossilized_$T; + +SLANG_DECLARE_FOSSILIZED_TYPE($T, Fossilized_$T); + +/// Serialize a `$T` +void serialize(IRSerializer const& serializer, $T& value); +%end +%for _,T in ipairs(irStructTypes) do +/// Fossilized representation of a value of type `$T` +struct Fossilized_$T +% if T.directSuperClass then + : public Fossilized<$(T.directSuperClass)> +% else + : public FossilizedRecordVal +% end { - serializeEnum(serializer, value); +% for _,f in ipairs(T.directFields) do + Fossilized<decltype($T::$f)> $f; +% end +}; + +/// Serialize a `value` of type `$T` +void serialize(IRSerializer const& serializer, $T& value) +{ + SLANG_UNUSED(value); + SLANG_SCOPED_SERIALIZER_STRUCT(serializer); +% if T.directSuperClass then + serialize(serializer, static_cast<$(T.directSuperClass)&>(value)); +% end +% for _,f in ipairs(T.directFields) do + serialize(serializer, value.$f); +% end } +% end +#else // FIDDLE OUTPUT: +#define FIDDLE_GENERATED_OUTPUT_ID 0 +#include "slang-serialize-ir.cpp.fiddle" +#endif // FIDDLE END + -/// Serialize a `value` of type `IRModuleInfo`, currently no extra information -/// besides the IRModule -SLANG_DECLARE_FOSSILIZED_AS_MEMBER(IRModuleInfo, module); -void serialize(IRSerializer const& serializer, IRModuleInfo& value) +// IROps are serialized as integers, and given a stable name +SLANG_DECLARE_FOSSILIZED_AS(IROp, FossilUInt); +void serialize(Serializer const& serializer, IROp& value) { - serialize(serializer, value.module); + auto stableName = isWriting(serializer) ? getOpcodeStableName(value) : kInvalidStableName; + serializeEnum(serializer, stableName); + if (isReading(serializer)) + { + value = getStableNameOpcode(stableName); + // It's possible we're reading a module serialized by a future version of + // Slang with as-yet unknown instructions. + // if this is the case, return IRUnrecognized and we can handle it later + if (value == kIROp_Invalid) + value = kIROp_Unrecognized; + } } // @@ -309,8 +395,9 @@ void serializeObject(IRSerializer const& serializer, IRModule*& value, IRModule* void IRSerialWriteContext::handleIRModule(IRSerializer const& serializer, IRModule*& value) { SLANG_SCOPED_SERIALIZER_STRUCT(serializer); - serialize(serializer, value->m_name); serialize(serializer, value->m_moduleInst); + serialize(serializer, value->m_name); + serialize(serializer, value->m_version); } void IRSerialReadContext::handleIRModule(IRSerializer const& serializer, IRModule*& value) @@ -319,8 +406,9 @@ void IRSerialReadContext::handleIRModule(IRSerializer const& serializer, IRModul value = new IRModule{_session}; SLANG_ASSERT(!_module); _module = value; - serialize(serializer, value->m_name); serialize(serializer, value->m_moduleInst); + serialize(serializer, value->m_name); + serialize(serializer, value->m_version); value->m_moduleInst->module = value; } @@ -357,7 +445,9 @@ void writeSerializedModuleIR( // The flow here is very similar to writeSerializedModuleAST which is very // well documented. - IRModuleInfo moduleInfo{.module = irModule}; + IRModuleInfo moduleInfo; + moduleInfo.fullVersion = SLANG_TAG_VERSION; + moduleInfo.module = irModule; BlobBuilder blobBuilder; { @@ -375,10 +465,37 @@ void writeSerializedModuleIR( cursor.addDataChunk(PropertyKeys<IRModule>::IRModule, data, size); } +Result readSerializedModuleInfo( + RIFF::Chunk const* chunk, + String& compilerVersion, + UInt& version, + String& name) +{ + auto dataChunk = as<RIFF::DataChunk>(chunk); + if (!dataChunk) + { + SLANG_UNEXPECTED("invalid format for serialized module IR"); + } + + Fossil::AnyValPtr rootValPtr = + Fossil::getRootValue(dataChunk->getPayload(), dataChunk->getPayloadSize()); + if (!rootValPtr) + { + SLANG_UNEXPECTED("invalid format for serialized module IR"); + } + + Fossilized<IRModuleInfo>* fossilizedModuleInfo = cast<Fossilized<IRModuleInfo>>(rootValPtr); + Fossilized<IRModule>* fossilizedModule = fossilizedModuleInfo->module; + version = fossilizedModule->m_version; + compilerVersion = fossilizedModuleInfo->fullVersion.get(); + name = fossilizedModuleInfo->module->m_name.get(); + return SLANG_OK; +} + // // Read a module, this currently does not do any on-demand loading // -void readSerializedModuleIR( +Result readSerializedModuleIR( RIFF::Chunk const* chunk, Session* session, SerialSourceLocReader* sourceLocReader, @@ -397,6 +514,13 @@ void readSerializedModuleIR( SLANG_UNEXPECTED("invalid format for serialized module IR"); } + Fossilized<IRModuleInfo>* fossilizedModuleInfo = cast<Fossilized<IRModuleInfo>>(rootValPtr); + + // Only one version supported so far, if we had multiple versions to + // support this is where we might branch + if (fossilizedModuleInfo->serializationVersion != IRModuleInfo::kSupportedSerializationVersion) + return SLANG_FAIL; + IRModuleInfo info; { auto sharedDecodingContext = RefPtr(new IRSerialReadContext(session, sourceLocReader)); @@ -417,20 +541,28 @@ void readSerializedModuleIR( // deserialization we didn't necessarily have this information handy at the // time. // - auto go = [](auto&& go, IRInst* parent, IRInst* inst) -> void + bool hasUnrecognizedInsts = false; + auto go = [&](auto&& go, IRInst* parent, IRInst* inst) -> void { + if (inst->getOp() == kIROp_Unrecognized) + hasUnrecognizedInsts = true; + inst->parent = parent; for (const auto child : inst->getDecorationsAndChildren()) go(go, inst, child); }; go(go, nullptr, info.module->getModuleInst()); + if (hasUnrecognizedInsts) + return SLANG_FAIL; + // // Module is finally valid (or at least as much as it was going it) and // ready to be used // info.module->buildMangledNameToGlobalInstMap(); outIRModule = info.module; + return SLANG_OK; } } // namespace Slang |
