|
| 1 | +# StableHLO Backend Completion Design Document |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This design document outlines the completion of the StableHLO backend for SKaiNET, which will enable compilation of computational graphs to StableHLO MLIR format. The current implementation provides basic functionality for add, matmul, and relu operations but needs to be expanded to support the full range of SKaiNET operations including mathematical operations, neural network layers, shape manipulations, and activation functions. |
| 6 | + |
| 7 | +The StableHLO backend will serve as a bridge between SKaiNET's high-level DSL and low-level optimized execution through XLA and other MLIR-based compilation toolchains. |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | +### Current Architecture |
| 12 | + |
| 13 | +The existing implementation consists of: |
| 14 | +- `StableHloModule` data class for representing MLIR output |
| 15 | +- `toStableHlo()` function for converting ComputeGraph to MLIR |
| 16 | +- Basic operation mapping for add, matmul, and relu |
| 17 | +- Simple SSA value management and type mapping |
| 18 | + |
| 19 | +### Enhanced Architecture |
| 20 | + |
| 21 | +The enhanced architecture will include: |
| 22 | + |
| 23 | +1. **Operation Registry System**: A pluggable system for registering StableHLO operation converters |
| 24 | +2. **Type System Integration**: Comprehensive mapping between SKaiNET and MLIR type systems |
| 25 | +3. **Optimization Framework**: Infrastructure for applying StableHLO-specific optimizations |
| 26 | +4. **Validation System**: MLIR syntax and semantic validation |
| 27 | +5. **Error Handling**: Comprehensive error reporting and fallback mechanisms |
| 28 | + |
| 29 | +### Component Hierarchy |
| 30 | + |
| 31 | +``` |
| 32 | +skainet-compile-hlo/ |
| 33 | +├── core/ |
| 34 | +│ ├── StableHloModule.kt (existing) |
| 35 | +│ ├── StableHloConverter.kt (new) |
| 36 | +│ └── StableHloRegistry.kt (new) |
| 37 | +├── operations/ |
| 38 | +│ ├── MathOperations.kt (new) |
| 39 | +│ ├── LinalgOperations.kt (new) |
| 40 | +│ ├── NeuralNetOperations.kt (new) |
| 41 | +│ ├── ShapeOperations.kt (new) |
| 42 | +│ └── ActivationOperations.kt (new) |
| 43 | +├── types/ |
| 44 | +│ ├── TypeMapper.kt (new) |
| 45 | +│ └── ShapeInference.kt (new) |
| 46 | +├── validation/ |
| 47 | +│ └── MlirValidator.kt (new) |
| 48 | +└── optimization/ |
| 49 | + └── StableHloOptimizer.kt (new) |
| 50 | +``` |
| 51 | + |
| 52 | +## Components and Interfaces |
| 53 | + |
| 54 | +### StableHloConverter |
| 55 | + |
| 56 | +The main converter class that orchestrates the conversion process: |
| 57 | + |
| 58 | +```kotlin |
| 59 | +public class StableHloConverter( |
| 60 | + private val registry: StableHloOperationRegistry, |
| 61 | + private val typeMapper: TypeMapper, |
| 62 | + private val validator: MlirValidator? = null |
| 63 | +) { |
| 64 | + public fun convert(graph: ComputeGraph, functionName: String = "main"): StableHloModule |
| 65 | + public fun convertWithOptimization(graph: ComputeGraph, optimizer: StableHloOptimizer): StableHloModule |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +### StableHloOperationRegistry |
| 70 | + |
| 71 | +A registry system for operation converters: |
| 72 | + |
| 73 | +```kotlin |
| 74 | +public interface StableHloOperationConverter { |
| 75 | + public val supportedOperations: Set<String> |
| 76 | + public fun convert( |
| 77 | + node: GraphNode, |
| 78 | + operands: List<String>, |
| 79 | + context: ConversionContext |
| 80 | + ): ConversionResult |
| 81 | +} |
| 82 | + |
| 83 | +public class StableHloOperationRegistry { |
| 84 | + public fun register(converter: StableHloOperationConverter) |
| 85 | + public fun getConverter(operationName: String): StableHloOperationConverter? |
| 86 | + public fun getSupportedOperations(): Set<String> |
| 87 | +} |
| 88 | +``` |
| 89 | + |
| 90 | +### TypeMapper |
| 91 | + |
| 92 | +Handles type system mapping between SKaiNET and MLIR: |
| 93 | + |
| 94 | +```kotlin |
| 95 | +public class TypeMapper { |
| 96 | + public fun mapDType(dtype: String): String |
| 97 | + public fun mapTensorType(spec: TensorSpec): String |
| 98 | + public fun mapFunctionSignature(inputs: List<TensorSpec>, outputs: List<TensorSpec>): String |
| 99 | + public fun inferBroadcastType(left: TensorSpec, right: TensorSpec): TensorSpec |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +### ConversionContext |
| 104 | + |
| 105 | +Context object for maintaining state during conversion: |
| 106 | + |
| 107 | +```kotlin |
| 108 | +public class ConversionContext( |
| 109 | + private val valueNames: MutableMap<String, String>, |
| 110 | + private val typeMapper: TypeMapper, |
| 111 | + private val stringBuilder: StringBuilder |
| 112 | +) { |
| 113 | + public fun getValueName(nodeId: String): String? |
| 114 | + public fun setValueName(nodeId: String, valueName: String) |
| 115 | + public fun nextTempValue(): String |
| 116 | + public fun emitOperation(operation: String) |
| 117 | + public fun emitComment(comment: String) |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +## Data Models |
| 122 | + |
| 123 | +### StableHloModule (Enhanced) |
| 124 | + |
| 125 | +```kotlin |
| 126 | +public data class StableHloModule( |
| 127 | + val content: String, |
| 128 | + val functionName: String, |
| 129 | + val inputSpecs: List<TensorSpec>, |
| 130 | + val outputSpecs: List<TensorSpec>, |
| 131 | + val metadata: Map<String, Any> = emptyMap() |
| 132 | +) { |
| 133 | + public fun validate(): ValidationResult |
| 134 | + public fun optimize(optimizer: StableHloOptimizer): StableHloModule |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +### ConversionResult |
| 139 | + |
| 140 | +```kotlin |
| 141 | +public sealed class ConversionResult { |
| 142 | + public data class Success( |
| 143 | + val outputValueName: String, |
| 144 | + val emittedOperations: List<String> |
| 145 | + ) : ConversionResult() |
| 146 | + |
| 147 | + public data class Failure( |
| 148 | + val error: String, |
| 149 | + val fallbackComment: String? = null |
| 150 | + ) : ConversionResult() |
| 151 | + |
| 152 | + public data class Unsupported( |
| 153 | + val operationName: String, |
| 154 | + val reason: String |
| 155 | + ) : ConversionResult() |
| 156 | +} |
| 157 | +``` |
| 158 | + |
| 159 | +### OperationMapping |
| 160 | + |
| 161 | +```kotlin |
| 162 | +public data class OperationMapping( |
| 163 | + val skainetOperation: String, |
| 164 | + val stableHloOperation: String, |
| 165 | + val attributeMapping: Map<String, String> = emptyMap(), |
| 166 | + val customConverter: ((GraphNode, List<String>, ConversionContext) -> ConversionResult)? = null |
| 167 | +) |
| 168 | +``` |
| 169 | + |
| 170 | +## Correctness Properties |
| 171 | + |
| 172 | +*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* |
| 173 | + |
| 174 | +### Property Reflection |
| 175 | + |
| 176 | +After reviewing all properties identified in the prework, several redundancies were identified: |
| 177 | +- Properties 1.2 and 5.1 both address MLIR syntax validation - consolidated into Property 1 |
| 178 | +- Properties about infrastructure (4.1, 4.3, 4.4, 5.4, 5.5, 6.3, 6.4, 6.5) are design concerns rather than testable behaviors |
| 179 | +- Properties can be grouped by functional area for better organization |
| 180 | + |
| 181 | +### Correctness Properties |
| 182 | + |
| 183 | +Property 1: Valid MLIR Generation |
| 184 | +*For any* ComputeGraph containing supported operations, the generated StableHLO MLIR code should be syntactically valid and parseable by MLIR tools |
| 185 | +**Validates: Requirements 1.1, 1.2, 5.1** |
| 186 | + |
| 187 | +Property 2: SSA Form Preservation |
| 188 | +*For any* sequence of chained operations in a ComputeGraph, the generated MLIR should maintain proper SSA form with correct value dependencies |
| 189 | +**Validates: Requirements 1.3** |
| 190 | + |
| 191 | +Property 3: Type Mapping Correctness |
| 192 | +*For any* TensorSpec with specified shape and data type, the emitted MLIR type annotations should correctly represent the SKaiNET types using appropriate MLIR syntax |
| 193 | +**Validates: Requirements 1.4, 3.1, 3.5** |
| 194 | + |
| 195 | +Property 4: Error Handling Consistency |
| 196 | +*For any* unsupported operation in a ComputeGraph, the system should emit clear error messages or fallback comments without crashing |
| 197 | +**Validates: Requirements 1.5, 5.3** |
| 198 | + |
| 199 | +Property 5: Mathematical Operation Mapping |
| 200 | +*For any* mathematical operation (add, subtract, multiply, divide), the generated StableHLO should contain the corresponding arithmetic operation with correct operands |
| 201 | +**Validates: Requirements 2.1** |
| 202 | + |
| 203 | +Property 6: Linear Algebra Operation Mapping |
| 204 | +*For any* linear algebra operation (matmul, transpose), the generated StableHLO should contain the appropriate stablehlo.dot_general or stablehlo.transpose operation |
| 205 | +**Validates: Requirements 2.2** |
| 206 | + |
| 207 | +Property 7: Activation Function Implementation |
| 208 | +*For any* activation function (relu, sigmoid, softmax), the generated StableHLO should implement the function using appropriate primitive operations |
| 209 | +**Validates: Requirements 2.3** |
| 210 | + |
| 211 | +Property 8: Convolutional Operation Mapping |
| 212 | +*For any* conv2d operation, the generated StableHLO should contain stablehlo.convolution with properly mapped attributes |
| 213 | +**Validates: Requirements 2.4** |
| 214 | + |
| 215 | +Property 9: Shape Operation Mapping |
| 216 | +*For any* shape operation (reshape, flatten, squeeze, unsqueeze), the generated StableHLO should contain appropriate stablehlo.reshape or stablehlo.broadcast_in_dim operations |
| 217 | +**Validates: Requirements 2.5** |
| 218 | + |
| 219 | +Property 10: Dynamic Shape Handling |
| 220 | +*For any* tensor with dynamic dimensions, the generated MLIR should use correct dynamic dimension syntax (? in tensor types) |
| 221 | +**Validates: Requirements 3.2** |
| 222 | + |
| 223 | +Property 11: Broadcasting Operation Generation |
| 224 | +*For any* operation requiring broadcasting between tensors of different shapes, the system should emit explicit broadcast operations in StableHLO |
| 225 | +**Validates: Requirements 3.3** |
| 226 | + |
| 227 | +Property 12: Type Conversion Handling |
| 228 | +*For any* operation involving mixed data types, the system should emit appropriate type conversion operations in StableHLO |
| 229 | +**Validates: Requirements 3.4** |
| 230 | + |
| 231 | +Property 13: Constant Value Handling |
| 232 | +*For any* constant value in the computation graph, the generated StableHLO should contain stablehlo.constant operations with correct attributes |
| 233 | +**Validates: Requirements 4.2** |
| 234 | + |
| 235 | +Property 14: Control Flow Mapping |
| 236 | +*For any* control flow construct in the graph, the system should emit appropriate stablehlo.if or stablehlo.while operations |
| 237 | +**Validates: Requirements 4.5** |
| 238 | + |
| 239 | +Property 15: Round-trip Validation |
| 240 | +*For any* generated StableHLO module, parsing and re-processing should preserve the essential computational semantics |
| 241 | +**Validates: Requirements 5.2** |
| 242 | + |
| 243 | +Property 16: ComputeGraph Interface Compatibility |
| 244 | +*For any* valid ComputeGraph implementation, the StableHLO backend should successfully process it without interface violations |
| 245 | +**Validates: Requirements 6.1** |
| 246 | + |
| 247 | +Property 17: Operation Metadata Integration |
| 248 | +*For any* operation with KSP-generated metadata, the StableHLO backend should correctly utilize the metadata for conversion |
| 249 | +**Validates: Requirements 6.2** |
| 250 | + |
| 251 | +## Error Handling |
| 252 | + |
| 253 | +The error handling strategy will include: |
| 254 | + |
| 255 | +1. **Validation Errors**: Pre-conversion validation of graph structure and operation compatibility |
| 256 | +2. **Conversion Errors**: Graceful handling of unsupported operations with fallback comments |
| 257 | +3. **Type Errors**: Clear error messages for type incompatibilities |
| 258 | +4. **MLIR Syntax Errors**: Post-generation validation with detailed error reporting |
| 259 | + |
| 260 | +### Error Categories |
| 261 | + |
| 262 | +```kotlin |
| 263 | +public sealed class StableHloError { |
| 264 | + public data class UnsupportedOperation( |
| 265 | + val operationName: String, |
| 266 | + val nodeId: String, |
| 267 | + val reason: String |
| 268 | + ) : StableHloError() |
| 269 | + |
| 270 | + public data class TypeMappingError( |
| 271 | + val sourceType: String, |
| 272 | + val context: String |
| 273 | + ) : StableHloError() |
| 274 | + |
| 275 | + public data class GraphValidationError( |
| 276 | + val message: String, |
| 277 | + val nodeId: String? = null |
| 278 | + ) : StableHloError() |
| 279 | + |
| 280 | + public data class MlirSyntaxError( |
| 281 | + val line: Int, |
| 282 | + val column: Int, |
| 283 | + val message: String |
| 284 | + ) : StableHloError() |
| 285 | +} |
| 286 | +``` |
| 287 | + |
| 288 | +## Testing Strategy |
| 289 | + |
| 290 | +### Unit Testing Approach |
| 291 | + |
| 292 | +Unit tests will focus on: |
| 293 | +- Individual operation converters with known inputs and expected outputs |
| 294 | +- Type mapping functions with various SKaiNET types |
| 295 | +- Error handling with invalid inputs |
| 296 | +- MLIR syntax validation with malformed inputs |
| 297 | + |
| 298 | +### Property-Based Testing Approach |
| 299 | + |
| 300 | +Property-based tests will use **Kotest Property Testing** framework and will verify: |
| 301 | +- Universal properties across all supported operations |
| 302 | +- Type system correctness across random tensor specifications |
| 303 | +- SSA form preservation across random graph structures |
| 304 | +- Error handling consistency across various failure scenarios |
| 305 | + |
| 306 | +Each property-based test will run a minimum of 100 iterations to ensure comprehensive coverage of the input space. |
| 307 | + |
| 308 | +### Integration Testing |
| 309 | + |
| 310 | +Integration tests will verify: |
| 311 | +- End-to-end conversion of complete neural network models |
| 312 | +- Compatibility with existing SKaiNET execution contexts |
| 313 | +- Performance characteristics of generated StableHLO code |
| 314 | + |
| 315 | +### Test Data Generation |
| 316 | + |
| 317 | +Smart generators will be implemented for: |
| 318 | +- Random but valid ComputeGraph instances |
| 319 | +- Tensor specifications with realistic shapes and types |
| 320 | +- Operation sequences that form valid neural network patterns |
| 321 | +- Edge cases like empty graphs, single-node graphs, and deeply nested structures |
| 322 | + |
| 323 | +## Implementation Plan |
| 324 | + |
| 325 | +The implementation will follow an incremental approach: |
| 326 | + |
| 327 | +1. **Core Infrastructure**: Implement the converter framework and registry system |
| 328 | +2. **Basic Operations**: Extend support for all mathematical and linear algebra operations |
| 329 | +3. **Neural Network Operations**: Add support for convolutions, pooling, and activations |
| 330 | +4. **Shape Operations**: Implement reshape, broadcast, and dimension manipulation operations |
| 331 | +5. **Advanced Features**: Add optimization passes and validation systems |
| 332 | +6. **Integration**: Ensure compatibility with existing SKaiNET infrastructure |
| 333 | + |
| 334 | +Each phase will include comprehensive testing and validation before proceeding to the next phase. |
0 commit comments