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}