Inspect DXIL Assembly with DirectX Shader Compiler
Inspecting the generated DirectX Intermediate Language (DXIL)
assembly is essential for debugging, performance profiling, and
verifying HLSL compiler optimizations. The DirectX Shader Compiler
(dxc.exe) provides built-in command-line arguments and
programmatic C++ APIs that allow developers to disassemble compiled
shader blobs back into human-readable, LLVM-based DXIL representation.
This guide explains how to generate, inspect, and extract DXIL assembly
using both the command-line utility and runtime APIs.
Inspecting DXIL via the DXC Command Line
The most straightforward method to inspect DXIL is using the
command-line interface provided by dxc.exe. You can either
disassemble an existing compiled shader binary or output the assembly
directly during compilation.
Disassembling During Compilation
To compile an HLSL source file and output the human-readable DXIL
assembly to a text file simultaneously, use the -Fc
flag:
dxc.exe -T ps_6_0 -E main -Fc shader_assembly.txt shader.hlsl-T ps_6_0: Specifies the shader profile target (Pixel Shader 6.0).-E main: Defines the entry point function.-Fc shader_assembly.txt: Outputs the human-readable assembly to the specified file.
If you omit the file path and want to print the disassembly directly to the terminal stdout without generating a binary, omit the output flag and direct the compiler to emit assembly:
dxc.exe -T cs_6_5 -E CSMain shader.hlsl -dumpbinDisassembling an Existing Binary
If you already have a compiled .bin, .cso,
or .dxil binary file, you can inspect its DXIL
representation using the -dumpbin argument:
dxc.exe -dumpbin compiled_shader.csoTo pipe this output directly into a file for review in a text editor:
dxc.exe -dumpbin compiled_shader.cso > disassembly.txtInspecting DXIL Programmatically Using the DXC API
For custom build tools or engine-level inspection, DXC provides the
IDxcCompiler3 interface to disassemble DXIL blobs in
C++.
Disassembly Workflow
- Initialize the DXC support instance using
DxcCreateInstance. - Obtain instances of
IDxcUtilsandIDxcCompiler3. - Wrap your compiled bytecode inside a
DxcBufferstructure. - Call
IDxcCompiler3::Disassemble. - Extract the disassembly string from the resulting
IDxcResult.
Example C++ Implementation
#include <windows.h>
#include <dxcapi.h>
#include <iostream>
void DisassembleDXIL(const void* bytecodeData, size_t bytecodeSize) {
IDxcUtils* pUtils = nullptr;
IDxcCompiler3* pCompiler = nullptr;
DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&pUtils));
DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&pCompiler));
DxcBuffer sourceBuffer = {};
sourceBuffer.Ptr = bytecodeData;
sourceBuffer.Size = bytecodeSize;
sourceBuffer.Encoding = DXC_CP_ACP;
IDxcResult* pResult = nullptr;
HRESULT hr = pCompiler->Disassemble(&sourceBuffer, IID_PPV_ARGS(&pResult));
if (SUCCEEDED(hr)) {
IDxcBlobUtf8* pDisassembly = nullptr;
pResult->GetOutput(DXC_OUT_DISASSEMBLY, IID_PPV_ARGS(&pDisassembly), nullptr);
if (pDisassembly && pDisassembly->GetStringLength() > 0) {
std::cout << pDisassembly->GetStringPointer() << std::endl;
}
if (pDisassembly) pDisassembly->Release();
pResult->Release();
}
if (pCompiler) pCompiler->Release();
if (pUtils) pUtils->Release();
}Reading the Generated DXIL
DXIL is an encapsulation of LLVM 3.7 IR (Intermediate Representation) augmented with DirectX-specific intrinsic operations and metadata. Key elements to look for when inspecting the assembly include:
- Resource Declarations (
!dx.resources): Found near the bottom in LLVM metadata blocks, detailing Constant Buffers, SRVs, UAVs, and Samplers, including register and space bindings. - Entry Points (
!dx.entryPoints): Lists signature parameters, shader model targets, and root signature attachments. - Intrinsics (
dx.op.*): Shader-specific operations are represented as internal function calls (e.g.,call %dx.types.ResRet.f32 @dx.op.sample...), showing resource access, math operations, and wave intrinsics.