Skip to main content

wowlab_engine_domain/rotation/bytecode/
instruction.rs

1//! Typed instructions and register identities for portable rotation bytecode.
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4pub(super) struct BoolRegister(pub(super) u32);
5
6impl BoolRegister {
7    pub(super) fn next(count: &mut u32) -> Self {
8        let value = Self(*count);
9
10        *count = count
11            .checked_add(1)
12            .expect("rotation bool register count exceeds u32");
13
14        value
15    }
16
17    #[expect(
18        clippy::trivially_copy_pass_by_ref,
19        reason = "the stable boolean-register conversion API borrows its receiver"
20    )]
21    pub(super) const fn as_usize(&self) -> usize {
22        self.0 as usize
23    }
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub(super) struct IntRegister(pub(super) u32);
28
29impl IntRegister {
30    pub(super) fn next(count: &mut u32) -> Self {
31        let value = Self(*count);
32
33        *count = count
34            .checked_add(1)
35            .expect("rotation int register count exceeds u32");
36
37        value
38    }
39
40    #[expect(
41        clippy::trivially_copy_pass_by_ref,
42        reason = "the stable integer-register conversion API borrows its receiver"
43    )]
44    pub(super) const fn as_usize(&self) -> usize {
45        self.0 as usize
46    }
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub(super) struct FloatRegister(pub(super) u32);
51
52impl FloatRegister {
53    pub(super) fn next(count: &mut u32) -> Self {
54        let value = Self(*count);
55
56        *count = count
57            .checked_add(1)
58            .expect("rotation float register count exceeds u32");
59
60        value
61    }
62
63    #[expect(
64        clippy::trivially_copy_pass_by_ref,
65        reason = "the stable float-register conversion API borrows its receiver"
66    )]
67    pub(super) const fn as_usize(&self) -> usize {
68        self.0 as usize
69    }
70}
71
72#[derive(Clone, Copy, Debug, Eq, PartialEq)]
73pub(super) struct InstructionAddress(pub(super) u32);
74
75impl InstructionAddress {
76    pub(super) const fn placeholder() -> Self {
77        Self(u32::MAX)
78    }
79
80    pub(super) fn from_len(len: usize) -> Self {
81        Self(u32::try_from(len).expect("rotation instruction count exceeds u32"))
82    }
83
84    #[expect(
85        clippy::trivially_copy_pass_by_ref,
86        reason = "the stable instruction-address conversion API borrows its receiver"
87    )]
88    pub(super) const fn as_usize(&self) -> usize {
89        self.0 as usize
90    }
91}
92
93#[derive(Clone, Copy, Debug, PartialEq)]
94pub(super) enum BoolValue {
95    Constant(bool),
96    Register(BoolRegister),
97}
98
99#[derive(Clone, Copy, Debug, PartialEq)]
100pub(super) enum IntValue {
101    Constant(i64),
102    Register(IntRegister),
103}
104
105#[derive(Clone, Copy, Debug, PartialEq)]
106pub(super) enum FloatValue {
107    Constant(f64),
108    Register(FloatRegister),
109}
110
111#[derive(Clone, Copy, Debug, Eq, PartialEq)]
112#[cfg(feature = "rotation-optimizations")]
113pub(super) enum FloatComparison {
114    Gt,
115    Gte,
116    Lt,
117    Lte,
118    Eq,
119    Ne,
120}
121
122#[derive(Clone, Copy, Debug, PartialEq)]
123pub(super) enum Instruction {
124    LoadBool {
125        target: BoolRegister,
126        offset: usize,
127    },
128    LoadI32 {
129        target: IntRegister,
130        offset: usize,
131    },
132    LoadF64 {
133        target: FloatRegister,
134        offset: usize,
135    },
136    StoreBool {
137        offset: usize,
138        value: BoolValue,
139    },
140    StoreI32 {
141        offset: usize,
142        value: IntValue,
143    },
144    StoreF64 {
145        offset: usize,
146        value: FloatValue,
147    },
148    #[cfg(not(feature = "rotation-optimizations"))]
149    Now {
150        target: FloatRegister,
151    },
152    AddF {
153        target: FloatRegister,
154        lhs: FloatValue,
155        rhs: FloatValue,
156    },
157    SubF {
158        target: FloatRegister,
159        lhs: FloatValue,
160        rhs: FloatValue,
161    },
162    MulF {
163        target: FloatRegister,
164        lhs: FloatValue,
165        rhs: FloatValue,
166    },
167    SafeDivF {
168        target: FloatRegister,
169        lhs: FloatValue,
170        rhs: FloatValue,
171    },
172    TrueModF {
173        target: FloatRegister,
174        lhs: FloatValue,
175        rhs: FloatValue,
176    },
177    MinF {
178        target: FloatRegister,
179        lhs: FloatValue,
180        rhs: FloatValue,
181    },
182    MaxF {
183        target: FloatRegister,
184        lhs: FloatValue,
185        rhs: FloatValue,
186    },
187    FloorF {
188        target: FloatRegister,
189        value: FloatValue,
190    },
191    CeilF {
192        target: FloatRegister,
193        value: FloatValue,
194    },
195    AbsF {
196        target: FloatRegister,
197        value: FloatValue,
198    },
199    CmpGtF {
200        target: BoolRegister,
201        lhs: FloatValue,
202        rhs: FloatValue,
203    },
204    CmpGteF {
205        target: BoolRegister,
206        lhs: FloatValue,
207        rhs: FloatValue,
208    },
209    CmpLtF {
210        target: BoolRegister,
211        lhs: FloatValue,
212        rhs: FloatValue,
213    },
214    CmpLteF {
215        target: BoolRegister,
216        lhs: FloatValue,
217        rhs: FloatValue,
218    },
219    CmpEqF {
220        target: BoolRegister,
221        lhs: FloatValue,
222        rhs: FloatValue,
223    },
224    CmpNeF {
225        target: BoolRegister,
226        lhs: FloatValue,
227        rhs: FloatValue,
228    },
229    CmpEqI {
230        target: BoolRegister,
231        lhs: IntValue,
232        rhs: IntValue,
233    },
234    CmpNeI {
235        target: BoolRegister,
236        lhs: IntValue,
237        rhs: IntValue,
238    },
239    CmpGtI {
240        target: BoolRegister,
241        lhs: IntValue,
242        rhs: IntValue,
243    },
244    CmpGteI {
245        target: BoolRegister,
246        lhs: IntValue,
247        rhs: IntValue,
248    },
249    CmpLtI {
250        target: BoolRegister,
251        lhs: IntValue,
252        rhs: IntValue,
253    },
254    CmpLteI {
255        target: BoolRegister,
256        lhs: IntValue,
257        rhs: IntValue,
258    },
259    AndB {
260        target: BoolRegister,
261        lhs: BoolValue,
262        rhs: BoolValue,
263    },
264    OrB {
265        target: BoolRegister,
266        lhs: BoolValue,
267        rhs: BoolValue,
268    },
269    SetBool {
270        target: BoolRegister,
271        value: bool,
272    },
273    JumpIf {
274        condition: BoolValue,
275        target: InstructionAddress,
276        when_true: bool,
277    },
278    #[cfg(feature = "rotation-optimizations")]
279    JumpIfBufferBool {
280        offset: usize,
281        target: InstructionAddress,
282        when_true: bool,
283    },
284    #[cfg(feature = "rotation-optimizations")]
285    JumpIfCooldownNotReady {
286        cooldown_offset: usize,
287        bypass_aura_offset: Option<usize>,
288        target: InstructionAddress,
289    },
290    #[cfg(feature = "rotation-optimizations")]
291    JumpIfTimestampStateMismatch {
292        offset: usize,
293        expected_active: bool,
294        target: InstructionAddress,
295    },
296    #[cfg(feature = "rotation-optimizations")]
297    JumpIfBufferF64ComparisonFalse {
298        offset: usize,
299        rhs: f64,
300        comparison: FloatComparison,
301        target: InstructionAddress,
302    },
303    NotB {
304        target: BoolRegister,
305        value: BoolValue,
306    },
307    BoolToFloat {
308        target: FloatRegister,
309        value: BoolValue,
310    },
311    BoolToInt {
312        target: IntRegister,
313        value: BoolValue,
314    },
315    IntToFloat {
316        target: FloatRegister,
317        value: IntValue,
318    },
319    IntToBool {
320        target: BoolRegister,
321        value: IntValue,
322    },
323    FloatToBool {
324        target: BoolRegister,
325        value: FloatValue,
326    },
327    FloatToInt {
328        target: IntRegister,
329        value: FloatValue,
330    },
331    SelectF {
332        target: FloatRegister,
333        condition: BoolValue,
334        if_true: FloatValue,
335        if_false: FloatValue,
336    },
337    SelectI {
338        target: IntRegister,
339        condition: BoolValue,
340        if_true: IntValue,
341        if_false: IntValue,
342    },
343    SelectB {
344        target: BoolRegister,
345        condition: BoolValue,
346        if_true: BoolValue,
347        if_false: BoolValue,
348    },
349    #[cfg(feature = "rotation-optimizations")]
350    ReturnCast {
351        spell_id: u32,
352        empower_rank: u8,
353    },
354    ReturnCastIf {
355        condition: BoolValue,
356        spell_id: u32,
357        empower_rank: u8,
358    },
359    ReturnWaitIf {
360        condition: BoolValue,
361        seconds: f32,
362    },
363    ReturnPoolIf {
364        condition: BoolValue,
365        target: f32,
366    },
367    ReturnUseItemIf {
368        condition: BoolValue,
369        gear_slot: u8,
370        empower_rank: u8,
371    },
372    ReturnNone,
373}