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
72 #[doc = "Add a register and an immediate"]
74 AddRegImm($t, $t, f32),
75 #[doc = "Multiply a register and an immediate"]
76 MulRegImm($t, $t, f32),
77 #[doc = "Divides a register and an immediate"]
78 DivRegImm($t, $t, f32),
79 #[doc = "Divides an immediate by a register"]
80 DivImmReg($t, $t, f32),
81 #[doc = "Subtract a register from an immediate"]
82 SubImmReg($t, $t, f32),
83 #[doc = "Subtract an immediate from a register"]
84 SubRegImm($t, $t, f32),
85 #[doc = "Take the module (least nonnegative remainder) of two registers"]
86 ModRegReg($t, $t, $t),
87 #[doc = "Take the module (least nonnegative remainder) of a register and an immediate"]
88 ModRegImm($t, $t, f32),
89 #[doc = "atan2 of a position `(y, x)` specified as register, immediate"]
90 AtanRegImm($t, $t, f32),
91 #[doc = "Compares a register with an immediate"]
92 CompareRegImm($t, $t, f32),
93
94 #[doc = "Compute the minimum of a register and an immediate"]
96 MinRegImm($t, $t, f32),
97 #[doc = "Compute the maximum of a register and an immediate"]
98 MaxRegImm($t, $t, f32),
99 #[doc = "Logical `AND` (short-circuiting)\n\nThis is equivalent to `if lhs == 0 { lhs } else { imm }`"]
100 AndRegImm($t, $t, f32),
101 #[doc = "Logical `OR` (short-circuiting)\n\nThis is equivalent to `if lhs != 0 { lhs } else { imm }`"]
102 OrRegImm($t, $t, f32),
103
104 #[doc = "Take the module (least nonnegative remainder) of an immediate and a register"]
106 ModImmReg($t, $t, f32),
107 #[doc = "atan2 of a position `(y, x)` specified as immediate, register"]
108 AtanImmReg($t, $t, f32),
109 #[doc = "Compares an immediate with a register"]
110 CompareImmReg($t, $t, f32),
111
112 #[doc = "Add two registers"]
114 AddRegReg($t, $t, $t),
115 #[doc = "Multiply two registers"]
116 MulRegReg($t, $t, $t),
117 #[doc = "Divides two registers"]
118 DivRegReg($t, $t, $t),
119 #[doc = "Subtract one register from another"]
120 SubRegReg($t, $t, $t),
121 #[doc = "Compares two registers"]
122 CompareRegReg($t, $t, $t),
123 #[doc = "atan2 of a position `(y, x)` specified as register, register"]
124 AtanRegReg($t, $t, $t),
125
126 #[doc = "Take the minimum of two registers"]
128 MinRegReg($t, $t, $t),
129 #[doc = "Take the maximum of two registers"]
130 MaxRegReg($t, $t, $t),
131 #[doc = "Logical `AND` (short-circuiting)\n\nThis is equivalent to `if lhs == 0 { lhs } else { rhs }`"]
132 AndRegReg($t, $t, $t),
133 #[doc = "Logical `OR` (short-circuiting)\n\nThis is equivalent to `if lhs != 0 { lhs } else { rhs }`"]
134 OrRegReg($t, $t, $t),
135
136 $(
137 $(#[$($a)*])*
138 $foo($($i),*)
139 ),*
140 }
141 };
142}
143
144opcodes!(
145 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
154 pub enum SsaOp<u32> {
155 }
157);
158
159impl SsaOp {
160 pub fn output(&self) -> Option<u32> {
162 match self {
163 SsaOp::Input(out, ..)
164 | SsaOp::CopyImm(out, ..)
165 | SsaOp::NegReg(out, ..)
166 | SsaOp::AbsReg(out, ..)
167 | SsaOp::RecipReg(out, ..)
168 | SsaOp::SqrtReg(out, ..)
169 | SsaOp::SquareReg(out, ..)
170 | SsaOp::FloorReg(out, ..)
171 | SsaOp::CeilReg(out, ..)
172 | SsaOp::RoundReg(out, ..)
173 | SsaOp::CopyReg(out, ..)
174 | SsaOp::SinReg(out, ..)
175 | SsaOp::CosReg(out, ..)
176 | SsaOp::TanReg(out, ..)
177 | SsaOp::AsinReg(out, ..)
178 | SsaOp::AcosReg(out, ..)
179 | SsaOp::AtanReg(out, ..)
180 | SsaOp::ExpReg(out, ..)
181 | SsaOp::LnReg(out, ..)
182 | SsaOp::NotReg(out, ..)
183 | SsaOp::AddRegImm(out, ..)
184 | SsaOp::MulRegImm(out, ..)
185 | SsaOp::DivRegImm(out, ..)
186 | SsaOp::DivImmReg(out, ..)
187 | SsaOp::SubImmReg(out, ..)
188 | SsaOp::SubRegImm(out, ..)
189 | SsaOp::AddRegReg(out, ..)
190 | SsaOp::MulRegReg(out, ..)
191 | SsaOp::DivRegReg(out, ..)
192 | SsaOp::SubRegReg(out, ..)
193 | SsaOp::AtanRegReg(out, ..)
194 | SsaOp::AtanRegImm(out, ..)
195 | SsaOp::AtanImmReg(out, ..)
196 | SsaOp::MinRegImm(out, ..)
197 | SsaOp::MaxRegImm(out, ..)
198 | SsaOp::MinRegReg(out, ..)
199 | SsaOp::MaxRegReg(out, ..)
200 | SsaOp::CompareRegReg(out, ..)
201 | SsaOp::CompareRegImm(out, ..)
202 | SsaOp::CompareImmReg(out, ..)
203 | SsaOp::ModRegReg(out, ..)
204 | SsaOp::ModRegImm(out, ..)
205 | SsaOp::ModImmReg(out, ..)
206 | SsaOp::AndRegImm(out, ..)
207 | SsaOp::AndRegReg(out, ..)
208 | SsaOp::OrRegImm(out, ..)
209 | SsaOp::OrRegReg(out, ..) => Some(*out),
210 SsaOp::Output(..) => None,
211 }
212 }
213 pub fn has_choice(&self) -> bool {
215 match self {
216 SsaOp::Input(..)
217 | SsaOp::Output(..)
218 | SsaOp::CopyImm(..)
219 | SsaOp::NegReg(..)
220 | SsaOp::AbsReg(..)
221 | SsaOp::RecipReg(..)
222 | SsaOp::SqrtReg(..)
223 | SsaOp::SquareReg(..)
224 | SsaOp::FloorReg(..)
225 | SsaOp::CeilReg(..)
226 | SsaOp::RoundReg(..)
227 | SsaOp::CopyReg(..)
228 | SsaOp::SinReg(..)
229 | SsaOp::CosReg(..)
230 | SsaOp::TanReg(..)
231 | SsaOp::AsinReg(..)
232 | SsaOp::AcosReg(..)
233 | SsaOp::AtanReg(..)
234 | SsaOp::ExpReg(..)
235 | SsaOp::LnReg(..)
236 | SsaOp::NotReg(..)
237 | SsaOp::AddRegImm(..)
238 | SsaOp::MulRegImm(..)
239 | SsaOp::SubRegImm(..)
240 | SsaOp::SubImmReg(..)
241 | SsaOp::AddRegReg(..)
242 | SsaOp::MulRegReg(..)
243 | SsaOp::SubRegReg(..)
244 | SsaOp::DivRegReg(..)
245 | SsaOp::DivRegImm(..)
246 | SsaOp::DivImmReg(..)
247 | SsaOp::AtanRegReg(..)
248 | SsaOp::AtanRegImm(..)
249 | SsaOp::AtanImmReg(..)
250 | SsaOp::CompareRegReg(..)
251 | SsaOp::CompareRegImm(..)
252 | SsaOp::CompareImmReg(..)
253 | SsaOp::ModRegReg(..)
254 | SsaOp::ModRegImm(..)
255 | SsaOp::ModImmReg(..) => false,
256 SsaOp::MinRegImm(..)
257 | SsaOp::MaxRegImm(..)
258 | SsaOp::MinRegReg(..)
259 | SsaOp::MaxRegReg(..)
260 | SsaOp::AndRegImm(..)
261 | SsaOp::AndRegReg(..)
262 | SsaOp::OrRegImm(..)
263 | SsaOp::OrRegReg(..) => true,
264 }
265 }
266}
267
268opcodes!(
269 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
282 pub enum RegOp<u8> {
283 Load(u8, u32),
286
287 Store(u8, u32),
289 }
290);
291
292impl RegOp {
293 pub fn visit_regs_mut<F: FnMut(&mut u8)>(&mut self, mut f: F) {
297 match self {
298 RegOp::CopyImm(out, imm) => {
299 let _: f32 = *imm;
300 f(out)
301 }
302 RegOp::NegReg(out, arg)
303 | RegOp::AbsReg(out, arg)
304 | RegOp::RecipReg(out, arg)
305 | RegOp::SqrtReg(out, arg)
306 | RegOp::SquareReg(out, arg)
307 | RegOp::FloorReg(out, arg)
308 | RegOp::CeilReg(out, arg)
309 | RegOp::RoundReg(out, arg)
310 | RegOp::CopyReg(out, arg)
311 | RegOp::SinReg(out, arg)
312 | RegOp::CosReg(out, arg)
313 | RegOp::TanReg(out, arg)
314 | RegOp::AsinReg(out, arg)
315 | RegOp::AcosReg(out, arg)
316 | RegOp::AtanReg(out, arg)
317 | RegOp::ExpReg(out, arg)
318 | RegOp::LnReg(out, arg)
319 | RegOp::NotReg(out, arg) => {
320 f(out);
321 f(arg);
322 }
323 RegOp::AddRegImm(out, arg, imm)
324 | RegOp::MulRegImm(out, arg, imm)
325 | RegOp::DivRegImm(out, arg, imm)
326 | RegOp::DivImmReg(out, arg, imm)
327 | RegOp::SubImmReg(out, arg, imm)
328 | RegOp::SubRegImm(out, arg, imm)
329 | RegOp::AtanRegImm(out, arg, imm)
330 | RegOp::AtanImmReg(out, arg, imm)
331 | RegOp::MinRegImm(out, arg, imm)
332 | RegOp::MaxRegImm(out, arg, imm)
333 | RegOp::CompareRegImm(out, arg, imm)
334 | RegOp::CompareImmReg(out, arg, imm)
335 | RegOp::ModRegImm(out, arg, imm)
336 | RegOp::ModImmReg(out, arg, imm)
337 | RegOp::AndRegImm(out, arg, imm)
338 | RegOp::OrRegImm(out, arg, imm) => {
339 let _: f32 = *imm; f(out);
341 f(arg);
342 }
343
344 RegOp::AddRegReg(out, lhs, rhs)
345 | RegOp::MulRegReg(out, lhs, rhs)
346 | RegOp::DivRegReg(out, lhs, rhs)
347 | RegOp::SubRegReg(out, lhs, rhs)
348 | RegOp::AtanRegReg(out, lhs, rhs)
349 | RegOp::MinRegReg(out, lhs, rhs)
350 | RegOp::MaxRegReg(out, lhs, rhs)
351 | RegOp::CompareRegReg(out, lhs, rhs)
352 | RegOp::ModRegReg(out, lhs, rhs)
353 | RegOp::AndRegReg(out, lhs, rhs)
354 | RegOp::OrRegReg(out, lhs, rhs) => {
355 f(out);
356 f(lhs);
357 f(rhs);
358 }
359
360 RegOp::Output(reg, imm)
361 | RegOp::Input(reg, imm)
362 | RegOp::Store(reg, imm)
363 | RegOp::Load(reg, imm) => {
364 let _: u32 = *imm; f(reg)
366 }
367 }
368 }
369
370 pub fn visit_regs<F: FnMut(u8)>(&self, mut f: F) {
374 match self {
375 RegOp::CopyImm(out, imm) => {
376 let _: f32 = *imm;
377 f(*out)
378 }
379 RegOp::NegReg(out, arg)
380 | RegOp::AbsReg(out, arg)
381 | RegOp::RecipReg(out, arg)
382 | RegOp::SqrtReg(out, arg)
383 | RegOp::SquareReg(out, arg)
384 | RegOp::FloorReg(out, arg)
385 | RegOp::CeilReg(out, arg)
386 | RegOp::RoundReg(out, arg)
387 | RegOp::CopyReg(out, arg)
388 | RegOp::SinReg(out, arg)
389 | RegOp::CosReg(out, arg)
390 | RegOp::TanReg(out, arg)
391 | RegOp::AsinReg(out, arg)
392 | RegOp::AcosReg(out, arg)
393 | RegOp::AtanReg(out, arg)
394 | RegOp::ExpReg(out, arg)
395 | RegOp::LnReg(out, arg)
396 | RegOp::NotReg(out, arg) => {
397 f(*out);
398 f(*arg);
399 }
400 RegOp::AddRegImm(out, arg, imm)
401 | RegOp::MulRegImm(out, arg, imm)
402 | RegOp::DivRegImm(out, arg, imm)
403 | RegOp::DivImmReg(out, arg, imm)
404 | RegOp::SubImmReg(out, arg, imm)
405 | RegOp::SubRegImm(out, arg, imm)
406 | RegOp::AtanRegImm(out, arg, imm)
407 | RegOp::AtanImmReg(out, arg, imm)
408 | RegOp::MinRegImm(out, arg, imm)
409 | RegOp::MaxRegImm(out, arg, imm)
410 | RegOp::CompareRegImm(out, arg, imm)
411 | RegOp::CompareImmReg(out, arg, imm)
412 | RegOp::ModRegImm(out, arg, imm)
413 | RegOp::ModImmReg(out, arg, imm)
414 | RegOp::AndRegImm(out, arg, imm)
415 | RegOp::OrRegImm(out, arg, imm) => {
416 let _: f32 = *imm; f(*out);
418 f(*arg);
419 }
420
421 RegOp::AddRegReg(out, lhs, rhs)
422 | RegOp::MulRegReg(out, lhs, rhs)
423 | RegOp::DivRegReg(out, lhs, rhs)
424 | RegOp::SubRegReg(out, lhs, rhs)
425 | RegOp::AtanRegReg(out, lhs, rhs)
426 | RegOp::MinRegReg(out, lhs, rhs)
427 | RegOp::MaxRegReg(out, lhs, rhs)
428 | RegOp::CompareRegReg(out, lhs, rhs)
429 | RegOp::ModRegReg(out, lhs, rhs)
430 | RegOp::AndRegReg(out, lhs, rhs)
431 | RegOp::OrRegReg(out, lhs, rhs) => {
432 f(*out);
433 f(*lhs);
434 f(*rhs);
435 }
436
437 RegOp::Output(reg, imm)
438 | RegOp::Input(reg, imm)
439 | RegOp::Store(reg, imm)
440 | RegOp::Load(reg, imm) => {
441 let _: u32 = *imm; f(*reg)
443 }
444 }
445 }
446}