Skip to content

Commit de6cc94

Browse files
cheneym2slangbotexpipiplus1
authored
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>
1 parent 96de7f6 commit de6cc94

File tree

8 files changed

+184
-7
lines changed

8 files changed

+184
-7
lines changed

include/slang.h

+6
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,7 @@ typedef uint32_t SlangSizeT;
10151015
SaveGLSLModuleBinSource,
10161016

10171017
SkipDownstreamLinking, // bool, experimental
1018+
DumpModule,
10181019
CountOf,
10191020
};
10201021

@@ -4422,6 +4423,11 @@ struct IModule : public IComponentType
44224423
virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(SlangInt32 index) = 0;
44234424

44244425
virtual SLANG_NO_THROW DeclReflection* SLANG_MCALL getModuleReflection() = 0;
4426+
4427+
/** Disassemble a module.
4428+
*/
4429+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL
4430+
disassemble(slang::IBlob** outDisassembledBlob) = 0;
44254431
};
44264432

44274433
#define SLANG_UUID_IModule IModule::getTypeGuid()

source/slang-record-replay/record/slang-module.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,12 @@ IEntryPointRecorder* ModuleRecorder::getEntryPointRecorder(slang::IEntryPoint* e
244244
return result.detach();
245245
}
246246
}
247+
248+
SlangResult ModuleRecorder::disassemble(ISlangBlob** outBlob)
249+
{
250+
// No need to record this call as it is just a query.
251+
slangRecordLog(LogLevel::Verbose, "%s\n", __PRETTY_FUNCTION__);
252+
auto res = m_actualModule->disassemble(outBlob);
253+
return res;
254+
}
247255
} // namespace SlangRecord

source/slang-record-replay/record/slang-module.h

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class ModuleRecorder : public IModuleRecorder, public IComponentTypeRecorder
5656
ISlangBlob** outDiagnostics) override;
5757
virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDependencyFileCount() override;
5858
virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(SlangInt32 index) override;
59+
virtual SLANG_NO_THROW SlangResult SLANG_MCALL
60+
disassemble(slang::IBlob** outDisassembly) override;
5961

6062
// Interfaces for `IComponentType`
6163
virtual SLANG_NO_THROW slang::ISession* SLANG_MCALL getSession() override

source/slang/slang-compiler.h

+12
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,18 @@ class Module : public ComponentType, public slang::IModule
18321832

18331833
// Source files that have been pulled into the module with `__include`.
18341834
Dictionary<SourceFile*, FileDecl*> m_mapSourceFileToFileDecl;
1835+
1836+
public:
1837+
SLANG_NO_THROW SlangResult SLANG_MCALL disassemble(slang::IBlob** outDisassembledBlob) override
1838+
{
1839+
if (!outDisassembledBlob)
1840+
return SLANG_E_INVALID_ARG;
1841+
String disassembly;
1842+
this->getIRModule()->getModuleInst()->dump(disassembly);
1843+
auto blob = StringUtil::createStringBlob(disassembly);
1844+
*outDisassembledBlob = blob.detach();
1845+
return SLANG_OK;
1846+
}
18351847
};
18361848
typedef Module LoadedModule;
18371849

source/slang/slang-ir.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -8950,24 +8950,33 @@ void IRInst::addBlock(IRBlock* block)
89508950
block->insertAtEnd(this);
89518951
}
89528952

8953-
void IRInst::dump()
8953+
void IRInst::dump(String& outStr)
89548954
{
8955+
StringBuilder sb;
8956+
89558957
if (auto intLit = as<IRIntLit>(this))
89568958
{
8957-
std::cout << intLit->getValue() << std::endl;
8959+
sb << intLit->getValue();
89588960
}
89598961
else if (auto stringLit = as<IRStringLit>(this))
89608962
{
8961-
std::cout << stringLit->getStringSlice().begin() << std::endl;
8963+
sb << stringLit->getStringSlice();
89628964
}
89638965
else
89648966
{
8965-
StringBuilder sb;
89668967
IRDumpOptions options;
89678968
StringWriter writer(&sb, Slang::WriterFlag::AutoFlush);
89688969
dumpIR(this, options, nullptr, &writer);
8969-
std::cout << sb.toString().begin() << std::endl;
89708970
}
8971+
8972+
outStr = sb.toString();
8973+
}
8974+
8975+
void IRInst::dump()
8976+
{
8977+
String s;
8978+
dump(s);
8979+
std::cout << s.begin() << std::endl;
89718980
}
89728981
} // namespace Slang
89738982

source/slang/slang-ir.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -813,10 +813,14 @@ struct IRInst
813813
///
814814
void _insertAt(IRInst* inPrev, IRInst* inNext, IRInst* inParent);
815815

816-
/// Print the IR to stdout for debugging purposes
816+
/// Print the IR to stdout for debugging purposes.
817817
///
818818
void dump();
819819

820+
/// Print the IR to a string for debugging purposes.
821+
///
822+
void dump(String& outStr);
823+
820824
/// Insert a basic block at the end of this func/code containing inst.
821825
void addBlock(IRBlock* block);
822826

source/slang/slang-options.cpp

+84-1
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,8 @@ void initCommandOptions(CommandOptions& options)
802802
{OptionKind::VerifyDebugSerialIr,
803803
"-verify-debug-serial-ir",
804804
nullptr,
805-
"Verify IR in the front-end."}};
805+
"Verify IR in the front-end."},
806+
{OptionKind::DumpModule, "-dump-module", nullptr, "Disassemble and print the module IR."}};
806807
_addOptions(makeConstArrayView(debuggingOpts), options);
807808

808809
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Experimental !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
@@ -2947,6 +2948,88 @@ SlangResult OptionsParser::_parse(int argc, char const* const* argv)
29472948
Int index = 0;
29482949
SLANG_RETURN_ON_FAIL(_expectInt(arg, index));
29492950
linkage->m_optionSet.add(OptionKind::BindlessSpaceIndex, (int)index);
2951+
break;
2952+
}
2953+
case OptionKind::DumpModule:
2954+
{
2955+
CommandLineArg fileName;
2956+
SLANG_RETURN_ON_FAIL(m_reader.expectArg(fileName));
2957+
auto desc = slang::SessionDesc();
2958+
ComPtr<slang::ISession> session;
2959+
m_session->createSession(desc, session.writeRef());
2960+
ComPtr<slang::IBlob> diagnostics;
2961+
2962+
// Coerce Slang to load from the given file, without letting it automatically
2963+
// choose .slang-module files over .slang files.
2964+
// First try to load as source string, and fall back to loading as an IR Blob.
2965+
// Avoid guessing based on filename or inspecting the file contents.
2966+
FileStream file;
2967+
if (SLANG_FAILED(file.init(
2968+
fileName.value,
2969+
FileMode::Open,
2970+
FileAccess::Read,
2971+
FileShare::None)))
2972+
{
2973+
m_sink->diagnose(arg.loc, Diagnostics::cannotOpenFile, fileName.value);
2974+
return SLANG_FAIL;
2975+
}
2976+
2977+
List<uint8_t> buffer;
2978+
file.seek(SeekOrigin::End, 0);
2979+
const Int64 size = file.getPosition();
2980+
buffer.setCount(size + 1);
2981+
file.seek(SeekOrigin::Start, 0);
2982+
SLANG_RETURN_ON_FAIL(file.readExactly(buffer.getBuffer(), (size_t)size));
2983+
buffer[size] = 0;
2984+
file.close();
2985+
2986+
ComPtr<slang::IModule> module;
2987+
module = session->loadModuleFromSourceString(
2988+
"module",
2989+
"path",
2990+
(const char*)buffer.getBuffer(),
2991+
diagnostics.writeRef());
2992+
if (!module)
2993+
{
2994+
// Load buffer as an IR blob
2995+
ComPtr<slang::IBlob> blob;
2996+
blob = RawBlob::create(buffer.getBuffer(), size);
2997+
2998+
module = session->loadModuleFromIRBlob(
2999+
"module",
3000+
"path",
3001+
blob,
3002+
diagnostics.writeRef());
3003+
}
3004+
3005+
if (module)
3006+
{
3007+
ComPtr<slang::IBlob> disassemblyBlob;
3008+
if (SLANG_FAILED(module->disassemble(disassemblyBlob.writeRef())))
3009+
{
3010+
m_sink->diagnose(arg.loc, Diagnostics::cannotDisassemble, fileName.value);
3011+
return SLANG_FAIL;
3012+
}
3013+
else
3014+
{
3015+
// success, print out the disassembly in a way that slang-test can read
3016+
m_sink->diagnoseRaw(
3017+
Severity::Note,
3018+
(const char*)disassemblyBlob->getBufferPointer());
3019+
}
3020+
}
3021+
else
3022+
{
3023+
if (diagnostics)
3024+
{
3025+
m_sink->diagnoseRaw(
3026+
Severity::Error,
3027+
(const char*)diagnostics->getBufferPointer());
3028+
}
3029+
return SLANG_FAIL;
3030+
}
3031+
3032+
29503033
break;
29513034
}
29523035
default:

tests/ir/dump-module.slang

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This tests slangc's -dump-module command.
2+
// Dumping ".slang" should mean just that, and it should not automatically load up
3+
// a ".slang-module" when available, because the intent of the -dump-module command
4+
// is to see the file you requested. If there's a bug in slang-module output, it's
5+
// important that -dump-module looks at the specific file you requested.
6+
7+
//TEST:COMPILE: tests/ir/dump-module.slang -o tests/ir/dump-module.slang-module -target spirv -embed-downstream-ir
8+
9+
//TEST:SIMPLE(filecheck=CHECK1): -dump-module tests/ir/dump-module.slang-module
10+
//TEST:SIMPLE(filecheck=CHECK2): -dump-module tests/ir/dump-module.slang
11+
12+
module "export-library-generics";
13+
14+
public cbuffer Constants {
15+
public float x;
16+
public float y;
17+
}
18+
19+
interface MyInterface
20+
{
21+
int myMethod(int a);
22+
}
23+
24+
struct MyType : MyInterface
25+
{
26+
int myMethod(int a)
27+
{
28+
return a * 3;
29+
}
30+
}
31+
32+
int genericFunc<T: MyInterface>(T arg)
33+
{
34+
return arg.myMethod(3);
35+
}
36+
37+
public int normalFuncUsesGeneric(int a)
38+
{
39+
MyType obj;
40+
return genericFunc(obj);
41+
}
42+
43+
public int normalFunc(int a, float b)
44+
{
45+
return a - floor(b);
46+
}
47+
48+
// CHECK1:EmbeddedDownstreamIR(6 : Int,
49+
// CHECK1: OpCapability Linkage
50+
51+
// CHECK2-NOT:EmbeddedDownstreamIR(6 : Int,
52+
// CHECK2-NOT: OpCapability Linkage
53+

0 commit comments

Comments
 (0)