|
1 | 1 | //! Convert TACKY IR to ASM |
2 | 2 |
|
| 3 | +use std::{collections::HashMap, hash::Hash}; |
| 4 | + |
3 | 5 | use crate::{asm, ast, shared_types::Identifier, tacky}; |
4 | 6 |
|
5 | 7 | fn simple_binary_to_asm( |
@@ -190,6 +192,59 @@ fn program_to_asm(prog: &tacky::Program) -> asm::Program { |
190 | 192 | asm::Program { function: func } |
191 | 193 | } |
192 | 194 |
|
| 195 | +struct MoveToStack { |
| 196 | + stack_size: i32, |
| 197 | + // Symbol to stack offset |
| 198 | + symbol_map: HashMap<String, i32>, |
| 199 | +} |
| 200 | +impl MoveToStack { |
| 201 | + fn new() -> MoveToStack { |
| 202 | + MoveToStack { |
| 203 | + stack_size: 0, |
| 204 | + symbol_map: HashMap::new(), |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + fn to_stack(&mut self, val: &mut asm::Operand) { |
| 209 | + if let asm::Operand::Pseudo(id) = val { |
| 210 | + let offset = if let Some(offset) = self.symbol_map.get(id.val()) { |
| 211 | + *offset |
| 212 | + } else { |
| 213 | + self.stack_size += 4; |
| 214 | + self.symbol_map.insert(id.val().clone(), self.stack_size); |
| 215 | + self.stack_size |
| 216 | + }; |
| 217 | + *val = asm::Operand::Stack(-offset); |
| 218 | + } |
| 219 | + } |
| 220 | + |
| 221 | + /// Move pseudo register operands to the stack. Returns needed stack space. |
| 222 | + fn move_to_stack(&mut self, prog: &mut asm::Program) -> i32 { |
| 223 | + prog |
| 224 | + .function |
| 225 | + .instructions |
| 226 | + .iter_mut() |
| 227 | + .for_each(|instr| match instr { |
| 228 | + asm::Instruction::Move { src, dst } => { |
| 229 | + self.to_stack(src); |
| 230 | + self.to_stack(dst); |
| 231 | + } |
| 232 | + asm::Instruction::Return => todo!(), |
| 233 | + asm::Instruction::Neg(operand) => todo!(), |
| 234 | + asm::Instruction::Not(operand) => todo!(), |
| 235 | + asm::Instruction::AllocateStack(_) => todo!(), |
| 236 | + asm::Instruction::Binary { op, src, dst } => todo!(), |
| 237 | + asm::Instruction::Idiv(operand) => todo!(), |
| 238 | + asm::Instruction::Cdq => todo!(), |
| 239 | + asm::Instruction::Cmp { src, dst } => todo!(), |
| 240 | + asm::Instruction::Jmp(identifier) => todo!(), |
| 241 | + asm::Instruction::JmpCC(condition_code, identifier) => todo!(), |
| 242 | + asm::Instruction::SetCC(condition_code, operand) => todo!(), |
| 243 | + asm::Instruction::Label(identifier) => todo!(), |
| 244 | + }); |
| 245 | + self.stack_size |
| 246 | + } |
| 247 | +} |
193 | 248 | /// Convert TACKY IR to ASM |
194 | 249 | pub fn tacky_to_asm(prog: &tacky::Program) -> asm::Program { |
195 | 250 | let asm_prog: asm::Program = program_to_asm(prog); |
@@ -227,4 +282,31 @@ mod tests { |
227 | 282 | }; |
228 | 283 | Ok(()) |
229 | 284 | } |
| 285 | + |
| 286 | + #[test] |
| 287 | + fn pseudo_to_stack() { |
| 288 | + let mut prog = asm::Program { |
| 289 | + function: asm::Function { |
| 290 | + name: Identifier::new("main"), |
| 291 | + instructions: vec![asm::Instruction::Move { |
| 292 | + src: asm::Operand::Pseudo(Identifier::new("reg1")), |
| 293 | + dst: asm::Operand::Register(asm::RegId::AX), |
| 294 | + }], |
| 295 | + }, |
| 296 | + }; |
| 297 | + let mut mts = MoveToStack::new(); |
| 298 | + mts.move_to_stack(&mut prog); |
| 299 | + match prog.function.instructions[..] { |
| 300 | + [ |
| 301 | + asm::Instruction::Move { |
| 302 | + src: asm::Operand::Stack(-4), |
| 303 | + dst: _, |
| 304 | + }, |
| 305 | + ] => .., |
| 306 | + _ => panic!( |
| 307 | + "Operand not moved to stack: {:?}", |
| 308 | + prog.function.instructions |
| 309 | + ), |
| 310 | + }; |
| 311 | + } |
230 | 312 | } |
0 commit comments