diff --git a/hblang/examples/pointers.hb b/hblang/examples/pointers.hb index 3334de92..c0250da0 100644 --- a/hblang/examples/pointers.hb +++ b/hblang/examples/pointers.hb @@ -2,10 +2,16 @@ main := fn(): int { a := 1; b := &a; modify(b); - return a - 2; + drop(a); + stack_reclamation_edge_case := 0; + return *b - 2; } modify := fn(a: *int): void { *a = 2; return; } + +drop := fn(a: int): void { + return; +} diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 7b2c4ceb..2f0919a8 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -388,8 +388,9 @@ struct RetReloc { } struct Loop { - offset: u32, - relocs: Vec, + var_count: usize, + offset: u32, + relocs: Vec, } struct Struct { @@ -637,7 +638,7 @@ impl<'a> Codegen<'a> { let reg = self.gpa.allocate(); self.code .encode(instrs::ld(reg.0, dreg.0, offset, size as _)); - self.gpa.free(dreg); + self.free_reg(dreg); reg } Loc::DerefRef(dreg, offset) => { @@ -814,7 +815,7 @@ impl<'a> Codegen<'a> { let size = self.size_of(val.ty); let stack = self.sa.alloc(size); self.store_stack(r.0, stack.offset, size as _); - self.gpa.free(r); + self.free_reg(r); Loc::Stack(stack, 0) } l => l, @@ -886,11 +887,14 @@ impl<'a> Codegen<'a> { }); } E::Ident { name, id, last } => { - let Some(var) = self.vars.iter_mut().find(|v| v.id == id) else { + let Some((index, var)) = self.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) + else { self.report(expr.pos(), format_args!("unknown variable: {}", name)) }; - let loc = match last.is_some_and(Cell::get) { + let loc = match last.is_some_and(Cell::get) + && !self.loops.last().is_some_and(|l| l.var_count > index) + { true => std::mem::replace(&mut var.value.loc, Loc::Imm(0)), false => var.value.loc.take_ref(), }; @@ -921,7 +925,7 @@ impl<'a> Codegen<'a> { E::Block { stmts, .. } => { for stmt in stmts { if let Loc::Reg(reg) = self.expr(stmt)?.loc { - self.gpa.free(reg); + self.free_reg(reg); } } Some(Value::VOID) @@ -938,7 +942,7 @@ impl<'a> Codegen<'a> { let reg = self.loc_to_reg(cond.loc, 1); let jump_offset = self.code.code.len() as u32; self.code.encode(instrs::jeq(reg.0, 0, 0)); - self.gpa.free(reg); + self.free_reg(reg); log::dbg!("if-then"); let then_unreachable = self.expr(then).is_none(); @@ -978,8 +982,9 @@ impl<'a> Codegen<'a> { log::dbg!("loop"); let loop_start = self.code.code.len() as u32; self.loops.push(Loop { - offset: loop_start, - relocs: Default::default(), + var_count: self.vars.len() as _, + offset: loop_start, + relocs: Default::default(), }); let body_unreachable = self.expr(body).is_none(); @@ -1002,6 +1007,14 @@ impl<'a> Codegen<'a> { dest.copy_from_slice(&offset.to_ne_bytes()); } + for var in self + .vars + .drain(loop_.var_count as usize..) + .collect::>() + { + self.free_loc(var.value.loc); + } + if is_unreachable { log::dbg!("infinite loop"); break 'a None; @@ -1087,7 +1100,7 @@ impl<'a> Codegen<'a> { if let Some(op) = Self::math_op(op, signed, size) { self.code.encode(op(lhs.0, lhs.0, rhs.0)); - self.gpa.free(rhs); + self.free_reg(rhs); break 'ops Some(Value { ty, @@ -1105,7 +1118,7 @@ impl<'a> Codegen<'a> { let op_fn = if signed { i::cmps } else { i::cmpu }; self.code.encode(op_fn(lhs.0, lhs.0, rhs.0)); - self.gpa.free(rhs); + self.free_reg(rhs); self.code.encode(instrs::cmpui(lhs.0, lhs.0, against)); if matches!(op, T::Eq | T::Lt | T::Gt) { self.code.encode(instrs::not(lhs.0, lhs.0)); @@ -1130,6 +1143,10 @@ impl<'a> Codegen<'a> { } } + fn free_reg(&mut self, reg: LinReg) { + self.gpa.free(reg); + } + fn math_op( op: T, signed: bool, @@ -1160,8 +1177,8 @@ impl<'a> Codegen<'a> { fn free_loc(&mut self, loc: Loc) { match loc { - Loc::Reg(reg) => self.gpa.free(reg), - Loc::Deref(reg, ..) => self.gpa.free(reg), + Loc::Reg(reg) => self.free_reg(reg), + Loc::Deref(reg, ..) => self.free_reg(reg), Loc::Stack(stack, ..) => self.sa.free(stack), _ => {} } @@ -1199,7 +1216,7 @@ impl<'a> Codegen<'a> { if let Some(op) = Self::math_op(op, signed, size) { self.code.encode(op(lhs, lhs, rhs.0)); - self.gpa.free(rhs); + self.free_reg(rhs); return if let Ctx::Dest(dest) = ctx { self.assign(dest.ty, dest.loc, owned.map_or(Loc::RegRef(lhs), Loc::Reg)); Some(Value::VOID) @@ -1264,7 +1281,7 @@ impl<'a> Codegen<'a> { Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)), Loc::Deref(reg, off) => { self.code.encode(instrs::st(lhs.0, reg.0, off, size as _)); - self.gpa.free(reg); + self.free_reg(reg); } Loc::DerefRef(reg, off) => { self.code.encode(instrs::st(lhs.0, reg, off, size as _)); @@ -1275,7 +1292,7 @@ impl<'a> Codegen<'a> { } l => unimplemented!("{:?}", l), } - self.gpa.free(lhs); + self.free_reg(lhs); } ..=16 if matches!(right, Loc::RegRef(1)) => { let (lhs, loff) = left.ref_to_ptr(); @@ -1288,8 +1305,8 @@ impl<'a> Codegen<'a> { self.code .encode(instrs::bmc(lhs.0, rhs.0, size.try_into().unwrap())); - self.gpa.free(lhs); - self.gpa.free(rhs); + self.free_reg(lhs); + self.free_reg(rhs); } } diff --git a/hblang/tests/codegen_tests_loops.txt b/hblang/tests/codegen_tests_loops.txt index 7c59f6d9..8788c0c7 100644 --- a/hblang/tests/codegen_tests_loops.txt +++ b/hblang/tests/codegen_tests_loops.txt @@ -1,3 +1,3 @@ -code size: 452 +code size: 475 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_pointers.txt b/hblang/tests/codegen_tests_pointers.txt index b124b668..032d953a 100644 --- a/hblang/tests/codegen_tests_pointers.txt +++ b/hblang/tests/codegen_tests_pointers.txt @@ -1,3 +1,3 @@ -code size: 331 +code size: 318 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_structs.txt b/hblang/tests/codegen_tests_structs.txt index db6996d1..99f9da09 100644 --- a/hblang/tests/codegen_tests_structs.txt +++ b/hblang/tests/codegen_tests_structs.txt @@ -1,3 +1,3 @@ -code size: 530 +code size: 538 ret: 3 status: Ok(())