gbf_core/decompiler/handlers/
special_two_operand.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#![deny(missing_docs)]

use crate::{
    decompiler::{
        ast::{assignable::AssignableKind, member_access, statement},
        function_decompiler::FunctionDecompilerError,
        function_decompiler_context::FunctionDecompilerContext,
        ProcessedInstruction, ProcessedInstructionBuilder,
    },
    instruction::Instruction,
    opcode::Opcode,
};

use super::OpcodeHandler;

/// Handles other instructions.
pub struct SpecialTwoOperandHandler;

impl OpcodeHandler for SpecialTwoOperandHandler {
    fn handle_instruction(
        &self,
        context: &mut FunctionDecompilerContext,
        instruction: &Instruction,
    ) -> Result<ProcessedInstruction, FunctionDecompilerError> {
        match instruction.opcode {
            Opcode::AccessMember => {
                let rhs = context.pop_assignable()?;
                let lhs = context.pop_assignable()?;

                let mut ma: AssignableKind = member_access(lhs, rhs)?.into();
                let ver = context
                    .ssa_context
                    .current_version_of_or_new(&ma.id_string());
                ma.set_ssa_version(ver);
                Ok(ProcessedInstructionBuilder::new().ssa_id(ma).build())
            }
            Opcode::Assign => {
                let rhs = context.pop_expression()?;
                let mut lhs = context.pop_assignable()?;

                // an assignment bumps the version of the lhs
                let ver = context.ssa_context.new_ssa_version_for(&lhs.id_string());
                lhs.set_ssa_version(ver);
                let stmt = statement(lhs, rhs);

                Ok(ProcessedInstructionBuilder::new()
                    .push_to_region(stmt.into())
                    .build())
            }
            _ => Err(FunctionDecompilerError::UnimplementedOpcode(
                instruction.opcode,
                context.current_block_id.unwrap(),
            )),
        }
    }
}