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