diff --git a/mlir/include/mlir/Dialect/DXSA/IR/DXSAControlFlowOps.td b/mlir/include/mlir/Dialect/DXSA/IR/DXSAControlFlowOps.td new file mode 100644 index 000000000000..af87e7890db7 --- /dev/null +++ b/mlir/include/mlir/Dialect/DXSA/IR/DXSAControlFlowOps.td @@ -0,0 +1,345 @@ +//===- DXSAControlFlowOps.td - DXSA control flow ops ----*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Control flow instructions of the DXSA dialect. Each op takes no operands +// and marks a boundary of a loop, switch or conditional construct, or +// returns from the program. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_DXSA_IR_DXSACONTROLFLOWOPS +#define MLIR_DIALECT_DXSA_IR_DXSACONTROLFLOWOPS + +include "mlir/Dialect/DXSA/IR/DXSAOpBase.td" + +//===----------------------------------------------------------------------===// +// dxsa.abort +//===----------------------------------------------------------------------===// + +def DXSA_Abort : DXSA_NoOperandOp<"abort"> { + let summary = "aborts shader execution"; + let description = [{ + The `dxsa.abort` operation terminates the current shader invocation + unconditionally. No further instructions of the current invocation + are executed and any side effects pending after this point are + discarded. + + Example: + + ```mlir + dxsa.abort + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.break +//===----------------------------------------------------------------------===// + +def DXSA_Break : DXSA_NoOperandOp<"break"> { + let summary = "exits the enclosing loop or switch"; + let description = [{ + The `dxsa.break` operation transfers execution to the instruction that + follows the innermost enclosing loop or switch construct. It is valid + only inside a loop or inside a case of a switch. + + Example: + + ```mlir + dxsa.break + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.call +//===----------------------------------------------------------------------===// + +def DXSA_Call : DXSA_Op<"call"> { + let summary = "calls a subroutine identified by a label"; + let description = [{ + The `dxsa.call` operation transfers execution to the subroutine + marked by `$operand`, a `label` reference. On `dxsa.ret` execution + resumes at the instruction after this call. + + Example: + + ```mlir + dxsa.call label<3> + ``` + }]; + let arguments = (ins DXSA_SrcOperandAttr:$operand); + let results = (outs); + let assemblyFormat = "$operand attr-dict"; +} + +//===----------------------------------------------------------------------===// +// dxsa.callc_z +//===----------------------------------------------------------------------===// + +class DXSA_CallcOp : DXSA_Op { + let arguments = (ins + DXSA_SrcOperandAttr:$cond, + DXSA_SrcOperandAttr:$label); + let results = (outs); + let assemblyFormat = "$cond `,` $label attr-dict"; +} + +def DXSA_CallcZ : DXSA_CallcOp<"callc_z"> { + let summary = "conditionally calls a subroutine when all condition bits are zero"; + let description = [{ + The `dxsa.callc_z` operation transfers execution to the subroutine + marked by `$label` when every bit of the selected component of + `$cond` is zero. Otherwise the call is skipped and execution falls + through to the next instruction. On `dxsa.ret` execution resumes at + the instruction after this call. + + Example: + + ```mlir + dxsa.callc_z r<0, >, label<3> + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.callc_nz +//===----------------------------------------------------------------------===// + +def DXSA_CallcNz : DXSA_CallcOp<"callc_nz"> { + let summary = "conditionally calls a subroutine when any condition bit is nonzero"; + let description = [{ + The `dxsa.callc_nz` operation transfers execution to the subroutine + marked by `$label` when any bit of the selected component of `$cond` + is nonzero. Otherwise the call is skipped and execution falls + through to the next instruction. On `dxsa.ret` execution resumes at + the instruction after this call. + + Example: + + ```mlir + dxsa.callc_nz r<0, >, label<3> + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.case +//===----------------------------------------------------------------------===// + +def DXSA_Case : DXSA_Op<"case"> { + let summary = "begins a case block of a switch"; + let description = [{ + The `dxsa.case` operation begins a case block of the enclosing + switch construct whose label is the 32-bit immediate `$operand`. + Multiple `dxsa.case` operations may precede the same block to make + several values share one code path. + + Example: + + ```mlir + dxsa.case l(0x2A) + ``` + }]; + let arguments = (ins DXSA_SrcOperandAttr:$operand); + let results = (outs); + let assemblyFormat = "$operand attr-dict"; +} + +//===----------------------------------------------------------------------===// +// dxsa.continue +//===----------------------------------------------------------------------===// + +def DXSA_Continue : DXSA_NoOperandOp<"continue"> { + let summary = "restarts the enclosing loop"; + let description = [{ + The `dxsa.continue` operation transfers execution back to the start of + the innermost enclosing loop, beginning its next iteration. It is valid + only inside a loop. + + Example: + + ```mlir + dxsa.continue + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.debug_break +//===----------------------------------------------------------------------===// + +def DXSA_DebugBreak : DXSA_NoOperandOp<"debug_break"> { + let summary = "signals a breakpoint to an attached shader debugger"; + let description = [{ + The `dxsa.debug_break` operation signals a breakpoint to an attached + shader debugger. With no debugger attached the operation has no + observable effect on the shader. + + Example: + + ```mlir + dxsa.debug_break + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.default +//===----------------------------------------------------------------------===// + +def DXSA_Default : DXSA_NoOperandOp<"default"> { + let summary = "begins the default block of a switch"; + let description = [{ + The `dxsa.default` operation begins the block of the enclosing switch + construct that runs when no case matches, behaving like `default` in C. + A switch construct may contain at most one default block. + + Example: + + ```mlir + dxsa.default + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.else +//===----------------------------------------------------------------------===// + +def DXSA_Else : DXSA_NoOperandOp<"else"> { + let summary = "begins the else block of an if construct"; + let description = [{ + The `dxsa.else` operation begins the optional block of the enclosing if + construct that runs when its condition is false. It is closed by the + matching `dxsa.endif`. + + Example: + + ```mlir + dxsa.else + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.endif +//===----------------------------------------------------------------------===// + +def DXSA_Endif : DXSA_NoOperandOp<"endif"> { + let summary = "closes an if construct"; + let description = [{ + The `dxsa.endif` operation closes the innermost enclosing if construct, + including its optional `dxsa.else` block. + + Example: + + ```mlir + dxsa.endif + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.endloop +//===----------------------------------------------------------------------===// + +def DXSA_Endloop : DXSA_NoOperandOp<"endloop"> { + let summary = "closes a loop construct"; + let description = [{ + The `dxsa.endloop` operation closes the innermost enclosing loop + construct; reaching it transfers execution back to the matching + `dxsa.loop` to begin the next iteration. + + Example: + + ```mlir + dxsa.endloop + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.endswitch +//===----------------------------------------------------------------------===// + +def DXSA_Endswitch : DXSA_NoOperandOp<"endswitch"> { + let summary = "closes a switch construct"; + let description = [{ + The `dxsa.endswitch` operation closes the innermost enclosing switch + construct. + + Example: + + ```mlir + dxsa.endswitch + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.label +//===----------------------------------------------------------------------===// + +def DXSA_Label : DXSA_Op<"label"> { + let summary = "declares the entry point of a subroutine"; + let description = [{ + The `dxsa.label` operation declares the entry point of a subroutine + identified by the `label` reference `$operand`. A matching + `dxsa.call` or `dxsa.callc_z`/`dxsa.callc_nz` transfers execution to + the instruction that follows. + + Example: + + ```mlir + dxsa.label label<3> + ``` + }]; + let arguments = (ins DXSA_DstOperandAttr:$operand); + let results = (outs); + let assemblyFormat = "$operand attr-dict"; +} + +//===----------------------------------------------------------------------===// +// dxsa.loop +//===----------------------------------------------------------------------===// + +def DXSA_Loop : DXSA_NoOperandOp<"loop"> { + let summary = "begins a loop construct"; + let description = [{ + The `dxsa.loop` operation begins a loop construct whose body repeats + until a `dxsa.break` transfers execution past the matching + `dxsa.endloop`. + + Example: + + ```mlir + dxsa.loop + ``` + }]; +} + +//===----------------------------------------------------------------------===// +// dxsa.ret +//===----------------------------------------------------------------------===// + +def DXSA_Ret : DXSA_NoOperandOp<"ret"> { + let summary = "returns from a subroutine or terminates the shader"; + let description = [{ + The `dxsa.ret` operation returns to the instruction after the call when + executed inside a subroutine, or terminates program execution otherwise. + + Example: + + ```mlir + dxsa.ret + ``` + }]; +} + +#endif // MLIR_DIALECT_DXSA_IR_DXSACONTROLFLOWOPS diff --git a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOpBase.td b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOpBase.td index 6f67ca4c3329..2633c49dd06b 100644 --- a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOpBase.td +++ b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOpBase.td @@ -28,6 +28,12 @@ class DXSA_Op traits = []> : // DXSA shared bases for ops with inline operands //===----------------------------------------------------------------------===// +class DXSA_NoOperandOp : DXSA_Op { + let arguments = (ins); + let results = (outs); + let assemblyFormat = "attr-dict"; +} + class DXSA_UnaryOp : DXSA_Op { let arguments = (ins DXSA_DstOperandAttr:$dst, diff --git a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td index 54e5b8ed7a33..a58caa02df95 100644 --- a/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td +++ b/mlir/include/mlir/Dialect/DXSA/IR/DXSAOps.td @@ -13,6 +13,7 @@ include "mlir/Dialect/DXSA/IR/DXSAOpBase.td" include "mlir/Dialect/DXSA/IR/DXSATypes.td" include "mlir/Dialect/DXSA/IR/DXSAFPArithOps.td" include "mlir/Dialect/DXSA/IR/DXSAConditionOps.td" +include "mlir/Dialect/DXSA/IR/DXSAControlFlowOps.td" include "mlir/Dialect/DXSA/IR/DXSABitwiseOps.td" include "mlir/Dialect/DXSA/IR/DXSATypeConversionOps.td" include "mlir/Dialect/DXSA/IR/DXSAAtomicOps.td" diff --git a/mlir/lib/Target/DXSA/BinaryParser.cpp b/mlir/lib/Target/DXSA/BinaryParser.cpp index b783e6be85f8..e3d894550900 100644 --- a/mlir/lib/Target/DXSA/BinaryParser.cpp +++ b/mlir/lib/Target/DXSA/BinaryParser.cpp @@ -2426,6 +2426,40 @@ class Parser { return PLAIN_OP(AtomicUMax, 1, 2, HasPreciseAttr::No); case D3D11_SB_OPCODE_ATOMIC_UMIN: return PLAIN_OP(AtomicUMin, 1, 2, HasPreciseAttr::No); + // Control flow instructions + case D3D11_SB_OPCODE_ABORT: + return PLAIN_OP(Abort, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_BREAK: + return PLAIN_OP(Break, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_CALL: + return PLAIN_OP(Call, 0, 1, HasPreciseAttr::No); + case D3D10_SB_OPCODE_CALLC: + if (DECODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN(*opcodeToken0) == + D3D10_SB_INSTRUCTION_TEST_NONZERO) + return PLAIN_OP(CallcNz, 0, 2, HasPreciseAttr::No); + return PLAIN_OP(CallcZ, 0, 2, HasPreciseAttr::No); + case D3D10_SB_OPCODE_CASE: + return PLAIN_OP(Case, 0, 1, HasPreciseAttr::No); + case D3D10_SB_OPCODE_CONTINUE: + return PLAIN_OP(Continue, 0, 0, HasPreciseAttr::No); + case D3D11_SB_OPCODE_DEBUG_BREAK: + return PLAIN_OP(DebugBreak, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_DEFAULT: + return PLAIN_OP(Default, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_ELSE: + return PLAIN_OP(Else, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_ENDIF: + return PLAIN_OP(Endif, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_ENDLOOP: + return PLAIN_OP(Endloop, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_ENDSWITCH: + return PLAIN_OP(Endswitch, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_LABEL: + return PLAIN_OP(Label, 1, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_LOOP: + return PLAIN_OP(Loop, 0, 0, HasPreciseAttr::No); + case D3D10_SB_OPCODE_RET: + return PLAIN_OP(Ret, 0, 0, HasPreciseAttr::No); } #undef SATURABLE_OP #undef PLAIN_OP diff --git a/mlir/test/Target/DXSA/control_flow_ops.test b/mlir/test/Target/DXSA/control_flow_ops.test new file mode 100644 index 000000000000..b036eab0c8ef --- /dev/null +++ b/mlir/test/Target/DXSA/control_flow_ops.test @@ -0,0 +1,112 @@ +// RUN: mlir-translate --split-input-file --import-dxsa-hex %s | FileCheck %s +// RUN: mlir-translate --split-input-file --import-dxsa-hex %s | mlir-opt --split-input-file --verify-roundtrip + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.abort +// CHECK-NEXT: } +0x010000cf + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.break +// CHECK-NEXT: } +0x01000002 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.call label<3> +// CHECK-NEXT: } +0x03000004, 0x0010a000, 0x00000003 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.callc_z r<0, >, label<3> +// CHECK-NEXT: } +0x05000005, 0x0010000a, 0x00000000, 0x0010a000, 0x00000003 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.callc_nz r<0, >, label<3> +// CHECK-NEXT: } +0x05040005, 0x0010000a, 0x00000000, 0x0010a000, 0x00000003 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.case l(0x2A) +// CHECK-NEXT: } +0x03000006, 0x00004001, 0x0000002a + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.continue +// CHECK-NEXT: } +0x01000007 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.debug_break +// CHECK-NEXT: } +0x010000d0 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.default +// CHECK-NEXT: } +0x0100000a + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.else +// CHECK-NEXT: } +0x01000012 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.endif +// CHECK-NEXT: } +0x01000015 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.endloop +// CHECK-NEXT: } +0x01000016 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.endswitch +// CHECK-NEXT: } +0x01000017 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.label label<3> +// CHECK-NEXT: } +0x0300002c, 0x0010a000, 0x00000003 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.loop +// CHECK-NEXT: } +0x01000030 + +// ----- + +// CHECK-LABEL: dxsa.module { +// CHECK-NEXT: dxsa.ret +// CHECK-NEXT: } +0x0100003e diff --git a/mlir/test/Target/DXSA/inputs/ret.bin b/mlir/test/Target/DXSA/inputs/ret.bin deleted file mode 100644 index baf54956f914..000000000000 Binary files a/mlir/test/Target/DXSA/inputs/ret.bin and /dev/null differ diff --git a/mlir/test/Target/DXSA/ret.mlir b/mlir/test/Target/DXSA/ret.mlir deleted file mode 100644 index e04f5c9bc9a2..000000000000 --- a/mlir/test/Target/DXSA/ret.mlir +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: mlir-translate --import-dxsa-bin %S/inputs/ret.bin | FileCheck %s -// RUN: mlir-translate --import-dxsa-bin %S/inputs/ret.bin | mlir-opt --verify-roundtrip - -// CHECK: dxsa.module { -// CHECK-NEXT: dxsa.instruction "ret" -// CHECK-NEXT: } - -module { - dxsa.instruction "ret" -}