summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-10-30 17:28:55 -0400
committerGitHub <noreply@github.com>2019-10-30 17:28:55 -0400
commit72f86c8273b196d204213f02e73ba772201f903d (patch)
tree914f750180e75c6d549bf0be80e9877f4f35c8ed
parent066bc37f34ab4f72edef2b71fab50b45c3bb627e (diff)
WIP: Simple separate IR module linkage working (#1100)
* Added RiffReadHelper * Move type to fourCC in Chunk simplifies some code. * Make MemoryArena able to track external blocks. Allow ownership of Data to vary. Changed IR serialization to use moved allocations to avoid copies. As it turns out all of the array writes could use unowned data, but doing so requires the IRData to stay in scope longer than IRSerialData, which it does at the moment - but perhaps needs better naming or a control for the feature. * Write out slang-module container. * WIP on -r option. Loading modules - with -r. * Making the serialized-module run (without using imported module). * Split compiling module from the test. * Separate module compilation with a function working. * Remove serialization test as not used. * Fix warning on gcc. * Updated test to have types across module boundary.
-rw-r--r--source/core/slang-riff.cpp13
-rw-r--r--source/core/slang-riff.h3
-rw-r--r--source/slang/slang-compiler.cpp69
-rw-r--r--source/slang/slang-compiler.h4
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-ir-link.cpp23
-rw-r--r--source/slang/slang-ir-serialize.cpp73
-rw-r--r--source/slang/slang-ir-serialize.h47
-rw-r--r--source/slang/slang-options.cpp21
-rw-r--r--tests/serialization/serialized-module-test.slang35
-rw-r--r--tests/serialization/serialized-module-test.slang.expected.txt4
-rw-r--r--tests/serialization/serialized-module.slang15
12 files changed, 248 insertions, 60 deletions
diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp
index 3a3722bb8..2e633f2e7 100644
--- a/source/core/slang-riff.cpp
+++ b/source/core/slang-riff.cpp
@@ -535,6 +535,19 @@ RiffContainer::Chunk* RiffContainer::ListChunk::findContained(FourCC fourCC) con
return nullptr;
}
+void RiffContainer::ListChunk::findContained(FourCC type, List<ListChunk*>& out)
+{
+ Chunk* chunk = m_containedChunks;
+ while (chunk)
+ {
+ if (chunk->m_fourCC == type && chunk->m_kind == Chunk::Kind::List)
+ {
+ out.add(static_cast<ListChunk*>(chunk));
+ }
+ chunk = chunk->m_next;
+ }
+}
+
RiffContainer::Data* RiffContainer::ListChunk::findContainedData(FourCC type) const
{
Chunk* found = findContained(type);
diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h
index 4d23e45c1..99d078625 100644
--- a/source/core/slang-riff.h
+++ b/source/core/slang-riff.h
@@ -245,6 +245,9 @@ public:
template <typename T>
T* findContainedData(FourCC type) const { return (T*)findContainedData(type, sizeof(T)); }
+ /// Find all contained that match the type
+ void findContained(FourCC type, List<ListChunk*>& out);
+
/// Find the list (including self) that matches subtype recursively
ListChunk* findListRec(FourCC subType);
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 87a5e01a8..705b4ed59 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -5,6 +5,7 @@
#include "../core/slang-io.h"
#include "../core/slang-string-util.h"
#include "../core/slang-hex-dump-util.h"
+#include "../core/slang-riff.h"
#include "slang-check.h"
#include "slang-compiler.h"
@@ -18,6 +19,8 @@
#include "slang-reflection.h"
#include "slang-emit.h"
+#include "slang-ir-serialize.h"
+
// Enable calling through to `fxc` or `dxc` to
// generate code on Windows.
#ifdef _WIN32
@@ -2187,38 +2190,64 @@ SlangResult dissassembleDXILUsingDXC(
EndToEndCompileRequest* endToEndReq,
Stream* stream)
{
- SLANG_UNUSED(stream);
+ RiffContainer container;
- auto linkage = endToEndReq->getLinkage();
- auto sink = endToEndReq->getSink();
- auto frontEndReq = endToEndReq->getFrontEndReq();
+ // TODO(JS): We may want a switch to control is we use compression and/or we may just want compressed by default.
+ // For now uncompressed is fine.
+ const auto compressionType = IRSerialBinary::CompressionType::None;
- for (auto translationUnit : frontEndReq->translationUnits)
{
- auto module = translationUnit->module;
- auto irModule = module->getIRModule();
+ // Module list
+ RiffContainer::ScopeChunk listScope(&container, RiffContainer::Chunk::Kind::List, IRSerialBinary::kSlangModuleListFourCc);
- SLANG_UNUSED(irModule);
+ auto linkage = endToEndReq->getLinkage();
+ auto sink = endToEndReq->getSink();
+ auto frontEndReq = endToEndReq->getFrontEndReq();
- // Okay, we need to serialize this module to our container file,
- // including both its name and generated IR code.
- }
+ IRSerialWriter::OptionFlags optionFlags = 0;
- auto program = endToEndReq->getSpecializedGlobalAndEntryPointsComponentType();
+ if (linkage->debugInfoLevel != DebugInfoLevel::None)
+ {
+ optionFlags |= IRSerialWriter::OptionFlag::DebugInfo;
+ }
-
+ SourceManager* sourceManager = frontEndReq->getSourceManager();
- // TODO: in the case where we have specialization, we might need
- // to serialize IR related to `program`...
+ for (auto translationUnit : frontEndReq->translationUnits)
+ {
+ auto module = translationUnit->module;
+ auto irModule = module->getIRModule();
- for (auto target : linkage->targets)
- {
- auto targetProgram = program->getTargetProgram(target);
- auto irModule = targetProgram->getOrCreateIRModuleForLayout(sink);
+ // Okay, we need to serialize this module to our container file.
+ // We currently don't serialize it's name..., but support for that could be added.
- // Okay, we need to serialize this target program and its IR too...
+ IRSerialData serialData;
+ IRSerialWriter writer;
+ SLANG_RETURN_ON_FAIL(writer.write(irModule, sourceManager, optionFlags, &serialData));
+ SLANG_RETURN_ON_FAIL(IRSerialWriter::writeContainer(serialData, compressionType, &container));
+ }
+
+ auto program = endToEndReq->getSpecializedGlobalAndEntryPointsComponentType();
+
+ // TODO: in the case where we have specialization, we might need
+ // to serialize IR related to `program`...
+
+ for (auto target : linkage->targets)
+ {
+ auto targetProgram = program->getTargetProgram(target);
+ auto irModule = targetProgram->getOrCreateIRModuleForLayout(sink);
+
+ // Okay, we need to serialize this target program and its IR too...
+ IRSerialData serialData;
+ IRSerialWriter writer;
+ SLANG_RETURN_ON_FAIL(writer.write(irModule, sourceManager, optionFlags, &serialData));
+ SLANG_RETURN_ON_FAIL(IRSerialWriter::writeContainer(serialData, compressionType, &container));
+ }
}
+ // We now write the RiffContainer to the stream
+ SLANG_RETURN_ON_FAIL(RiffUtil::write(container.getRoot(), true, stream));
+
return SLANG_OK;
}
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index a527d3a31..cd99c4079 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1260,6 +1260,9 @@ namespace Slang
bool m_requireCacheFileSystem = false;
bool m_useFalcorCustomSharedKeywordSemantics = false;
+ // Modules that have been read in with the -r option
+ List<RefPtr<IRModule>> m_libModules;
+
private:
Session* m_session = nullptr;
@@ -1299,6 +1302,7 @@ namespace Slang
bool isBeingImported(Module* module);
List<RefPtr<Type>> m_specializedTypes;
+
};
/// Shared functionality between front- and back-end compile requests.
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 6623b7195..405590111 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -111,6 +111,7 @@ DIAGNOSTIC( 80, Error, duplicateOutputPathsForEntryPointAndTarget, "multiple
DIAGNOSTIC( 81, Error, parametersAfterLoadReproIgnored, "parameters after -load-repro [file] are ignored")
DIAGNOSTIC( 82, Error, unableToWriteReproFile, "unable to write repro file '%0'");
DIAGNOSTIC( 83, Error, unableToWriteModuleContainer, "unable to write module container '%0'");
+DIAGNOSTIC( 84, Error, unableToReadModuleContainer, "unable to read module container '%0'");
//
// 1xxxx - Lexical anaylsis
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index 1cdc2cfc9..1102ecb3e 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -1339,15 +1339,26 @@ LinkedIR linkIR(
state->irModule = sharedContext->module;
+ auto linkage = compileRequest->getLinkage();
+
// We need to be able to look up IR definitions for any symbols in
// modules that the program depends on (transitively). To
// accelerate lookup, we will create a symbol table for looking
// up IR definitions by their mangled name.
//
+
+ List<IRModule*> irModules;
program->enumerateIRModules([&](IRModule* irModule)
{
- insertGlobalValueSymbols(sharedContext, irModule);
+ irModules.add(irModule);
});
+ irModules.addRange(linkage->m_libModules.getBuffer()->readRef(), linkage->m_libModules.getCount());
+
+ // Add any modules that were loaded as libraries
+ for (IRModule* irModule : irModules)
+ {
+ insertGlobalValueSymbols(sharedContext, irModule);
+ }
// We will also insert the IR global symbols from the IR module
// attached to the `TargetProgram`, since this module is
@@ -1374,7 +1385,6 @@ LinkedIR linkIR(
cloneGlobalValue(context, (IRWitnessTable*)sym.Value->irGlobalValue);
}
-
// Next, we make sure to clone the global value for
// the entry point function itself, and rely on
// this step to recursively copy over anything else
@@ -1401,17 +1411,18 @@ LinkedIR linkIR(
// In the long run we do not want to *ever* iterate over all the
// instructions in all the input modules.
//
- program->enumerateIRModules([&](IRModule* irModule)
+
+ for (IRModule* irModule : irModules)
{
- for(auto inst : irModule->getGlobalInsts())
+ for (auto inst : irModule->getGlobalInsts())
{
auto bindInst = as<IRBindGlobalGenericParam>(inst);
- if(!bindInst)
+ if (!bindInst)
continue;
cloneValue(context, bindInst);
}
- });
+ }
// TODO: *technically* we should consider the case where
// we have global variables with initializers, since
diff --git a/source/slang/slang-ir-serialize.cpp b/source/slang/slang-ir-serialize.cpp
index 97b070f9c..5c16f70f3 100644
--- a/source/slang/slang-ir-serialize.cpp
+++ b/source/slang/slang-ir-serialize.cpp
@@ -809,7 +809,7 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType,
{
ScopeChunk scope(container, Chunk::Kind::Data, chunkId);
Bin::ArrayHeader header;
- header.m_numEntries = uint32_t(numEntries);
+ header.numEntries = uint32_t(numEntries);
container->write(&header, sizeof(header));
container->write(data, typeSize * numEntries);
@@ -823,8 +823,8 @@ static Result _writeArrayChunk(IRSerialBinary::CompressionType compressionType,
ByteEncodeUtil::encodeLiteUInt32((const uint32_t*)data, numCompressedEntries, compressedPayload);
Bin::CompressedArrayHeader header;
- header.m_numEntries = uint32_t(numEntries);
- header.m_numCompressedEntries = uint32_t(numCompressedEntries);
+ header.numEntries = uint32_t(numEntries);
+ header.numCompressedEntries = uint32_t(numCompressedEntries);
container->write(&header, sizeof(header));
@@ -961,8 +961,8 @@ Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uin
ScopeChunk scope(container, Chunk::Kind::Data, SLANG_MAKE_COMPRESSED_FOUR_CC(chunkId));
Bin::CompressedArrayHeader header;
- header.m_numEntries = uint32_t(array.getCount());
- header.m_numCompressedEntries = 0;
+ header.numEntries = uint32_t(array.getCount());
+ header.numCompressedEntries = 0;
container->write(&header, sizeof(header));
@@ -986,7 +986,7 @@ Result _writeInstArrayChunk(IRSerialBinary::CompressionType compressionType, uin
// Write the header
{
Bin::ModuleHeader moduleHeader;
- moduleHeader.m_compressionType = uint32_t(Bin::CompressionType::VariableByteLite);
+ moduleHeader.compressionType = uint32_t(Bin::CompressionType::VariableByteLite);
ScopeChunk scopeHeader(container, Chunk::Kind::Data, Bin::kSlangModuleHeaderFourCc);
container->write(&moduleHeader, sizeof(moduleHeader));
}
@@ -1065,11 +1065,11 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, R
Bin::CompressedArrayHeader header;
SLANG_RETURN_ON_FAIL(read.read(header));
- void* dst = listOut.setSize(header.m_numEntries);
- SLANG_ASSERT(header.m_numCompressedEntries == uint32_t((header.m_numEntries * typeSize) / sizeof(uint32_t)));
+ void* dst = listOut.setSize(header.numEntries);
+ SLANG_ASSERT(header.numCompressedEntries == uint32_t((header.numEntries * typeSize) / sizeof(uint32_t)));
// Decode..
- ByteEncodeUtil::decodeLiteUInt32(read.getData(), header.m_numCompressedEntries, (uint32_t*)dst);
+ ByteEncodeUtil::decodeLiteUInt32(read.getData(), header.numCompressedEntries, (uint32_t*)dst);
break;
}
case Bin::CompressionType::None:
@@ -1077,9 +1077,9 @@ static Result _readArrayChunk(IRSerialBinary::CompressionType compressionType, R
// Read uncompressed
Bin::ArrayHeader header;
SLANG_RETURN_ON_FAIL(read.read(header));
- const size_t payloadSize = header.m_numEntries * typeSize;
+ const size_t payloadSize = header.numEntries * typeSize;
SLANG_ASSERT(payloadSize == read.getRemainingSize());
- void* dst = listOut.setSize(header.m_numEntries);
+ void* dst = listOut.setSize(header.numEntries);
::memcpy(dst, read.getData(), payloadSize);
break;
}
@@ -1097,7 +1097,7 @@ static Result _readArrayChunk(const IRSerialBinary::ModuleHeader* header, RiffCo
if (dataChunk->m_fourCC == SLANG_MAKE_COMPRESSED_FOUR_CC(dataChunk->m_fourCC))
{
// If it has compression, use the compression type set in the header
- compressionType = Bin::CompressionType(header->m_compressionType);
+ compressionType = Bin::CompressionType(header->compressionType);
}
ListResizerForType<T> resizer(arrayOut);
return _readArrayChunk(compressionType, dataChunk, resizer);
@@ -1191,7 +1191,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::ModuleHeader* moduleHead
Bin::CompressionType compressionType = Bin::CompressionType::None;
if (chunk->m_fourCC == SLANG_MAKE_COMPRESSED_FOUR_CC(chunk->m_fourCC))
{
- compressionType = Bin::CompressionType(moduleHeader->m_compressionType);
+ compressionType = Bin::CompressionType(moduleHeader->compressionType);
}
switch (compressionType)
@@ -1208,7 +1208,7 @@ static Result _readInstArrayChunk(const IRSerialBinary::ModuleHeader* moduleHead
Bin::CompressedArrayHeader header;
SLANG_RETURN_ON_FAIL(read.read(header));
- arrayOut.setCount(header.m_numEntries);
+ arrayOut.setCount(header.numEntries);
SLANG_RETURN_ON_FAIL(_decodeInsts(compressionType, read.getData(), read.getRemainingSize(), arrayOut));
break;
@@ -1357,6 +1357,51 @@ static int _calcFixSourceLoc(const IRSerialData::DebugSourceInfo& info, SourceVi
return int(sourceView->getRange().begin.getRaw()) - int(info.m_startSourceLoc);
}
+/* static */Result IRSerialReader::readStreamModules(Stream* stream, Session* session, SourceManager* sourceManager, List<RefPtr<IRModule>>& outModules)
+{
+ // Load up the module
+ RiffContainer container;
+ SLANG_RETURN_ON_FAIL(RiffUtil::read(stream, container));
+
+ List<RiffContainer::ListChunk*> moduleChunks;
+ // First try to find a list
+ {
+ RiffContainer::ListChunk* listChunk = container.getRoot()->findListRec(IRSerialBinary::kSlangModuleListFourCc);
+ if (listChunk)
+ {
+ listChunk->findContained(IRSerialBinary::kSlangModuleFourCc, moduleChunks);
+ }
+ else
+ {
+ // Maybe its just a single module
+ RiffContainer::ListChunk* moduleChunk = container.getRoot()->findListRec(IRSerialBinary::kSlangModuleFourCc);
+ if (!moduleChunk)
+ {
+ // Couldn't find any modules
+ return SLANG_FAIL;
+ }
+ moduleChunks.add(moduleChunk);
+ }
+ }
+
+ // Okay, we need to decode into ir modules
+ for (auto moduleChunk : moduleChunks)
+ {
+ IRSerialData serialData;
+
+ SLANG_RETURN_ON_FAIL(IRSerialReader::readContainer(moduleChunk, &serialData));
+
+ // Construct into a module
+ RefPtr<IRModule> irModule;
+ IRSerialReader reader;
+ SLANG_RETURN_ON_FAIL(reader.read(serialData, session, sourceManager, irModule));
+
+ outModules.add(irModule);
+ }
+
+ return SLANG_OK;
+}
+
/* static */Result IRSerialReader::read(const IRSerialData& data, Session* session, SourceManager* sourceManager, RefPtr<IRModule>& moduleOut)
{
typedef Ser::Inst::PayloadType PayloadType;
diff --git a/source/slang/slang-ir-serialize.h b/source/slang/slang-ir-serialize.h
index ed9441874..d1f78d5f8 100644
--- a/source/slang/slang-ir-serialize.h
+++ b/source/slang/slang-ir-serialize.h
@@ -357,42 +357,44 @@ struct IRSerialBinary
VariableByteLite,
};
- static const uint32_t kRiffFourCc = RiffFourCC::kRiff;
+ static const FourCC kRiffFourCc = RiffFourCC::kRiff;
- static const uint32_t kSlangModuleFourCc = SLANG_FOUR_CC('S', 'L', 'm', 'd'); ///< Holds all the slang specific chunks
+ static const FourCC kSlangModuleListFourCc = SLANG_FOUR_CC('S', 'L', 'm', 'l');
- static const uint32_t kSlangModuleHeaderFourCc = SLANG_FOUR_CC('S', 'L', 'h', 'd');
+ static const FourCC kSlangModuleFourCc = SLANG_FOUR_CC('S', 'L', 'm', 'd'); ///< Holds all the slang specific chunks
- static const uint32_t kInstFourCc = SLANG_FOUR_CC('S', 'L', 'i', 'n');
- static const uint32_t kChildRunFourCc = SLANG_FOUR_CC('S', 'L', 'c', 'r');
- static const uint32_t kExternalOperandsFourCc = SLANG_FOUR_CC('S', 'L', 'e', 'o');
+ static const FourCC kSlangModuleHeaderFourCc = SLANG_FOUR_CC('S', 'L', 'h', 'd');
- static const uint32_t kCompressedInstFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kInstFourCc);
- static const uint32_t kCompressedChildRunFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kChildRunFourCc);
- static const uint32_t kCompressedExternalOperandsFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kExternalOperandsFourCc);
+ static const FourCC kInstFourCc = SLANG_FOUR_CC('S', 'L', 'i', 'n');
+ static const FourCC kChildRunFourCc = SLANG_FOUR_CC('S', 'L', 'c', 'r');
+ static const FourCC kExternalOperandsFourCc = SLANG_FOUR_CC('S', 'L', 'e', 'o');
- static const uint32_t kStringFourCc = SLANG_FOUR_CC('S', 'L', 's', 't');
+ static const FourCC kCompressedInstFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kInstFourCc);
+ static const FourCC kCompressedChildRunFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kChildRunFourCc);
+ static const FourCC kCompressedExternalOperandsFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kExternalOperandsFourCc);
- static const uint32_t kUInt32SourceLocFourCc = SLANG_FOUR_CC('S', 'r', 's', '4');
+ static const FourCC kStringFourCc = SLANG_FOUR_CC('S', 'L', 's', 't');
- static const uint32_t kDebugStringFourCc = SLANG_FOUR_CC('S', 'd', 's', 't');
- static const uint32_t kDebugLineInfoFourCc = SLANG_FOUR_CC('S', 'd', 'l', 'n');
- static const uint32_t kDebugAdjustedLineInfoFourCc = SLANG_FOUR_CC('S', 'd', 'a', 'l');
- static const uint32_t kDebugSourceInfoFourCc = SLANG_FOUR_CC('S', 'd', 's', 'o');
- static const uint32_t kDebugSourceLocRunFourCc = SLANG_FOUR_CC('S', 'd', 's', 'r');
+ static const FourCC kUInt32SourceLocFourCc = SLANG_FOUR_CC('S', 'r', 's', '4');
+
+ static const FourCC kDebugStringFourCc = SLANG_FOUR_CC('S', 'd', 's', 't');
+ static const FourCC kDebugLineInfoFourCc = SLANG_FOUR_CC('S', 'd', 'l', 'n');
+ static const FourCC kDebugAdjustedLineInfoFourCc = SLANG_FOUR_CC('S', 'd', 'a', 'l');
+ static const FourCC kDebugSourceInfoFourCc = SLANG_FOUR_CC('S', 'd', 's', 'o');
+ static const FourCC kDebugSourceLocRunFourCc = SLANG_FOUR_CC('S', 'd', 's', 'r');
struct ModuleHeader
{
- uint32_t m_compressionType; ///< Holds the compression type used (if used at all)
+ uint32_t compressionType; ///< Holds the compression type used (if used at all)
};
struct ArrayHeader
{
- uint32_t m_numEntries;
+ uint32_t numEntries;
};
struct CompressedArrayHeader
{
- uint32_t m_numEntries; ///< The number of entries
- uint32_t m_numCompressedEntries; ///< The amount of compressed entries
+ uint32_t numEntries; ///< The number of entries
+ uint32_t numCompressedEntries; ///< The amount of compressed entries
};
};
@@ -501,12 +503,17 @@ struct IRSerialReader
/// Read a stream to fill in dataOut IRSerialData
static Result readStream(Stream* stream, IRSerialData* dataOut);
+ /// Read potentially multiple modules from a stream
+ static Result readStreamModules(Stream* stream, Session* session, SourceManager* manager, List<RefPtr<IRModule>>& outModules);
+
/// Read a stream to fill in dataOut IRSerialData
static Result readContainer(RiffContainer::ListChunk* module, IRSerialData* outData);
/// Read a module from serial data
Result read(const IRSerialData& data, Session* session, SourceManager* sourceManager, RefPtr<IRModule>& moduleOut);
+
+
/// Get the representation cache
StringRepresentationCache& getStringRepresentationCache() { return m_stringRepresentationCache; }
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index e9a8e7e04..76ebcca52 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -11,6 +11,7 @@
#include "slang-file-system.h"
#include "slang-state-serialize.h"
+#include "slang-ir-serialize.h"
#include <assert.h>
@@ -857,6 +858,26 @@ struct OptionsParser
return SLANG_FAIL;
}
}
+ else if (argStr == "-r")
+ {
+ String moduleName;
+ SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, moduleName));
+
+ // We need to deserialize and add the modules
+ FileStream fileStream(moduleName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
+
+ List<RefPtr<IRModule>> irModules;
+ if (SLANG_FAILED(IRSerialReader::readStreamModules(&fileStream, asInternal(session), requestImpl->getFrontEndReq()->getSourceManager(), irModules)))
+ {
+ sink->diagnose(SourceLoc(), Diagnostics::unableToReadModuleContainer, moduleName);
+ return SLANG_FAIL;
+ }
+
+ // TODO(JS): May be better to have a ITypeComponent that encapsulates a collection of modules
+ // For now just add to the linkage
+ auto linkage = requestImpl->getLinkage();
+ linkage->m_libModules.addRange(irModules.getBuffer(), irModules.getCount());
+ }
else if (argStr == "-v")
{
sink->diagnoseRaw(Severity::Note, session->getBuildTagString());
diff --git a/tests/serialization/serialized-module-test.slang b/tests/serialization/serialized-module-test.slang
new file mode 100644
index 000000000..63c31e039
--- /dev/null
+++ b/tests/serialization/serialized-module-test.slang
@@ -0,0 +1,35 @@
+// serialized-module-test.slang
+
+// A test to try out the basics of module
+// serialization.
+
+//TEST:SIMPLE_EX: tests/serialization/serialized-module.slang -o tests/serialization/serialized-module.slang-module
+//TEST:COMPARE_COMPUTE_EX:-slang -compute -xslang -r -xslang tests/serialization/serialized-module.slang-module
+
+//import serialized_module;
+
+// This is fragile - needs match the definition in serialized_module
+struct Thing
+{
+ int a;
+ int b;
+};
+
+// TODO: need to get the name mangling to line up!
+int foo(Thing thing);
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 ], stride=4):dxbinding(0),glbinding(0),out,name outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ Thing thing;
+
+ int index = (int)dispatchThreadID.x;
+
+ thing.a = index;
+ thing.b = -index;
+
+ outputBuffer[index] = foo(thing);
+}
diff --git a/tests/serialization/serialized-module-test.slang.expected.txt b/tests/serialization/serialized-module-test.slang.expected.txt
new file mode 100644
index 000000000..bc856dafa
--- /dev/null
+++ b/tests/serialization/serialized-module-test.slang.expected.txt
@@ -0,0 +1,4 @@
+0
+1
+2
+3
diff --git a/tests/serialization/serialized-module.slang b/tests/serialization/serialized-module.slang
new file mode 100644
index 000000000..e94edf8d4
--- /dev/null
+++ b/tests/serialization/serialized-module.slang
@@ -0,0 +1,15 @@
+//TEST_IGNORE_FILE:
+
+// serialized-module.slang
+
+struct Thing
+{
+ int a;
+ int b;
+};
+
+int foo(Thing thing)
+{
+ return (thing.a + thing.b) - thing.b;
+}
+