forked from AbleOS/holey-bytes
if a phy does not depend of different phy in the same loop we can modify it in place saving a register copy
This commit is contained in:
parent
803095c0c5
commit
49387dbe16
|
@ -794,7 +794,7 @@ main := fn(): int {
|
|||
multiple_breaks := fn(arg: int): int {
|
||||
loop if arg < 10 {
|
||||
arg += 1
|
||||
//if arg == 3 break
|
||||
if arg == 3 break
|
||||
} else break
|
||||
return arg
|
||||
}
|
||||
|
@ -809,7 +809,7 @@ multiple_breaks := fn(arg: int): int {
|
|||
// } else break
|
||||
// return arg
|
||||
//}
|
||||
//
|
||||
|
||||
//continue_and_state_change := fn(arg: int): int {
|
||||
// loop if arg < 10 {
|
||||
// if arg == 2 {
|
||||
|
|
|
@ -20,6 +20,7 @@ use {
|
|||
mem,
|
||||
ops::{self, Range},
|
||||
rc::Rc,
|
||||
usize,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -35,6 +36,37 @@ macro_rules! node_loc {
|
|||
};
|
||||
}
|
||||
|
||||
struct Drom(&'static str);
|
||||
|
||||
impl Drop for Drom {
|
||||
fn drop(&mut self) {
|
||||
log::inf!("{}", self.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BitSet {
|
||||
data: Vec<usize>,
|
||||
}
|
||||
|
||||
impl BitSet {
|
||||
const ELEM_SIZE: usize = std::mem::size_of::<usize>() * 8;
|
||||
|
||||
pub fn clear(&mut self, bit_size: usize) {
|
||||
let new_len = (bit_size + Self::ELEM_SIZE - 1) / Self::ELEM_SIZE;
|
||||
self.data.clear();
|
||||
self.data.resize(new_len, 0);
|
||||
}
|
||||
|
||||
pub fn set(&mut self, idx: usize) -> bool {
|
||||
let data_idx = idx / Self::ELEM_SIZE;
|
||||
let sub_idx = idx % Self::ELEM_SIZE;
|
||||
let prev = self.data[data_idx] & (1 << sub_idx);
|
||||
self.data[data_idx] |= 1 << sub_idx;
|
||||
prev == 0
|
||||
}
|
||||
}
|
||||
|
||||
type Nid = u32;
|
||||
|
||||
mod reg {
|
||||
|
@ -431,13 +463,19 @@ mod ty {
|
|||
|
||||
struct Nodes {
|
||||
values: Vec<PoolSlot>,
|
||||
visited: BitSet,
|
||||
free: u32,
|
||||
lookup: HashMap<(Kind, [Nid; MAX_INPUTS], ty::Id), Nid>,
|
||||
}
|
||||
|
||||
impl Default for Nodes {
|
||||
fn default() -> Self {
|
||||
Self { values: Default::default(), free: u32::MAX, lookup: Default::default() }
|
||||
Self {
|
||||
values: Default::default(),
|
||||
free: u32::MAX,
|
||||
lookup: Default::default(),
|
||||
visited: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,6 +759,13 @@ impl Nodes {
|
|||
self.remove(id)
|
||||
}
|
||||
|
||||
fn iter(&self) -> impl DoubleEndedIterator<Item = (Nid, &Node)> {
|
||||
self.values.iter().enumerate().filter_map(|(i, s)| match s {
|
||||
PoolSlot::Value(v) => Some((i as _, v)),
|
||||
PoolSlot::Next(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter, node: Nid, rcs: &mut [usize]) -> fmt::Result {
|
||||
let mut is_ready = || {
|
||||
if rcs[node as usize] == 0 {
|
||||
|
@ -803,6 +848,27 @@ impl Nodes {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn graphviz_low(&self, out: &mut String) -> std::fmt::Result {
|
||||
use std::fmt::Write;
|
||||
|
||||
for (i, node) in self.iter() {
|
||||
let color = if self.is_cfg(i) { "yellow" } else { "white" };
|
||||
writeln!(out, "node{i}[label=\"{}\" color={color}]", node.kind)?;
|
||||
for &o in &node.outputs {
|
||||
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "black" };
|
||||
writeln!(out, "node{o} -> node{i}[color={color}]",)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn graphviz(&self) {
|
||||
let out = &mut String::new();
|
||||
_ = self.graphviz_low(out);
|
||||
log::inf!("{out}");
|
||||
}
|
||||
|
||||
fn is_cfg(&self, o: Nid) -> bool {
|
||||
matches!(
|
||||
self[o].kind,
|
||||
|
@ -819,49 +885,63 @@ impl Nodes {
|
|||
|
||||
fn check_final_integrity(&self) {
|
||||
let mut failed = false;
|
||||
for (slot, i) in self.values.iter().zip(0u32..) {
|
||||
match slot {
|
||||
PoolSlot::Value(node) => {
|
||||
debug_assert_eq!(node.lock_rc, 0, "{:?}", node.kind);
|
||||
if !matches!(node.kind, Kind::Return | Kind::End) && node.outputs.is_empty() {
|
||||
log::err!("outputs are empry {i} {:?}", node.kind);
|
||||
failed = true;
|
||||
}
|
||||
for (i, node) in self.iter() {
|
||||
debug_assert_eq!(node.lock_rc, 0, "{:?}", node.kind);
|
||||
if !matches!(node.kind, Kind::Return | Kind::End) && node.outputs.is_empty() {
|
||||
log::err!("outputs are empry {i} {:?}", node.kind);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
for &o in &node.outputs {
|
||||
let mut occurs = 0;
|
||||
let other = match &self.values[o as usize] {
|
||||
PoolSlot::Value(other) => other,
|
||||
PoolSlot::Next(_) => {
|
||||
log::err!(
|
||||
"the edge points to dropped node: {i} {:?} {o}",
|
||||
node.kind,
|
||||
);
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Kind::Call { ref args, .. } = other.kind {
|
||||
occurs = args.iter().filter(|&&el| el == i).count();
|
||||
}
|
||||
occurs += self[o].inputs.iter().filter(|&&el| el == i).count();
|
||||
if occurs == 0 {
|
||||
log::err!(
|
||||
"the edge is not bidirectional: {i} {:?} {o} {:?}",
|
||||
node.kind,
|
||||
other.kind
|
||||
);
|
||||
failed = true;
|
||||
}
|
||||
for &o in &node.outputs {
|
||||
let mut occurs = 0;
|
||||
let other = match &self.values[o as usize] {
|
||||
PoolSlot::Value(other) => other,
|
||||
PoolSlot::Next(_) => {
|
||||
log::err!("the edge points to dropped node: {i} {:?} {o}", node.kind,);
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Kind::Call { ref args, .. } = other.kind {
|
||||
occurs = args.iter().filter(|&&el| el == i).count();
|
||||
}
|
||||
occurs += self[o].inputs.iter().filter(|&&el| el == i).count();
|
||||
if occurs == 0 {
|
||||
log::err!(
|
||||
"the edge is not bidirectional: {i} {:?} {o} {:?}",
|
||||
node.kind,
|
||||
other.kind
|
||||
);
|
||||
failed = true;
|
||||
}
|
||||
PoolSlot::Next(_) => {}
|
||||
}
|
||||
}
|
||||
if failed {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_scope_integrity(&self, scope: &[Variable]) {
|
||||
for v in scope {
|
||||
debug_assert!(self[v.value].lock_rc > 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn climb(&mut self, from: Nid, mut for_each: impl FnMut(Nid, &Node) -> bool) -> bool {
|
||||
fn climb_impl(
|
||||
nodes: &mut Nodes,
|
||||
from: Nid,
|
||||
for_each: &mut impl FnMut(Nid, &Node) -> bool,
|
||||
) -> bool {
|
||||
{ nodes[from].inputs }.iter().any(|&n| {
|
||||
n != Nid::MAX
|
||||
&& nodes.visited.set(n as usize)
|
||||
&& (for_each(n, &nodes[n]) || climb_impl(nodes, n, for_each))
|
||||
})
|
||||
}
|
||||
self.visited.clear(self.values.len());
|
||||
climb_impl(self, from, &mut for_each)
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<u32> for Nodes {
|
||||
|
@ -912,6 +992,18 @@ impl Kind {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Kind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Kind::ConstInt { value } => write!(f, "#{value}"),
|
||||
Kind::Tuple { index } => write!(f, "tupl[{index}]"),
|
||||
Kind::BinOp { op } => write!(f, "{op}"),
|
||||
Kind::Call { func, .. } => write!(f, "call {func}"),
|
||||
slf => write!(f, "{slf:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_INPUTS: usize = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1534,6 +1626,8 @@ impl Codegen {
|
|||
loob.scope[index].value = phy;
|
||||
}
|
||||
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
|
||||
Some(self.ci.vars[index].value)
|
||||
}
|
||||
Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => {
|
||||
|
@ -1617,17 +1711,20 @@ impl Codegen {
|
|||
for then_var in then_scope {
|
||||
self.ci.nodes.unlock_remove(then_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
return None;
|
||||
} else if lcntrl == Nid::MAX {
|
||||
for then_var in then_scope {
|
||||
self.ci.nodes.unlock_remove(then_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
return Some(0);
|
||||
} else if rcntrl == Nid::MAX {
|
||||
for else_var in &self.ci.vars {
|
||||
self.ci.nodes.unlock_remove(else_var.value);
|
||||
}
|
||||
self.ci.vars = then_scope;
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
self.ci.ctrl = lcntrl;
|
||||
return Some(0);
|
||||
}
|
||||
|
@ -1652,6 +1749,7 @@ impl Codegen {
|
|||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
@ -1700,6 +1798,7 @@ impl Codegen {
|
|||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
}
|
||||
|
||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||
|
@ -1709,8 +1808,13 @@ impl Codegen {
|
|||
return None;
|
||||
}
|
||||
|
||||
self.ci.nodes.lock(self.ci.ctrl);
|
||||
|
||||
std::mem::swap(&mut self.ci.vars, &mut break_scope);
|
||||
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
self.ci.nodes.check_scope_integrity(&break_scope);
|
||||
self.ci.nodes.check_scope_integrity(&scope);
|
||||
for ((dest_var, scope_var), loop_var) in
|
||||
self.ci.vars.iter_mut().zip(scope).zip(break_scope)
|
||||
{
|
||||
|
@ -1740,6 +1844,8 @@ impl Codegen {
|
|||
dest_var.value = phy;
|
||||
}
|
||||
|
||||
self.ci.nodes.unlock(self.ci.ctrl);
|
||||
|
||||
Some(0)
|
||||
}
|
||||
Expr::Break { pos } => {
|
||||
|
@ -1774,12 +1880,15 @@ impl Codegen {
|
|||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
self.ci.nodes.check_scope_integrity(&loob.break_scope);
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.end;
|
||||
None
|
||||
}
|
||||
Expr::Continue { pos } => {
|
||||
todo!();
|
||||
let Some(loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
return None;
|
||||
|
@ -1813,6 +1922,7 @@ impl Codegen {
|
|||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.end;
|
||||
|
@ -1883,10 +1993,14 @@ impl Codegen {
|
|||
0
|
||||
};
|
||||
|
||||
_ = self.ci.nodes[self.ci.ctrl];
|
||||
_ = self.ci.nodes[self.ci.end];
|
||||
_ = self.ci.nodes[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);
|
||||
|
||||
let expected = *self.ci.ret.get_or_insert(self.tof(value));
|
||||
|
@ -2006,6 +2120,8 @@ impl Codegen {
|
|||
}
|
||||
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.ci.nodes.graphviz();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.ci.nodes.check_final_integrity();
|
||||
|
@ -2121,11 +2237,21 @@ impl Codegen {
|
|||
let left_unreachable = self.color_control(self.ci.nodes[ctrl].outputs[0]);
|
||||
let right_unreachable = self.color_control(self.ci.nodes[ctrl].outputs[1]);
|
||||
|
||||
let dest = left_unreachable.or(right_unreachable)?;
|
||||
let dest = match (left_unreachable, right_unreachable) {
|
||||
(None, None) => return None,
|
||||
(None, Some(n)) | (Some(n), None) => n,
|
||||
(Some(l), Some(r)) if l == r => l,
|
||||
(Some(left), Some(right)) => {
|
||||
todo!()
|
||||
}
|
||||
};
|
||||
|
||||
if self.ci.nodes[dest].kind == Kind::Loop {
|
||||
return Some(dest);
|
||||
}
|
||||
|
||||
debug_assert!(left_unreachable.is_none() || right_unreachable.is_none());
|
||||
|
||||
debug_assert_eq!(self.ci.nodes[dest].kind, Kind::Region);
|
||||
|
||||
for i in 0..self.ci.nodes[dest].outputs.len() {
|
||||
|
@ -2189,7 +2315,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
fn color_phy(&mut self, maybe_phy: Nid) {
|
||||
let Node { kind: Kind::Phi, inputs: [_, left, right], .. } = self.ci.nodes[maybe_phy]
|
||||
let Node { kind: Kind::Phi, inputs: [region, left, right], .. } = self.ci.nodes[maybe_phy]
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
@ -2198,12 +2324,14 @@ impl Codegen {
|
|||
let rcolor = self.color_expr_consume(right);
|
||||
|
||||
if self.ci.nodes[maybe_phy].color != 0 {
|
||||
//if let Some(c) = lcolor {
|
||||
// self.ci.recolor(left, c, self.ci.nodes[maybe_phy].color);
|
||||
//}
|
||||
//if let Some(c) = rcolor {
|
||||
// self.ci.recolor(right, c, self.ci.nodes[maybe_phy].color);
|
||||
//}
|
||||
// loop phy
|
||||
if let Some(c) = rcolor
|
||||
&& !self.ci.nodes.climb(right, |i, n| {
|
||||
matches!(n.kind, Kind::Phi) && n.inputs[0] == region && i != maybe_phy
|
||||
})
|
||||
{
|
||||
self.ci.recolor(right, c, self.ci.nodes[maybe_phy].color);
|
||||
}
|
||||
} else {
|
||||
let color = match (lcolor, rcolor) {
|
||||
(None, None) => self.ci.next_color(),
|
||||
|
@ -2268,19 +2396,19 @@ impl Codegen {
|
|||
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||
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);
|
||||
// }
|
||||
//}
|
||||
// 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(),
|
||||
|
|
|
@ -7,8 +7,8 @@ main:
|
|||
ADDI64 r254, r254, 8d
|
||||
JALA r0, r31, 0a
|
||||
fib:
|
||||
ADDI64 r254, r254, -64d
|
||||
ST r31, r254, 0a, 64h
|
||||
ADDI64 r254, r254, -56d
|
||||
ST r31, r254, 0a, 56h
|
||||
CP r32, r2
|
||||
CP r33, r32
|
||||
LI64 r34, 0d
|
||||
|
@ -17,15 +17,14 @@ fib:
|
|||
CP r36, r35
|
||||
2: JNE r33, r34, :0
|
||||
JMP :1
|
||||
0: SUB64 r37, r33, r35
|
||||
ADD64 r38, r1, r36
|
||||
CP r33, r37
|
||||
0: SUB64 r33, r33, r35
|
||||
ADD64 r37, r1, r36
|
||||
CP r1, r36
|
||||
CP r36, r38
|
||||
CP r36, r37
|
||||
JMP :2
|
||||
1: LD r31, r254, 0a, 64h
|
||||
ADDI64 r254, r254, 64d
|
||||
1: LD r31, r254, 0a, 56h
|
||||
ADDI64 r254, r254, 56d
|
||||
JALA r0, r31, 0a
|
||||
code size: 207
|
||||
code size: 204
|
||||
ret: 55
|
||||
status: Ok(())
|
||||
|
|
Loading…
Reference in a new issue