yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaStable names and backwards compat for serialized IR modules (#7644)00746bf09

master
6.5 KiB199 linesraw

Design Document: Slang IR Module Backwards Compatibility

Overview

This document describes the design and implementation of backwards compatibility support for serialized Slang IR modules. The feature enables Slang to load IR modules compiled with different versions of the compiler, providing version information and graceful handling of incompatible modules.

Motivation

As Slang evolves, the intermediate representation (IR) may change with new instructions being added or existing ones being modified. Without backwards compatibility:

  • Users cannot load modules compiled with older versions of Slang
  • There's no way to detect version mismatches between modules
  • Module compatibility issues are opaque to users

This feature addresses these issues by introducing versioning and stable instruction naming.

User-Facing Changes

New Command Line Options

  1. -get-module-info <module-file>

    • Prints information about a serialized IR module without loading it
    • Output includes:
      • Module name
      • Module version
      • Compiler version that created the module
    • Example usage: slangc -get-module-info mymodule.slang-module
  2. -get-supported-module-versions

    • Prints the range of module versions this compiler supports
    • Output includes minimum and maximum supported versions
    • Example usage: slangc -get-supported-module-versions

API Changes

New method in ISession interface:

SlangResult loadModuleInfoFromIRBlob(
    slang::IBlob* source,
    SlangInt& outModuleVersion,
    const char*& outModuleCompilerVersion,
    const char*& outModuleName);

This allows programmatic inspection of module metadata without full deserialization.

Technical Design

Stable Instruction Names

The core mechanism for backwards compatibility is the introduction of stable names for IR instructions:

  1. Stable Name Table (slang-ir-insts-stable-names.lua)

    • Maps instruction names to unique integer IDs
    • IDs are permanent once assigned
    • New instructions get new IDs, never reusing old ones
  2. Runtime Mapping

    • getOpcodeStableName(IROp): Convert runtime opcode to stable ID
    • getStableNameOpcode(UInt): Convert stable ID back to runtime opcode
    • Unknown stable IDs map to kIROp_Unrecognized

Module Versioning

Two types of versions are tracked:

  1. Module Version (IRModule::m_version)

    • Semantic version of the IR instruction set
    • Range: k_minSupportedModuleVersion to k_maxSupportedModuleVersion
    • Stored in each serialized module
  2. Serialization Version (IRModuleInfo::serializationVersion)

    • Version of the serialization format itself
    • Currently version 0
    • Allows future changes to serialization structure

Compiler Version Tracking

Each module stores the exact compiler version (SLANG_TAG_VERSION) that created it. This enables version-specific workarounds if needed in the future.

Validation System

A GitHub Actions workflow (check-ir-stable-names.yml) ensures consistency:

  1. Check Mode: Validates that:

    • All IR instructions have stable names
    • No duplicate stable IDs exist
    • The stable name table is a bijection with current instructions
  2. Update Mode: Automatically assigns stable IDs to new instructions

The validation is implemented in check-ir-stable-names.lua which:

  • Loads instruction definitions from slang-ir-insts.lua
  • Compares against slang-ir-insts-stable-names.lua
  • Reports missing entries or inconsistencies

Breaking Changes and Version Management

When to Update Module Version

The module version must be updated when:

  1. Adding Instructions (Minor Version Bump)

    • Increment k_maxSupportedModuleVersion
    • Older compilers can still load modules that don't use new instructions
  2. Removing Instructions (Major Version Bump)

    • Increment k_maxSupportedModuleVersion
    • Update k_minSupportedModuleVersion to exclude versions with removed instructions
    • This breaks compatibility with older modules using removed instructions
  3. Changing Instruction Semantics

    • Even if the instruction name remains the same
    • Requires version bump to prevent incorrect behavior
    • To avoid bumping the minimum supported version, one may instead introduce a new instruction and just bump k_maxSupportedModuleVersion

Serialization Format Changes

Changes to how data is serialized (not what data) require updating serializationVersion:

  • Changes to the RIFF container structure
  • Different encoding for instruction payloads
  • Reordering of serialized data

Implementation Details

Module Loading Flow

  1. Version Check

    if (fossilizedModuleInfo->serializationVersion != IRModuleInfo::kSupportedSerializationVersion)
        return SLANG_FAIL;
  2. Instruction Deserialization

    • Stable IDs are converted to runtime opcodes
    • Unknown IDs become kIROp_Unrecognized
  3. Validation Pass

    • After deserialization, check for any kIROp_Unrecognized instructions
    • Fail loading if any are found

Error Handling

  • Incompatible serialization versions: Immediate failure
  • Unknown instructions: Mark as unrecognized, fail after full deserialization (this should be caught by the next check)
  • Module version out of range: Fail after deserialization

Future Considerations

Potential Enhancements

  1. Graceful Degradation

    • Skip unrecognized instructions if they're not critical
    • Provide compatibility shims for removed instructions
  2. Module Migration Tools

    • Utility to upgrade old modules to new formats
    • Batch processing for large codebases

Maintenance Guidelines

  1. Regular CI Validation

    • The GitHub Action ensures stable names stay synchronized
    • Catches missing entries before merge
  2. Version Documentation

    • Maintain changelog of what changed in each module version
    • Document any version-specific workarounds
  3. Testing

    • Test loading of modules from previous versions
    • Verify error messages for incompatible modules

Conclusion

This backwards compatibility system provides a robust foundation for Slang IR evolution while maintaining compatibility where possible. The combination of stable instruction naming, comprehensive versioning, and automated validation ensures that:

  • Users can reliably use modules across Slang versions
  • Developers can evolve the IR with clear compatibility boundaries
  • Version mismatches are detected and reported clearly

The system is designed to be maintainable and extensible, with clear guidelines for when and how to make breaking changes.

1# Design Document: Slang IR Module Backwards Compatibility
2
3## Overview
4
5This document describes the design and implementation of backwards compatibility support for serialized Slang IR modules. The feature enables Slang to load IR modules compiled with different versions of the compiler, providing version information and graceful handling of incompatible modules.
6
7## Motivation
8
9As Slang evolves, the intermediate representation (IR) may change with new instructions being added or existing ones being modified. Without backwards compatibility:
10
11- Users cannot load modules compiled with older versions of Slang
12- There's no way to detect version mismatches between modules
13- Module compatibility issues are opaque to users
14
15This feature addresses these issues by introducing versioning and stable instruction naming.
16
17## User-Facing Changes
18
19### New Command Line Options
20
211. **`-get-module-info <module-file>`**
22
23   - Prints information about a serialized IR module without loading it
24   - Output includes:
25     - Module name
26     - Module version
27     - Compiler version that created the module
28   - Example usage: `slangc -get-module-info mymodule.slang-module`
29
302. **`-get-supported-module-versions`**
31   - Prints the range of module versions this compiler supports
32   - Output includes minimum and maximum supported versions
33   - Example usage: `slangc -get-supported-module-versions`
34
35### API Changes
36
37New method in `ISession` interface:
38
39```cpp
40SlangResult loadModuleInfoFromIRBlob(
41    slang::IBlob* source,
42    SlangInt& outModuleVersion,
43    const char*& outModuleCompilerVersion,
44    const char*& outModuleName);
45```
46
47This allows programmatic inspection of module metadata without full deserialization.
48
49## Technical Design
50
51### Stable Instruction Names
52
53The core mechanism for backwards compatibility is the introduction of stable names for IR instructions:
54
551. **Stable Name Table** (`slang-ir-insts-stable-names.lua`)
56
57   - Maps instruction names to unique integer IDs
58   - IDs are permanent once assigned
59   - New instructions get new IDs, never reusing old ones
60
612. **Runtime Mapping**
62   - `getOpcodeStableName(IROp)`: Convert runtime opcode to stable ID
63   - `getStableNameOpcode(UInt)`: Convert stable ID back to runtime opcode
64   - Unknown stable IDs map to `kIROp_Unrecognized`
65
66### Module Versioning
67
68Two types of versions are tracked:
69
701. **Module Version** (`IRModule::m_version`)
71
72   - Semantic version of the IR instruction set
73   - Range: `k_minSupportedModuleVersion` to `k_maxSupportedModuleVersion`
74   - Stored in each serialized module
75
762. **Serialization Version** (`IRModuleInfo::serializationVersion`)
77   - Version of the serialization format itself
78   - Currently version 0
79   - Allows future changes to serialization structure
80
81### Compiler Version Tracking
82
83Each module stores the exact compiler version (`SLANG_TAG_VERSION`) that created it. This enables version-specific workarounds if needed in the future.
84
85### Validation System
86
87A GitHub Actions workflow (`check-ir-stable-names.yml`) ensures consistency:
88
891. **Check Mode**: Validates that:
90
91   - All IR instructions have stable names
92   - No duplicate stable IDs exist
93   - The stable name table is a bijection with current instructions
94
952. **Update Mode**: Automatically assigns stable IDs to new instructions
96
97The validation is implemented in `check-ir-stable-names.lua` which:
98
99- Loads instruction definitions from `slang-ir-insts.lua`
100- Compares against `slang-ir-insts-stable-names.lua`
101- Reports missing entries or inconsistencies
102
103## Breaking Changes and Version Management
104
105### When to Update Module Version
106
107The module version must be updated when:
108
1091. **Adding Instructions** (Minor Version Bump)
110
111   - Increment `k_maxSupportedModuleVersion`
112   - Older compilers can still load modules that don't use new instructions
113
1142. **Removing Instructions** (Major Version Bump)
115
116   - Increment `k_maxSupportedModuleVersion`
117   - Update `k_minSupportedModuleVersion` to exclude versions with removed instructions
118   - This breaks compatibility with older modules using removed instructions
119
1203. **Changing Instruction Semantics**
121   - Even if the instruction name remains the same
122   - Requires version bump to prevent incorrect behavior
123   - To avoid bumping the minimum supported version, one may instead introduce
124     a new instruction and just bump `k_maxSupportedModuleVersion`
125
126### Serialization Format Changes
127
128Changes to how data is serialized (not what data) require updating `serializationVersion`:
129
130- Changes to the RIFF container structure
131- Different encoding for instruction payloads
132- Reordering of serialized data
133
134## Implementation Details
135
136### Module Loading Flow
137
1381. **Version Check**
139
140   ```cpp
141   if (fossilizedModuleInfo->serializationVersion != IRModuleInfo::kSupportedSerializationVersion)
142       return SLANG_FAIL;
143   ```
144
1452. **Instruction Deserialization**
146
147   - Stable IDs are converted to runtime opcodes
148   - Unknown IDs become `kIROp_Unrecognized`
149
1503. **Validation Pass**
151   - After deserialization, check for any `kIROp_Unrecognized` instructions
152   - Fail loading if any are found
153
154### Error Handling
155
156- Incompatible serialization versions: Immediate failure
157- Unknown instructions: Mark as unrecognized, fail after full deserialization
158  (this should be caught by the next check)
159- Module version out of range: Fail after deserialization
160
161## Future Considerations
162
163### Potential Enhancements
164
1651. **Graceful Degradation**
166
167   - Skip unrecognized instructions if they're not critical
168   - Provide compatibility shims for removed instructions
169
1702. **Module Migration Tools**
171
172   - Utility to upgrade old modules to new formats
173   - Batch processing for large codebases
174
175### Maintenance Guidelines
176
1771. **Regular CI Validation**
178
179   - The GitHub Action ensures stable names stay synchronized
180   - Catches missing entries before merge
181
1822. **Version Documentation**
183
184   - Maintain changelog of what changed in each module version
185   - Document any version-specific workarounds
186
1873. **Testing**
188   - Test loading of modules from previous versions
189   - Verify error messages for incompatible modules
190
191## Conclusion
192
193This backwards compatibility system provides a robust foundation for Slang IR evolution while maintaining compatibility where possible. The combination of stable instruction naming, comprehensive versioning, and automated validation ensures that:
194
195- Users can reliably use modules across Slang versions
196- Developers can evolve the IR with clear compatibility boundaries
197- Version mismatches are detected and reported clearly
198
199The system is designed to be maintainable and extensible, with clear guidelines for when and how to make breaking changes.