binaryninja/low_level_il/
operation.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use binaryninjacore_sys::{
16    BNGetCachedLowLevelILPossibleValueSet, BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList,
17    BNLowLevelILGetOperandList, BNLowLevelILInstruction,
18};
19
20use super::*;
21use crate::architecture::{
22    CoreFlag, CoreFlagGroup, CoreFlagWrite, CoreIntrinsic, CoreRegister, CoreRegisterStack,
23    FlagGroupId, FlagId, FlagWriteId, IntrinsicId, RegisterStackId,
24};
25use crate::variable::PossibleValueSet;
26use std::collections::BTreeMap;
27use std::fmt::{Debug, Formatter};
28use std::marker::PhantomData;
29use std::mem;
30
31pub struct Operation<'func, M, F, O>
32where
33    M: FunctionMutability,
34    F: FunctionForm,
35    O: OperationArguments,
36{
37    pub(crate) function: &'func LowLevelILFunction<M, F>,
38    pub(crate) op: BNLowLevelILInstruction,
39    pub(crate) expr_idx: LowLevelExpressionIndex,
40    _args: PhantomData<O>,
41}
42
43impl<'func, M, F, O> Operation<'func, M, F, O>
44where
45    M: FunctionMutability,
46    F: FunctionForm,
47    O: OperationArguments,
48{
49    pub(crate) fn new(
50        function: &'func LowLevelILFunction<M, F>,
51        op: BNLowLevelILInstruction,
52        expr_idx: LowLevelExpressionIndex,
53    ) -> Self {
54        Self {
55            function,
56            op,
57            expr_idx,
58            _args: PhantomData,
59        }
60    }
61
62    pub fn address(&self) -> u64 {
63        self.op.address
64    }
65
66    fn get_operand_list(&self, operand_idx: usize) -> Vec<u64> {
67        let mut count = 0;
68        let raw_list_ptr = unsafe {
69            BNLowLevelILGetOperandList(
70                self.function.handle,
71                self.expr_idx.0,
72                operand_idx,
73                &mut count,
74            )
75        };
76        assert!(!raw_list_ptr.is_null());
77        let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() };
78        unsafe { BNLowLevelILFreeOperandList(raw_list_ptr) };
79        list
80    }
81
82    fn get_constraint(&self, operand_idx: usize) -> PossibleValueSet {
83        let raw_pvs = unsafe {
84            BNGetCachedLowLevelILPossibleValueSet(
85                self.function.handle,
86                self.op.operands[operand_idx] as usize,
87            )
88        };
89        PossibleValueSet::from_owned_core_raw(raw_pvs)
90    }
91
92    /// Get the raw operand from the operand list.
93    ///
94    /// This has no type information associated with it. It's up to the caller to know what the correct type of the
95    /// underlying u64 should be.
96    ///
97    /// # Panic
98    /// `idx` must be less than 4. This is to protect against an out of bounds access.
99    ///
100    /// # Safety
101    /// Even if `idx` is valid, it may index to an uninitialized or unused value. Make sure you index into an operand that
102    /// you know should be initialized properly.
103    pub unsafe fn get_operand(&self, idx: usize) -> u64 {
104        assert!(idx < 4);
105        self.op.operands[idx]
106    }
107}
108
109impl<M, O> Operation<'_, M, NonSSA, O>
110where
111    M: FunctionMutability,
112    O: OperationArguments,
113{
114    /// Get the [`CoreFlagWrite`] for the operation.
115    ///
116    /// NOTE: This is only expected to be present for lifted IL.
117    pub fn flag_write(&self) -> Option<CoreFlagWrite> {
118        match self.op.flags {
119            0 => None,
120            id => self.function.arch().flag_write_from_id(FlagWriteId(id)),
121        }
122    }
123}
124
125// LLIL_NOP, LLIL_NORET, LLIL_BP, LLIL_UNDEF, LLIL_UNIMPL
126pub struct NoArgs;
127
128impl<M, F> Debug for Operation<'_, M, F, NoArgs>
129where
130    M: FunctionMutability,
131    F: FunctionForm,
132{
133    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
134        f.debug_struct("NoArgs").finish()
135    }
136}
137
138// LLIL_POP
139pub struct Pop;
140
141impl<M, F> Operation<'_, M, F, Pop>
142where
143    M: FunctionMutability,
144    F: FunctionForm,
145{
146    pub fn size(&self) -> usize {
147        self.op.size
148    }
149}
150
151impl<M, F> Debug for Operation<'_, M, F, Pop>
152where
153    M: FunctionMutability,
154    F: FunctionForm,
155{
156    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157        f.debug_struct("Pop")
158            .field("address", &self.address())
159            .field("size", &self.size())
160            .finish()
161    }
162}
163
164// LLIL_SYSCALL
165pub struct Syscall;
166
167impl<M, F> Debug for Operation<'_, M, F, Syscall>
168where
169    M: FunctionMutability,
170    F: FunctionForm,
171{
172    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173        f.debug_struct("Syscall").finish()
174    }
175}
176
177// LLIL_SYSCALL_SSA
178pub struct SyscallSsa;
179
180impl<'func, M, F> Operation<'func, M, F, SyscallSsa>
181where
182    M: FunctionMutability,
183    F: FunctionForm,
184{
185    /// Get the output expression of the call.
186    ///
187    /// NOTE: This is currently always [`CallOutputSsa`].
188    pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
189        LowLevelILExpression::new(
190            self.function,
191            LowLevelExpressionIndex(self.op.operands[0] as usize),
192        )
193    }
194
195    /// Get the parameter expression of the call.
196    ///
197    /// NOTE: This is currently always [`CallParamSsa`].
198    pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
199        LowLevelILExpression::new(
200            self.function,
201            LowLevelExpressionIndex(self.op.operands[2] as usize),
202        )
203    }
204
205    /// Get the stack expression of the call.
206    ///
207    /// NOTE: This is currently always [`CallStackSsa`].
208    pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
209        LowLevelILExpression::new(
210            self.function,
211            LowLevelExpressionIndex(self.op.operands[1] as usize),
212        )
213    }
214}
215
216impl<M, F> Debug for Operation<'_, M, F, SyscallSsa>
217where
218    M: FunctionMutability,
219    F: FunctionForm,
220{
221    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
222        f.debug_struct("SyscallSsa")
223            .field("output_expr", &self.output_expr())
224            .field("param_expr", &self.param_expr())
225            .field("stack_expr", &self.stack_expr())
226            .finish()
227    }
228}
229
230// LLIL_INTRINSIC, LLIL_INTRINSIC_SSA
231pub struct Intrinsic;
232
233#[derive(Debug, Clone, Copy, PartialEq)]
234pub enum IntrinsicOutput {
235    Reg(CoreRegister),
236    Flag(CoreFlag),
237}
238
239impl From<CoreRegister> for IntrinsicOutput {
240    fn from(value: CoreRegister) -> Self {
241        Self::Reg(value)
242    }
243}
244
245impl From<CoreFlag> for IntrinsicOutput {
246    fn from(value: CoreFlag) -> Self {
247        Self::Flag(value)
248    }
249}
250
251impl<M, F> Operation<'_, M, F, Intrinsic>
252where
253    M: FunctionMutability,
254    F: FunctionForm,
255{
256    pub fn intrinsic(&self) -> Option<CoreIntrinsic> {
257        let raw_id = self.op.operands[2] as u32;
258        self.function.arch().intrinsic_from_id(IntrinsicId(raw_id))
259    }
260
261    /// Get the output list.
262    pub fn outputs(&self) -> Vec<IntrinsicOutput> {
263        // Convert the operand to either a register or flag id.
264        let operand_to_output = |o: u64| {
265            if o & (1 << 32) != 0 {
266                self.function
267                    .arch()
268                    .flag_from_id(FlagId((o & 0xffffffff) as u32))
269                    .expect("Invalid core flag ID")
270                    .into()
271            } else {
272                self.function
273                    .arch()
274                    .register_from_id(RegisterId((o & 0xffffffff) as u32))
275                    .expect("Invalid register ID")
276                    .into()
277            }
278        };
279
280        self.get_operand_list(0)
281            .into_iter()
282            .map(operand_to_output)
283            .collect::<Vec<_>>()
284    }
285
286    /// Get the input list for the intrinsic.
287    ///
288    /// This will just be a CallParamSsa expression.
289    #[inline]
290    pub fn inputs(&self) -> LowLevelILExpression<'_, M, F, ValueExpr> {
291        LowLevelILExpression::new(
292            self.function,
293            LowLevelExpressionIndex(self.op.operands[3] as usize),
294        )
295    }
296}
297
298impl<M, F> Debug for Operation<'_, M, F, Intrinsic>
299where
300    M: FunctionMutability,
301    F: FunctionForm,
302{
303    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
304        use crate::architecture::Intrinsic;
305        f.debug_struct("Intrinsic")
306            .field("address", &self.address())
307            .field(
308                "intrinsic",
309                &self.intrinsic().expect("Valid intrinsic").name(),
310            )
311            .field("outputs", &self.outputs())
312            .field("inputs", &self.inputs())
313            .finish()
314    }
315}
316
317// LLIL_SET_REG
318pub struct SetReg;
319
320impl<'func, M, F> Operation<'func, M, F, SetReg>
321where
322    M: FunctionMutability,
323    F: FunctionForm,
324{
325    pub fn size(&self) -> usize {
326        self.op.size
327    }
328
329    pub fn dest_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
330        let raw_id = RegisterId(self.op.operands[0] as u32);
331        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
332    }
333
334    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
335        LowLevelILExpression::new(
336            self.function,
337            LowLevelExpressionIndex(self.op.operands[1] as usize),
338        )
339    }
340}
341
342impl<M, F> Debug for Operation<'_, M, F, SetReg>
343where
344    M: FunctionMutability,
345    F: FunctionForm,
346{
347    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
348        f.debug_struct("SetReg")
349            .field("address", &self.address())
350            .field("size", &self.size())
351            .field("dest_reg", &self.dest_reg())
352            .field("source_expr", &self.source_expr())
353            .finish()
354    }
355}
356
357// LLIL_SET_REG_SSA
358pub struct SetRegSsa;
359
360impl<'func, M, F> Operation<'func, M, F, SetRegSsa>
361where
362    M: FunctionMutability,
363    F: FunctionForm,
364{
365    pub fn size(&self) -> usize {
366        self.op.size
367    }
368
369    pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
370        let raw_id = RegisterId(self.op.operands[0] as u32);
371        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
372            .expect("Bad register ID");
373        let version = self.op.operands[1] as u32;
374        LowLevelILSSARegisterKind::new_full(reg_kind, version)
375    }
376
377    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
378        LowLevelILExpression::new(
379            self.function,
380            LowLevelExpressionIndex(self.op.operands[2] as usize),
381        )
382    }
383}
384
385impl<M, F> Debug for Operation<'_, M, F, SetRegSsa>
386where
387    M: FunctionMutability,
388    F: FunctionForm,
389{
390    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
391        f.debug_struct("SetRegSsa")
392            .field("address", &self.address())
393            .field("size", &self.size())
394            .field("dest_reg", &self.dest_reg())
395            .field("source_expr", &self.source_expr())
396            .finish()
397    }
398}
399
400// LLIL_SET_REG_PARTIAL_SSA
401pub struct SetRegPartialSsa;
402
403impl<'func, M, F> Operation<'func, M, F, SetRegPartialSsa>
404where
405    M: FunctionMutability,
406    F: FunctionForm,
407{
408    pub fn size(&self) -> usize {
409        self.op.size
410    }
411
412    pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
413        let full_raw_id = RegisterId(self.op.operands[0] as u32);
414        let version = self.op.operands[1] as u32;
415        let partial_raw_id = RegisterId(self.op.operands[2] as u32);
416        let full_reg =
417            CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID");
418        let partial_reg =
419            CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID");
420        LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version)
421    }
422
423    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
424        LowLevelILExpression::new(
425            self.function,
426            LowLevelExpressionIndex(self.op.operands[3] as usize),
427        )
428    }
429}
430
431impl<M, F> Debug for Operation<'_, M, F, SetRegPartialSsa>
432where
433    M: FunctionMutability,
434    F: FunctionForm,
435{
436    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
437        f.debug_struct("SetRegPartialSsa")
438            .field("address", &self.address())
439            .field("size", &self.size())
440            .field("dest_reg", &self.dest_reg())
441            .field("source_expr", &self.source_expr())
442            .finish()
443    }
444}
445
446// LLIL_SET_REG_SPLIT
447pub struct SetRegSplit;
448
449impl<'func, M, F> Operation<'func, M, F, SetRegSplit>
450where
451    M: FunctionMutability,
452    F: FunctionForm,
453{
454    pub fn size(&self) -> usize {
455        self.op.size
456    }
457
458    pub fn dest_reg_high(&self) -> LowLevelILRegisterKind<CoreRegister> {
459        let raw_id = RegisterId(self.op.operands[0] as u32);
460        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
461    }
462
463    pub fn dest_reg_low(&self) -> LowLevelILRegisterKind<CoreRegister> {
464        let raw_id = RegisterId(self.op.operands[1] as u32);
465        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
466    }
467
468    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
469        LowLevelILExpression::new(
470            self.function,
471            LowLevelExpressionIndex(self.op.operands[2] as usize),
472        )
473    }
474}
475
476impl<M, F> Debug for Operation<'_, M, F, SetRegSplit>
477where
478    M: FunctionMutability,
479    F: FunctionForm,
480{
481    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
482        f.debug_struct("SetRegSplit")
483            .field("address", &self.address())
484            .field("size", &self.size())
485            .field("dest_reg_high", &self.dest_reg_high())
486            .field("dest_reg_low", &self.dest_reg_low())
487            .field("source_expr", &self.source_expr())
488            .finish()
489    }
490}
491
492// LLIL_SET_REG_SPLIT_SSA
493pub struct SetRegSplitSsa;
494
495impl<'func, M, F> Operation<'func, M, F, SetRegSplitSsa>
496where
497    M: FunctionMutability,
498    F: FunctionForm,
499{
500    pub fn size(&self) -> usize {
501        self.op.size
502    }
503
504    /// Because of the fixed operand list size we use another expression for the dest high register.
505    ///
506    /// NOTE: This should always be an expression of [`RegSsa`].
507    pub fn dest_expr_high(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
508        LowLevelILExpression::new(
509            self.function,
510            LowLevelExpressionIndex(self.op.operands[0] as usize),
511        )
512    }
513
514    /// Because of the fixed operand list size we use another expression for the dest low register.
515    ///
516    /// NOTE: This should always be an expression of [`RegSsa`].
517    pub fn dest_expr_low(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
518        LowLevelILExpression::new(
519            self.function,
520            LowLevelExpressionIndex(self.op.operands[1] as usize),
521        )
522    }
523
524    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
525        LowLevelILExpression::new(
526            self.function,
527            LowLevelExpressionIndex(self.op.operands[2] as usize),
528        )
529    }
530}
531
532impl<M, F> Debug for Operation<'_, M, F, SetRegSplitSsa>
533where
534    M: FunctionMutability,
535    F: FunctionForm,
536{
537    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
538        f.debug_struct("SetRegSplitSsa")
539            .field("address", &self.address())
540            .field("size", &self.size())
541            .field("dest_expr_high", &self.dest_expr_high())
542            .field("dest_expr_low", &self.dest_expr_low())
543            .field("source_expr", &self.source_expr())
544            .finish()
545    }
546}
547
548// LLIL_SET_FLAG
549pub struct SetFlag;
550
551impl<'func, M, F> Operation<'func, M, F, SetFlag>
552where
553    M: FunctionMutability,
554    F: FunctionForm,
555{
556    pub fn dest_flag(&self) -> CoreFlag {
557        self.function
558            .arch()
559            .flag_from_id(FlagId(self.op.operands[0] as u32))
560            .expect("Bad flag ID")
561    }
562
563    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
564        LowLevelILExpression::new(
565            self.function,
566            LowLevelExpressionIndex(self.op.operands[1] as usize),
567        )
568    }
569}
570
571impl<M, F> Debug for Operation<'_, M, F, SetFlag>
572where
573    M: FunctionMutability,
574    F: FunctionForm,
575{
576    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
577        f.debug_struct("SetFlag")
578            .field("address", &self.address())
579            .field("dest_flag", &self.dest_flag())
580            .field("source_expr", &self.source_expr())
581            .finish()
582    }
583}
584
585// LLIL_SET_FLAG_SSA
586pub struct SetFlagSsa;
587
588impl<'func, M, F> Operation<'func, M, F, SetFlagSsa>
589where
590    M: FunctionMutability,
591    F: FunctionForm,
592{
593    pub fn dest_flag(&self) -> LowLevelILSSAFlag<CoreFlag> {
594        let flag = self
595            .function
596            .arch()
597            .flag_from_id(FlagId(self.op.operands[0] as u32))
598            .expect("Bad flag ID");
599        let version = self.op.operands[1] as u32;
600        LowLevelILSSAFlag::new(flag, version)
601    }
602
603    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
604        LowLevelILExpression::new(
605            self.function,
606            LowLevelExpressionIndex(self.op.operands[2] as usize),
607        )
608    }
609}
610
611impl<M, F> Debug for Operation<'_, M, F, SetFlagSsa>
612where
613    M: FunctionMutability,
614    F: FunctionForm,
615{
616    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
617        f.debug_struct("SetFlagSsa")
618            .field("address", &self.address())
619            .field("dest_flag", &self.dest_flag())
620            .field("source_expr", &self.source_expr())
621            .finish()
622    }
623}
624// LLIL_LOAD
625pub struct Load;
626
627impl<'func, M, F> Operation<'func, M, F, Load>
628where
629    M: FunctionMutability,
630    F: FunctionForm,
631{
632    pub fn size(&self) -> usize {
633        self.op.size
634    }
635
636    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
637        LowLevelILExpression::new(
638            self.function,
639            LowLevelExpressionIndex(self.op.operands[0] as usize),
640        )
641    }
642}
643
644impl<M, F> Debug for Operation<'_, M, F, Load>
645where
646    M: FunctionMutability,
647    F: FunctionForm,
648{
649    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
650        f.debug_struct("Load")
651            .field("address", &self.address())
652            .field("size", &self.size())
653            .field("source_expr", &self.source_expr())
654            .finish()
655    }
656}
657
658// LLIL_LOAD_SSA
659pub struct LoadSsa;
660
661impl<'func, M, F> Operation<'func, M, F, LoadSsa>
662where
663    M: FunctionMutability,
664    F: FunctionForm,
665{
666    pub fn size(&self) -> usize {
667        self.op.size
668    }
669
670    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
671        LowLevelILExpression::new(
672            self.function,
673            LowLevelExpressionIndex(self.op.operands[0] as usize),
674        )
675    }
676
677    pub fn source_memory_version(&self) -> u64 {
678        self.op.operands[1]
679    }
680}
681
682impl<M, F> Debug for Operation<'_, M, F, LoadSsa>
683where
684    M: FunctionMutability,
685    F: FunctionForm,
686{
687    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
688        f.debug_struct("LoadSsa")
689            .field("address", &self.address())
690            .field("size", &self.size())
691            .field("source_expr", &self.source_expr())
692            .finish()
693    }
694}
695
696// LLIL_STORE
697pub struct Store;
698
699impl<'func, M, F> Operation<'func, M, F, Store>
700where
701    M: FunctionMutability,
702    F: FunctionForm,
703{
704    pub fn size(&self) -> usize {
705        self.op.size
706    }
707
708    pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
709        LowLevelILExpression::new(
710            self.function,
711            LowLevelExpressionIndex(self.op.operands[0] as usize),
712        )
713    }
714
715    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
716        LowLevelILExpression::new(
717            self.function,
718            LowLevelExpressionIndex(self.op.operands[1] as usize),
719        )
720    }
721}
722
723impl<M, F> Debug for Operation<'_, M, F, Store>
724where
725    M: FunctionMutability,
726    F: FunctionForm,
727{
728    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
729        f.debug_struct("Store")
730            .field("address", &self.address())
731            .field("size", &self.size())
732            .field("dest_expr", &self.dest_expr())
733            .field("source_expr", &self.source_expr())
734            .finish()
735    }
736}
737
738// LLIL_STORE_SSA
739pub struct StoreSsa;
740
741impl<'func, M, F> Operation<'func, M, F, StoreSsa>
742where
743    M: FunctionMutability,
744    F: FunctionForm,
745{
746    pub fn size(&self) -> usize {
747        self.op.size
748    }
749
750    pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
751        LowLevelILExpression::new(
752            self.function,
753            LowLevelExpressionIndex(self.op.operands[0] as usize),
754        )
755    }
756
757    pub fn dest_memory_version(&self) -> u64 {
758        self.op.operands[1]
759    }
760
761    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
762        LowLevelILExpression::new(
763            self.function,
764            LowLevelExpressionIndex(self.op.operands[3] as usize),
765        )
766    }
767
768    pub fn source_memory_version(&self) -> u64 {
769        self.op.operands[2]
770    }
771}
772
773impl<M, F> Debug for Operation<'_, M, F, StoreSsa>
774where
775    M: FunctionMutability,
776    F: FunctionForm,
777{
778    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
779        f.debug_struct("StoreSsa")
780            .field("address", &self.address())
781            .field("size", &self.size())
782            .field("dest_expr", &self.dest_expr())
783            .field("source_expr", &self.source_expr())
784            .finish()
785    }
786}
787
788// LLIL_REG
789pub struct Reg;
790
791impl<M, F> Operation<'_, M, F, Reg>
792where
793    M: FunctionMutability,
794    F: FunctionForm,
795{
796    pub fn size(&self) -> usize {
797        self.op.size
798    }
799
800    pub fn source_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
801        let raw_id = RegisterId(self.op.operands[0] as u32);
802        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
803    }
804}
805
806impl<M, F> Debug for Operation<'_, M, F, Reg>
807where
808    M: FunctionMutability,
809    F: FunctionForm,
810{
811    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
812        f.debug_struct("Reg")
813            .field("address", &self.address())
814            .field("size", &self.size())
815            .field("source_reg", &self.source_reg())
816            .finish()
817    }
818}
819
820// LLIL_REG_SSA
821pub struct RegSsa;
822
823impl<M, F> Operation<'_, M, F, RegSsa>
824where
825    M: FunctionMutability,
826    F: FunctionForm,
827{
828    pub fn size(&self) -> usize {
829        self.op.size
830    }
831
832    pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
833        let raw_id = RegisterId(self.op.operands[0] as u32);
834        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
835            .expect("Bad register ID");
836        let version = self.op.operands[1] as u32;
837        LowLevelILSSARegisterKind::new_full(reg_kind, version)
838    }
839}
840
841impl<M, F> Debug for Operation<'_, M, F, RegSsa>
842where
843    M: FunctionMutability,
844    F: FunctionForm,
845{
846    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
847        f.debug_struct("RegSsa")
848            .field("address", &self.address())
849            .field("size", &self.size())
850            .field("source_reg", &self.source_reg())
851            .finish()
852    }
853}
854
855// LLIL_REG_SSA_PARTIAL
856pub struct RegPartialSsa;
857
858impl<M, F> Operation<'_, M, F, RegPartialSsa>
859where
860    M: FunctionMutability,
861    F: FunctionForm,
862{
863    pub fn size(&self) -> usize {
864        self.op.size
865    }
866
867    pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
868        let full_raw_id = RegisterId(self.op.operands[0] as u32);
869        let version = self.op.operands[1] as u32;
870        let partial_raw_id = RegisterId(self.op.operands[2] as u32);
871        let full_reg =
872            CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID");
873        let partial_reg =
874            CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID");
875        LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version)
876    }
877}
878
879impl<M, F> Debug for Operation<'_, M, F, RegPartialSsa>
880where
881    M: FunctionMutability,
882    F: FunctionForm,
883{
884    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
885        f.debug_struct("RegPartialSsa")
886            .field("address", &self.address())
887            .field("size", &self.size())
888            .field("source_reg", &self.source_reg())
889            .finish()
890    }
891}
892
893// LLIL_REG_SPLIT
894pub struct RegSplit;
895
896impl<M, F> Operation<'_, M, F, RegSplit>
897where
898    M: FunctionMutability,
899    F: FunctionForm,
900{
901    pub fn size(&self) -> usize {
902        self.op.size
903    }
904
905    pub fn low_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
906        let raw_id = RegisterId(self.op.operands[0] as u32);
907        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
908    }
909
910    pub fn high_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
911        let raw_id = RegisterId(self.op.operands[1] as u32);
912        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
913    }
914}
915
916impl<M, F> Debug for Operation<'_, M, F, RegSplit>
917where
918    M: FunctionMutability,
919    F: FunctionForm,
920{
921    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
922        f.debug_struct("RegSplit")
923            .field("address", &self.address())
924            .field("size", &self.size())
925            .field("low_reg", &self.low_reg())
926            .field("high_reg", &self.high_reg())
927            .finish()
928    }
929}
930
931// LLIL_REG_SPLIT_SSA
932pub struct RegSplitSsa;
933
934impl<M, F> Operation<'_, M, F, RegSplitSsa>
935where
936    M: FunctionMutability,
937    F: FunctionForm,
938{
939    pub fn size(&self) -> usize {
940        self.op.size
941    }
942
943    pub fn low_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
944        let raw_id = RegisterId(self.op.operands[0] as u32);
945        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
946            .expect("Bad register ID");
947        let version = self.op.operands[1] as u32;
948        LowLevelILSSARegisterKind::new_full(reg_kind, version)
949    }
950
951    pub fn high_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
952        let raw_id = RegisterId(self.op.operands[2] as u32);
953        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
954            .expect("Bad register ID");
955        let version = self.op.operands[3] as u32;
956        LowLevelILSSARegisterKind::new_full(reg_kind, version)
957    }
958}
959
960impl<M, F> Debug for Operation<'_, M, F, RegSplitSsa>
961where
962    M: FunctionMutability,
963    F: FunctionForm,
964{
965    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
966        f.debug_struct("RegSplitSsa")
967            .field("address", &self.address())
968            .field("size", &self.size())
969            .field("low_reg", &self.low_reg())
970            .field("high_reg", &self.high_reg())
971            .finish()
972    }
973}
974
975// LLIL_REG_STACK_PUSH
976pub struct RegStackPush;
977
978impl<'func, M, F> Operation<'func, M, F, RegStackPush>
979where
980    M: FunctionMutability,
981    F: FunctionForm,
982{
983    pub fn size(&self) -> usize {
984        self.op.size
985    }
986
987    pub fn dest_reg_stack(&self) -> CoreRegisterStack {
988        let raw_id = self.op.operands[0] as u32;
989        self.function
990            .arch()
991            .register_stack_from_id(RegisterStackId(raw_id))
992            .expect("Bad register stack ID")
993    }
994
995    pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
996        LowLevelILExpression::new(
997            self.function,
998            LowLevelExpressionIndex(self.op.operands[1] as usize),
999        )
1000    }
1001}
1002
1003impl<M, F> Debug for Operation<'_, M, F, RegStackPush>
1004where
1005    M: FunctionMutability,
1006    F: FunctionForm,
1007{
1008    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1009        f.debug_struct("RegStackPush")
1010            .field("address", &self.address())
1011            .field("size", &self.size())
1012            .field("dest_reg_stack", &self.dest_reg_stack())
1013            .field("source_expr", &self.source_expr())
1014            .finish()
1015    }
1016}
1017
1018// LLIL_REG_STACK_POP
1019pub struct RegStackPop;
1020
1021impl<M, F> Operation<'_, M, F, RegStackPop>
1022where
1023    M: FunctionMutability,
1024    F: FunctionForm,
1025{
1026    pub fn size(&self) -> usize {
1027        self.op.size
1028    }
1029
1030    pub fn source_reg_stack(&self) -> CoreRegisterStack {
1031        let raw_id = self.op.operands[0] as u32;
1032        self.function
1033            .arch()
1034            .register_stack_from_id(RegisterStackId(raw_id))
1035            .expect("Bad register stack ID")
1036    }
1037}
1038
1039impl<M, F> Debug for Operation<'_, M, F, RegStackPop>
1040where
1041    M: FunctionMutability,
1042    F: FunctionForm,
1043{
1044    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1045        f.debug_struct("RegStackPop")
1046            .field("address", &self.address())
1047            .field("size", &self.size())
1048            .field("source_reg_stack", &self.source_reg_stack())
1049            .finish()
1050    }
1051}
1052
1053// LLIL_REG_STACK_FREE_REG
1054pub struct RegStackFreeReg;
1055
1056impl<M, F> Operation<'_, M, F, RegStackFreeReg>
1057where
1058    M: FunctionMutability,
1059    F: FunctionForm,
1060{
1061    pub fn size(&self) -> usize {
1062        self.op.size
1063    }
1064
1065    pub fn dest_reg(&self) -> CoreRegister {
1066        let raw_id = self.op.operands[0] as u32;
1067        self.function
1068            .arch()
1069            .register_from_id(RegisterId(raw_id))
1070            .expect("Bad register ID")
1071    }
1072}
1073
1074impl<M, F> Debug for Operation<'_, M, F, RegStackFreeReg>
1075where
1076    M: FunctionMutability,
1077    F: FunctionForm,
1078{
1079    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1080        f.debug_struct("RegStackFreeReg")
1081            .field("address", &self.address())
1082            .field("size", &self.size())
1083            .field("dest_reg", &self.dest_reg())
1084            .finish()
1085    }
1086}
1087
1088// LLIL_FLAG, LLIL_FLAG_SSA
1089pub struct Flag;
1090
1091impl<M, F> Operation<'_, M, F, Flag>
1092where
1093    M: FunctionMutability,
1094    F: FunctionForm,
1095{
1096    pub fn source_flag(&self) -> CoreFlag {
1097        self.function
1098            .arch()
1099            .flag_from_id(FlagId(self.op.operands[0] as u32))
1100            .expect("Bad flag ID")
1101    }
1102}
1103
1104impl<M, F> Debug for Operation<'_, M, F, Flag>
1105where
1106    M: FunctionMutability,
1107    F: FunctionForm,
1108{
1109    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1110        f.debug_struct("Flag")
1111            .field("source_flag", &self.source_flag())
1112            .finish()
1113    }
1114}
1115
1116// LLIL_FLAG_BIT, LLIL_FLAG_BIT_SSA
1117pub struct FlagBit;
1118
1119impl<M, F> Debug for Operation<'_, M, F, FlagBit>
1120where
1121    M: FunctionMutability,
1122    F: FunctionForm,
1123{
1124    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1125        f.debug_struct("FlagBit").finish()
1126    }
1127}
1128
1129// LLIL_JUMP
1130pub struct Jump;
1131
1132impl<'func, M, F> Operation<'func, M, F, Jump>
1133where
1134    M: FunctionMutability,
1135    F: FunctionForm,
1136{
1137    pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1138        LowLevelILExpression::new(
1139            self.function,
1140            LowLevelExpressionIndex(self.op.operands[0] as usize),
1141        )
1142    }
1143}
1144
1145impl<M, F> Debug for Operation<'_, M, F, Jump>
1146where
1147    M: FunctionMutability,
1148    F: FunctionForm,
1149{
1150    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1151        f.debug_struct("Jump")
1152            .field("target", &self.target())
1153            .finish()
1154    }
1155}
1156
1157// LLIL_JUMP_TO
1158pub struct JumpTo;
1159
1160struct TargetListIter<'func, M, F>
1161where
1162    M: FunctionMutability,
1163    F: FunctionForm,
1164{
1165    function: &'func LowLevelILFunction<M, F>,
1166    cursor: BNLowLevelILInstruction,
1167    cursor_operand: usize,
1168}
1169
1170impl<M, F> TargetListIter<'_, M, F>
1171where
1172    M: FunctionMutability,
1173    F: FunctionForm,
1174{
1175    fn next(&mut self) -> u64 {
1176        if self.cursor_operand >= 3 {
1177            self.cursor = unsafe {
1178                BNGetLowLevelILByIndex(self.function.handle, self.cursor.operands[3] as usize)
1179            };
1180            self.cursor_operand = 0;
1181        }
1182        let result = self.cursor.operands[self.cursor_operand];
1183        self.cursor_operand += 1;
1184        result
1185    }
1186}
1187
1188impl<'func, M, F> Operation<'func, M, F, JumpTo>
1189where
1190    M: FunctionMutability,
1191    F: FunctionForm,
1192{
1193    pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1194        LowLevelILExpression::new(
1195            self.function,
1196            LowLevelExpressionIndex(self.op.operands[0] as usize),
1197        )
1198    }
1199
1200    pub fn target_list(&self) -> BTreeMap<u64, LowLevelInstructionIndex> {
1201        let mut result = BTreeMap::new();
1202        let count = self.op.operands[1] as usize / 2;
1203        let mut list = TargetListIter {
1204            function: self.function,
1205            cursor: unsafe {
1206                BNGetLowLevelILByIndex(self.function.handle, self.op.operands[2] as usize)
1207            },
1208            cursor_operand: 0,
1209        };
1210
1211        for _ in 0..count {
1212            let value = list.next();
1213            let target = LowLevelInstructionIndex(list.next() as usize);
1214            result.insert(value, target);
1215        }
1216
1217        result
1218    }
1219}
1220
1221impl<M, F> Debug for Operation<'_, M, F, JumpTo>
1222where
1223    M: FunctionMutability,
1224    F: FunctionForm,
1225{
1226    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1227        f.debug_struct("JumpTo")
1228            .field("target", &self.target())
1229            .field("target_list", &self.target_list())
1230            .finish()
1231    }
1232}
1233
1234// LLIL_CALL, LLIL_CALL_STACK_ADJUST
1235pub struct Call;
1236
1237impl<'func, M, F> Operation<'func, M, F, Call>
1238where
1239    M: FunctionMutability,
1240    F: FunctionForm,
1241{
1242    pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1243        LowLevelILExpression::new(
1244            self.function,
1245            LowLevelExpressionIndex(self.op.operands[0] as usize),
1246        )
1247    }
1248
1249    pub fn stack_adjust(&self) -> Option<u64> {
1250        use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CALL_STACK_ADJUST;
1251
1252        if self.op.operation == LLIL_CALL_STACK_ADJUST {
1253            Some(self.op.operands[1])
1254        } else {
1255            None
1256        }
1257    }
1258}
1259
1260impl<M, F> Debug for Operation<'_, M, F, Call>
1261where
1262    M: FunctionMutability,
1263    F: FunctionForm,
1264{
1265    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1266        f.debug_struct("Call")
1267            .field("target", &self.target())
1268            .field("stack_adjust", &self.stack_adjust())
1269            .finish()
1270    }
1271}
1272
1273// LLIL_CALL_SSA
1274pub struct CallSsa;
1275
1276impl<'func, M, F> Operation<'func, M, F, CallSsa>
1277where
1278    M: FunctionMutability,
1279    F: FunctionForm,
1280{
1281    pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1282        LowLevelILExpression::new(
1283            self.function,
1284            LowLevelExpressionIndex(self.op.operands[1] as usize),
1285        )
1286    }
1287
1288    /// Get the output expression of the call.
1289    ///
1290    /// NOTE: This is currently always [`CallOutputSsa`].
1291    pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1292        LowLevelILExpression::new(
1293            self.function,
1294            LowLevelExpressionIndex(self.op.operands[0] as usize),
1295        )
1296    }
1297
1298    /// Get the parameter expression of the call.
1299    ///
1300    /// NOTE: This is currently always [`CallParamSsa`].
1301    pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1302        LowLevelILExpression::new(
1303            self.function,
1304            LowLevelExpressionIndex(self.op.operands[3] as usize),
1305        )
1306    }
1307
1308    /// Get the stack expression of the call.
1309    ///
1310    /// NOTE: This is currently always [`CallStackSsa`].
1311    pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1312        LowLevelILExpression::new(
1313            self.function,
1314            LowLevelExpressionIndex(self.op.operands[2] as usize),
1315        )
1316    }
1317}
1318
1319impl<M, F> Debug for Operation<'_, M, F, CallSsa>
1320where
1321    M: FunctionMutability,
1322    F: FunctionForm,
1323{
1324    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1325        f.debug_struct("CallSsa")
1326            .field("target", &self.target())
1327            .field("output_expr", &self.output_expr())
1328            .field("param_expr", &self.param_expr())
1329            .field("stack_expr", &self.stack_expr())
1330            .finish()
1331    }
1332}
1333
1334// LLIL_CALL_OUTPUT_SSA
1335pub struct CallOutputSsa;
1336
1337impl<M, F> Operation<'_, M, F, CallOutputSsa>
1338where
1339    M: FunctionMutability,
1340    F: FunctionForm,
1341{
1342    pub fn dest_regs(&self) -> Vec<LowLevelILSSARegisterKind<CoreRegister>> {
1343        let operand_list = self.get_operand_list(1);
1344
1345        // The operand list contains a list of ([0: reg, 1: version], ...).
1346        let paired_ssa_reg = |paired: &[u64]| {
1347            let raw_id = RegisterId(paired[0] as u32);
1348            let version = paired[1] as u32;
1349            let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
1350                .expect("Bad register ID");
1351            LowLevelILSSARegisterKind::new_full(reg_kind, version)
1352        };
1353
1354        operand_list.chunks_exact(2).map(paired_ssa_reg).collect()
1355    }
1356
1357    pub fn dest_memory_version(&self) -> u64 {
1358        self.op.operands[0]
1359    }
1360}
1361
1362impl<M, F> Debug for Operation<'_, M, F, CallOutputSsa>
1363where
1364    M: FunctionMutability,
1365    F: FunctionForm,
1366{
1367    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1368        f.debug_struct("CallOutputSsa")
1369            .field("dest_regs", &self.dest_regs())
1370            .finish()
1371    }
1372}
1373
1374// LLIL_CALL_PARAM_SSA
1375pub struct CallParamSsa;
1376
1377impl<'func, M, F> Operation<'func, M, F, CallParamSsa>
1378where
1379    M: FunctionMutability,
1380    F: FunctionForm,
1381{
1382    pub fn param_exprs(&self) -> Vec<LowLevelILExpression<'func, M, F, ValueExpr>> {
1383        self.get_operand_list(0)
1384            .into_iter()
1385            .map(|val| LowLevelExpressionIndex(val as usize))
1386            .map(|expr_idx| LowLevelILExpression::new(self.function, expr_idx))
1387            .collect()
1388    }
1389}
1390
1391impl<M, F> Debug for Operation<'_, M, F, CallParamSsa>
1392where
1393    M: FunctionMutability,
1394    F: FunctionForm,
1395{
1396    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1397        f.debug_struct("CallParamSsa")
1398            .field("param_exprs", &self.param_exprs())
1399            .finish()
1400    }
1401}
1402
1403// LLIL_CALL_STACK_SSA
1404pub struct CallStackSsa;
1405
1406impl<M, F> Operation<'_, M, F, CallStackSsa>
1407where
1408    M: FunctionMutability,
1409    F: FunctionForm,
1410{
1411    pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
1412        let raw_id = RegisterId(self.op.operands[0] as u32);
1413        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
1414            .expect("Bad register ID");
1415        let version = self.op.operands[1] as u32;
1416        LowLevelILSSARegisterKind::new_full(reg_kind, version)
1417    }
1418}
1419
1420impl<M, F> Debug for Operation<'_, M, F, CallStackSsa>
1421where
1422    M: FunctionMutability,
1423    F: FunctionForm,
1424{
1425    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1426        f.debug_struct("CallStackSsa")
1427            .field("source_reg", &self.source_reg())
1428            .finish()
1429    }
1430}
1431
1432// LLIL_RET
1433pub struct Ret;
1434
1435impl<'func, M, F> Operation<'func, M, F, Ret>
1436where
1437    M: FunctionMutability,
1438    F: FunctionForm,
1439{
1440    pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1441        LowLevelILExpression::new(
1442            self.function,
1443            LowLevelExpressionIndex(self.op.operands[0] as usize),
1444        )
1445    }
1446}
1447
1448impl<M, F> Debug for Operation<'_, M, F, Ret>
1449where
1450    M: FunctionMutability,
1451    F: FunctionForm,
1452{
1453    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1454        f.debug_struct("Ret")
1455            .field("target", &self.target())
1456            .finish()
1457    }
1458}
1459
1460// LLIL_IF
1461pub struct If;
1462
1463impl<'func, M, F> Operation<'func, M, F, If>
1464where
1465    M: FunctionMutability,
1466    F: FunctionForm,
1467{
1468    pub fn condition(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1469        LowLevelILExpression::new(
1470            self.function,
1471            LowLevelExpressionIndex(self.op.operands[0] as usize),
1472        )
1473    }
1474
1475    pub fn true_target(&self) -> LowLevelILInstruction<'func, M, F> {
1476        LowLevelILInstruction::new(
1477            self.function,
1478            LowLevelInstructionIndex(self.op.operands[1] as usize),
1479        )
1480    }
1481
1482    pub fn false_target(&self) -> LowLevelILInstruction<'func, M, F> {
1483        LowLevelILInstruction::new(
1484            self.function,
1485            LowLevelInstructionIndex(self.op.operands[2] as usize),
1486        )
1487    }
1488}
1489
1490impl<M, F> Debug for Operation<'_, M, F, If>
1491where
1492    M: FunctionMutability,
1493    F: FunctionForm,
1494{
1495    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1496        f.debug_struct("If")
1497            .field("condition", &self.condition())
1498            .field("true_target", &self.true_target())
1499            .field("false_target", &self.false_target())
1500            .finish()
1501    }
1502}
1503
1504// LLIL_GOTO
1505pub struct Goto;
1506
1507impl<'func, M, F> Operation<'func, M, F, Goto>
1508where
1509    M: FunctionMutability,
1510    F: FunctionForm,
1511{
1512    pub fn target(&self) -> LowLevelILInstruction<'func, M, F> {
1513        LowLevelILInstruction::new(
1514            self.function,
1515            LowLevelInstructionIndex(self.op.operands[0] as usize),
1516        )
1517    }
1518}
1519
1520impl<M, F> Debug for Operation<'_, M, F, Goto>
1521where
1522    M: FunctionMutability,
1523    F: FunctionForm,
1524{
1525    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1526        f.debug_struct("Goto")
1527            .field("target", &self.target())
1528            .finish()
1529    }
1530}
1531
1532// LLIL_FLAG_COND
1533// Valid only in Lifted IL
1534pub struct FlagCond;
1535
1536impl<M, F> Debug for Operation<'_, M, F, FlagCond>
1537where
1538    M: FunctionMutability,
1539    F: FunctionForm,
1540{
1541    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1542        f.debug_struct("FlagCond").finish()
1543    }
1544}
1545
1546// LLIL_FLAG_GROUP
1547// Valid only in Lifted IL
1548pub struct FlagGroup;
1549
1550impl<M, F> Operation<'_, M, F, FlagGroup>
1551where
1552    M: FunctionMutability,
1553    F: FunctionForm,
1554{
1555    pub fn flag_group(&self) -> CoreFlagGroup {
1556        let id = self.op.operands[0] as u32;
1557        self.function
1558            .arch()
1559            .flag_group_from_id(FlagGroupId(id))
1560            .unwrap()
1561    }
1562}
1563
1564impl<M, F> Debug for Operation<'_, M, F, FlagGroup>
1565where
1566    M: FunctionMutability,
1567    F: FunctionForm,
1568{
1569    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1570        f.debug_struct("FlagGroup")
1571            .field("flag_group", &self.flag_group())
1572            .finish()
1573    }
1574}
1575
1576// LLIL_TRAP
1577pub struct Trap;
1578
1579impl<M, F> Operation<'_, M, F, Trap>
1580where
1581    M: FunctionMutability,
1582    F: FunctionForm,
1583{
1584    pub fn vector(&self) -> u64 {
1585        self.op.operands[0]
1586    }
1587}
1588
1589impl<M, F> Debug for Operation<'_, M, F, Trap>
1590where
1591    M: FunctionMutability,
1592    F: FunctionForm,
1593{
1594    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1595        f.debug_struct("Trap")
1596            .field("vector", &self.vector())
1597            .finish()
1598    }
1599}
1600
1601// LLIL_REG_PHI
1602pub struct RegPhi;
1603impl<M, F> Operation<'_, M, F, RegPhi>
1604where
1605    M: FunctionMutability,
1606    F: FunctionForm,
1607{
1608    pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
1609        let raw_id = RegisterId(self.op.operands[0] as u32);
1610        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
1611            .expect("Bad register ID");
1612        let version = self.op.operands[1] as u32;
1613        LowLevelILSSARegisterKind::new_full(reg_kind, version)
1614    }
1615
1616    pub fn source_regs(&self) -> Vec<LowLevelILSSARegisterKind<CoreRegister>> {
1617        let operand_list = self.get_operand_list(2);
1618        let arch = self.function.arch();
1619        operand_list
1620            .chunks_exact(2)
1621            .map(|chunk| {
1622                let (register, version) = (chunk[0], chunk[1]);
1623                LowLevelILSSARegisterKind::new_full(
1624                    LowLevelILRegisterKind::from_raw(&arch, RegisterId(register as u32))
1625                        .expect("Bad register ID"),
1626                    version as u32,
1627                )
1628            })
1629            .collect()
1630    }
1631}
1632
1633impl<M, F> Debug for Operation<'_, M, F, RegPhi>
1634where
1635    M: FunctionMutability,
1636    F: FunctionForm,
1637{
1638    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1639        f.debug_struct("RegPhi")
1640            .field("dest_reg", &self.dest_reg())
1641            .field("source_regs", &self.source_regs())
1642            .finish()
1643    }
1644}
1645
1646// LLIL_FLAG_PHI
1647pub struct FlagPhi;
1648
1649impl<M, F> Operation<'_, M, F, FlagPhi>
1650where
1651    M: FunctionMutability,
1652    F: FunctionForm,
1653{
1654    pub fn dest_flag(&self) -> LowLevelILSSAFlag<CoreFlag> {
1655        let flag = self
1656            .function
1657            .arch()
1658            .flag_from_id(FlagId(self.op.operands[0] as u32))
1659            .expect("Bad flag ID");
1660        let version = self.op.operands[1] as u32;
1661        LowLevelILSSAFlag::new(flag, version)
1662    }
1663
1664    pub fn source_flags(&self) -> Vec<LowLevelILSSAFlag<CoreFlag>> {
1665        let operand_list = self.get_operand_list(2);
1666        operand_list
1667            .chunks_exact(2)
1668            .map(|chunk| {
1669                let (flag, version) = (chunk[0], chunk[1]);
1670                let flag = self
1671                    .function
1672                    .arch()
1673                    .flag_from_id(FlagId(flag as u32))
1674                    .expect("Bad flag ID");
1675                LowLevelILSSAFlag::new(flag, version as u32)
1676            })
1677            .collect()
1678    }
1679}
1680
1681impl<M, F> Debug for Operation<'_, M, F, FlagPhi>
1682where
1683    M: FunctionMutability,
1684    F: FunctionForm,
1685{
1686    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1687        f.debug_struct("FlagPhi")
1688            .field("dest_flag", &self.dest_flag())
1689            .field("source_flags", &self.source_flags())
1690            .finish()
1691    }
1692}
1693
1694// LLIL_MEM_PHI
1695pub struct MemPhi;
1696
1697impl<M, F> Operation<'_, M, F, MemPhi>
1698where
1699    M: FunctionMutability,
1700    F: FunctionForm,
1701{
1702    pub fn dest_memory_version(&self) -> usize {
1703        self.op.operands[0] as usize
1704    }
1705
1706    pub fn source_memory_versions(&self) -> Vec<usize> {
1707        let operand_list = self.get_operand_list(1);
1708        operand_list.into_iter().map(|op| op as usize).collect()
1709    }
1710}
1711
1712impl<M, F> Debug for Operation<'_, M, F, MemPhi>
1713where
1714    M: FunctionMutability,
1715    F: FunctionForm,
1716{
1717    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1718        f.debug_struct("MemPhi")
1719            .field("dest_memory_version", &self.dest_memory_version())
1720            .field("source_memory_versions", &self.source_memory_versions())
1721            .finish()
1722    }
1723}
1724
1725// LLIL_CONST, LLIL_CONST_PTR
1726pub struct Const;
1727
1728impl<M, F> Operation<'_, M, F, Const>
1729where
1730    M: FunctionMutability,
1731    F: FunctionForm,
1732{
1733    pub fn size(&self) -> usize {
1734        self.op.size
1735    }
1736
1737    pub fn value(&self) -> u64 {
1738        #[cfg(debug_assertions)]
1739        {
1740            let raw = self.op.operands[0] as i64;
1741
1742            let is_safe = match raw.overflowing_shr(self.op.size as u32 * 8) {
1743                (_, true) => true,
1744                (res, false) => [-1, 0].contains(&res),
1745            };
1746
1747            if !is_safe {
1748                log::error!(
1749                    "il expr @ {:x} contains constant 0x{:x} as {} byte value (doesn't fit!)",
1750                    self.op.address,
1751                    self.op.operands[0],
1752                    self.op.size
1753                );
1754            }
1755        }
1756
1757        let mask: u64 = if self.op.size == 0 {
1758            1
1759        } else if self.op.size < mem::size_of::<u64>() {
1760            let m = -1i64 << (self.op.size * 8);
1761            !m as u64
1762        } else {
1763            (-1i64) as u64
1764        };
1765
1766        self.op.operands[0] & mask
1767    }
1768}
1769
1770impl<M, F> Debug for Operation<'_, M, F, Const>
1771where
1772    M: FunctionMutability,
1773    F: FunctionForm,
1774{
1775    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1776        f.debug_struct("Const")
1777            .field("size", &self.size())
1778            .field("value", &self.value())
1779            .finish()
1780    }
1781}
1782
1783// LLIL_FLOAT_CONST
1784pub struct FloatConst;
1785
1786impl<M, F> Operation<'_, M, F, FloatConst>
1787where
1788    M: FunctionMutability,
1789    F: FunctionForm,
1790{
1791    pub fn size(&self) -> usize {
1792        self.op.size
1793    }
1794
1795    pub fn raw_value(&self) -> u64 {
1796        self.op.operands[0]
1797    }
1798
1799    pub fn float_value(&self) -> f64 {
1800        let raw_bits = self.raw_value();
1801        match self.op.size {
1802            4 => {
1803                // For f32, take the lower 32 bits and convert to f32
1804                let bits32 = (raw_bits & 0xFFFFFFFF) as u32;
1805                f32::from_bits(bits32) as f64
1806            }
1807            8 => {
1808                // For f64, use all 64 bits
1809                f64::from_bits(raw_bits)
1810            }
1811            _ => {
1812                // Log error for unexpected sizes
1813                log::error!(
1814                    "il expr @ {:x} has invalid float size {} (expected 4 or 8 bytes)",
1815                    self.op.address,
1816                    self.op.size
1817                );
1818                f64::NAN
1819            }
1820        }
1821    }
1822}
1823
1824impl<M, F> Debug for Operation<'_, M, F, FloatConst>
1825where
1826    M: FunctionMutability,
1827    F: FunctionForm,
1828{
1829    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1830        f.debug_struct("FloatConst")
1831            .field("size", &self.size())
1832            .field("float_value", &self.float_value())
1833            .field("raw_value", &self.raw_value())
1834            .finish()
1835    }
1836}
1837
1838// LLIL_EXTERN_PTR
1839pub struct Extern;
1840
1841impl<M, F> Operation<'_, M, F, Extern>
1842where
1843    M: FunctionMutability,
1844    F: FunctionForm,
1845{
1846    pub fn size(&self) -> usize {
1847        self.op.size
1848    }
1849
1850    pub fn value(&self) -> u64 {
1851        #[cfg(debug_assertions)]
1852        {
1853            let raw = self.op.operands[0] as i64;
1854
1855            let is_safe = match raw.overflowing_shr(self.op.size as u32 * 8) {
1856                (_, true) => true,
1857                (res, false) => [-1, 0].contains(&res),
1858            };
1859
1860            if !is_safe {
1861                log::error!(
1862                    "il expr @ {:x} contains extern 0x{:x} as {} byte value (doesn't fit!)",
1863                    self.op.address,
1864                    self.op.operands[0],
1865                    self.op.size
1866                );
1867            }
1868        }
1869
1870        let mut mask = -1i64 as u64;
1871
1872        if self.op.size < mem::size_of::<u64>() {
1873            mask <<= self.op.size * 8;
1874            mask = !mask;
1875        }
1876
1877        self.op.operands[0] & mask
1878    }
1879}
1880
1881impl<M, F> Debug for Operation<'_, M, F, Extern>
1882where
1883    M: FunctionMutability,
1884    F: FunctionForm,
1885{
1886    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1887        f.debug_struct("Extern")
1888            .field("size", &self.size())
1889            .field("value", &self.value())
1890            .finish()
1891    }
1892}
1893
1894// LLIL_ADD, LLIL_SUB, LLIL_AND, LLIL_OR
1895// LLIL_XOR, LLIL_LSL, LLIL_LSR, LLIL_ASR
1896// LLIL_ROL, LLIL_ROR, LLIL_MUL, LLIL_MULU_DP,
1897// LLIL_MULS_DP, LLIL_DIVU, LLIL_DIVS, LLIL_MODU,
1898// LLIL_MODS
1899pub struct BinaryOp;
1900
1901impl<'func, M, F> Operation<'func, M, F, BinaryOp>
1902where
1903    M: FunctionMutability,
1904    F: FunctionForm,
1905{
1906    pub fn size(&self) -> usize {
1907        self.op.size
1908    }
1909
1910    pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1911        LowLevelILExpression::new(
1912            self.function,
1913            LowLevelExpressionIndex(self.op.operands[0] as usize),
1914        )
1915    }
1916
1917    pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1918        LowLevelILExpression::new(
1919            self.function,
1920            LowLevelExpressionIndex(self.op.operands[1] as usize),
1921        )
1922    }
1923}
1924
1925impl<M, F> Debug for Operation<'_, M, F, BinaryOp>
1926where
1927    M: FunctionMutability,
1928    F: FunctionForm,
1929{
1930    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1931        f.debug_struct("BinaryOp")
1932            .field("size", &self.size())
1933            .field("left", &self.left())
1934            .field("right", &self.right())
1935            .finish()
1936    }
1937}
1938
1939// LLIL_ADC, LLIL_SBB, LLIL_RLC, LLIL_RRC
1940pub struct BinaryOpCarry;
1941
1942impl<'func, M, F> Operation<'func, M, F, BinaryOpCarry>
1943where
1944    M: FunctionMutability,
1945    F: FunctionForm,
1946{
1947    pub fn size(&self) -> usize {
1948        self.op.size
1949    }
1950
1951    pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1952        LowLevelILExpression::new(
1953            self.function,
1954            LowLevelExpressionIndex(self.op.operands[0] as usize),
1955        )
1956    }
1957
1958    pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1959        LowLevelILExpression::new(
1960            self.function,
1961            LowLevelExpressionIndex(self.op.operands[1] as usize),
1962        )
1963    }
1964
1965    pub fn carry(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
1966        LowLevelILExpression::new(
1967            self.function,
1968            LowLevelExpressionIndex(self.op.operands[2] as usize),
1969        )
1970    }
1971}
1972
1973impl<M, F> Debug for Operation<'_, M, F, BinaryOpCarry>
1974where
1975    M: FunctionMutability,
1976    F: FunctionForm,
1977{
1978    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1979        f.debug_struct("BinaryOpCarry")
1980            .field("size", &self.size())
1981            .field("left", &self.left())
1982            .field("right", &self.right())
1983            .field("carry", &self.carry())
1984            .finish()
1985    }
1986}
1987
1988// LLIL_PUSH, LLIL_NEG, LLIL_NOT, LLIL_SX,
1989// LLIL_ZX, LLIL_LOW_PART, LLIL_BOOL_TO_INT, LLIL_UNIMPL_MEM
1990pub struct UnaryOp;
1991
1992impl<'func, M, F> Operation<'func, M, F, UnaryOp>
1993where
1994    M: FunctionMutability,
1995    F: FunctionForm,
1996{
1997    pub fn size(&self) -> usize {
1998        self.op.size
1999    }
2000
2001    pub fn operand(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
2002        LowLevelILExpression::new(
2003            self.function,
2004            LowLevelExpressionIndex(self.op.operands[0] as usize),
2005        )
2006    }
2007}
2008
2009impl<M, F> Debug for Operation<'_, M, F, UnaryOp>
2010where
2011    M: FunctionMutability,
2012    F: FunctionForm,
2013{
2014    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2015        f.debug_struct("UnaryOp")
2016            .field("size", &self.size())
2017            .field("operand", &self.operand())
2018            .finish()
2019    }
2020}
2021
2022// LLIL_CMP_X
2023pub struct Condition;
2024
2025impl<'func, M, F> Operation<'func, M, F, Condition>
2026where
2027    M: FunctionMutability,
2028    F: FunctionForm,
2029{
2030    pub fn size(&self) -> usize {
2031        self.op.size
2032    }
2033
2034    pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
2035        LowLevelILExpression::new(
2036            self.function,
2037            LowLevelExpressionIndex(self.op.operands[0] as usize),
2038        )
2039    }
2040
2041    pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
2042        LowLevelILExpression::new(
2043            self.function,
2044            LowLevelExpressionIndex(self.op.operands[1] as usize),
2045        )
2046    }
2047}
2048
2049impl<M, F> Debug for Operation<'_, M, F, Condition>
2050where
2051    M: FunctionMutability,
2052    F: FunctionForm,
2053{
2054    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2055        f.debug_struct("Condition")
2056            .field("size", &self.size())
2057            .field("left", &self.left())
2058            .field("right", &self.right())
2059            .finish()
2060    }
2061}
2062
2063// LLIL_UNIMPL_MEM
2064pub struct UnimplMem;
2065
2066impl<'func, M, F> Operation<'func, M, F, UnimplMem>
2067where
2068    M: FunctionMutability,
2069    F: FunctionForm,
2070{
2071    pub fn size(&self) -> usize {
2072        self.op.size
2073    }
2074
2075    pub fn mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> {
2076        LowLevelILExpression::new(
2077            self.function,
2078            LowLevelExpressionIndex(self.op.operands[0] as usize),
2079        )
2080    }
2081}
2082
2083impl<M, F> Debug for Operation<'_, M, F, UnimplMem>
2084where
2085    M: FunctionMutability,
2086    F: FunctionForm,
2087{
2088    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2089        f.debug_struct("UnimplMem")
2090            .field("size", &self.size())
2091            .field("mem_expr", &self.mem_expr())
2092            .finish()
2093    }
2094}
2095
2096// LLIL_ASSERT
2097pub struct Assert;
2098
2099impl<M, F> Operation<'_, M, F, Assert>
2100where
2101    M: FunctionMutability,
2102    F: FunctionForm,
2103{
2104    pub fn size(&self) -> usize {
2105        self.op.size
2106    }
2107
2108    pub fn source_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
2109        let raw_id = RegisterId(self.op.operands[0] as u32);
2110        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
2111    }
2112
2113    pub fn constraint(&self) -> PossibleValueSet {
2114        self.get_constraint(1)
2115    }
2116}
2117
2118impl<M, F> Debug for Operation<'_, M, F, Assert>
2119where
2120    M: FunctionMutability,
2121    F: FunctionForm,
2122{
2123    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2124        f.debug_struct("Assert")
2125            .field("size", &self.size())
2126            .field("source_reg", &self.source_reg())
2127            .field("constraint", &self.constraint())
2128            .finish()
2129    }
2130}
2131
2132// LLIL_ASSERT_SSA
2133pub struct AssertSsa;
2134
2135impl<M, F> Operation<'_, M, F, AssertSsa>
2136where
2137    M: FunctionMutability,
2138    F: FunctionForm,
2139{
2140    pub fn size(&self) -> usize {
2141        self.op.size
2142    }
2143
2144    pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
2145        let raw_id = RegisterId(self.op.operands[0] as u32);
2146        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
2147            .expect("Bad register ID");
2148        let version = self.op.operands[1] as u32;
2149        LowLevelILSSARegisterKind::new_full(reg_kind, version)
2150    }
2151
2152    pub fn constraint(&self) -> PossibleValueSet {
2153        self.get_constraint(2)
2154    }
2155}
2156
2157impl<M, F> Debug for Operation<'_, M, F, AssertSsa>
2158where
2159    M: FunctionMutability,
2160    F: FunctionForm,
2161{
2162    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2163        f.debug_struct("AssertSsa")
2164            .field("size", &self.size())
2165            .field("source_reg", &self.source_reg())
2166            .field("constraint", &self.constraint())
2167            .finish()
2168    }
2169}
2170
2171// LLIL_FORCE_VER
2172pub struct ForceVersion;
2173
2174impl<M, F> Operation<'_, M, F, ForceVersion>
2175where
2176    M: FunctionMutability,
2177    F: FunctionForm,
2178{
2179    pub fn size(&self) -> usize {
2180        self.op.size
2181    }
2182
2183    pub fn dest_reg(&self) -> LowLevelILRegisterKind<CoreRegister> {
2184        let raw_id = RegisterId(self.op.operands[0] as u32);
2185        LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID")
2186    }
2187}
2188
2189impl<M, F> Debug for Operation<'_, M, F, ForceVersion>
2190where
2191    M: FunctionMutability,
2192    F: FunctionForm,
2193{
2194    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2195        f.debug_struct("ForceVersion")
2196            .field("size", &self.size())
2197            .field("dest_reg", &self.dest_reg())
2198            .finish()
2199    }
2200}
2201
2202// LLIL_FORCE_VER_SSA
2203pub struct ForceVersionSsa;
2204
2205impl<M, F> Operation<'_, M, F, ForceVersionSsa>
2206where
2207    M: FunctionMutability,
2208    F: FunctionForm,
2209{
2210    pub fn size(&self) -> usize {
2211        self.op.size
2212    }
2213
2214    pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
2215        let raw_id = RegisterId(self.op.operands[0] as u32);
2216        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
2217            .expect("Bad register ID");
2218        let version = self.op.operands[1] as u32;
2219        LowLevelILSSARegisterKind::new_full(reg_kind, version)
2220    }
2221
2222    pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> {
2223        let raw_id = RegisterId(self.op.operands[2] as u32);
2224        let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id)
2225            .expect("Bad register ID");
2226        let version = self.op.operands[3] as u32;
2227        LowLevelILSSARegisterKind::new_full(reg_kind, version)
2228    }
2229}
2230
2231impl<M, F> Debug for Operation<'_, M, F, ForceVersionSsa>
2232where
2233    M: FunctionMutability,
2234    F: FunctionForm,
2235{
2236    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2237        f.debug_struct("ForceVersionSsa")
2238            .field("size", &self.size())
2239            .field("dest_reg", &self.dest_reg())
2240            .field("source_reg", &self.source_reg())
2241            .finish()
2242    }
2243}
2244
2245// LLIL_SEPARATE_PARAM_LIST_SSA
2246pub struct SeparateParamListSsa;
2247
2248impl<'func, M, F> Operation<'func, M, F, SeparateParamListSsa>
2249where
2250    M: FunctionMutability,
2251    F: FunctionForm,
2252{
2253    pub fn param_exprs(&self) -> Vec<LowLevelILExpression<'func, M, F, ValueExpr>> {
2254        self.get_operand_list(0)
2255            .into_iter()
2256            .map(|val| LowLevelExpressionIndex(val as usize))
2257            .map(|expr_idx| LowLevelILExpression::new(self.function, expr_idx))
2258            .collect()
2259    }
2260}
2261
2262impl<M, F> Debug for Operation<'_, M, F, SeparateParamListSsa>
2263where
2264    M: FunctionMutability,
2265    F: FunctionForm,
2266{
2267    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2268        f.debug_struct("SeparateParamListSsa")
2269            .field("param_exprs", &self.param_exprs())
2270            .finish()
2271    }
2272}
2273
2274// TODO TEST_BIT
2275
2276pub trait OperationArguments: 'static {}
2277
2278impl OperationArguments for NoArgs {}
2279impl OperationArguments for Pop {}
2280impl OperationArguments for Syscall {}
2281impl OperationArguments for SyscallSsa {}
2282impl OperationArguments for Intrinsic {}
2283impl OperationArguments for SetReg {}
2284impl OperationArguments for SetRegSsa {}
2285impl OperationArguments for SetRegPartialSsa {}
2286impl OperationArguments for SetRegSplit {}
2287impl OperationArguments for SetRegSplitSsa {}
2288impl OperationArguments for SetFlag {}
2289impl OperationArguments for SetFlagSsa {}
2290impl OperationArguments for Load {}
2291impl OperationArguments for LoadSsa {}
2292impl OperationArguments for Store {}
2293impl OperationArguments for StoreSsa {}
2294impl OperationArguments for Reg {}
2295impl OperationArguments for RegSsa {}
2296impl OperationArguments for RegPartialSsa {}
2297impl OperationArguments for RegSplit {}
2298impl OperationArguments for RegSplitSsa {}
2299impl OperationArguments for RegStackPush {}
2300impl OperationArguments for RegStackPop {}
2301impl OperationArguments for RegStackFreeReg {}
2302impl OperationArguments for Flag {}
2303impl OperationArguments for FlagBit {}
2304impl OperationArguments for Jump {}
2305impl OperationArguments for JumpTo {}
2306impl OperationArguments for Call {}
2307impl OperationArguments for CallSsa {}
2308impl OperationArguments for CallOutputSsa {}
2309impl OperationArguments for CallParamSsa {}
2310impl OperationArguments for CallStackSsa {}
2311impl OperationArguments for Ret {}
2312impl OperationArguments for If {}
2313impl OperationArguments for Goto {}
2314impl OperationArguments for FlagCond {}
2315impl OperationArguments for FlagGroup {}
2316impl OperationArguments for Trap {}
2317impl OperationArguments for RegPhi {}
2318impl OperationArguments for FlagPhi {}
2319impl OperationArguments for MemPhi {}
2320impl OperationArguments for Const {}
2321impl OperationArguments for FloatConst {}
2322impl OperationArguments for Extern {}
2323impl OperationArguments for BinaryOp {}
2324impl OperationArguments for BinaryOpCarry {}
2325impl OperationArguments for UnaryOp {}
2326impl OperationArguments for Condition {}
2327impl OperationArguments for UnimplMem {}
2328impl OperationArguments for Assert {}
2329impl OperationArguments for AssertSsa {}
2330impl OperationArguments for ForceVersion {}
2331impl OperationArguments for ForceVersionSsa {}
2332impl OperationArguments for SeparateParamListSsa {}