swamp_code_gen/
disasm.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use source_map_cache::SourceMapWrapper;
6use source_map_node::FileId;
7use std::fmt;
8use std::fmt::Write;
9use swamp_vm_debug_info::DebugInfo;
10use swamp_vm_disasm::disasm_instructions_color;
11use swamp_vm_isa::BinaryInstruction;
12use swamp_vm_types::types::{VariableRegister, VmType, show_frame_memory, write_basic_type};
13use swamp_vm_types::{FrameMemoryAddress, InstructionRange};
14
15#[must_use]
16pub const fn is_valid_file_id(file_id: FileId) -> bool {
17    file_id != 0 && file_id != 0xffff
18}
19pub fn show_parameters_and_variables(
20    return_type: &VmType,
21    variables: &[VariableRegister],
22    f: &mut dyn Write,
23) -> Result<(), fmt::Error> {
24    if !return_type.is_scalar() {
25        writeln!(f, "{}: {}", tinter::blue("r0"), &return_type,)?;
26        write_basic_type(&return_type.basic_type, FrameMemoryAddress(0), f, 0)?;
27        writeln!(f)?;
28    }
29
30    for variable_register in variables {
31        writeln!(
32            f,
33            "var{}: ({}): {} {}",
34            tinter::yellow(format!("{}", variable_register.unique_id_in_function)),
35            tinter::magenta(variable_register),
36            variable_register.register.ty,
37            variable_register.register.comment
38        )?;
39    }
40
41    Ok(())
42}
43
44/// # Panics
45///
46#[must_use]
47pub fn disasm_function(
48    return_type: &VmType,
49    instructions: &[BinaryInstruction],
50    range: &InstructionRange,
51    debug_info: &DebugInfo,
52    source_map_wrapper: &SourceMapWrapper,
53    use_color: bool,
54) -> String {
55    let mut header_output = String::new();
56
57    let info = debug_info.fetch(range.start.0 as usize).unwrap();
58
59    show_frame_memory(
60        &info.function_debug_info.frame_memory,
61        &mut header_output,
62        use_color,
63    )
64    .unwrap();
65
66    show_parameters_and_variables(
67        return_type,
68        &info.function_debug_info.frame_memory.variable_registers,
69        &mut header_output,
70    )
71    .expect("should work");
72
73    let asm = disasm_instructions_color(
74        instructions,
75        range,
76        debug_info,
77        source_map_wrapper,
78        use_color,
79    );
80
81    format!("{header_output}\n{asm}",)
82}
83
84pub fn disasm_whole_program(
85    debug_info: &DebugInfo,
86    source_map_wrapper: &SourceMapWrapper,
87    instructions: &[BinaryInstruction],
88    use_color: bool,
89) {
90    let mut current_ip: u32 = 0;
91
92    while current_ip < (instructions.len() - 1) as u32 {
93        if let Some(debug_info_for_pc) = debug_info.fetch(current_ip as usize) {
94            // log to stdout since this is a feature "asked" by the user
95            println!(
96                "{} ==========================================================================",
97                debug_info_for_pc.function_debug_info.name
98            );
99            let end_ip = current_ip + debug_info_for_pc.function_debug_info.ip_range.count.0;
100            //let instructions_slice = &instructions[current_ip as usize..end_ip as usize];
101
102            let output_string = disasm_function(
103                &debug_info_for_pc.function_debug_info.return_type,
104                instructions,
105                &debug_info_for_pc.function_debug_info.ip_range,
106                debug_info,
107                source_map_wrapper,
108                use_color,
109            );
110            println!("{output_string}"); // log to stdout since this is a feature "asked" by the user
111            current_ip = end_ip;
112        } else {
113            panic!("instruction pointer that is not covered")
114        }
115    }
116}