Skip to main content

dxbc_reader/
format.rs

1//! The operand format of each instruction: how many destination and source operands the token format gives an opcode,
2//! and what each carries. [`decode`](crate::decode()) checks every instruction against it, so a program whose
3//! instruction has another operand count is not a program of this format.
4#![deny(
5    clippy::arithmetic_side_effects,
6    clippy::indexing_slicing,
7    clippy::cast_possible_truncation
8)]
9
10/// What an operand of an instruction carries.
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum OperandClass {
13    /// 32-bit float data. A float operand may carry the negate and absolute-value modifiers.
14    Float,
15    /// 64-bit float data, two lanes of the register pair per value.
16    Double,
17    /// 32-bit integer data. Whether it is signed is the instruction's (`iadd`, `uadd`...); the token stream does not say.
18    Integer,
19    /// A register with no data of its own: a resource, sampler, unordered-access view, thread-group shared memory or
20    /// output stream the instruction reads from, writes to or asks about.
21    Resource,
22    /// Data whose type the sources disagree on, or that the instruction takes from elsewhere: a sampled or loaded
23    /// value has the type its resource declares, `resinfo`, `sampleinfo` and `bufinfo` return the type their control
24    /// bits choose.
25    Varies,
26}
27
28/// The operands of one opcode, destinations first as they are stored.
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct OperandFormat {
31    /// The destination operands: registers the instruction writes. A `Resource` destination is a view it writes through.
32    pub destinations: &'static [OperandClass],
33    /// The source operands.
34    pub sources: &'static [OperandClass],
35}
36impl OperandFormat {
37    /// The number of operands, destinations and sources.
38    pub fn operands(&self) -> usize {
39        self.destinations.len().saturating_add(self.sources.len())
40    }
41}
42
43const fn entry(
44    destinations: &'static [OperandClass],
45    sources: &'static [OperandClass],
46) -> Option<OperandFormat> {
47    Some(OperandFormat {
48        destinations,
49        sources,
50    })
51}
52
53/// The operand format of `opcode` (the opcode token's low 11 bits, see [`opcode_name`](crate::opcode_name)). `None` for
54/// the opcodes without one: declarations, which [`Declared`](crate::Declared) types, and `call`, `callc`, `label` and
55/// `interface_call`, whose operands are not registers a program declares.
56///
57/// The table is the one vkd3d and DXVK both publish, with their counts agreeing for every opcode both list; where the
58/// sources disagree on a type class it is [`OperandClass::Varies`]. `umad`, `emitthencut`, `emitthencut_stream` and
59/// `eval_snapped` come from DXVK alone, and `uaddc` and `usubb` (two destinations and two sources) from Microsoft's
60/// instruction reference, since neither public table lists them.
61pub fn operand_format(opcode: u16) -> Option<OperandFormat> {
62    use OperandClass::{Double as D, Float as F, Integer as I, Resource as R, Varies as V};
63    match opcode {
64        0 => entry(&[F], &[F, F]),                  // add
65        1 => entry(&[I], &[I, I]),                  // and
66        2 => entry(&[], &[]),                       // break
67        3 => entry(&[], &[I]),                      // breakc
68        6 => entry(&[], &[I]),                      // case
69        7 => entry(&[], &[]),                       // continue
70        8 => entry(&[], &[I]),                      // continuec
71        9 => entry(&[], &[]),                       // cut
72        10 => entry(&[], &[]),                      // default
73        11 => entry(&[F], &[F]),                    // deriv_rtx
74        12 => entry(&[F], &[F]),                    // deriv_rty
75        13 => entry(&[], &[I]),                     // discard
76        14 => entry(&[F], &[F, F]),                 // div
77        15 => entry(&[F], &[F, F]),                 // dp2
78        16 => entry(&[F], &[F, F]),                 // dp3
79        17 => entry(&[F], &[F, F]),                 // dp4
80        18 => entry(&[], &[]),                      // else
81        19 => entry(&[], &[]),                      // emit
82        20 => entry(&[], &[]),                      // emitthencut
83        21 => entry(&[], &[]),                      // endif
84        22 => entry(&[], &[]),                      // endloop
85        23 => entry(&[], &[]),                      // endswitch
86        24 => entry(&[I], &[F, F]),                 // eq
87        25 => entry(&[F], &[F]),                    // exp
88        26 => entry(&[F], &[F]),                    // frc
89        27 => entry(&[I], &[F]),                    // ftoi
90        28 => entry(&[I], &[F]),                    // ftou
91        29 => entry(&[I], &[F, F]),                 // ge
92        30 => entry(&[I], &[I, I]),                 // iadd
93        31 => entry(&[], &[I]),                     // if
94        32 => entry(&[I], &[I, I]),                 // ieq
95        33 => entry(&[I], &[I, I]),                 // ige
96        34 => entry(&[I], &[I, I]),                 // ilt
97        35 => entry(&[I], &[I, I, I]),              // imad
98        36 => entry(&[I], &[I, I]),                 // imax
99        37 => entry(&[I], &[I, I]),                 // imin
100        38 => entry(&[I, I], &[I, I]),              // imul
101        39 => entry(&[I], &[I, I]),                 // ine
102        40 => entry(&[I], &[I]),                    // ineg
103        41 => entry(&[I], &[I, I]),                 // ishl
104        42 => entry(&[I], &[I, I]),                 // ishr
105        43 => entry(&[F], &[I]),                    // itof
106        45 => entry(&[V], &[I, R]),                 // ld
107        46 => entry(&[V], &[I, R, I]),              // ld_ms
108        47 => entry(&[F], &[F]),                    // log
109        48 => entry(&[], &[]),                      // loop
110        49 => entry(&[I], &[F, F]),                 // lt
111        50 => entry(&[F], &[F, F, F]),              // mad
112        51 => entry(&[F], &[F, F]),                 // min
113        52 => entry(&[F], &[F, F]),                 // max
114        54 => entry(&[F], &[F]),                    // mov
115        55 => entry(&[F], &[I, F, F]),              // movc
116        56 => entry(&[F], &[F, F]),                 // mul
117        57 => entry(&[I], &[F, F]),                 // ne
118        58 => entry(&[], &[]),                      // nop
119        59 => entry(&[I], &[I]),                    // not
120        60 => entry(&[I], &[I, I]),                 // or
121        61 => entry(&[F], &[I, R]),                 // resinfo
122        62 => entry(&[], &[]),                      // ret
123        63 => entry(&[], &[I]),                     // retc
124        64 => entry(&[F], &[F]),                    // round_ne
125        65 => entry(&[F], &[F]),                    // round_ni
126        66 => entry(&[F], &[F]),                    // round_pi
127        67 => entry(&[F], &[F]),                    // round_z
128        68 => entry(&[F], &[F]),                    // rsq
129        69 => entry(&[V], &[F, R, R]),              // sample
130        70 => entry(&[F], &[F, R, R, F]),           // sample_c
131        71 => entry(&[F], &[F, R, R, F]),           // sample_c_lz
132        72 => entry(&[V], &[F, R, R, F]),           // sample_l
133        73 => entry(&[V], &[F, R, R, F, F]),        // sample_d
134        74 => entry(&[V], &[F, R, R, F]),           // sample_b
135        75 => entry(&[F], &[F]),                    // sqrt
136        76 => entry(&[], &[I]),                     // switch
137        77 => entry(&[F, F], &[F]),                 // sincos
138        78 => entry(&[I, I], &[I, I]),              // udiv
139        79 => entry(&[I], &[I, I]),                 // ult
140        80 => entry(&[I], &[I, I]),                 // uge
141        81 => entry(&[I, I], &[I, I]),              // umul
142        82 => entry(&[I], &[I, I, I]),              // umad
143        83 => entry(&[I], &[I, I]),                 // umax
144        84 => entry(&[I], &[I, I]),                 // umin
145        85 => entry(&[I], &[I, I]),                 // ushr
146        86 => entry(&[F], &[I]),                    // utof
147        87 => entry(&[I], &[I, I]),                 // xor
148        108 => entry(&[F], &[F, R, R]),             // lod
149        109 => entry(&[V], &[F, R, R]),             // gather4
150        110 => entry(&[F], &[R, I]),                // sample_pos
151        111 => entry(&[V], &[R]),                   // sample_info
152        117 => entry(&[], &[R]),                    // emit_stream
153        118 => entry(&[], &[R]),                    // cut_stream
154        119 => entry(&[], &[R]),                    // emitthencut_stream
155        121 => entry(&[V], &[R]),                   // bufinfo
156        122 => entry(&[F], &[F]),                   // deriv_rtx_coarse
157        123 => entry(&[F], &[F]),                   // deriv_rtx_fine
158        124 => entry(&[F], &[F]),                   // deriv_rty_coarse
159        125 => entry(&[F], &[F]),                   // deriv_rty_fine
160        126 => entry(&[F], &[F, R, R, F]),          // gather4_c
161        127 => entry(&[F], &[F, I, R, R]),          // gather4_po
162        128 => entry(&[F], &[F, I, R, R, F]),       // gather4_po_c
163        129 => entry(&[F], &[F]),                   // rcp
164        130 => entry(&[I], &[F]),                   // f32tof16
165        131 => entry(&[F], &[I]),                   // f16tof32
166        132 => entry(&[I, I], &[I, I]),             // uaddc
167        133 => entry(&[I, I], &[I, I]),             // usubb
168        134 => entry(&[I], &[I]),                   // countbits
169        135 => entry(&[I], &[I]),                   // firstbit_hi
170        136 => entry(&[I], &[I]),                   // firstbit_lo
171        137 => entry(&[I], &[I]),                   // firstbit_shi
172        138 => entry(&[I], &[I, I, I]),             // ubfe
173        139 => entry(&[I], &[I, I, I]),             // ibfe
174        140 => entry(&[I], &[I, I, I, I]),          // bfi
175        141 => entry(&[I], &[I]),                   // bfrev
176        142 => entry(&[F, F], &[I, F, F]),          // swapc
177        163 => entry(&[V], &[I, R]),                // ld_uav_typed
178        164 => entry(&[R], &[I, V]),                // store_uav_typed
179        165 => entry(&[I], &[I, R]),                // ld_raw
180        166 => entry(&[R], &[I, I]),                // store_raw
181        167 => entry(&[I], &[I, I, R]),             // ld_structured
182        168 => entry(&[R], &[I, I, I]),             // store_structured
183        169 => entry(&[R], &[I, I]),                // atomic_and
184        170 => entry(&[R], &[I, I]),                // atomic_or
185        171 => entry(&[R], &[I, I]),                // atomic_xor
186        172 => entry(&[R], &[I, I, I]),             // atomic_cmp_store
187        173 => entry(&[R], &[I, I]),                // atomic_iadd
188        174 => entry(&[R], &[I, I]),                // atomic_imax
189        175 => entry(&[R], &[I, I]),                // atomic_imin
190        176 => entry(&[R], &[I, I]),                // atomic_umax
191        177 => entry(&[R], &[I, I]),                // atomic_umin
192        178 => entry(&[I], &[R]),                   // imm_atomic_alloc
193        179 => entry(&[I], &[R]),                   // imm_atomic_consume
194        180 => entry(&[I, R], &[I, I]),             // imm_atomic_iadd
195        181 => entry(&[I, R], &[I, I]),             // imm_atomic_and
196        182 => entry(&[I, R], &[I, I]),             // imm_atomic_or
197        183 => entry(&[I, R], &[I, I]),             // imm_atomic_xor
198        184 => entry(&[I, R], &[I, I]),             // imm_atomic_exch
199        185 => entry(&[I, R], &[I, I, I]),          // imm_atomic_cmp_exch
200        186 => entry(&[I, R], &[I, I]),             // imm_atomic_imax
201        187 => entry(&[I, R], &[I, I]),             // imm_atomic_imin
202        188 => entry(&[I, R], &[I, I]),             // imm_atomic_umax
203        189 => entry(&[I, R], &[I, I]),             // imm_atomic_umin
204        190 => entry(&[], &[]),                     // sync
205        191 => entry(&[D], &[D, D]),                // dadd
206        192 => entry(&[D], &[D, D]),                // dmax
207        193 => entry(&[D], &[D, D]),                // dmin
208        194 => entry(&[D], &[D, D]),                // dmul
209        195 => entry(&[I], &[D, D]),                // deq
210        196 => entry(&[I], &[D, D]),                // dge
211        197 => entry(&[I], &[D, D]),                // dlt
212        198 => entry(&[I], &[D, D]),                // dne
213        199 => entry(&[D], &[D]),                   // dmov
214        200 => entry(&[D], &[I, D, D]),             // dmovc
215        201 => entry(&[F], &[D]),                   // dtof
216        202 => entry(&[D], &[F]),                   // ftod
217        203 => entry(&[F], &[F, V]),                // eval_snapped
218        204 => entry(&[F], &[F, I]),                // eval_sample_index
219        205 => entry(&[F], &[F]),                   // eval_centroid
220        210 => entry(&[D], &[D, D]),                // ddiv
221        211 => entry(&[D], &[D, D, D]),             // dfma
222        212 => entry(&[D], &[D]),                   // drcp
223        213 => entry(&[I], &[I, I, I]),             // msad
224        214 => entry(&[I], &[D]),                   // dtoi
225        215 => entry(&[I], &[D]),                   // dtou
226        216 => entry(&[D], &[I]),                   // itod
227        217 => entry(&[D], &[I]),                   // utod
228        219 => entry(&[V, I], &[F, R, R]),          // gather4_feedback
229        220 => entry(&[F, I], &[F, R, R, F]),       // gather4_c_feedback
230        221 => entry(&[F, I], &[F, I, R, R]),       // gather4_po_feedback
231        222 => entry(&[F, I], &[F, I, R, R, F]),    // gather4_po_c_feedback
232        223 => entry(&[V, I], &[I, R]),             // ld_feedback
233        224 => entry(&[V, I], &[I, R, I]),          // ld_ms_feedback
234        225 => entry(&[V, I], &[I, R]),             // ld_uav_typed_feedback
235        226 => entry(&[I, I], &[I, R]),             // ld_raw_feedback
236        227 => entry(&[I, I], &[I, I, R]),          // ld_structured_feedback
237        228 => entry(&[V, I], &[F, R, R, F]),       // sample_l_feedback
238        229 => entry(&[F, I], &[F, R, R, F]),       // sample_c_lz_feedback
239        230 => entry(&[V, I], &[F, R, R, F]),       // sample_clamp_feedback
240        231 => entry(&[V, I], &[F, R, R, F, F]),    // sample_b_clamp_feedback
241        232 => entry(&[V, I], &[F, R, R, F, F, F]), // sample_d_clamp_feedback
242        233 => entry(&[F, I], &[F, R, R, F, F]),    // sample_c_clamp_feedback
243        234 => entry(&[I], &[I]),                   // check_access_fully_mapped
244        _ => None,
245    }
246}