Skip to main content

vermilion_codegen/
binemit.rs

1//! A module for compiling Vermilion IR to bytecode.
2
3use crate::ir::{Module, Function, FunctionValue};
4use crate::entities::{Symbol};
5use crate::instruction::{InstructionData, Opcode};
6use std::collections::HashMap;
7use vermilion_object::{Artifact};
8
9/// A struct for emitting binary.
10pub struct Binemit {
11
12    /// The module to compile from.
13    pub module: Module,
14
15    /// The artifact that the compiler is emitting to.
16    artifact: Artifact,
17
18    /// Offset for compilation
19    offset: usize,
20
21    /// A list of symbols and their IDs.
22    symbols: HashMap<String, i64>,
23
24}
25
26impl Binemit {
27
28    /// Creates a new Binemit instance from a module.  This itself
29    /// doesn't actually compile the module.
30    pub fn new(module: Module) -> Self {
31        Binemit {
32            module,
33            artifact: Artifact::new(),
34            offset: 0,
35            symbols: HashMap::new()
36        }
37    }
38
39    /// Gets the byte for an opcode.
40    fn opcode_byte(opcode: Opcode) -> u8 {
41        // TODO: GET OPCODEW
42        match opcode {
43            Opcode::Pop => 0x05,
44            Opcode::Clone => 0x06,
45            Opcode::Clear => 0x07,
46            Opcode::Trap => 0x0a,
47            Opcode::BooleanAdd => 0x0e,
48            Opcode::BooleanSubtract => 0x0f,
49            Opcode::ByteAdd => 0x10,
50            Opcode::ByteSubtract => 0x11,
51            Opcode::ByteMultiply => 0x12,
52            Opcode::ByteDivide => 0x13,
53            Opcode::ByteRemainder => 0x14,
54            Opcode::IntegerAdd => 0x15,
55            Opcode::IntegerSubtract => 0x16,
56            Opcode::IntegerMultiply => 0x17,
57            Opcode::IntegerDivide => 0x18,
58            Opcode::IntegerRemainder => 0x19,
59            Opcode::FloatAdd => 0x1a,
60            Opcode::FloatSubtract => 0x1b,
61            Opcode::FloatMultiply => 0x1c,
62            Opcode::FloatDivide => 0x1d,
63            Opcode::FloatRemainder => 0x1e,
64            Opcode::CastBoolean => 0x1f,
65            Opcode::CastByte => 0x20,
66            Opcode::CastInteger => 0x21,
67            Opcode::CastFloat => 0x22,
68            Opcode::NegateBoolean => 0x23,
69            Opcode::NegateByte => 0x0, // unsupported instruction
70            Opcode::NegateInteger => 0x24,
71            Opcode::NegateFloat => 0x25,
72            Opcode::Load => 0x26,
73            Opcode::Store => 0x27,
74            Opcode::Realloc => 0x28,
75            Opcode::HeapSize => 0x29,
76            Opcode::Alloc => 0x2a,
77            Opcode::ReallocSection => 0x2b,
78            Opcode::SectionAddr => 0x2c,
79            Opcode::SectionShiftLeft => 0x2d,
80            Opcode::SectionShiftRight => 0x2e,
81            Opcode::Free => 0x2f,
82            Opcode::FreeAndShift => 0x30,
83            Opcode::Branch => 0x31,
84            Opcode::BranchIfZero => 0x32,
85            Opcode::BranchIfNotZero => 0x33,
86            Opcode::Equal => 0x34,
87            Opcode::GreaterThan => 0x35,
88            Opcode::LessThan => 0x36,
89            Opcode::GreaterThanOrEqual => 0x37,
90            Opcode::LessThanOrEqual => 0x38,
91            Opcode::Call => 0x39,
92            Opcode::Return => 0x3a
93        }
94    }
95
96    fn get_instruction_size(&self, func: &Function, inst: &InstructionData) -> i64 {
97        let mut size = 0;
98        for item in &inst.args {
99            size += self.get_size(func, func.values.get(item.0 as usize).unwrap());
100        }
101        size += 1;
102
103        size
104    }
105
106    /// Recursively checks the size of a value.
107    pub fn get_size(&self, func: &Function, value: &FunctionValue) -> i64 {
108        let size: i64;
109
110        match value {
111            FunctionValue::Block(_) => {
112                size = 9;
113            },
114            FunctionValue::Boolean(_) => {
115                size = 2;
116            },
117            FunctionValue::Byte(_) => {
118                size = 2;
119            },
120            FunctionValue::Integer(_) => {
121                size = 9;
122            },
123            FunctionValue::Float(_) => {
124                size = 9;
125            },
126            FunctionValue::Symbol(_) => {
127                size = 9;
128            },
129            FunctionValue::Instruction(data) => {
130                size = self.get_instruction_size(func, data);
131            }
132        }
133
134        size
135    }
136
137    fn compile_instruction(&self, func: &Function, blocks: &Vec<usize>, inst: &InstructionData) -> Vec<u8> {
138        let mut val = Vec::new();
139
140        for arg in &inst.args {
141            val.append(&mut self.compile_value(func, blocks, &func.values[arg.0 as usize]));
142        }
143
144        val.push(Binemit::opcode_byte(inst.opcode.clone()));
145
146        val
147    }
148
149    /// Compiles a value.
150    fn compile_value(&self, func: &Function, blocks: &Vec<usize>, value: &FunctionValue) -> Vec<u8> {
151        let mut val = Vec::new();
152        match value {
153            FunctionValue::Block(bl) => {
154                //size = 9;
155                // push integer
156                val.push(3);
157                
158                let mut addr = (bl.0 as i64).to_le_bytes().to_vec();
159                val.append(&mut addr);
160            },
161            FunctionValue::Boolean(r) => {
162                val.push(1);
163                if *r {
164                    val.push(1);
165                } else {
166                    val.push(0);
167                }
168                //val.push(r ? 1 : 0);
169            },
170            FunctionValue::Byte(r) => {
171                val.push(2);
172                val.push(*r);
173            },
174            FunctionValue::Integer(r) => {
175                val.push(3);
176                
177                let mut addr = r.to_le_bytes().to_vec();
178                val.append(&mut addr);
179            },
180            FunctionValue::Float(r) => {
181                val.push(4);
182                
183                let mut addr = r.to_le_bytes().to_vec();
184                val.append(&mut addr);
185            },
186            FunctionValue::Symbol(r) => {
187                val.push(3);
188                
189                let mut addr = self.symbols.get(r).unwrap().to_le_bytes().to_vec();
190                val.append(&mut addr);
191            },
192            FunctionValue::Instruction(data) => {
193                val = self.compile_instruction(func, blocks, &data);
194            }
195        }
196        val
197    }
198
199    /// Calculates the addresses of all blocks in a function
200    fn calc_addresses(&self, func: &Function) -> Vec<usize> {
201        let mut blocks = Vec::new();
202        let mut end = self.offset;
203
204        for block in &func.blocks {
205            let insts = &block.instructions;
206            let mut size = 0;
207
208            for inst in insts {
209                size += self.get_instruction_size(&func, &inst);
210            }
211
212            blocks.push(end);
213            end += size as usize;
214        }
215
216        blocks
217    }
218
219    /// Compiles a single function to bytecode.
220    fn compile_function(&self, func: &Function) -> Vec<u8> {
221        let mut bytes = Vec::new();
222
223        let blocks = self.calc_addresses(&func);
224
225        for block in &func.blocks {
226            for inst in &block.instructions {
227                bytes.append(&mut self.compile_instruction(func, &blocks, &inst))
228            }
229        }
230
231        bytes
232    }
233
234    /// Compiles the module to a list of bytes.
235    pub fn emit(&mut self) -> Artifact {
236        let mut artifact = self.artifact.clone();
237        let mut bytes = Vec::new();
238
239        // Resolve symbols
240        let mut id = 0;
241        for symbol in &self.module.symbols {
242            self.symbols.insert(symbol.0.to_string(), id);
243            id += 1;
244        }
245
246        for symbol in &self.module.symbols {
247            match symbol.1 {
248                Symbol::Local(func) => {
249                    artifact.symbols.insert(self.symbols[&symbol.0.clone()], vermilion_object::Symbol::Local(symbol.0.to_string(), self.offset));
250                    bytes.append(&mut self.compile_function(&func));
251                },
252                Symbol::External => {
253                    artifact.declare_function(self.symbols[&symbol.0.clone()], symbol.0.to_string());
254                }
255            }
256        }
257
258        artifact.program = bytes;
259
260        artifact
261    }
262
263}