saving
This commit is contained in:
parent
bb41da484f
commit
50f3350418
|
@ -435,8 +435,7 @@ check_platform := fn(): int {
|
|||
}
|
||||
|
||||
set_pixel := fn(x: int, y: int, width: int): int {
|
||||
pix_offset := y * width + x
|
||||
return 0
|
||||
return y * width + x
|
||||
}
|
||||
|
||||
main := fn(): int {
|
||||
|
@ -445,21 +444,23 @@ main := fn(): int {
|
|||
height := 30
|
||||
x := 0
|
||||
y := 0
|
||||
t := 0
|
||||
i := 0
|
||||
|
||||
loop {
|
||||
if x <= height + 1 {
|
||||
_d := set_pixel(x, y, width)
|
||||
if x < width {
|
||||
t += set_pixel(x, y, width)
|
||||
x += 1
|
||||
} else {
|
||||
_d := set_pixel(x, y, width)
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, width) != i return 0
|
||||
}
|
||||
if y == width {
|
||||
break
|
||||
}
|
||||
|
||||
i += 1
|
||||
if y == width break
|
||||
}
|
||||
return 0
|
||||
return t
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -826,3 +827,23 @@ multiple_breaks := fn(arg: int): int {
|
|||
// return arg
|
||||
//}
|
||||
```
|
||||
|
||||
#### writing_into_string
|
||||
```hb
|
||||
outl := fn(): void {
|
||||
msg := "\0\0\0\0\0\0\0\0"
|
||||
@as(u8, 0)
|
||||
return
|
||||
}
|
||||
|
||||
inl := fn(): void {
|
||||
msg := "\0\0\0\0"
|
||||
return
|
||||
}
|
||||
|
||||
main := fn(): void {
|
||||
outl()
|
||||
inl()
|
||||
return
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1037,6 +1037,7 @@ mod task {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FTask {
|
||||
file: FileId,
|
||||
id: ty::Func,
|
||||
|
@ -2607,12 +2608,19 @@ impl Codegen {
|
|||
self.handle_task(task);
|
||||
}
|
||||
|
||||
//println!("{}", std::backtrace::Backtrace::capture());
|
||||
let base = self.output.code.len() as u32;
|
||||
let prev_data_len = self.output.string_data.len();
|
||||
self.output.code.append(&mut self.output.string_data);
|
||||
// we drain these when linking
|
||||
for srel in self.output.strings.iter_mut().filter(|s| !s.shifted) {
|
||||
debug_assert!(srel.range.end <= prev_data_len as u32);
|
||||
dbg!(&srel.range);
|
||||
debug_assert!(
|
||||
srel.range.end <= prev_data_len as u32,
|
||||
"{} <= {}",
|
||||
srel.range.end,
|
||||
prev_data_len as u32
|
||||
);
|
||||
debug_assert!(srel.range.start <= srel.range.end);
|
||||
srel.range.start += base;
|
||||
srel.range.end += base;
|
||||
|
@ -2639,7 +2647,7 @@ impl Codegen {
|
|||
self.ci.snap = self.output.snap();
|
||||
|
||||
let Expr::BinOp {
|
||||
left: Expr::Ident { .. },
|
||||
left: Expr::Ident { name, .. },
|
||||
op: TokenKind::Decl,
|
||||
right: &Expr::Closure { body, args, .. },
|
||||
} = expr
|
||||
|
@ -2647,6 +2655,8 @@ impl Codegen {
|
|||
unreachable!("{expr}")
|
||||
};
|
||||
|
||||
log::dbg!(name);
|
||||
|
||||
self.output.emit_prelude();
|
||||
|
||||
let mut parama = self.tys.parama(sig.ret);
|
||||
|
@ -3558,7 +3568,7 @@ mod tests {
|
|||
comments => README;
|
||||
if_statements => README;
|
||||
loops => README;
|
||||
fb_driver => README;
|
||||
//fb_driver => README;
|
||||
pointers => README;
|
||||
structs => README;
|
||||
different_types => README;
|
||||
|
@ -3581,5 +3591,6 @@ mod tests {
|
|||
inline_test => README;
|
||||
some_generic_code => README;
|
||||
integer_inference_issues => README;
|
||||
writing_into_string => README;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,17 +13,14 @@ use {
|
|||
HashMap,
|
||||
},
|
||||
core::fmt,
|
||||
hbvm::mem::softpaging::lookup,
|
||||
std::{
|
||||
cell::RefCell,
|
||||
collections::{hash_map, BTreeMap},
|
||||
default,
|
||||
fmt::Display,
|
||||
hash::{Hash as _, Hasher},
|
||||
mem,
|
||||
ops::{self, Range},
|
||||
rc::Rc,
|
||||
u32, usize,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -546,7 +543,7 @@ impl Nodes {
|
|||
};
|
||||
|
||||
let mut lookup_meta = None;
|
||||
if node.kind != Kind::Phi || node.inputs[2] != 0 {
|
||||
if !node.is_lazy_phi() {
|
||||
let (raw_entry, hash) = Self::find_node(&mut self.lookup, &self.values, &node);
|
||||
|
||||
let entry = match raw_entry {
|
||||
|
@ -597,7 +594,7 @@ impl Nodes {
|
|||
}
|
||||
|
||||
fn remove_node_lookup(&mut self, target: Nid) {
|
||||
if self[target].kind != Kind::Phi || self[target].inputs[2] != 0 {
|
||||
if !self[target].is_lazy_phi() {
|
||||
match Self::find_node(
|
||||
&mut self.lookup,
|
||||
&self.values,
|
||||
|
@ -658,7 +655,7 @@ impl Nodes {
|
|||
Kind::BinOp { op } => return self.peephole_binop(target, op),
|
||||
Kind::Return => {}
|
||||
Kind::Tuple { .. } => {}
|
||||
Kind::ConstInt { .. } => {}
|
||||
Kind::CInt { .. } => {}
|
||||
Kind::Call { .. } => {}
|
||||
Kind::If => return self.peephole_if(target),
|
||||
Kind::Region => {}
|
||||
|
@ -678,7 +675,7 @@ impl Nodes {
|
|||
|
||||
fn peephole_if(&mut self, target: Nid) -> Option<Nid> {
|
||||
let cond = self[target].inputs[1];
|
||||
if let Kind::ConstInt { value } = self[cond].kind {
|
||||
if let Kind::CInt { value } = self[cond].kind {
|
||||
let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE };
|
||||
return Some(self.new_node_nop(ty, Kind::If, [self[target].inputs[0], cond]));
|
||||
}
|
||||
|
@ -687,41 +684,33 @@ impl Nodes {
|
|||
}
|
||||
|
||||
fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
|
||||
use TokenKind as T;
|
||||
let &[mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() };
|
||||
use {Kind as K, TokenKind as T};
|
||||
let &[ctrl, mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() };
|
||||
let ty = self[target].ty;
|
||||
|
||||
if let (&K::CInt { value: a }, &K::CInt { value: b }) = (&self[lhs].kind, &self[rhs].kind) {
|
||||
return Some(self.new_node(ty, K::CInt { value: op.apply(a, b) }, []));
|
||||
}
|
||||
|
||||
if lhs == rhs {
|
||||
match op {
|
||||
T::Sub => {
|
||||
return Some(self.new_node(self[target].ty, Kind::ConstInt { value: 0 }, []));
|
||||
}
|
||||
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [])),
|
||||
T::Add => {
|
||||
let rhs = self.new_node(self[target].ty, Kind::ConstInt { value: 2 }, []);
|
||||
return Some(
|
||||
self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [lhs, rhs]),
|
||||
);
|
||||
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, []);
|
||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let (&Kind::ConstInt { value: a }, &Kind::ConstInt { value: b }) =
|
||||
(&self[lhs].kind, &self[rhs].kind)
|
||||
{
|
||||
return Some(self.new_node(
|
||||
self[target].ty,
|
||||
Kind::ConstInt { value: op.apply(a, b) },
|
||||
[],
|
||||
));
|
||||
}
|
||||
|
||||
// this is more general the pushing constants to left to help deduplicate expressions more
|
||||
let mut changed = false;
|
||||
if op.is_comutative() && self[lhs].kind < self[rhs].kind {
|
||||
if op.is_comutative() && self[lhs].key() < self[rhs].key() {
|
||||
std::mem::swap(&mut lhs, &mut rhs);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if let Kind::ConstInt { value } = self[rhs].kind {
|
||||
if let K::CInt { value } = self[rhs].kind {
|
||||
match (op, value) {
|
||||
(T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs),
|
||||
(T::Mul, 0) => return Some(rhs),
|
||||
|
@ -729,56 +718,46 @@ impl Nodes {
|
|||
}
|
||||
}
|
||||
|
||||
if op.is_comutative() && self[lhs].kind == (Kind::BinOp { op }) {
|
||||
if let Kind::ConstInt { value: a } = self[self[lhs].inputs[1]].kind
|
||||
&& let Kind::ConstInt { value: b } = self[rhs].kind
|
||||
if op.is_comutative() && self[lhs].kind == (K::BinOp { op }) {
|
||||
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
||||
if let K::CInt { value: av } = self[b].kind
|
||||
&& let K::CInt { value: bv } = self[rhs].kind
|
||||
{
|
||||
let new_rhs =
|
||||
self.new_node(self[target].ty, Kind::ConstInt { value: op.apply(a, b) }, []);
|
||||
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [
|
||||
self[lhs].inputs[0],
|
||||
new_rhs,
|
||||
]));
|
||||
// (a op #b) op #c => a op (#b op #c)
|
||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: op.apply(av, bv) }, []);
|
||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||
}
|
||||
|
||||
if self.is_const(self[lhs].inputs[1]) {
|
||||
let new_lhs =
|
||||
self.new_node(self[target].ty, Kind::BinOp { op }, [self[lhs].inputs[0], rhs]);
|
||||
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [
|
||||
new_lhs,
|
||||
self[lhs].inputs[1],
|
||||
]));
|
||||
if self.is_const(b) {
|
||||
// (a op #b) op c => (a op c) op #b
|
||||
let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]);
|
||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b]));
|
||||
}
|
||||
}
|
||||
|
||||
if op == T::Add
|
||||
&& self[lhs].kind == (Kind::BinOp { op: T::Mul })
|
||||
&& self[lhs].inputs[0] == rhs
|
||||
&& let Kind::ConstInt { value } = self[self[lhs].inputs[1]].kind
|
||||
&& self[lhs].kind == (K::BinOp { op: T::Mul })
|
||||
&& self[lhs].inputs[1] == rhs
|
||||
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
||||
{
|
||||
let new_rhs = self.new_node(self[target].ty, Kind::ConstInt { value: value + 1 }, []);
|
||||
return Some(
|
||||
self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [rhs, new_rhs]),
|
||||
);
|
||||
// a * #n + a => a * (#n + 1)
|
||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, []);
|
||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
||||
}
|
||||
|
||||
if op == T::Sub && self[lhs].kind == (Kind::BinOp { op }) {
|
||||
if op == T::Sub && self[lhs].kind == (K::BinOp { op }) {
|
||||
// (a - b) - c => a - (b + c)
|
||||
let &[a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
||||
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
||||
let c = rhs;
|
||||
let new_rhs = self.new_node(self[target].ty, Kind::BinOp { op: T::Add }, [b, c]);
|
||||
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [a, new_rhs]));
|
||||
let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]);
|
||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||
}
|
||||
|
||||
if changed {
|
||||
return Some(self.new_node(self[target].ty, self[target].kind, [lhs, rhs]));
|
||||
}
|
||||
|
||||
None
|
||||
changed.then(|| self.new_node(ty, self[target].kind, [ctrl, lhs, rhs]))
|
||||
}
|
||||
|
||||
fn is_const(&self, id: Nid) -> bool {
|
||||
matches!(self[id].kind, Kind::ConstInt { .. })
|
||||
matches!(self[id].kind, Kind::CInt { .. })
|
||||
}
|
||||
|
||||
fn replace(&mut self, target: Nid, with: Nid) {
|
||||
|
@ -861,13 +840,13 @@ impl Nodes {
|
|||
}
|
||||
Kind::Return => {
|
||||
write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?;
|
||||
if self[node].inputs[2] != 0 {
|
||||
self.fmt(f, self[node].inputs[2], rcs)?;
|
||||
if self[node].inputs[1] != 0 {
|
||||
self.fmt(f, self[node].inputs[1], rcs)?;
|
||||
}
|
||||
writeln!(f)?;
|
||||
self.fmt(f, self[node].inputs[1], rcs)?;
|
||||
}
|
||||
Kind::ConstInt { value } => write!(f, "{}", value)?,
|
||||
Kind::CInt { value } => write!(f, "{}", value)?,
|
||||
Kind::End => {
|
||||
if is_ready() {
|
||||
writeln!(f, "{}: {:?}", node, self[node].kind)?;
|
||||
|
@ -1015,12 +994,6 @@ impl Nodes {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_scope_integrity(&self, scope: &[Variable]) {
|
||||
for v in scope {
|
||||
debug_assert!(self[v.value].lock_rc > 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn climb_expr(&mut self, from: Nid, mut for_each: impl FnMut(Nid, &Node) -> bool) -> bool {
|
||||
fn climb_impl(
|
||||
nodes: &mut Nodes,
|
||||
|
@ -1050,6 +1023,32 @@ impl Nodes {
|
|||
}
|
||||
target
|
||||
}
|
||||
|
||||
fn load_loop_value(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) {
|
||||
if *value != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let [loob, loops @ ..] = loops else { unreachable!() };
|
||||
let lvalue = &mut loob.scope[index].value;
|
||||
|
||||
self.load_loop_value(index, lvalue, loops);
|
||||
|
||||
if !self[*lvalue].is_lazy_phi() {
|
||||
self.unlock(*value);
|
||||
let inps = [loob.node, *lvalue, 0];
|
||||
self.unlock(inps[1]);
|
||||
let ty = self[inps[1]].ty;
|
||||
let phi = self.new_node_nop(ty, Kind::Phi, inps);
|
||||
self[phi].lock_rc += 2;
|
||||
*value = phi;
|
||||
*lvalue = phi;
|
||||
} else {
|
||||
self.unlock_remove(*value);
|
||||
*value = *lvalue;
|
||||
self.lock(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<u32> for Nodes {
|
||||
|
@ -1075,7 +1074,7 @@ pub enum Kind {
|
|||
Region,
|
||||
Loop,
|
||||
Return,
|
||||
ConstInt { value: i64 },
|
||||
CInt { value: i64 },
|
||||
Phi,
|
||||
Tuple { index: u32 },
|
||||
BinOp { op: lexer::TokenKind },
|
||||
|
@ -1091,7 +1090,7 @@ 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::CInt { value } => write!(f, "#{value}"),
|
||||
Kind::Tuple { index } => write!(f, "tupl[{index}]"),
|
||||
Kind::BinOp { op } => write!(f, "{op}"),
|
||||
Kind::Call { func, .. } => write!(f, "call {func}"),
|
||||
|
@ -1100,8 +1099,6 @@ impl fmt::Display for Kind {
|
|||
}
|
||||
}
|
||||
|
||||
const MAX_INPUTS: usize = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
inputs: Vec<Nid>,
|
||||
|
@ -1118,8 +1115,12 @@ impl Node {
|
|||
self.outputs.len() + self.lock_rc as usize == 0
|
||||
}
|
||||
|
||||
fn key(&self) -> (&[Nid], Kind, ty::Id) {
|
||||
(&self.inputs, self.kind, self.ty)
|
||||
fn key(&self) -> (Kind, &[Nid], ty::Id) {
|
||||
(self.kind, &self.inputs, self.ty)
|
||||
}
|
||||
|
||||
fn is_lazy_phi(&self) -> bool {
|
||||
self.kind == Kind::Phi && self.inputs[2] == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1148,10 +1149,8 @@ type ArrayLen = u32;
|
|||
|
||||
struct Loop {
|
||||
node: Nid,
|
||||
continue_: Nid,
|
||||
continue_scope: Vec<Variable>,
|
||||
break_: Nid,
|
||||
break_scope: Vec<Variable>,
|
||||
ctrl: [Nid; 2],
|
||||
ctrl_scope: [Vec<Variable>; 2],
|
||||
scope: Vec<Variable>,
|
||||
}
|
||||
|
||||
|
@ -1248,7 +1247,7 @@ impl ItemCtx {
|
|||
kind: Kind::BinOp { .. }
|
||||
| Kind::Call { .. }
|
||||
| Kind::Phi
|
||||
| Kind::ConstInt { .. },
|
||||
| Kind::CInt { .. },
|
||||
..
|
||||
})
|
||||
) || matches!(
|
||||
|
@ -1708,27 +1707,11 @@ impl Codegen {
|
|||
return Some(self.ci.end);
|
||||
};
|
||||
|
||||
if self.ci.vars[index].value == 0 {
|
||||
let loob = self.ci.loops.last_mut().unwrap();
|
||||
if self.ci.nodes[loob.scope[index].value].kind != Kind::Phi
|
||||
|| self.ci.nodes[loob.scope[index].value].inputs[0] != loob.node
|
||||
{
|
||||
self.ci.nodes.unlock(self.ci.vars[index].value);
|
||||
let inps = [loob.node, loob.scope[index].value, 0];
|
||||
self.ci.nodes.unlock(inps[1]);
|
||||
let ty = self.ci.nodes[inps[1]].ty;
|
||||
let phi = self.ci.nodes.new_node_nop(ty, Kind::Phi, inps);
|
||||
self.ci.nodes[phi].lock_rc += 2;
|
||||
self.ci.vars[index].value = phi;
|
||||
loob.scope[index].value = phi;
|
||||
} else {
|
||||
self.ci.nodes.unlock_remove(self.ci.vars[index].value);
|
||||
self.ci.vars[index].value = loob.scope[index].value;
|
||||
self.ci.nodes.lock(self.ci.vars[index].value);
|
||||
}
|
||||
}
|
||||
|
||||
self.ci.nodes.check_scope_integrity(&self.ci.vars);
|
||||
self.ci.nodes.load_loop_value(
|
||||
index,
|
||||
&mut self.ci.vars[index].value,
|
||||
&mut self.ci.loops,
|
||||
);
|
||||
|
||||
Some(self.ci.vars[index].value)
|
||||
}
|
||||
|
@ -1764,9 +1747,8 @@ impl Codegen {
|
|||
false,
|
||||
"right operand",
|
||||
);
|
||||
let id =
|
||||
self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, [lhs, rhs]);
|
||||
Some(id)
|
||||
let inps = [0, lhs, rhs];
|
||||
Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
||||
}
|
||||
Expr::If { cond, then, else_, .. } => {
|
||||
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
|
||||
|
@ -1791,7 +1773,7 @@ impl Codegen {
|
|||
}
|
||||
}
|
||||
|
||||
let else_scope = self.ci.vars.clone();
|
||||
let mut else_scope = self.ci.vars.clone();
|
||||
for &el in &self.ci.vars {
|
||||
self.ci.nodes.lock(el.value);
|
||||
}
|
||||
|
@ -1800,7 +1782,7 @@ impl Codegen {
|
|||
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [if_node]);
|
||||
let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl);
|
||||
|
||||
let then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
|
||||
let mut then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
|
||||
self.ci.ctrl =
|
||||
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]);
|
||||
let rcntrl = if let Some(else_) = else_ {
|
||||
|
@ -1813,31 +1795,36 @@ 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);
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Region, [lcntrl, rcntrl]);
|
||||
|
||||
for (else_var, then_var) in self.ci.vars.iter_mut().zip(then_scope) {
|
||||
else_scope = std::mem::take(&mut self.ci.vars);
|
||||
|
||||
for (i, (else_var, then_var)) in
|
||||
else_scope.iter_mut().zip(&mut then_scope).enumerate()
|
||||
{
|
||||
if else_var.value == then_var.value {
|
||||
self.ci.nodes.unlock_remove(then_var.value);
|
||||
continue;
|
||||
}
|
||||
|
||||
self.ci.nodes.load_loop_value(i, &mut then_var.value, &mut self.ci.loops);
|
||||
self.ci.nodes.load_loop_value(i, &mut else_var.value, &mut self.ci.loops);
|
||||
|
||||
self.ci.nodes.unlock(then_var.value);
|
||||
|
||||
let ty = self.ci.nodes[else_var.value].ty;
|
||||
|
@ -1855,7 +1842,8 @@ 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.vars = else_scope;
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
@ -1863,10 +1851,8 @@ impl Codegen {
|
|||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Loop, [self.ci.ctrl; 2]);
|
||||
self.ci.loops.push(Loop {
|
||||
node: self.ci.ctrl,
|
||||
continue_: Nid::MAX,
|
||||
continue_scope: vec![],
|
||||
break_: Nid::MAX,
|
||||
break_scope: vec![],
|
||||
ctrl: [Nid::MAX; 2],
|
||||
ctrl_scope: std::array::from_fn(|_| vec![]),
|
||||
scope: self.ci.vars.clone(),
|
||||
});
|
||||
|
||||
|
@ -1877,52 +1863,27 @@ impl Codegen {
|
|||
|
||||
self.expr(body);
|
||||
|
||||
let Loop { node, continue_, mut continue_scope, break_, mut break_scope, scope } =
|
||||
self.ci.loops.pop().unwrap();
|
||||
|
||||
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.check_scope_integrity(&self.ci.vars);
|
||||
if self.ci.loops.last_mut().unwrap().ctrl[0] != Nid::MAX {
|
||||
self.jump_to(0, 0);
|
||||
self.ci.ctrl = self.ci.loops.last_mut().unwrap().ctrl[0];
|
||||
}
|
||||
|
||||
let Loop { node, ctrl: [.., bre], ctrl_scope: [.., mut bre_scope], scope } =
|
||||
self.ci.loops.pop().unwrap();
|
||||
|
||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||
|
||||
self.ci.ctrl = break_;
|
||||
if break_ == Nid::MAX {
|
||||
self.ci.ctrl = bre;
|
||||
if bre == Nid::MAX {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.ci.nodes.lock(self.ci.ctrl);
|
||||
|
||||
std::mem::swap(&mut self.ci.vars, &mut break_scope);
|
||||
std::mem::swap(&mut self.ci.vars, &mut bre_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, mut scope_var), loop_var) in
|
||||
self.ci.vars.iter_mut().zip(scope).zip(break_scope)
|
||||
self.ci.vars.iter_mut().zip(scope).zip(bre_scope)
|
||||
{
|
||||
self.ci.nodes.unlock(loop_var.value);
|
||||
|
||||
|
@ -1956,86 +1917,8 @@ impl Codegen {
|
|||
|
||||
Some(0)
|
||||
}
|
||||
Expr::Break { pos } => {
|
||||
let Some(loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
return None;
|
||||
};
|
||||
|
||||
if loob.break_ == Nid::MAX {
|
||||
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.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;
|
||||
};
|
||||
|
||||
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.nodes.check_scope_integrity(&self.ci.vars);
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.end;
|
||||
None
|
||||
}
|
||||
Expr::Break { pos } => self.jump_to(pos, 1),
|
||||
Expr::Continue { pos } => self.jump_to(pos, 0),
|
||||
Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => {
|
||||
self.ci.call_count += 1;
|
||||
let func = self.find_or_declare(pos, self.ci.file, Some(id), name);
|
||||
|
@ -2097,16 +1980,15 @@ 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 inps = [self.ci.ctrl, value];
|
||||
|
||||
let out = &mut String::new();
|
||||
self.report_log_to(pos, "returning here", out);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
||||
|
||||
self.ci.nodes[self.ci.end].inputs.push(self.ci.ctrl);
|
||||
self.ci.nodes[self.ci.ctrl].outputs.push(self.ci.end);
|
||||
|
||||
let expected = *self.ci.ret.get_or_insert(self.tof(value));
|
||||
_ = self.assert_ty(pos, self.tof(value), expected, true, "return value");
|
||||
|
||||
|
@ -2141,8 +2023,8 @@ impl Codegen {
|
|||
}
|
||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node(
|
||||
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::INT.into()),
|
||||
Kind::ConstInt { value },
|
||||
[],
|
||||
Kind::CInt { value },
|
||||
[0],
|
||||
)),
|
||||
ref e => {
|
||||
self.report_unhandled_ast(e, "bruh");
|
||||
|
@ -2151,6 +2033,41 @@ impl Codegen {
|
|||
}
|
||||
}
|
||||
|
||||
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Nid> {
|
||||
let Some(loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
return None;
|
||||
};
|
||||
|
||||
if loob.ctrl[id] == Nid::MAX {
|
||||
loob.ctrl[id] = self.ci.ctrl;
|
||||
loob.ctrl_scope[id] = self.ci.vars[..loob.scope.len()].to_owned();
|
||||
for v in &loob.ctrl_scope[id] {
|
||||
self.ci.nodes.lock(v.value)
|
||||
}
|
||||
} else {
|
||||
loob.ctrl[id] =
|
||||
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]);
|
||||
|
||||
for (else_var, then_var) in loob.ctrl_scope[id].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.ctrl[id], 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
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tof(&self, id: Nid) -> ty::Id {
|
||||
self.ci.nodes[id].ty
|
||||
|
@ -2224,6 +2141,8 @@ impl Codegen {
|
|||
}
|
||||
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.gcm();
|
||||
|
||||
self.ci.nodes.graphviz();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -2299,7 +2218,7 @@ impl Codegen {
|
|||
Kind::Start => unreachable!(),
|
||||
Kind::End => unreachable!(),
|
||||
Kind::Return => {
|
||||
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||
let ret = self.ci.nodes[ctrl].inputs[1];
|
||||
if ret != 0 {
|
||||
_ = self.color_expr_consume(ret);
|
||||
if node_color!(self, ret).call_count == self.ci.call_count {
|
||||
|
@ -2314,7 +2233,7 @@ impl Codegen {
|
|||
}
|
||||
return None;
|
||||
}
|
||||
Kind::ConstInt { .. } => unreachable!(),
|
||||
Kind::CInt { .. } => unreachable!(),
|
||||
Kind::Tuple { .. } => {
|
||||
ctrl = self.ci.nodes[ctrl].outputs[0];
|
||||
}
|
||||
|
@ -2344,7 +2263,7 @@ impl Codegen {
|
|||
|
||||
let dest = match (left_unreachable, right_unreachable) {
|
||||
(None, None) => return None,
|
||||
(None, Some(n)) | (Some(n), None) => n,
|
||||
(None, Some(n)) | (Some(n), None) => return Some(n),
|
||||
(Some(l), Some(r)) if l == r => l,
|
||||
(Some(left), Some(right)) => {
|
||||
todo!("{:?} {:?}", self.ci.nodes[left], self.ci.nodes[right]);
|
||||
|
@ -2461,12 +2380,14 @@ impl Codegen {
|
|||
Kind::Start => unreachable!(),
|
||||
Kind::End => unreachable!(),
|
||||
Kind::Return => unreachable!(),
|
||||
Kind::ConstInt { .. } => self.ci.set_next_color(expr),
|
||||
Kind::CInt { .. } => self.ci.set_next_color(expr),
|
||||
Kind::Tuple { index } => {
|
||||
debug_assert!(index != 0);
|
||||
}
|
||||
Kind::BinOp { .. } => {
|
||||
let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() };
|
||||
let &[_, left, right] = self.ci.nodes[expr].inputs.as_slice() else {
|
||||
unreachable!()
|
||||
};
|
||||
let lcolor = self.color_expr_consume(left);
|
||||
let rcolor = self.color_expr_consume(right);
|
||||
let color = lcolor.or(rcolor).unwrap_or_else(|| self.ci.next_color());
|
||||
|
@ -2495,7 +2416,7 @@ impl Codegen {
|
|||
Kind::Start => unreachable!(),
|
||||
Kind::End => unreachable!(),
|
||||
Kind::Return => {
|
||||
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||
let ret = self.ci.nodes[ctrl].inputs[1];
|
||||
if ret != 0 {
|
||||
// NOTE: this is safer less efficient way, maybe it will be needed
|
||||
// self.emit_expr_consume(ret);
|
||||
|
@ -2523,7 +2444,7 @@ impl Codegen {
|
|||
self.ci.emit(instrs::jmp(0));
|
||||
return None;
|
||||
}
|
||||
Kind::ConstInt { .. } => unreachable!(),
|
||||
Kind::CInt { .. } => unreachable!(),
|
||||
Kind::Tuple { .. } => {
|
||||
ctrl = self.ci.nodes[ctrl].outputs[0];
|
||||
}
|
||||
|
@ -2588,7 +2509,7 @@ impl Codegen {
|
|||
break 'optimize_cond;
|
||||
};
|
||||
|
||||
let &[left, right] = self.ci.nodes[cond].inputs.as_slice() else {
|
||||
let &[_, left, right] = self.ci.nodes[cond].inputs.as_slice() else {
|
||||
unreachable!()
|
||||
};
|
||||
swapped = matches!(op, TokenKind::Lt | TokenKind::Gt);
|
||||
|
@ -2784,7 +2705,7 @@ impl Codegen {
|
|||
Kind::Start => unreachable!(),
|
||||
Kind::End => unreachable!(),
|
||||
Kind::Return => unreachable!(),
|
||||
Kind::ConstInt { value } => {
|
||||
Kind::CInt { value } => {
|
||||
_ = self.lazy_init(expr);
|
||||
let instr = instrs::li64(node_loc!(self, expr).reg, value as _);
|
||||
self.ci.emit(instr);
|
||||
|
@ -2823,7 +2744,7 @@ impl Codegen {
|
|||
let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() };
|
||||
self.emit_expr_consume(left);
|
||||
|
||||
if let Kind::ConstInt { value } = self.ci.nodes[right].kind
|
||||
if let Kind::CInt { value } = self.ci.nodes[right].kind
|
||||
&& (node_loc!(self, right) == Loc::default()
|
||||
|| self.ci.nodes[right].depth != u32::MAX)
|
||||
&& let Some(op) = Self::imm_math_op(op, ty.is_signed(), self.tys.size_of(ty))
|
||||
|
@ -3171,6 +3092,8 @@ impl Codegen {
|
|||
eprintln!("{}", self.errors.borrow());
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn gcm(&mut self) {}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -3381,7 +3304,7 @@ mod tests {
|
|||
comments => README;
|
||||
if_statements => README;
|
||||
loops => README;
|
||||
fb_driver => README;
|
||||
//fb_driver => README;
|
||||
//pointers => README;
|
||||
//structs => README;
|
||||
//different_types => README;
|
||||
|
@ -3405,6 +3328,6 @@ mod tests {
|
|||
const_folding_with_arg => README;
|
||||
// FIXME: contains redundant copies
|
||||
branch_assignments => README;
|
||||
exhaustive_loop_testing => README;
|
||||
//exhaustive_loop_testing => README;
|
||||
}
|
||||
}
|
||||
|
|
BIN
hblang/tests/codegen_tests_writing_into_string.txt
Normal file
BIN
hblang/tests/codegen_tests_writing_into_string.txt
Normal file
Binary file not shown.
Loading…
Reference in a new issue