diff options
| author | cheneym2 <acheney@nvidia.com> | 2025-03-20 11:38:46 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-20 23:38:46 +0800 |
| commit | de6cc94e3b7fa5d1b8eeb53993dbf3ca2cec1cc1 (patch) | |
| tree | 0913d39d83c4beff06a854b6503bd05d395077b4 /source | |
| parent | 96de7f6a9dccabd1801dcbf1eb76e0967d7f5fe8 (diff) | |
Add -dump-module command to slangc (#6638)
* Add -dump-module command to slangc
The new -dump-module command to slangc will load and disassemble a slang module, similar to what would be seen by the -dump-ir command, except that -dump-ir tells slangc to print IR as it performs some compilation command. That is, -dump-ir requires
some larger compilation task.
-dump-module on the otherhand requires no additional goal and will simply load a module and print its IR to stdout independently from other compilation steps.
Its intended purpose is to inspect .slang-module files on disk.
It can also be used on .slang files which will be parsed and lowered
if slang does not find an associated ".slang-module" version of the
module on disk.
The compilation API is extended with a new IModule::disassemble()
method which retrieves the string representation of the dumped IR.
Closes #6599
* format code
* Use FileStream not FILE
* format code
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Co-authored-by: Ellie Hermaszewska <ellieh@nvidia.com>
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang-record-replay/record/slang-module.cpp | 8 | ||||
| -rw-r--r-- | source/slang-record-replay/record/slang-module.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-compiler.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 19 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 85 |
6 files changed, 125 insertions, 7 deletions
diff --git a/source/slang-record-replay/record/slang-module.cpp b/source/slang-record-replay/record/slang-module.cpp index 2071a8491..628a29c90 100644 --- a/source/slang-record-replay/record/slang-module.cpp +++ b/source/slang-record-replay/record/slang-module.cpp @@ -244,4 +244,12 @@ IEntryPointRecorder* ModuleRecorder::getEntryPointRecorder(slang::IEntryPoint* e return result.detach(); } } + +SlangResult ModuleRecorder::disassemble(ISlangBlob** outBlob) +{ + // No need to record this call as it is just a query. + slangRecordLog(LogLevel::Verbose, "%s\n", __PRETTY_FUNCTION__); + auto res = m_actualModule->disassemble(outBlob); + return res; +} } // namespace SlangRecord diff --git a/source/slang-record-replay/record/slang-module.h b/source/slang-record-replay/record/slang-module.h index 7608ac52d..d9c83576d 100644 --- a/source/slang-record-replay/record/slang-module.h +++ b/source/slang-record-replay/record/slang-module.h @@ -56,6 +56,8 @@ public: ISlangBlob** outDiagnostics) override; virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDependencyFileCount() override; virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(SlangInt32 index) override; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + disassemble(slang::IBlob** outDisassembly) override; // Interfaces for `IComponentType` virtual SLANG_NO_THROW slang::ISession* SLANG_MCALL getSession() override diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index cfcbe816f..d4e05bc48 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1832,6 +1832,18 @@ private: // Source files that have been pulled into the module with `__include`. Dictionary<SourceFile*, FileDecl*> m_mapSourceFileToFileDecl; + +public: + SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(slang::IBlob** outDisassembledBlob) override + { + if (!outDisassembledBlob) + return SLANG_E_INVALID_ARG; + String disassembly; + this->getIRModule()->getModuleInst()->dump(disassembly); + auto blob = StringUtil::createStringBlob(disassembly); + *outDisassembledBlob = blob.detach(); + return SLANG_OK; + } }; typedef Module LoadedModule; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 92e51fe3b..6d1d76afc 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -8950,24 +8950,33 @@ void IRInst::addBlock(IRBlock* block) block->insertAtEnd(this); } -void IRInst::dump() +void IRInst::dump(String& outStr) { + StringBuilder sb; + if (auto intLit = as<IRIntLit>(this)) { - std::cout << intLit->getValue() << std::endl; + sb << intLit->getValue(); } else if (auto stringLit = as<IRStringLit>(this)) { - std::cout << stringLit->getStringSlice().begin() << std::endl; + sb << stringLit->getStringSlice(); } else { - StringBuilder sb; IRDumpOptions options; StringWriter writer(&sb, Slang::WriterFlag::AutoFlush); dumpIR(this, options, nullptr, &writer); - std::cout << sb.toString().begin() << std::endl; } + + outStr = sb.toString(); +} + +void IRInst::dump() +{ + String s; + dump(s); + std::cout << s.begin() << std::endl; } } // namespace Slang diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index aa74c0704..64125be9a 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -813,10 +813,14 @@ struct IRInst /// void _insertAt(IRInst* inPrev, IRInst* inNext, IRInst* inParent); - /// Print the IR to stdout for debugging purposes + /// Print the IR to stdout for debugging purposes. /// void dump(); + /// Print the IR to a string for debugging purposes. + /// + void dump(String& outStr); + /// Insert a basic block at the end of this func/code containing inst. void addBlock(IRBlock* block); diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 977cf322c..ed7775e84 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -802,7 +802,8 @@ void initCommandOptions(CommandOptions& options) {OptionKind::VerifyDebugSerialIr, "-verify-debug-serial-ir", nullptr, - "Verify IR in the front-end."}}; + "Verify IR in the front-end."}, + {OptionKind::DumpModule, "-dump-module", nullptr, "Disassemble and print the module IR."}}; _addOptions(makeConstArrayView(debuggingOpts), options); /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Experimental !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -2949,6 +2950,88 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv) linkage->m_optionSet.add(OptionKind::BindlessSpaceIndex, (int)index); break; } + case OptionKind::DumpModule: + { + CommandLineArg fileName; + SLANG_RETURN_ON_FAIL(m_reader.expectArg(fileName)); + auto desc = slang::SessionDesc(); + ComPtr<slang::ISession> session; + m_session->createSession(desc, session.writeRef()); + ComPtr<slang::IBlob> diagnostics; + + // Coerce Slang to load from the given file, without letting it automatically + // choose .slang-module files over .slang files. + // First try to load as source string, and fall back to loading as an IR Blob. + // Avoid guessing based on filename or inspecting the file contents. + FileStream file; + if (SLANG_FAILED(file.init( + fileName.value, + FileMode::Open, + FileAccess::Read, + FileShare::None))) + { + m_sink->diagnose(arg.loc, Diagnostics::cannotOpenFile, fileName.value); + return SLANG_FAIL; + } + + List<uint8_t> buffer; + file.seek(SeekOrigin::End, 0); + const Int64 size = file.getPosition(); + buffer.setCount(size + 1); + file.seek(SeekOrigin::Start, 0); + SLANG_RETURN_ON_FAIL(file.readExactly(buffer.getBuffer(), (size_t)size)); + buffer[size] = 0; + file.close(); + + ComPtr<slang::IModule> module; + module = session->loadModuleFromSourceString( + "module", + "path", + (const char*)buffer.getBuffer(), + diagnostics.writeRef()); + if (!module) + { + // Load buffer as an IR blob + ComPtr<slang::IBlob> blob; + blob = RawBlob::create(buffer.getBuffer(), size); + + module = session->loadModuleFromIRBlob( + "module", + "path", + blob, + diagnostics.writeRef()); + } + + if (module) + { + ComPtr<slang::IBlob> disassemblyBlob; + if (SLANG_FAILED(module->disassemble(disassemblyBlob.writeRef()))) + { + m_sink->diagnose(arg.loc, Diagnostics::cannotDisassemble, fileName.value); + return SLANG_FAIL; + } + else + { + // success, print out the disassembly in a way that slang-test can read + m_sink->diagnoseRaw( + Severity::Note, + (const char*)disassemblyBlob->getBufferPointer()); + } + } + else + { + if (diagnostics) + { + m_sink->diagnoseRaw( + Severity::Error, + (const char*)diagnostics->getBufferPointer()); + } + return SLANG_FAIL; + } + + + break; + } default: { // Hmmm, we looked up and produced a valid enum, but it wasn't handled in the |
