1use serde::{Deserialize, Serialize};
2
3macro_rules! opcodes {
5 (
6 $(#[$($attrss:meta)*])*
7 pub enum $name:ident<$t:ty> {}
8 ) => {
9 opcodes!(
10 $(#[$($attrss)*])*
11 pub enum $name<$t> {,}
12 );
13 };
14 (
15 $(#[$($attrss:meta)*])*
16 pub enum $name:ident<$t:ty> {
17 $(
18 $(#[$($a:meta)*])*
19 $foo:ident($($i:ty),*)
20 ),*
21 ,
22 }
23 ) => {
24 $(#[$($attrss)*])*
25 pub enum $name {
26 #[doc = "Writes an output variable by index"]
28 Output($t, u32),
29 #[doc = "Read an input variable by index"]
30 Input($t, u32),
31 #[doc = "Copies the given register"]
32 CopyReg($t, $t),
33 #[doc = "Copy an immediate to a register"]
34 CopyImm($t, f32),
35
36 #[doc = "Negate the given register"]
38 NegReg($t, $t),
39 #[doc = "Take the absolute value of the given register"]
40 AbsReg($t, $t),
41 #[doc = "Take the reciprocal of the given register (1.0 / value)"]
42 RecipReg($t, $t),
43 #[doc = "Take the square root of the given register"]
44 SqrtReg($t, $t),
45 #[doc = "Square the given register"]
46 SquareReg($t, $t),
47 #[doc = "Returns the largest integer less than or equal to `self`"]
48 FloorReg($t, $t),
49 #[doc = "Returns the smallest integer greater than or equal to `self`"]
50 CeilReg($t, $t),
51 #[doc = "Returns the nearest integer to `self`. If a value is half-way between two integers, round away from `0.0`."]
52 RoundReg($t, $t),
53 #[doc = "Computes the sine of the given register (in radians)"]
54 SinReg($t, $t),
55 #[doc = "Computes the cosine of the given register (in radians)"]
56 CosReg($t, $t),
57 #[doc = "Computes the tangent of the given register (in radians)"]
58 TanReg($t, $t),
59 #[doc = "Computes the arcsin of the given register (in radians)"]
60 AsinReg($t, $t),
61 #[doc = "Computes the arccos of the given register (in radians)"]
62 AcosReg($t, $t),
63 #[doc = "Computes the arctangent of the given register (in radians)"]
64 AtanReg($t, $t),
65 #[doc = "Computes the exponential function of the given register"]
66 ExpReg($t, $t),
67 #[doc = "Computes the natural log of the given register"]
68 LnReg($t, $t),
69 #[doc = "Computes the logical negation of the given register\n\nEquivalent to `if arg == 0 { 1 } else { 0 }`"]
70 NotReg($t, $t),
71 #[doc = "Returns a pseudo-random value in the 0.0-1.0 range from a given seed"]
72 RandReg($t, $t),
73
74 #[doc = "Add a register and an immediate"]
76 AddRegImm($t, $t, f32),
77 #[doc = "Multiply a register and an immediate"]
78 MulRegImm($t, $t, f32),
79 #[doc = "Divides a register and an immediate"]
80 DivRegImm($t, $t, f32),
81 #[doc = "Divides an immediate by a register"]
82 DivImmReg($t, $t, f32),
83 #[doc = "Subtract a register from an immediate"]
84 SubImmReg($t, $t, f32),
85 #[doc = "Subtract an immediate from a register"]
86 SubRegImm($t, $t, f32),
87 #[doc = "Take the module (least nonnegative remainder) of two registers"]
88 ModRegReg($t, $t, $t),
89 #[doc = "Take the module (least nonnegative remainder) of a register and an immediate"]
90 ModRegImm($t, $t, f32),
91 #[doc = "atan2 of a position `(y, x)` specified as register, immediate"]
92 AtanRegImm($t, $t, f32),
93 #[doc = "Compares a register with an immediate"]
94 CompareRegImm($t, $t, f32),
95 #[doc = "Pseudo-random mixing of a register with an immediate"]
96 MixRegImm($t, $t, f32),
97
98 #[doc = "Compute the minimum of a register and an immediate"]
100 MinRegImm($t, $t, f32),
101 #[doc = "Compute the maximum of a register and an immediate"]
102 MaxRegImm($t, $t, f32),
103 #[doc = "Logical `AND` (short-circuiting)\n\nThis is equivalent to `if lhs == 0 { lhs } else { imm }`"]
104 AndRegImm($t, $t, f32),
105 #[doc = "Logical `OR` (short-circuiting)\n\nThis is equivalent to `if lhs != 0 { lhs } else { imm }`"]
106 OrRegImm($t, $t, f32),
107
108 #[doc = "Take the module (least nonnegative remainder) of an immediate and a register"]
110 ModImmReg($t, $t, f32),
111 #[doc = "atan2 of a position `(y, x)` specified as immediate, register"]
112 AtanImmReg($t, $t, f32),
113 #[doc = "Compares an immediate with a register"]
114 CompareImmReg($t, $t, f32),
115 #[doc = "Pseudo-random mixing of an immediate and a register"]
116 MixImmReg($t, $t, f32),
117
118 #[doc = "Add two registers"]
120 AddRegReg($t, $t, $t),
121 #[doc = "Multiply two registers"]
122 MulRegReg($t, $t, $t),
123 #[doc = "Divides two registers"]
124 DivRegReg($t, $t, $t),
125 #[doc = "Subtract one register from another"]
126 SubRegReg($t, $t, $t),
127 #[doc = "Compares two registers"]
128 CompareRegReg($t, $t, $t),
129 #[doc = "atan2 of a position `(y, x)` specified as register, register"]
130 AtanRegReg($t, $t, $t),
131 #[doc = "Pseudo-random mixing of two registers"]
132 MixRegReg($t, $t, $t),
133
134 #[doc = "Take the minimum of two registers"]
136 MinRegReg($t, $t, $t),
137 #[doc = "Take the maximum of two registers"]
138 MaxRegReg($t, $t, $t),
139 #[doc = "Logical `AND` (short-circuiting)\n\nThis is equivalent to `if lhs == 0 { lhs } else { rhs }`"]
140 AndRegReg($t, $t, $t),
141 #[doc = "Logical `OR` (short-circuiting)\n\nThis is equivalent to `if lhs != 0 { lhs } else { rhs }`"]
142 OrRegReg($t, $t, $t),
143
144 $(
145 $(#[$($a)*])*
146 $foo($($i),*)
147 ),*
148 }
149 };
150}
151
152opcodes!(
153 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
162 pub enum SsaOp<u32> {
163 }
165);
166
167impl SsaOp {
168 pub fn output(&self) -> Option<u32> {
170 match self {
171 SsaOp::Input(out, ..)
172 | SsaOp::CopyImm(out, ..)
173 | SsaOp::NegReg(out, ..)
174 | SsaOp::AbsReg(out, ..)
175 | SsaOp::RecipReg(out, ..)
176 | SsaOp::SqrtReg(out, ..)
177 | SsaOp::SquareReg(out, ..)
178 | SsaOp::FloorReg(out, ..)
179 | SsaOp::CeilReg(out, ..)
180 | SsaOp::RoundReg(out, ..)
181 | SsaOp::CopyReg(out, ..)
182 | SsaOp::SinReg(out, ..)
183 | SsaOp::CosReg(out, ..)
184 | SsaOp::TanReg(out, ..)
185 | SsaOp::AsinReg(out, ..)
186 | SsaOp::AcosReg(out, ..)
187 | SsaOp::AtanReg(out, ..)
188 | SsaOp::ExpReg(out, ..)
189 | SsaOp::LnReg(out, ..)
190 | SsaOp::NotReg(out, ..)
191 | SsaOp::RandReg(out, ..)
192 | SsaOp::AddRegImm(out, ..)
193 | SsaOp::MulRegImm(out, ..)
194 | SsaOp::DivRegImm(out, ..)
195 | SsaOp::DivImmReg(out, ..)
196 | SsaOp::SubImmReg(out, ..)
197 | SsaOp::SubRegImm(out, ..)
198 | SsaOp::AddRegReg(out, ..)
199 | SsaOp::MulRegReg(out, ..)
200 | SsaOp::DivRegReg(out, ..)
201 | SsaOp::SubRegReg(out, ..)
202 | SsaOp::AtanRegReg(out, ..)
203 | SsaOp::AtanRegImm(out, ..)
204 | SsaOp::AtanImmReg(out, ..)
205 | SsaOp::MinRegImm(out, ..)
206 | SsaOp::MaxRegImm(out, ..)
207 | SsaOp::MinRegReg(out, ..)
208 | SsaOp::MaxRegReg(out, ..)
209 | SsaOp::CompareRegReg(out, ..)
210 | SsaOp::CompareRegImm(out, ..)
211 | SsaOp::CompareImmReg(out, ..)
212 | SsaOp::MixRegReg(out, ..)
213 | SsaOp::MixRegImm(out, ..)
214 | SsaOp::MixImmReg(out, ..)
215 | SsaOp::ModRegReg(out, ..)
216 | SsaOp::ModRegImm(out, ..)
217 | SsaOp::ModImmReg(out, ..)
218 | SsaOp::AndRegImm(out, ..)
219 | SsaOp::AndRegReg(out, ..)
220 | SsaOp::OrRegImm(out, ..)
221 | SsaOp::OrRegReg(out, ..) => Some(*out),
222 SsaOp::Output(..) => None,
223 }
224 }
225 pub fn has_choice(&self) -> bool {
227 match self {
228 SsaOp::Input(..)
229 | SsaOp::Output(..)
230 | SsaOp::CopyImm(..)
231 | SsaOp::NegReg(..)
232 | SsaOp::AbsReg(..)
233 | SsaOp::RecipReg(..)
234 | SsaOp::SqrtReg(..)
235 | SsaOp::SquareReg(..)
236 | SsaOp::FloorReg(..)
237 | SsaOp::CeilReg(..)
238 | SsaOp::RoundReg(..)
239 | SsaOp::CopyReg(..)
240 | SsaOp::SinReg(..)
241 | SsaOp::CosReg(..)
242 | SsaOp::TanReg(..)
243 | SsaOp::AsinReg(..)
244 | SsaOp::AcosReg(..)
245 | SsaOp::AtanReg(..)
246 | SsaOp::ExpReg(..)
247 | SsaOp::LnReg(..)
248 | SsaOp::NotReg(..)
249 | SsaOp::RandReg(..)
250 | SsaOp::AddRegImm(..)
251 | SsaOp::MulRegImm(..)
252 | SsaOp::SubRegImm(..)
253 | SsaOp::SubImmReg(..)
254 | SsaOp::AddRegReg(..)
255 | SsaOp::MulRegReg(..)
256 | SsaOp::SubRegReg(..)
257 | SsaOp::DivRegReg(..)
258 | SsaOp::DivRegImm(..)
259 | SsaOp::DivImmReg(..)
260 | SsaOp::AtanRegReg(..)
261 | SsaOp::AtanRegImm(..)
262 | SsaOp::AtanImmReg(..)
263 | SsaOp::CompareRegReg(..)
264 | SsaOp::CompareRegImm(..)
265 | SsaOp::CompareImmReg(..)
266 | SsaOp::MixRegReg(..)
267 | SsaOp::MixRegImm(..)
268 | SsaOp::MixImmReg(..)
269 | SsaOp::ModRegReg(..)
270 | SsaOp::ModRegImm(..)
271 | SsaOp::ModImmReg(..) => false,
272 SsaOp::MinRegImm(..)
273 | SsaOp::MaxRegImm(..)
274 | SsaOp::MinRegReg(..)
275 | SsaOp::MaxRegReg(..)
276 | SsaOp::AndRegImm(..)
277 | SsaOp::AndRegReg(..)
278 | SsaOp::OrRegImm(..)
279 | SsaOp::OrRegReg(..) => true,
280 }
281 }
282}
283
284opcodes!(
285 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
298 pub enum RegOp<u8> {
299 Load(u8, u32),
302
303 Store(u8, u32),
305 }
306);
307
308impl RegOp {
309 pub fn visit_regs_mut<F: FnMut(&mut u8)>(&mut self, mut f: F) {
313 match self {
314 RegOp::CopyImm(out, imm) => {
315 let _: f32 = *imm;
316 f(out)
317 }
318 RegOp::NegReg(out, arg)
319 | RegOp::AbsReg(out, arg)
320 | RegOp::RecipReg(out, arg)
321 | RegOp::SqrtReg(out, arg)
322 | RegOp::SquareReg(out, arg)
323 | RegOp::FloorReg(out, arg)
324 | RegOp::CeilReg(out, arg)
325 | RegOp::RoundReg(out, arg)
326 | RegOp::CopyReg(out, arg)
327 | RegOp::SinReg(out, arg)
328 | RegOp::CosReg(out, arg)
329 | RegOp::TanReg(out, arg)
330 | RegOp::AsinReg(out, arg)
331 | RegOp::AcosReg(out, arg)
332 | RegOp::AtanReg(out, arg)
333 | RegOp::ExpReg(out, arg)
334 | RegOp::LnReg(out, arg)
335 | RegOp::NotReg(out, arg)
336 | RegOp::RandReg(out, arg) => {
337 f(out);
338 f(arg);
339 }
340 RegOp::AddRegImm(out, arg, imm)
341 | RegOp::MulRegImm(out, arg, imm)
342 | RegOp::DivRegImm(out, arg, imm)
343 | RegOp::DivImmReg(out, arg, imm)
344 | RegOp::SubImmReg(out, arg, imm)
345 | RegOp::SubRegImm(out, arg, imm)
346 | RegOp::AtanRegImm(out, arg, imm)
347 | RegOp::AtanImmReg(out, arg, imm)
348 | RegOp::MinRegImm(out, arg, imm)
349 | RegOp::MaxRegImm(out, arg, imm)
350 | RegOp::CompareRegImm(out, arg, imm)
351 | RegOp::CompareImmReg(out, arg, imm)
352 | RegOp::MixRegImm(out, arg, imm)
353 | RegOp::MixImmReg(out, arg, imm)
354 | RegOp::ModRegImm(out, arg, imm)
355 | RegOp::ModImmReg(out, arg, imm)
356 | RegOp::AndRegImm(out, arg, imm)
357 | RegOp::OrRegImm(out, arg, imm) => {
358 let _: f32 = *imm; f(out);
360 f(arg);
361 }
362
363 RegOp::AddRegReg(out, lhs, rhs)
364 | RegOp::MulRegReg(out, lhs, rhs)
365 | RegOp::DivRegReg(out, lhs, rhs)
366 | RegOp::SubRegReg(out, lhs, rhs)
367 | RegOp::AtanRegReg(out, lhs, rhs)
368 | RegOp::MinRegReg(out, lhs, rhs)
369 | RegOp::MaxRegReg(out, lhs, rhs)
370 | RegOp::CompareRegReg(out, lhs, rhs)
371 | RegOp::MixRegReg(out, lhs, rhs)
372 | RegOp::ModRegReg(out, lhs, rhs)
373 | RegOp::AndRegReg(out, lhs, rhs)
374 | RegOp::OrRegReg(out, lhs, rhs) => {
375 f(out);
376 f(lhs);
377 f(rhs);
378 }
379
380 RegOp::Output(reg, imm)
381 | RegOp::Input(reg, imm)
382 | RegOp::Store(reg, imm)
383 | RegOp::Load(reg, imm) => {
384 let _: u32 = *imm; f(reg)
386 }
387 }
388 }
389
390 pub fn visit_regs<F: FnMut(u8)>(&self, mut f: F) {
394 match self {
395 RegOp::CopyImm(out, imm) => {
396 let _: f32 = *imm;
397 f(*out)
398 }
399 RegOp::NegReg(out, arg)
400 | RegOp::AbsReg(out, arg)
401 | RegOp::RecipReg(out, arg)
402 | RegOp::SqrtReg(out, arg)
403 | RegOp::SquareReg(out, arg)
404 | RegOp::FloorReg(out, arg)
405 | RegOp::CeilReg(out, arg)
406 | RegOp::RoundReg(out, arg)
407 | RegOp::CopyReg(out, arg)
408 | RegOp::SinReg(out, arg)
409 | RegOp::CosReg(out, arg)
410 | RegOp::TanReg(out, arg)
411 | RegOp::AsinReg(out, arg)
412 | RegOp::AcosReg(out, arg)
413 | RegOp::AtanReg(out, arg)
414 | RegOp::ExpReg(out, arg)
415 | RegOp::LnReg(out, arg)
416 | RegOp::NotReg(out, arg)
417 | RegOp::RandReg(out, arg) => {
418 f(*out);
419 f(*arg);
420 }
421 RegOp::AddRegImm(out, arg, imm)
422 | RegOp::MulRegImm(out, arg, imm)
423 | RegOp::DivRegImm(out, arg, imm)
424 | RegOp::DivImmReg(out, arg, imm)
425 | RegOp::SubImmReg(out, arg, imm)
426 | RegOp::SubRegImm(out, arg, imm)
427 | RegOp::AtanRegImm(out, arg, imm)
428 | RegOp::AtanImmReg(out, arg, imm)
429 | RegOp::MinRegImm(out, arg, imm)
430 | RegOp::MaxRegImm(out, arg, imm)
431 | RegOp::CompareRegImm(out, arg, imm)
432 | RegOp::CompareImmReg(out, arg, imm)
433 | RegOp::MixRegImm(out, arg, imm)
434 | RegOp::MixImmReg(out, arg, imm)
435 | RegOp::ModRegImm(out, arg, imm)
436 | RegOp::ModImmReg(out, arg, imm)
437 | RegOp::AndRegImm(out, arg, imm)
438 | RegOp::OrRegImm(out, arg, imm) => {
439 let _: f32 = *imm; f(*out);
441 f(*arg);
442 }
443
444 RegOp::AddRegReg(out, lhs, rhs)
445 | RegOp::MulRegReg(out, lhs, rhs)
446 | RegOp::DivRegReg(out, lhs, rhs)
447 | RegOp::SubRegReg(out, lhs, rhs)
448 | RegOp::AtanRegReg(out, lhs, rhs)
449 | RegOp::MinRegReg(out, lhs, rhs)
450 | RegOp::MaxRegReg(out, lhs, rhs)
451 | RegOp::CompareRegReg(out, lhs, rhs)
452 | RegOp::MixRegReg(out, lhs, rhs)
453 | RegOp::ModRegReg(out, lhs, rhs)
454 | RegOp::AndRegReg(out, lhs, rhs)
455 | RegOp::OrRegReg(out, lhs, rhs) => {
456 f(*out);
457 f(*lhs);
458 f(*rhs);
459 }
460
461 RegOp::Output(reg, imm)
462 | RegOp::Input(reg, imm)
463 | RegOp::Store(reg, imm)
464 | RegOp::Load(reg, imm) => {
465 let _: u32 = *imm; f(*reg)
467 }
468 }
469 }
470}