forked from AbleOS/holey-bytes
implementing multiple breaks
This commit is contained in:
parent
514c2fe630
commit
803095c0c5
|
@ -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
|
||||||
}
|
//}
|
||||||
```
|
```
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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(())
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue