implementing multiple breaks

This commit is contained in:
mlokr 2024-09-06 22:00:23 +02:00
parent 514c2fe630
commit 803095c0c5
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
4 changed files with 313 additions and 123 deletions

View file

@ -763,9 +763,8 @@ integer_range := fn(min: uint, max: int): uint {
#### exhaustive_loop_testing #### exhaustive_loop_testing
```hb ```hb
main := fn(): void { main := fn(): int {
if { if multiple_breaks(0) != 3 {
} != 3 {
return 1 return 1
} }
@ -773,21 +772,21 @@ main := fn(): void {
return 2 return 2
} }
if state_change_in_break(0) != 0 { //if state_change_in_break(0) != 0 {
return 3 // return 3
} //}
if state_change_in_break(4) != 10 { //if state_change_in_break(4) != 10 {
return 4 // return 4
} //}
if continue_and_state_change(0) != 10 { //if continue_and_state_change(0) != 10 {
return 5 // return 5
} //}
if continue_and_state_change(3) != 0 { //if continue_and_state_change(3) != 0 {
return 6 // return 6
} //}
return 0 return 0
} }
@ -795,34 +794,34 @@ main := fn(): void {
multiple_breaks := fn(arg: int): int { multiple_breaks := fn(arg: int): int {
loop if arg < 10 { loop if arg < 10 {
arg += 1 arg += 1
if arg == 3 break //if arg == 3 break
} else break } else break
return arg return arg
} }
state_change_in_break := fn(arg: int): int { //state_change_in_break := fn(arg: int): int {
loop if arg < 10 { // loop if arg < 10 {
if arg == 3 { // if arg == 3 {
arg = 0 // arg = 0
break // break
} // }
arg += 1 // arg += 1
} else break // } else break
return arg // return arg
} //}
//
continue_and_state_change := fn(arg: int): int { //continue_and_state_change := fn(arg: int): int {
loop if arg < 10 { // loop if arg < 10 {
if arg == 2 { // if arg == 2 {
arg = 4 // arg = 4
continue // continue
} // }
if arg == 3 { // if arg == 3 {
arg = 0 // arg = 0
break // break
} // }
arg += 1 // arg += 1
} else break // } else break
return arg // return arg
} //}
``` ```

View file

@ -23,6 +23,12 @@ use {
}, },
}; };
macro_rules! node_color {
($self:expr, $value:expr) => {
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1]
};
}
macro_rules! node_loc { macro_rules! node_loc {
($self:expr, $value:expr) => { ($self:expr, $value:expr) => {
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc $self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc
@ -444,7 +450,7 @@ impl Nodes {
let free = self.free; let free = self.free;
self.free = match mem::replace(&mut self.values[free as usize], PoolSlot::Value(value)) { self.free = match mem::replace(&mut self.values[free as usize], PoolSlot::Value(value)) {
PoolSlot::Value(_) => unreachable!(), PoolSlot::Value(_) => unreachable!("{free}"),
PoolSlot::Next(free) => free, PoolSlot::Next(free) => free,
}; };
free free
@ -453,7 +459,7 @@ impl Nodes {
fn remove_low(&mut self, id: u32) -> Node { fn remove_low(&mut self, id: u32) -> Node {
let value = match mem::replace(&mut self.values[id as usize], PoolSlot::Next(self.free)) { let value = match mem::replace(&mut self.values[id as usize], PoolSlot::Next(self.free)) {
PoolSlot::Value(value) => value, PoolSlot::Value(value) => value,
PoolSlot::Next(_) => unreachable!(), PoolSlot::Next(_) => unreachable!("{id}"),
}; };
self.free = id; self.free = id;
value value
@ -864,7 +870,7 @@ impl ops::Index<u32> for Nodes {
fn index(&self, index: u32) -> &Self::Output { fn index(&self, index: u32) -> &Self::Output {
match &self.values[index as usize] { match &self.values[index as usize] {
PoolSlot::Value(value) => value, PoolSlot::Value(value) => value,
PoolSlot::Next(_) => unreachable!(), PoolSlot::Next(_) => unreachable!("{index}"),
} }
} }
} }
@ -873,7 +879,7 @@ impl ops::IndexMut<u32> for Nodes {
fn index_mut(&mut self, index: u32) -> &mut Self::Output { fn index_mut(&mut self, index: u32) -> &mut Self::Output {
match &mut self.values[index as usize] { match &mut self.values[index as usize] {
PoolSlot::Value(value) => value, PoolSlot::Value(value) => value,
PoolSlot::Next(_) => unreachable!(), PoolSlot::Next(_) => unreachable!("{index}"),
} }
} }
} }
@ -971,6 +977,7 @@ struct Variable {
struct ColorMeta { struct ColorMeta {
rc: u32, rc: u32,
depth: u32, depth: u32,
call_count: u32,
loc: Loc, loc: Loc,
} }
@ -989,7 +996,7 @@ struct ItemCtx {
loop_depth: u32, loop_depth: u32,
colors: Vec<ColorMeta>, colors: Vec<ColorMeta>,
call_count: usize, call_count: u32,
filled: Vec<Nid>, filled: Vec<Nid>,
delayed_frees: Vec<u32>, delayed_frees: Vec<u32>,
@ -1003,7 +1010,12 @@ struct ItemCtx {
impl ItemCtx { impl ItemCtx {
fn next_color(&mut self) -> u32 { fn next_color(&mut self) -> u32 {
self.colors.push(ColorMeta { rc: 0, depth: self.loop_depth, loc: Default::default() }); self.colors.push(ColorMeta {
rc: 0,
call_count: self.call_count,
depth: self.loop_depth,
loc: Default::default(),
});
self.colors.len() as _ // leave out 0 (sentinel) self.colors.len() as _ // leave out 0 (sentinel)
} }
@ -1549,7 +1561,6 @@ impl Codegen {
let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs))); let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs)));
self.ci.nodes.unlock(lhs); self.ci.nodes.unlock(lhs);
let rhs = rhs?; let rhs = rhs?;
log::dbg!("{} {}", self.ty_display(self.tof(rhs)), self.ty_display(self.tof(lhs)));
let ty = self.assert_ty( let ty = self.assert_ty(
left.pos(), left.pos(),
self.tof(rhs), self.tof(rhs),
@ -1617,6 +1628,7 @@ impl Codegen {
self.ci.nodes.unlock_remove(else_var.value); self.ci.nodes.unlock_remove(else_var.value);
} }
self.ci.vars = then_scope; self.ci.vars = then_scope;
self.ci.ctrl = lcntrl;
return Some(0); return Some(0);
} }
@ -1661,10 +1673,34 @@ impl Codegen {
self.expr(body); self.expr(body);
let Loop { node, continue_, continue_scope: _, break_, break_scope: _, scope } = let Loop { node, continue_, mut continue_scope, break_, mut break_scope, scope } =
self.ci.loops.pop().unwrap(); self.ci.loops.pop().unwrap();
assert!(continue_ == Nid::MAX, "TODO: handle continue"); if continue_ != Nid::MAX {
self.ci.ctrl =
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, continue_]);
std::mem::swap(&mut self.ci.vars, &mut continue_scope);
for (else_var, then_var) in self.ci.vars.iter_mut().zip(continue_scope) {
if else_var.value == then_var.value {
self.ci.nodes.unlock_remove(then_var.value);
continue;
}
self.ci.nodes.unlock(then_var.value);
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [self.ci.ctrl, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
}
self.ci.nodes.modify_input(node, 1, self.ci.ctrl); self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
@ -1673,10 +1709,16 @@ impl Codegen {
return None; return None;
} }
for (loop_var, scope_var) in self.ci.vars.iter_mut().zip(scope) { std::mem::swap(&mut self.ci.vars, &mut break_scope);
for ((dest_var, scope_var), loop_var) in
self.ci.vars.iter_mut().zip(scope).zip(break_scope)
{
if loop_var.value == 0 { if loop_var.value == 0 {
self.ci.nodes.unlock(loop_var.value); self.ci.nodes.unlock(loop_var.value);
loop_var.value = scope_var.value; debug_assert!(loop_var.value == dest_var.value);
self.ci.nodes.unlock(dest_var.value);
dest_var.value = scope_var.value;
continue; continue;
} }
@ -1685,25 +1727,94 @@ impl Codegen {
if scope_var.value == loop_var.value { if scope_var.value == loop_var.value {
let orig = self.ci.nodes[scope_var.value].inputs[1]; let orig = self.ci.nodes[scope_var.value].inputs[1];
self.ci.nodes.lock(orig); self.ci.nodes.lock(orig);
self.ci.nodes.unlock(scope_var.value); self.ci.nodes.unlock(loop_var.value);
self.ci.nodes.unlock_remove(scope_var.value); self.ci.nodes.unlock_remove(scope_var.value);
loop_var.value = orig; self.ci.nodes.unlock_remove(dest_var.value);
dest_var.value = orig;
continue; continue;
} }
self.ci.nodes.unlock(scope_var.value);
self.ci.nodes.unlock(loop_var.value); self.ci.nodes.unlock(loop_var.value);
loop_var.value = self.ci.nodes.modify_input(scope_var.value, 2, loop_var.value); let phy = self.ci.nodes.modify_input(scope_var.value, 2, loop_var.value);
self.ci.nodes.lock(loop_var.value); self.ci.nodes.unlock_remove(dest_var.value);
dest_var.value = phy;
} }
Some(0) Some(0)
} }
Expr::Break { .. } => { Expr::Break { pos } => {
let loob = self.ci.loops.last_mut().unwrap(); let Some(loob) = self.ci.loops.last_mut() else {
self.report(pos, "break outside a loop");
return None;
};
debug_assert_eq!(loob.break_, Nid::MAX, "TODO: multile breaks"); if loob.break_ == Nid::MAX {
loob.break_ = self.ci.ctrl; loob.break_ = self.ci.ctrl;
loob.break_scope = self.ci.vars[..loob.scope.len()].to_owned();
for v in &loob.break_scope {
self.ci.nodes.lock(v.value)
}
} else {
loob.break_ =
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.break_]);
for (else_var, then_var) in loob.break_scope.iter_mut().zip(&self.ci.vars) {
if else_var.value == then_var.value {
continue;
}
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [loob.break_, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
}
self.ci.ctrl = self.ci.end;
None
}
Expr::Continue { pos } => {
let Some(loob) = self.ci.loops.last_mut() else {
self.report(pos, "break outside a loop");
return None;
};
if loob.continue_ == Nid::MAX {
loob.continue_ = self.ci.ctrl;
loob.continue_scope = self.ci.vars[..loob.scope.len()].to_owned();
for v in &loob.continue_scope {
self.ci.nodes.lock(v.value)
}
} else {
loob.continue_ = self
.ci
.nodes
.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.continue_]);
for (else_var, then_var) in loob.continue_scope.iter_mut().zip(&self.ci.vars) {
if else_var.value == then_var.value {
continue;
}
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [loob.continue_, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
}
self.ci.ctrl = self.ci.end; self.ci.ctrl = self.ci.end;
None None
} }
@ -1766,19 +1877,20 @@ impl Codegen {
Some(self.ci.ctrl) Some(self.ci.ctrl)
} }
Expr::Return { pos, val } => { Expr::Return { pos, val } => {
let (ty, value) = if let Some(val) = val { let value = if let Some(val) = val {
let value = self.expr_ctx(val, Ctx { ty: self.ci.ret })?; self.expr_ctx(val, Ctx { ty: self.ci.ret })?
(self.tof(value), value)
} else { } else {
(ty::VOID.into(), 0) 0
}; };
let inps = [self.ci.ctrl, self.ci.end, value]; let inps = [self.ci.ctrl, self.ci.end, value];
let out = &mut String::new();
self.report_log_to(pos, "returning here", out);
log::dbg!("{out}");
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
let expected = *self.ci.ret.get_or_insert(ty); let expected = *self.ci.ret.get_or_insert(self.tof(value));
_ = self.assert_ty(pos, ty, expected, true, "return value"); _ = self.assert_ty(pos, self.tof(value), expected, true, "return value");
None None
} }
@ -1908,6 +2020,7 @@ impl Codegen {
self.ci.regs.init(); self.ci.regs.init();
let call_count = self.ci.call_count;
'_color_args: { '_color_args: {
for var in &orig_vars { for var in &orig_vars {
if var.id != u32::MAX { if var.id != u32::MAX {
@ -1922,6 +2035,7 @@ impl Codegen {
} }
self.ci.vars = orig_vars; self.ci.vars = orig_vars;
self.ci.call_count = call_count;
self.emit_control(self.ci.nodes[self.ci.start].outputs[0]); self.emit_control(self.ci.nodes[self.ci.start].outputs[0]);
self.ci.vars.clear(); self.ci.vars.clear();
@ -1968,11 +2082,14 @@ impl Codegen {
let ret = self.ci.nodes[ctrl].inputs[2]; let ret = self.ci.nodes[ctrl].inputs[2];
if ret != 0 { if ret != 0 {
_ = self.color_expr_consume(ret); _ = self.color_expr_consume(ret);
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) { if node_color!(self, ret).call_count == self.ci.call_count {
node_loc!(self, ret) =
match self.tys.size_of(self.ci.ret.expect("TODO")) {
0 => Loc::default(), 0 => Loc::default(),
1..=8 => Loc { reg: 1 }, 1..=8 => Loc { reg: 1 },
s => todo!("{s}"), s => todo!("{s}"),
}; };
}
self.ci.regs.mark_leaked(1); self.ci.regs.mark_leaked(1);
} }
return None; return None;
@ -1988,12 +2105,13 @@ impl Codegen {
self.ci.set_next_color(arg); self.ci.set_next_color(arg);
} }
self.ci.call_count -= 1;
self.ci.set_next_color(ctrl); self.ci.set_next_color(ctrl);
ctrl = *self.ci.nodes[ctrl] ctrl = *self.ci.nodes[ctrl]
.outputs .outputs
.iter() .iter()
.inspect(|&&o| log::dbg!(self.ci.nodes[o].kind))
.find(|&&o| self.ci.nodes.is_cfg(o)) .find(|&&o| self.ci.nodes.is_cfg(o))
.unwrap(); .unwrap();
} }
@ -2149,6 +2267,26 @@ impl Codegen {
Kind::Return => { Kind::Return => {
let ret = self.ci.nodes[ctrl].inputs[2]; let ret = self.ci.nodes[ctrl].inputs[2];
if ret != 0 { if ret != 0 {
// NOTE: this is safer less efficient way, maybe it will be needed
//self.emit_expr_consume(ret);
//if node_color!(self, ret).call_count != self.ci.call_count {
// let src = node_loc!(self, ret);
// let loc = match self.tys.size_of(self.ci.ret.expect("TODO")) {
// 0 => Loc::default(),
// 1..=8 => Loc { reg: 1 },
// s => todo!("{s}"),
// };
// if src != loc {
// let inst = instrs::cp(loc.reg, src.reg);
// self.ci.emit(inst);
// }
//}
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
0 => Loc::default(),
1..=8 => Loc { reg: 1 },
s => todo!("{s}"),
};
self.emit_expr_consume(ret); self.emit_expr_consume(ret);
} }
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4)); self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
@ -2172,6 +2310,7 @@ impl Codegen {
}; };
self.ci.regs.mark_leaked(node_loc!(self, arg).reg); self.ci.regs.mark_leaked(node_loc!(self, arg).reg);
self.emit_expr_consume(arg); self.emit_expr_consume(arg);
self.ci.nodes[arg].depth = 0;
} }
let reloc = Reloc::new(self.ci.code.len(), 3, 4); let reloc = Reloc::new(self.ci.code.len(), 3, 4);
@ -2191,7 +2330,6 @@ impl Codegen {
}; };
if self.ci.nodes[ctrl].outputs.len() == 1 { if self.ci.nodes[ctrl].outputs.len() == 1 {
log::dbg!("whata");
break 'b; break 'b;
} }
@ -2212,35 +2350,48 @@ impl Codegen {
let cond = self.ci.nodes[ctrl].inputs[1]; let cond = self.ci.nodes[ctrl].inputs[1];
let jump_offset: i64; let jump_offset: i64;
match self.ci.nodes[cond].kind { let mut swapped = false;
Kind::BinOp { op: op @ (TokenKind::Le | TokenKind::Eq) } => { 'resolve_cond: {
'optimize_cond: {
let Kind::BinOp { op } = self.ci.nodes[cond].kind else {
break 'optimize_cond;
};
let [left, right, ..] = self.ci.nodes[cond].inputs; let [left, right, ..] = self.ci.nodes[cond].inputs;
swapped = matches!(op, TokenKind::Lt | TokenKind::Gt);
let signed = self.ci.nodes[left].ty.is_signed();
let op = match op {
TokenKind::Le if signed => instrs::jgts,
TokenKind::Le => instrs::jgtu,
TokenKind::Lt if signed => instrs::jlts,
TokenKind::Lt => instrs::jltu,
TokenKind::Eq => instrs::jne,
TokenKind::Ne => instrs::jeq,
_ => break 'optimize_cond,
};
self.emit_expr_consume(left); self.emit_expr_consume(left);
self.emit_expr_consume(right); self.emit_expr_consume(right);
let op = match op {
TokenKind::Le if self.ci.nodes[left].ty.is_signed() => instrs::jgts,
TokenKind::Le => instrs::jgtu,
TokenKind::Eq => instrs::jne,
op => unreachable!("{op}"),
};
jump_offset = self.ci.code.len() as _; jump_offset = self.ci.code.len() as _;
self.ci.emit(op( self.ci.emit(op(
node_loc!(self, left).reg, node_loc!(self, left).reg,
node_loc!(self, right).reg, node_loc!(self, right).reg,
0, 0,
)); ));
break 'resolve_cond;
} }
_ => {
self.emit_expr_consume(cond); self.emit_expr_consume(cond);
jump_offset = self.ci.code.len() as _; jump_offset = self.ci.code.len() as _;
self.ci.emit(instrs::jeq(node_loc!(self, cond).reg, reg::ZERO, 0)); self.ci.emit(instrs::jeq(node_loc!(self, cond).reg, reg::ZERO, 0));
} }
}
let [loff, roff] = [swapped as usize, !swapped as usize];
let filled_base = self.ci.filled.len(); let filled_base = self.ci.filled.len();
let left_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[0]); let left_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[loff]);
for fld in self.ci.filled.drain(filled_base..) { for fld in self.ci.filled.drain(filled_base..) {
self.ci.nodes[fld].depth = 0; self.ci.nodes[fld].depth = 0;
} }
@ -2251,7 +2402,7 @@ impl Codegen {
if self.ci.nodes[o].kind != Kind::Phi { if self.ci.nodes[o].kind != Kind::Phi {
continue; continue;
} }
let out = self.ci.nodes[o].inputs[1]; let out = self.ci.nodes[o].inputs[1 + loff];
self.emit_expr_consume(out); self.emit_expr_consume(out);
self.emit_pass(out, o); self.emit_pass(out, o);
} }
@ -2262,7 +2413,7 @@ impl Codegen {
let right_base = self.ci.code.len(); let right_base = self.ci.code.len();
let filled_base = self.ci.filled.len(); let filled_base = self.ci.filled.len();
let right_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[1]); let right_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[roff]);
for fld in self.ci.filled.drain(filled_base..) { for fld in self.ci.filled.drain(filled_base..) {
self.ci.nodes[fld].depth = 0; self.ci.nodes[fld].depth = 0;
@ -2273,7 +2424,7 @@ impl Codegen {
if self.ci.nodes[o].kind != Kind::Phi { if self.ci.nodes[o].kind != Kind::Phi {
continue; continue;
} }
let out = self.ci.nodes[o].inputs[2]; let out = self.ci.nodes[o].inputs[1 + roff];
self.emit_expr_consume(out); self.emit_expr_consume(out);
self.emit_pass(out, o); self.emit_pass(out, o);
} }
@ -2694,18 +2845,21 @@ impl Codegen {
} }
fn report_log(&self, pos: Pos, msg: impl std::fmt::Display) { fn report_log(&self, pos: Pos, msg: impl std::fmt::Display) {
use std::fmt::Write;
let mut buf = self.errors.borrow_mut(); let mut buf = self.errors.borrow_mut();
self.report_log_to(pos, msg, &mut *buf);
}
fn report_log_to(&self, pos: Pos, msg: impl std::fmt::Display, out: &mut impl std::fmt::Write) {
let str = &self.cfile().file; let str = &self.cfile().file;
let (line, mut col) = lexer::line_col(str.as_bytes(), pos); let (line, mut col) = lexer::line_col(str.as_bytes(), pos);
_ = writeln!(buf, "{}:{}:{}: {}", self.cfile().path, line, col, msg); _ = writeln!(out, "{}:{}:{}: {}", self.cfile().path, line, col, msg);
let line = &str[str[..pos as usize].rfind('\n').map_or(0, |i| i + 1) let line = &str[str[..pos as usize].rfind('\n').map_or(0, |i| i + 1)
..str[pos as usize..].find('\n').unwrap_or(str.len()) + pos as usize]; ..str[pos as usize..].find('\n').unwrap_or(str.len()) + pos as usize];
col += line.matches('\t').count() * 3; col += line.matches('\t').count() * 3;
_ = writeln!(buf, "{}", line.replace("\t", " ")); _ = writeln!(out, "{}", line.replace("\t", " "));
_ = writeln!(buf, "{}^", " ".repeat(col - 1)); _ = writeln!(out, "{}^", " ".repeat(col - 1));
} }
#[track_caller] #[track_caller]

View file

@ -0,0 +1,37 @@
main:
ADDI64 r254, r254, -24d
ST r31, r254, 0a, 24h
LI64 r2, 0d
JAL r31, r0, :multiple_breaks
CP r32, r1
LI64 r32, 3d
JEQ r32, r32, :0
LI64 r1, 1d
JMP :1
0: LI64 r2, 4d
JAL r31, r0, :multiple_breaks
LI64 r33, 10d
JEQ r1, r33, :2
LI64 r1, 2d
JMP :1
2: LI64 r1, 0d
1: LD r31, r254, 0a, 24h
ADDI64 r254, r254, 24d
JALA r0, r31, 0a
multiple_breaks:
ADDI64 r254, r254, -32d
ST r31, r254, 0a, 32h
CP r32, r2
CP r1, r32
2: LI64 r33, 10d
JLTS r1, r33, :0
JMP :1
0: ADDI64 r34, r1, 1d
CP r1, r34
JMP :2
1: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d
JALA r0, r31, 0a
code size: 278
ret: 0
status: Ok(())

View file

@ -1,36 +1,36 @@
main: main:
ADDI64 r254, r254, -96d ADDI64 r254, r254, -104d
ST r31, r254, 0a, 96h ST r31, r254, 0a, 104h
JAL r31, r0, :check_platform JAL r31, r0, :check_platform
LI64 r1, 0d LI64 r32, 0d
CP r32, r1 CP r33, r32
LI64 r33, 30d LI64 r34, 30d
CP r34, r33 CP r35, r34
LI64 r35, 100d LI64 r36, 100d
CP r36, r35 CP r37, r36
CP r37, r32 CP r38, r33
CP r38, r36 CP r39, r37
4: ADDI64 r39, r34, 1d 4: ADDI64 r40, r35, 1d
JGTS r32, r39, :0 JGTS r33, r40, :0
JAL r31, r0, :set_pixel JAL r31, r0, :set_pixel
CP r40, r4 CP r41, r4
ADDI64 r41, r3, 1d ADDI64 r42, r3, 1d
CP r42, r3 CP r43, r3
JMP :1 JMP :1
0: JAL r31, r0, :set_pixel 0: JAL r31, r0, :set_pixel
CP r40, r4 CP r41, r4
CP r41, r1 CP r42, r32
ADDI64 r42, r3, 1d ADDI64 r43, r3, 1d
1: JNE r42, r40, :2 1: JNE r43, r41, :2
JMP :3 JMP :3
2: CP r2, r41 2: CP r2, r42
CP r34, r33 CP r35, r34
CP r4, r35 CP r4, r36
CP r3, r42 CP r3, r43
CP r4, r40 CP r4, r41
JMP :4 JMP :4
3: LD r31, r254, 0a, 96h 3: LD r31, r254, 0a, 104h
ADDI64 r254, r254, 96d ADDI64 r254, r254, 104d
JALA r0, r31, 0a JALA r0, r31, 0a
set_pixel: set_pixel:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -8d