rabbitizer/
instruction.rs

1/* SPDX-FileCopyrightText: © 2022-2024 Decompollaborate */
2/* SPDX-License-Identifier: MIT */
3
4use crate::{
5    access_type_enum, instr_category_enum, instr_descriptor, instr_id_enum, instr_id_type_enum,
6    instr_suffix_enum, operand_type_enum, registers_enum, utils,
7};
8
9#[repr(C)]
10#[derive(Debug, Clone)]
11#[allow(non_camel_case_types)]
12pub struct Instruction {
13    word: u32,
14    _mandatorybits: u32,
15    pub unique_id: instr_id_enum::InstrId,
16    descriptor: *const instr_descriptor::InstrDescriptor,
17    instr_id_type: instr_id_type_enum::InstrIdType,
18    pub vram: u32,
19    _handwritten_category: bool,
20    pub in_handwritten_function: bool,
21    pub category: instr_category_enum::InstrCategory,
22    pub flags: u32,
23}
24
25#[link(name = "rabbitizer", kind = "static")]
26extern "C" {
27    fn RabbitizerInstrId_getOpcodeName(
28        unique_id: instr_id_enum::InstrId,
29    ) -> *const core::ffi::c_char;
30}
31
32extern "C" {
33    fn RabInstrIdType_getName(id_type: instr_id_type_enum::InstrIdType)
34        -> *const core::ffi::c_char;
35}
36
37extern "C" {
38    fn RabbitizerInstruction_init(self_: *mut Instruction, word: u32, vram: u32);
39    fn RabbitizerInstruction_destroy(self_: *mut Instruction);
40
41    fn RabbitizerInstruction_processUniqueId(self_: *mut Instruction);
42}
43
44extern "C" {
45    fn RabbitizerInstructionRsp_init(self_: *mut Instruction, word: u32, vram: u32);
46    fn RabbitizerInstructionRsp_destroy(self_: *mut Instruction);
47
48    fn RabbitizerInstructionRsp_processUniqueId(self_: *mut Instruction);
49}
50
51extern "C" {
52    fn RabbitizerInstructionR3000GTE_init(self_: *mut Instruction, word: u32, vram: u32);
53    fn RabbitizerInstructionR3000GTE_destroy(self_: *mut Instruction);
54
55    fn RabbitizerInstructionR3000GTE_processUniqueId(self_: *mut Instruction);
56}
57
58extern "C" {
59    fn RabbitizerInstructionR5900_init(self_: *mut Instruction, word: u32, vram: u32);
60    fn RabbitizerInstructionR5900_destroy(self_: *mut Instruction);
61
62    fn RabbitizerInstructionR5900_processUniqueId(self_: *mut Instruction);
63}
64
65extern "C" {
66    fn RabbitizerInstructionR4000Allegrex_init(self_: *mut Instruction, word: u32, vram: u32);
67    fn RabbitizerInstructionR4000Allegrex_destroy(self_: *mut Instruction);
68
69    fn RabbitizerInstructionR4000Allegrex_processUniqueId(self_: *mut Instruction);
70}
71
72extern "C" {
73    fn RabbitizerInstruction_getRaw(self_: *const Instruction) -> u32;
74    fn RabbitizerInstruction_getProcessedImmediate(self_: *const Instruction) -> i32;
75    fn RabbitizerInstruction_getInstrIndexAsVram(self_: *const Instruction) -> u32;
76    fn RabbitizerInstruction_getBranchOffset(self_: *const Instruction) -> i32;
77
78    fn RabbitizerInstruction_getBranchOffsetGeneric(self_: *const Instruction) -> i32;
79    fn RabbitizerInstruction_getBranchVramGeneric(self_: *const Instruction) -> u32;
80    fn RabbitizerInstruction_getDestinationGpr(self_: *const Instruction) -> i8;
81    fn RabbitizerInstruction_outputsToGprZero(self_: *const Instruction) -> bool;
82    fn RabbitizerInstruction_blankOut(self_: *mut Instruction);
83    fn RabbitizerInstruction_isImplemented(self_: *const Instruction) -> bool;
84    fn RabbitizerInstruction_isLikelyHandwritten(self_: *const Instruction) -> bool;
85    fn RabbitizerInstruction_isNop(self_: *const Instruction) -> bool;
86    fn RabbitizerInstruction_isUnconditionalBranch(self_: *const Instruction) -> bool;
87    fn RabbitizerInstruction_isFunctionCall(self_: *const Instruction) -> bool;
88    fn RabbitizerInstruction_isReturn(self_: *const Instruction) -> bool;
89    fn RabbitizerInstruction_isJumptableJump(self_: *const Instruction) -> bool;
90
91    fn RabbitizerInstruction_hasDelaySlot(self_: *const Instruction) -> bool;
92
93    fn RabbitizerInstruction_sameOpcode(
94        self_: *const Instruction,
95        other: *const Instruction,
96    ) -> bool;
97    fn RabbitizerInstruction_sameOpcodeButDifferentArguments(
98        self_: *const Instruction,
99        other: *const Instruction,
100    ) -> bool;
101    fn RabbitizerInstruction_hasOperand(
102        self_: *const Instruction,
103        operand: operand_type_enum::OperandType,
104    ) -> bool;
105    fn RabbitizerInstruction_hasOperandAlias(
106        self_: *const Instruction,
107        operand: operand_type_enum::OperandType,
108    ) -> bool;
109
110    fn RabbitizerInstruction_isValid(self_: *const Instruction) -> bool;
111
112    fn RabbitizerInstruction_getSizeForBuffer(
113        self_: *const Instruction,
114        immOverrideLength: utils::SizeT,
115        extraLJust: core::ffi::c_int,
116    ) -> utils::SizeT;
117    fn RabbitizerInstruction_disassemble(
118        self_: *const Instruction,
119        dst: *mut core::ffi::c_char,
120        immOverride: *const core::ffi::c_char,
121        immOverrideLength: utils::SizeT,
122        extraLJust: core::ffi::c_int,
123    ) -> utils::SizeT;
124}
125
126extern "C" {
127    fn RabbitizerInstrDescriptor_instrSuffix(
128        self_: *const instr_descriptor::InstrDescriptor,
129    ) -> instr_suffix_enum::InstrSuffix;
130    fn RabbitizerInstrDescriptor_isBranch(self_: *const instr_descriptor::InstrDescriptor) -> bool;
131    fn RabbitizerInstrDescriptor_isBranchLikely(
132        self_: *const instr_descriptor::InstrDescriptor,
133    ) -> bool;
134    fn RabbitizerInstrDescriptor_isJump(self_: *const instr_descriptor::InstrDescriptor) -> bool;
135    fn RabbitizerInstrDescriptor_isJumpWithAddress(
136        self_: *const instr_descriptor::InstrDescriptor,
137    ) -> bool;
138    fn RabbitizerInstrDescriptor_isTrap(self_: *const instr_descriptor::InstrDescriptor) -> bool;
139    fn RabbitizerInstrDescriptor_isFloat(self_: *const instr_descriptor::InstrDescriptor) -> bool;
140    fn RabbitizerInstrDescriptor_isDouble(self_: *const instr_descriptor::InstrDescriptor) -> bool;
141    fn RabbitizerInstrDescriptor_isUnsigned(
142        self_: *const instr_descriptor::InstrDescriptor,
143    ) -> bool;
144
145    fn RabbitizerInstrDescriptor_modifiesRs(
146        self_: *const instr_descriptor::InstrDescriptor,
147    ) -> bool;
148    fn RabbitizerInstrDescriptor_modifiesRt(
149        self_: *const instr_descriptor::InstrDescriptor,
150    ) -> bool;
151    fn RabbitizerInstrDescriptor_modifiesRd(
152        self_: *const instr_descriptor::InstrDescriptor,
153    ) -> bool;
154    fn RabbitizerInstrDescriptor_readsRs(self_: *const instr_descriptor::InstrDescriptor) -> bool;
155    fn RabbitizerInstrDescriptor_readsRt(self_: *const instr_descriptor::InstrDescriptor) -> bool;
156    fn RabbitizerInstrDescriptor_readsRd(self_: *const instr_descriptor::InstrDescriptor) -> bool;
157
158    fn RabbitizerInstrDescriptor_readsHI(self_: *const instr_descriptor::InstrDescriptor) -> bool;
159    fn RabbitizerInstrDescriptor_readsLO(self_: *const instr_descriptor::InstrDescriptor) -> bool;
160    fn RabbitizerInstrDescriptor_modifiesHI(
161        self_: *const instr_descriptor::InstrDescriptor,
162    ) -> bool;
163    fn RabbitizerInstrDescriptor_modifiesLO(
164        self_: *const instr_descriptor::InstrDescriptor,
165    ) -> bool;
166
167    fn RabbitizerInstrDescriptor_modifiesFs(
168        self_: *const instr_descriptor::InstrDescriptor,
169    ) -> bool;
170    fn RabbitizerInstrDescriptor_modifiesFt(
171        self_: *const instr_descriptor::InstrDescriptor,
172    ) -> bool;
173    fn RabbitizerInstrDescriptor_modifiesFd(
174        self_: *const instr_descriptor::InstrDescriptor,
175    ) -> bool;
176    fn RabbitizerInstrDescriptor_readsFs(self_: *const instr_descriptor::InstrDescriptor) -> bool;
177    fn RabbitizerInstrDescriptor_readsFt(self_: *const instr_descriptor::InstrDescriptor) -> bool;
178    fn RabbitizerInstrDescriptor_readsFd(self_: *const instr_descriptor::InstrDescriptor) -> bool;
179
180    fn RabbitizerInstrDescriptor_notEmittedByCompilers(
181        self_: *const instr_descriptor::InstrDescriptor,
182    ) -> bool;
183    fn RabbitizerInstrDescriptor_canBeHi(self_: *const instr_descriptor::InstrDescriptor) -> bool;
184    fn RabbitizerInstrDescriptor_canBeLo(self_: *const instr_descriptor::InstrDescriptor) -> bool;
185    fn RabbitizerInstrDescriptor_doesLink(self_: *const instr_descriptor::InstrDescriptor) -> bool;
186    fn RabbitizerInstrDescriptor_doesDereference(
187        self_: *const instr_descriptor::InstrDescriptor,
188    ) -> bool;
189    fn RabbitizerInstrDescriptor_doesLoad(self_: *const instr_descriptor::InstrDescriptor) -> bool;
190    fn RabbitizerInstrDescriptor_doesStore(self_: *const instr_descriptor::InstrDescriptor)
191        -> bool;
192    fn RabbitizerInstrDescriptor_maybeIsMove(
193        self_: *const instr_descriptor::InstrDescriptor,
194    ) -> bool;
195    fn RabbitizerInstrDescriptor_isPseudo(self_: *const instr_descriptor::InstrDescriptor) -> bool;
196    fn RabbitizerInstrDescriptor_getAccessType(
197        self_: *const instr_descriptor::InstrDescriptor,
198    ) -> access_type_enum::AccessType;
199    fn RabbitizerInstrDescriptor_doesUnsignedMemoryAccess(
200        self_: *const instr_descriptor::InstrDescriptor,
201    ) -> bool;
202}
203
204impl Drop for Instruction {
205    fn drop(&mut self) {
206        unsafe {
207            match self.category {
208                instr_category_enum::InstrCategory::CPU => {
209                    RabbitizerInstruction_destroy(self);
210                }
211                instr_category_enum::InstrCategory::RSP => {
212                    RabbitizerInstructionRsp_destroy(self);
213                }
214                instr_category_enum::InstrCategory::R3000GTE => {
215                    RabbitizerInstructionR3000GTE_destroy(self);
216                }
217                instr_category_enum::InstrCategory::R5900 => {
218                    RabbitizerInstructionR5900_destroy(self);
219                }
220                instr_category_enum::InstrCategory::R4000ALLEGREX => {
221                    RabbitizerInstructionR4000Allegrex_destroy(self);
222                }
223                instr_category_enum::InstrCategory::MAX => {
224                    core::panic!();
225                }
226            }
227        }
228    }
229}
230
231impl Instruction {
232    pub fn new(word: u32, vram: u32, instr_cat: instr_category_enum::InstrCategory) -> Self {
233        unsafe {
234            let mut instr: std::mem::MaybeUninit<Instruction> = std::mem::MaybeUninit::uninit();
235            match instr_cat {
236                instr_category_enum::InstrCategory::CPU => {
237                    RabbitizerInstruction_init(instr.as_mut_ptr(), word, vram);
238                    RabbitizerInstruction_processUniqueId(instr.as_mut_ptr());
239                }
240                instr_category_enum::InstrCategory::RSP => {
241                    RabbitizerInstructionRsp_init(instr.as_mut_ptr(), word, vram);
242                    RabbitizerInstructionRsp_processUniqueId(instr.as_mut_ptr());
243                }
244                instr_category_enum::InstrCategory::R3000GTE => {
245                    RabbitizerInstructionR3000GTE_init(instr.as_mut_ptr(), word, vram);
246                    RabbitizerInstructionR3000GTE_processUniqueId(instr.as_mut_ptr());
247                }
248                instr_category_enum::InstrCategory::R5900 => {
249                    RabbitizerInstructionR5900_init(instr.as_mut_ptr(), word, vram);
250                    RabbitizerInstructionR5900_processUniqueId(instr.as_mut_ptr());
251                }
252                instr_category_enum::InstrCategory::R4000ALLEGREX => {
253                    RabbitizerInstructionR4000Allegrex_init(instr.as_mut_ptr(), word, vram);
254                    RabbitizerInstructionR4000Allegrex_processUniqueId(instr.as_mut_ptr());
255                }
256                instr_category_enum::InstrCategory::MAX => {
257                    core::panic!();
258                } // _ => not used in purpose
259            }
260            instr.assume_init()
261        }
262    }
263
264    pub fn get_opcode(&self) -> u32 {
265        utils::shiftr(self.word, 26, 6)
266    }
267
268    pub fn get_rs(&self) -> u32 {
269        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_rs) {
270            core::panic!();
271        }
272
273        utils::shiftr(self.word, 21, 5)
274    }
275
276    pub fn get_rs_o32(&self) -> registers_enum::registers::GprO32 {
277        self.get_rs().try_into().unwrap()
278    }
279
280    pub fn get_rs_n32(&self) -> registers_enum::registers::GprN32 {
281        self.get_rs().try_into().unwrap()
282    }
283
284    pub fn get_rt(&self) -> u32 {
285        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_rt) {
286            core::panic!();
287        }
288
289        utils::shiftr(self.word, 16, 5)
290    }
291
292    pub fn get_rt_o32(&self) -> registers_enum::registers::GprO32 {
293        self.get_rt().try_into().unwrap()
294    }
295
296    pub fn get_rt_n32(&self) -> registers_enum::registers::GprN32 {
297        self.get_rt().try_into().unwrap()
298    }
299
300    pub fn get_rd(&self) -> u32 {
301        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_rd) {
302            core::panic!();
303        }
304
305        utils::shiftr(self.word, 11, 5)
306    }
307
308    pub fn get_rd_o32(&self) -> registers_enum::registers::GprO32 {
309        self.get_rd().try_into().unwrap()
310    }
311
312    pub fn get_rd_n32(&self) -> registers_enum::registers::GprN32 {
313        self.get_rd().try_into().unwrap()
314    }
315
316    pub fn get_sa(&self) -> u32 {
317        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_sa) {
318            core::panic!();
319        }
320
321        utils::shiftr(self.word, 6, 5)
322    }
323
324    pub fn get_function(&self) -> u32 {
325        //if !self.has_operand_alias(operand_type_enum::OperandType::cpu_function) {
326        //    core::panic!();
327        //}
328
329        utils::shiftr(self.word, 0, 6)
330    }
331
332    pub fn get_cop0d(&self) -> u32 {
333        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_cop0d) {
334            core::panic!();
335        }
336
337        utils::shiftr(self.word, 11, 5)
338    }
339
340    pub fn get_cop0d_cop0(&self) -> registers_enum::registers::Cop0 {
341        self.get_cop0d().try_into().unwrap()
342    }
343
344    pub fn get_instr_index(&self) -> u32 {
345        utils::shiftr(self.word, 0, 26)
346    }
347
348    pub fn get_immediate(&self) -> u16 {
349        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_immediate) {
350            core::panic!();
351        }
352
353        utils::shiftr(self.word, 0, 16).try_into().unwrap()
354    }
355
356    pub fn get_code(&self) -> u32 {
357        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_code) {
358            core::panic!();
359        }
360
361        utils::shiftr(self.word, 6, 20)
362    }
363
364    pub fn get_code_upper(&self) -> u32 {
365        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_code) {
366            core::panic!();
367        }
368
369        utils::shiftr(self.word, 16, 10)
370    }
371
372    pub fn get_code_lower(&self) -> u32 {
373        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_code_lower) {
374            core::panic!();
375        }
376
377        utils::shiftr(self.word, 6, 10)
378    }
379
380    pub fn get_copraw(&self) -> u32 {
381        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_copraw) {
382            core::panic!();
383        }
384
385        utils::shiftr(self.word, 0, 25)
386    }
387
388    pub fn get_fs(&self) -> u32 {
389        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_fs) {
390            core::panic!();
391        }
392
393        utils::shiftr(self.word, 11, 5)
394    }
395
396    pub fn get_fs_o32(&self) -> registers_enum::registers::Cop1O32 {
397        self.get_fs().try_into().unwrap()
398    }
399
400    pub fn get_fs_n32(&self) -> registers_enum::registers::Cop1N32 {
401        self.get_fs().try_into().unwrap()
402    }
403
404    pub fn get_fs_n64(&self) -> registers_enum::registers::Cop1N64 {
405        self.get_fs().try_into().unwrap()
406    }
407
408    pub fn get_ft(&self) -> u32 {
409        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_ft) {
410            core::panic!();
411        }
412
413        utils::shiftr(self.word, 16, 5)
414    }
415
416    pub fn get_ft_o32(&self) -> registers_enum::registers::Cop1O32 {
417        self.get_ft().try_into().unwrap()
418    }
419
420    pub fn get_ft_n32(&self) -> registers_enum::registers::Cop1N32 {
421        self.get_ft().try_into().unwrap()
422    }
423
424    pub fn get_ft_n64(&self) -> registers_enum::registers::Cop1N64 {
425        self.get_ft().try_into().unwrap()
426    }
427
428    pub fn get_fd(&self) -> u32 {
429        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_fd) {
430            core::panic!();
431        }
432
433        utils::shiftr(self.word, 6, 5)
434    }
435
436    pub fn get_fd_o32(&self) -> registers_enum::registers::Cop1O32 {
437        self.get_fd().try_into().unwrap()
438    }
439
440    pub fn get_fd_n32(&self) -> registers_enum::registers::Cop1N32 {
441        self.get_fd().try_into().unwrap()
442    }
443
444    pub fn get_fd_n64(&self) -> registers_enum::registers::Cop1N64 {
445        self.get_fd().try_into().unwrap()
446    }
447
448    pub fn get_cop1cs(&self) -> u32 {
449        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_cop1cs) {
450            core::panic!();
451        }
452
453        utils::shiftr(self.word, 11, 5)
454    }
455
456    pub fn get_cop1cs_cop1control(&self) -> registers_enum::registers::Cop1Control {
457        self.get_cop1cs().try_into().unwrap()
458    }
459
460    pub fn get_cop2t(&self) -> u32 {
461        if !self.has_operand_alias(operand_type_enum::OperandType::cpu_cop2t) {
462            core::panic!();
463        }
464
465        utils::shiftr(self.word, 16, 5)
466    }
467
468    pub fn get_cop2t_cop2(&self) -> registers_enum::registers::Cop2 {
469        self.get_cop2t().try_into().unwrap()
470    }
471
472    pub fn flags_get_r5900_disasm_as_data(&self) -> utils::TrinaryValue {
473        utils::shiftr(self.flags, 0, 2).try_into().unwrap()
474    }
475    pub fn flags_set_r5900_disasm_as_data(&mut self, value: utils::TrinaryValue) {
476        self.flags = utils::bitrepack(self.flags, value.into(), 0, 2);
477    }
478
479    pub fn flags_get_r5900_use_dollar(&self) -> utils::TrinaryValue {
480        utils::shiftr(self.flags, 2, 2).try_into().unwrap()
481    }
482    pub fn flags_set_r5900_use_dollar(&mut self, value: utils::TrinaryValue) {
483        self.flags = utils::bitrepack(self.flags, value.into(), 2, 2);
484    }
485
486    pub fn instr_id_type_name(&self) -> &'static str {
487        unsafe { std::ffi::CStr::from_ptr(RabInstrIdType_getName(self.instr_id_type)) }
488            .to_str()
489            .unwrap()
490    }
491
492    pub fn raw(&self) -> u32 {
493        unsafe { RabbitizerInstruction_getRaw(self) }
494    }
495    pub fn processed_immediate(&self) -> i32 {
496        unsafe { RabbitizerInstruction_getProcessedImmediate(self) }
497    }
498    pub fn instr_index_as_vram(&self) -> u32 {
499        unsafe { RabbitizerInstruction_getInstrIndexAsVram(self) }
500    }
501    pub fn branch_offset(&self) -> i32 {
502        unsafe { RabbitizerInstruction_getBranchOffset(self) }
503    }
504
505    pub fn branch_offset_generic(&self) -> i32 {
506        unsafe { RabbitizerInstruction_getBranchOffsetGeneric(self) }
507    }
508
509    pub fn branch_vram_generic(&self) -> u32 {
510        unsafe { RabbitizerInstruction_getBranchVramGeneric(self) }
511    }
512    pub fn destination_gpr(&self) -> Option<u32> {
513        unsafe {
514            let reg: i8 = RabbitizerInstruction_getDestinationGpr(self);
515
516            if reg < 0 {
517                return None;
518            }
519            Some(reg as u32)
520        }
521    }
522    pub fn outputs_to_gpr_zero(&self) -> bool {
523        unsafe { RabbitizerInstruction_outputsToGprZero(self) }
524    }
525    pub fn opcode_name(&self) -> &'static str {
526        unsafe {
527            std::ffi::CStr::from_ptr(RabbitizerInstrId_getOpcodeName(self.unique_id))
528                .to_str()
529                .unwrap()
530        }
531    }
532
533    pub fn blank_out(mut self) {
534        unsafe { RabbitizerInstruction_blankOut(&mut self) }
535    }
536
537    #[deprecated(since = "1.8.4", note = "please use `is_valid` instead")]
538    pub fn is_implemented(&self) -> bool {
539        unsafe { RabbitizerInstruction_isImplemented(self) }
540    }
541    pub fn is_likely_handwritten(&self) -> bool {
542        unsafe { RabbitizerInstruction_isLikelyHandwritten(self) }
543    }
544    pub fn is_nop(&self) -> bool {
545        unsafe { RabbitizerInstruction_isNop(self) }
546    }
547    pub fn is_unconditional_branch(&self) -> bool {
548        unsafe { RabbitizerInstruction_isUnconditionalBranch(self) }
549    }
550    pub fn is_function_call(&self) -> bool {
551        unsafe { RabbitizerInstruction_isFunctionCall(self) }
552    }
553
554    pub fn is_return(&self) -> bool {
555        unsafe { RabbitizerInstruction_isReturn(self) }
556    }
557    pub fn is_jumptable_jump(&self) -> bool {
558        unsafe { RabbitizerInstruction_isJumptableJump(self) }
559    }
560
561    pub fn has_delay_slot(&self) -> bool {
562        unsafe { RabbitizerInstruction_hasDelaySlot(self) }
563    }
564
565    pub fn same_opcode(&self, other: &Instruction) -> bool {
566        unsafe { RabbitizerInstruction_sameOpcode(self, other) }
567    }
568    pub fn same_opcode_but_different_arguments(&self, other: &Instruction) -> bool {
569        unsafe { RabbitizerInstruction_sameOpcodeButDifferentArguments(self, other) }
570    }
571
572    pub fn has_operand(&self, operand: operand_type_enum::OperandType) -> bool {
573        unsafe { RabbitizerInstruction_hasOperand(self, operand) }
574    }
575    pub fn has_operand_alias(&self, operand: operand_type_enum::OperandType) -> bool {
576        unsafe { RabbitizerInstruction_hasOperandAlias(self, operand) }
577    }
578
579    pub fn is_valid(&self) -> bool {
580        unsafe { RabbitizerInstruction_isValid(self) }
581    }
582
583    pub fn get_operand_type(&self, index: usize) -> operand_type_enum::OperandType {
584        unsafe { &*self.descriptor }.get_operand_type(index)
585    }
586
587    pub fn get_operands_slice(&self) -> &[operand_type_enum::OperandType] {
588        unsafe { &*self.descriptor }.operands_slice()
589    }
590
591    pub fn instr_suffix(&self) -> instr_suffix_enum::InstrSuffix {
592        unsafe { RabbitizerInstrDescriptor_instrSuffix(self.descriptor) }
593    }
594    pub fn is_branch(&self) -> bool {
595        unsafe { RabbitizerInstrDescriptor_isBranch(self.descriptor) }
596    }
597    pub fn is_branch_likely(&self) -> bool {
598        unsafe { RabbitizerInstrDescriptor_isBranchLikely(self.descriptor) }
599    }
600    pub fn is_jump(&self) -> bool {
601        unsafe { RabbitizerInstrDescriptor_isJump(self.descriptor) }
602    }
603    pub fn is_jump_with_address(&self) -> bool {
604        unsafe { RabbitizerInstrDescriptor_isJumpWithAddress(self.descriptor) }
605    }
606    pub fn is_trap(&self) -> bool {
607        unsafe { RabbitizerInstrDescriptor_isTrap(self.descriptor) }
608    }
609    pub fn is_float(&self) -> bool {
610        unsafe { RabbitizerInstrDescriptor_isFloat(self.descriptor) }
611    }
612    pub fn is_double(&self) -> bool {
613        unsafe { RabbitizerInstrDescriptor_isDouble(self.descriptor) }
614    }
615    pub fn is_unsigned(&self) -> bool {
616        unsafe { RabbitizerInstrDescriptor_isUnsigned(self.descriptor) }
617    }
618    pub fn modifies_rs(&self) -> bool {
619        unsafe { RabbitizerInstrDescriptor_modifiesRs(self.descriptor) }
620    }
621    pub fn modifies_rt(&self) -> bool {
622        unsafe { RabbitizerInstrDescriptor_modifiesRt(self.descriptor) }
623    }
624    pub fn modifies_rd(&self) -> bool {
625        unsafe { RabbitizerInstrDescriptor_modifiesRd(self.descriptor) }
626    }
627    pub fn reads_rs(&self) -> bool {
628        unsafe { RabbitizerInstrDescriptor_readsRs(self.descriptor) }
629    }
630    pub fn reads_rt(&self) -> bool {
631        unsafe { RabbitizerInstrDescriptor_readsRt(self.descriptor) }
632    }
633    pub fn reads_rd(&self) -> bool {
634        unsafe { RabbitizerInstrDescriptor_readsRd(self.descriptor) }
635    }
636    pub fn reads_hi(&self) -> bool {
637        unsafe { RabbitizerInstrDescriptor_readsHI(self.descriptor) }
638    }
639    pub fn reads_lo(&self) -> bool {
640        unsafe { RabbitizerInstrDescriptor_readsLO(self.descriptor) }
641    }
642    pub fn modifies_hi(&self) -> bool {
643        unsafe { RabbitizerInstrDescriptor_modifiesHI(self.descriptor) }
644    }
645    pub fn modifies_lo(&self) -> bool {
646        unsafe { RabbitizerInstrDescriptor_modifiesLO(self.descriptor) }
647    }
648    pub fn modifies_fs(&self) -> bool {
649        unsafe { RabbitizerInstrDescriptor_modifiesFs(self.descriptor) }
650    }
651    pub fn modifies_ft(&self) -> bool {
652        unsafe { RabbitizerInstrDescriptor_modifiesFt(self.descriptor) }
653    }
654    pub fn modifies_fd(&self) -> bool {
655        unsafe { RabbitizerInstrDescriptor_modifiesFd(self.descriptor) }
656    }
657    pub fn reads_fs(&self) -> bool {
658        unsafe { RabbitizerInstrDescriptor_readsFs(self.descriptor) }
659    }
660    pub fn reads_ft(&self) -> bool {
661        unsafe { RabbitizerInstrDescriptor_readsFt(self.descriptor) }
662    }
663    pub fn reads_fd(&self) -> bool {
664        unsafe { RabbitizerInstrDescriptor_readsFd(self.descriptor) }
665    }
666
667    // @deprecated
668    pub fn not_emited_by_compilers(&self) -> bool {
669        unsafe { RabbitizerInstrDescriptor_notEmittedByCompilers(self.descriptor) }
670    }
671    pub fn not_emitted_by_compilers(&self) -> bool {
672        unsafe { RabbitizerInstrDescriptor_notEmittedByCompilers(self.descriptor) }
673    }
674    pub fn can_be_hi(&self) -> bool {
675        unsafe { RabbitizerInstrDescriptor_canBeHi(self.descriptor) }
676    }
677    pub fn can_be_lo(&self) -> bool {
678        unsafe { RabbitizerInstrDescriptor_canBeLo(self.descriptor) }
679    }
680    pub fn does_link(&self) -> bool {
681        unsafe { RabbitizerInstrDescriptor_doesLink(self.descriptor) }
682    }
683    pub fn does_dereference(&self) -> bool {
684        unsafe { RabbitizerInstrDescriptor_doesDereference(self.descriptor) }
685    }
686    pub fn does_load(&self) -> bool {
687        unsafe { RabbitizerInstrDescriptor_doesLoad(self.descriptor) }
688    }
689    pub fn does_store(&self) -> bool {
690        unsafe { RabbitizerInstrDescriptor_doesStore(self.descriptor) }
691    }
692    pub fn maybe_is_move(&self) -> bool {
693        unsafe { RabbitizerInstrDescriptor_maybeIsMove(self.descriptor) }
694    }
695    pub fn is_pseudo(&self) -> bool {
696        unsafe { RabbitizerInstrDescriptor_isPseudo(self.descriptor) }
697    }
698    pub fn access_type(&self) -> access_type_enum::AccessType {
699        unsafe { RabbitizerInstrDescriptor_getAccessType(self.descriptor) }
700    }
701    pub fn does_unsigned_memory_access(&self) -> bool {
702        unsafe { RabbitizerInstrDescriptor_doesUnsignedMemoryAccess(self.descriptor) }
703    }
704
705    pub fn disassemble(
706        &self,
707        imm_override: Option<&str>,
708        extra_l_just: core::ffi::c_int,
709    ) -> String {
710        let (imm_override_ptr, imm_override_len) = utils::c_string_from_str(imm_override);
711
712        unsafe {
713            let buffer_size =
714                RabbitizerInstruction_getSizeForBuffer(self, imm_override_len, extra_l_just);
715
716            let mut buffer: Vec<u8> = vec![0; buffer_size + 1];
717            let disassembled_size = RabbitizerInstruction_disassemble(
718                self,
719                buffer.as_mut_ptr() as *mut core::ffi::c_char,
720                imm_override_ptr,
721                imm_override_len,
722                extra_l_just,
723            );
724            buffer.truncate(disassembled_size);
725
726            String::from_utf8(buffer).unwrap()
727        }
728    }
729}