diff --git a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td index 33055b8991dc..08de536face1 100644 --- a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td +++ b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td @@ -255,6 +255,22 @@ def DXSA_SystemValueNameAttr : let assemblyFormat = "`<` $value `>`"; } +def DXSA_Condition_Zero : I32EnumAttrCase<"zero", 0>; +def DXSA_Condition_NonZero : I32EnumAttrCase<"non_zero", 1>; + +def DXSA_Condition : I32EnumAttr< + "Condition", "DXBC boolean condition", [ + DXSA_Condition_Zero, + DXSA_Condition_NonZero + ]> { + let cppNamespace = "::mlir::dxsa"; + let genSpecializedAttr = 0; +} + +def DXSA_ConditionAttr : EnumAttr { + let assemblyFormat = "`<` $value `>`"; +} + //===----------------------------------------------------------------------===// // DXSA ComponentMask bit-enum (mask field of operand, normalized to bits 0..3) //===----------------------------------------------------------------------===// @@ -1072,4 +1088,93 @@ def DXSA_DclStream : DXSA_Op<"dcl_stream"> { let assemblyFormat = [{ $index attr-dict }]; } +// Base class for operations with a condition attribute and a single operand. +class DXSA_CondOp : DXSA_Op { + let arguments = (ins DXSA_ConditionAttr:$cond, DXSA_OperandType:$operand); + let assemblyFormat = [{ $cond `,` $operand attr-dict}]; +} + +def DXSA_If : DXSA_CondOp<"if"> { + let summary = "branch based on logical OR result"; + let description = [{ + Example: + ```mlir + module { + %0 = dxsa.index.imm {imm = 0 : i32} + %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} + dxsa.if , %1 + } + ``` + }]; +} + +def DXSA_Breakc : DXSA_CondOp<"breakc"> { + let summary = "break (conditional)"; + let description = [{ + Conditionally move the point of execution to the instruction after the next + endloop or endswitch. + + Example: + ```mlir + module { + %0 = dxsa.index.imm {imm = 0 : i32} + %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} + dxsa.breakc , %1 + } + ``` + }]; +} + +def DXSA_Continuec : DXSA_CondOp<"continuec"> { + let summary = "continue (conditional)"; + let description = [{ + Conditionally continue execution at the beginning of the current loop. + + Example: + ```mlir + module { + %0 = dxsa.index.imm {imm = 0 : i32} + %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} + dxsa.continuec , %1 + } + ``` + }]; +} + +def DXSA_Retc : DXSA_CondOp<"retc"> { + let summary = "return (conditional)"; + let description = [{ + If within a subroutine, conditionally return to the instruction after the + call. If not inside a subroutine, terminate program execution. + + Example: + ```mlir + module { + %0 = dxsa.index.imm {imm = 0 : i32} + %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} + dxsa.retc , %1 + } + ``` + }]; +} + +def DXSA_Discard : DXSA_CondOp<"discard"> { + let summary = "conditionally flag results of Pixel Shader to be discarded when the end of the program is reached"; + let description = [{ + The `discard` instruction flags the current pixel as terminated, while + continuing execution, so that other pixels executing in parallel may obtain + derivatives if necessary. Even though execution continues, all Pixel Shader + output writes before or after the `discard` instruction are discarded. + + Example: + ```mlir + module { + %0 = dxsa.index.imm {imm = 0 : i32} + %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} + dxsa.discard , %1 + } + ``` + }]; +} + #endif // DXSA_OPS diff --git a/mlir/lib/Target/DXSA/BinaryParser.cpp b/mlir/lib/Target/DXSA/BinaryParser.cpp index 0e0e38c70fa1..fff64c6258fe 100644 --- a/mlir/lib/Target/DXSA/BinaryParser.cpp +++ b/mlir/lib/Target/DXSA/BinaryParser.cpp @@ -733,6 +733,12 @@ class DXBuilder { optionalToAttr(space)); } + template + Instruction buildConditionInstruction(dxsa::Condition cond, Operand operand, + Location loc) { + return Inst::create(builder, loc, cond, operand); + } + private: MLIRContext *context; ModuleOp module; @@ -1476,6 +1482,19 @@ class Parser { return builder.buildDclSampler(id, lbound, ubound, space, *mode, loc); } + template + FailureOr parseConditionInstruction(uint32_t opcodeToken, + Location loc) { + dxsa::Condition cond = DECODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN(opcodeToken) + ? dxsa::Condition::non_zero + : dxsa::Condition::zero; + + auto operand = parseOperand(); + FAILURE_IF_FAILED(operand); + + return builder.buildConditionInstruction(cond, *operand, loc); + } + OptionalParseResult parseDclInstruction(uint32_t opcodeToken, Location loc, Instruction &out) { FailureOr result; @@ -1567,6 +1586,21 @@ class Parser { case D3D10_SB_OPCODE_DCL_SAMPLER: result = parseDclSampler(opcodeToken, loc); break; + case D3D10_SB_OPCODE_IF: + result = parseConditionInstruction(opcodeToken, loc); + break; + case D3D10_SB_OPCODE_BREAKC: + result = parseConditionInstruction(opcodeToken, loc); + break; + case D3D10_SB_OPCODE_CONTINUEC: + result = parseConditionInstruction(opcodeToken, loc); + break; + case D3D10_SB_OPCODE_RETC: + result = parseConditionInstruction(opcodeToken, loc); + break; + case D3D10_SB_OPCODE_DISCARD: + result = parseConditionInstruction(opcodeToken, loc); + break; default: return std::nullopt; } diff --git a/mlir/test/Target/DXSA/breakc.mlir b/mlir/test/Target/DXSA/breakc.mlir new file mode 100644 index 000000000000..770655ca1053 --- /dev/null +++ b/mlir/test/Target/DXSA/breakc.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/breakc.bin | FileCheck %s + +// CHECK: module { +// CHECK-NEXT: %0 = dxsa.index.imm {imm = 0 : i32} +// CHECK-NEXT: %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} +// CHECK-NEXT: dxsa.breakc , %1 +// CHECK-NEXT: } diff --git a/mlir/test/Target/DXSA/continuec.mlir b/mlir/test/Target/DXSA/continuec.mlir new file mode 100644 index 000000000000..9a5ffb1824de --- /dev/null +++ b/mlir/test/Target/DXSA/continuec.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/continuec.bin | FileCheck %s + +// CHECK: module { +// CHECK-NEXT: %0 = dxsa.index.imm {imm = 0 : i32} +// CHECK-NEXT: %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} +// CHECK-NEXT: dxsa.continuec , %1 +// CHECK-NEXT: } diff --git a/mlir/test/Target/DXSA/discard.mlir b/mlir/test/Target/DXSA/discard.mlir new file mode 100644 index 000000000000..f543994f8f17 --- /dev/null +++ b/mlir/test/Target/DXSA/discard.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/discard.bin | FileCheck %s + +// CHECK: module { +// CHECK-NEXT: %0 = dxsa.index.imm {imm = 0 : i32} +// CHECK-NEXT: %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} +// CHECK-NEXT: dxsa.discard , %1 +// CHECK-NEXT: } diff --git a/mlir/test/Target/DXSA/if.mlir b/mlir/test/Target/DXSA/if.mlir new file mode 100644 index 000000000000..536dbb8b2c49 --- /dev/null +++ b/mlir/test/Target/DXSA/if.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/if.bin | FileCheck %s + +// CHECK: module { +// CHECK-NEXT: %0 = dxsa.index.imm {imm = 0 : i32} +// CHECK-NEXT: %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} +// CHECK-NEXT: dxsa.if , %1 +// CHECK-NEXT: } diff --git a/mlir/test/Target/DXSA/inputs/breakc.bin b/mlir/test/Target/DXSA/inputs/breakc.bin new file mode 100644 index 000000000000..50a679a7a25c Binary files /dev/null and b/mlir/test/Target/DXSA/inputs/breakc.bin differ diff --git a/mlir/test/Target/DXSA/inputs/continuec.bin b/mlir/test/Target/DXSA/inputs/continuec.bin new file mode 100644 index 000000000000..2df42f339c9f Binary files /dev/null and b/mlir/test/Target/DXSA/inputs/continuec.bin differ diff --git a/mlir/test/Target/DXSA/inputs/discard.bin b/mlir/test/Target/DXSA/inputs/discard.bin new file mode 100644 index 000000000000..576f4eb2e29c Binary files /dev/null and b/mlir/test/Target/DXSA/inputs/discard.bin differ diff --git a/mlir/test/Target/DXSA/inputs/if.bin b/mlir/test/Target/DXSA/inputs/if.bin new file mode 100644 index 000000000000..d0a26017cb32 Binary files /dev/null and b/mlir/test/Target/DXSA/inputs/if.bin differ diff --git a/mlir/test/Target/DXSA/inputs/retc.bin b/mlir/test/Target/DXSA/inputs/retc.bin new file mode 100644 index 000000000000..b25d9e079847 Binary files /dev/null and b/mlir/test/Target/DXSA/inputs/retc.bin differ diff --git a/mlir/test/Target/DXSA/retc.mlir b/mlir/test/Target/DXSA/retc.mlir new file mode 100644 index 000000000000..6ee9edc7624e --- /dev/null +++ b/mlir/test/Target/DXSA/retc.mlir @@ -0,0 +1,7 @@ +// RUN: mlir-translate --import-dxsa-bin %S/inputs/retc.bin | FileCheck %s + +// CHECK: module { +// CHECK-NEXT: %0 = dxsa.index.imm {imm = 0 : i32} +// CHECK-NEXT: %1 = dxsa.operand %0 {num_components = 4 : i32, one = 0 : i32, type = 0 : i32} +// CHECK-NEXT: dxsa.retc , %1 +// CHECK-NEXT: }