From 3d636622da7fd572a72f6e928150864613ba47c2 Mon Sep 17 00:00:00 2001 From: Andrew Savonichev Date: Mon, 25 May 2026 23:53:54 +0900 Subject: [PATCH] [mlir][dxsa] Add dcl_interface and dcl_interface_dynamicindexed dcl_interface binds multiple dcl_function_table declarations, so they can be accessed either statically or dynamically. Each table is bound at runtime, but the compiler must know every variant to generate a specialized version of the shader. --- mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td | 41 +++++++++++++++ mlir/lib/Target/DXSA/BinaryParser.cpp | 48 ++++++++++++++++++ mlir/test/Target/DXSA/dcl_interface.mlir | 6 +++ .../test/Target/DXSA/inputs/dcl_interface.bin | Bin 0 -> 48 bytes 4 files changed, 95 insertions(+) create mode 100644 mlir/test/Target/DXSA/dcl_interface.mlir create mode 100644 mlir/test/Target/DXSA/inputs/dcl_interface.bin diff --git a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td index 5b0b03264fa5..e1de251ba1ca 100644 --- a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td +++ b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td @@ -255,6 +255,23 @@ def DXSA_SystemValueNameAttr : let assemblyFormat = "$value"; } +def DXSA_InterfaceAccess_Immediate : I32EnumAttrCase<"immediate", 0>; +def DXSA_InterfaceAccess_Dynamic : I32EnumAttrCase<"dynamic", 1>; + +def DXSA_InterfaceAccess : I32EnumAttr< + "InterfaceAccess", "DXBC access kind for an interface", [ + DXSA_InterfaceAccess_Immediate, + DXSA_InterfaceAccess_Dynamic + ]> { + let cppNamespace = "::mlir::dxsa"; + let genSpecializedAttr = 0; +} + +def DXSA_InterfaceAccessAttr : + EnumAttr { + let assemblyFormat = "$value"; +} + //===----------------------------------------------------------------------===// // DXSA ComponentMask bit-enum (mask field of operand, normalized to bits 0..3) //===----------------------------------------------------------------------===// @@ -754,4 +771,28 @@ def DXSA_DclFunctionTable : DXSA_Op<"dcl_function_table"> { let assemblyFormat = "$index `,` `<` `functions` `=` $functions `>` attr-dict"; } +def DXSA_DclInterface : DXSA_Op<"dcl_interface"> { + let summary = "declares function table pointers (interfaces)"; + let description = [{ + Declare an `array_length` of function table pointers (interfaces). Each + table can be bound at runtime, and it should contain `table_length` function + bodies. + + Example: + ```mlir + dxsa.dcl_function_body 0 + dxsa.dcl_function_body 1 + dxsa.dcl_function_table 0, + dxsa.dcl_interface 1, + ``` + }]; + let arguments = (ins I32Attr:$index, DXSA_InterfaceAccessAttr:$access, I32Attr:$array_length, I32Attr:$table_length, DenseI32ArrayAttr:$tables); + let assemblyFormat = [{ $index `,` `<` + `access` `=` $access `,` + `array_length` `=` $array_length `,` + `table_length` `=` $table_length `,` + `tables` `=` $tables `>` attr-dict + }]; +} + #endif // DXSA_OPS diff --git a/mlir/lib/Target/DXSA/BinaryParser.cpp b/mlir/lib/Target/DXSA/BinaryParser.cpp index 35a4e9887602..bdc34356f831 100644 --- a/mlir/lib/Target/DXSA/BinaryParser.cpp +++ b/mlir/lib/Target/DXSA/BinaryParser.cpp @@ -646,6 +646,15 @@ class DXBuilder { builder, loc, index, DenseI32ArrayAttr::get(ctx, functions)); } + Instruction buildDclInterface(uint32_t index, dxsa::InterfaceAccess access, + uint32_t arrayLength, uint32_t tableLength, + ArrayRef tables, Location loc) { + auto *ctx = builder.getContext(); + return dxsa::DclInterface::create(builder, loc, index, access, arrayLength, + tableLength, + DenseI32ArrayAttr::get(ctx, tables)); + } + private: MLIRContext *context; ModuleOp module; @@ -1209,6 +1218,42 @@ class Parser { return builder.buildDclFunctionTable(*index, functions, loc); } + FailureOr parseDclInterface(uint32_t opcodeToken, Location loc) { + bool isDynamic = DECODE_D3D11_SB_INTERFACE_INDEXED_BIT(opcodeToken); + auto access = dxsa::symbolizeInterfaceAccess(isDynamic); + assert(access && "unhandled interface access kind"); // access kind is 1 bit + + // Index of the interface (start index for an array). + auto index = parseToken(); + FAILURE_IF_FAILED(index); + + // Number of call sites (number of bodies in each table). + auto tableLength = parseToken(); + FAILURE_IF_FAILED(tableLength); + + auto interfaceArrayLength = parseToken(); + FAILURE_IF_FAILED(interfaceArrayLength); + + // Number of tables (variants). + uint32_t interfaceLength = + DECODE_D3D11_SB_INTERFACE_TABLE_LENGTH(*interfaceArrayLength); + + // Number of slots to be defined at runtime. + uint32_t arrayLength = + DECODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(*interfaceArrayLength); + + SmallVector tables; + tables.resize(interfaceLength); + for (uint32_t i = 0; i < interfaceLength; ++i) { + auto tableIndex = parseToken(); + FAILURE_IF_FAILED(tableIndex); + tables[i] = *tableIndex; + } + + return builder.buildDclInterface(*index, *access, arrayLength, *tableLength, + tables, loc); + } + OptionalParseResult parseDclInstruction(uint32_t opcodeToken, Location loc, Instruction &out) { FailureOr result; @@ -1261,6 +1306,9 @@ class Parser { case D3D11_SB_OPCODE_DCL_FUNCTION_TABLE: result = parseDclFunctionTable(loc); break; + case D3D11_SB_OPCODE_DCL_INTERFACE: + result = parseDclInterface(opcodeToken, loc); + break; default: return std::nullopt; } diff --git a/mlir/test/Target/DXSA/dcl_interface.mlir b/mlir/test/Target/DXSA/dcl_interface.mlir new file mode 100644 index 000000000000..11c9cbdd67cc --- /dev/null +++ b/mlir/test/Target/DXSA/dcl_interface.mlir @@ -0,0 +1,6 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/dcl_interface.bin | FileCheck %s + +// CHECK-LABEL: module + +// CHECK-NEXT: dxsa.dcl_interface 0, +// CHECK-NEXT: dxsa.dcl_interface 0, \ No newline at end of file diff --git a/mlir/test/Target/DXSA/inputs/dcl_interface.bin b/mlir/test/Target/DXSA/inputs/dcl_interface.bin new file mode 100644 index 0000000000000000000000000000000000000000..74141aed86e2f8756bc4be915eeb3c51a2472d42 GIT binary patch literal 48 bcmbQl!NA4<1dKq;#PAoy1hXeGU>64fSa<_F literal 0 HcmV?d00001