better somehow
This commit is contained in:
parent
6977cb218c
commit
f013e90936
|
@ -89,7 +89,6 @@ pub enum DisasmError<'a> {
|
||||||
InstructionOutOfBounds(&'a str),
|
InstructionOutOfBounds(&'a str),
|
||||||
FmtFailed(core::fmt::Error),
|
FmtFailed(core::fmt::Error),
|
||||||
HasOutOfBoundsJumps,
|
HasOutOfBoundsJumps,
|
||||||
HasDirectInstructionCycles,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "disasm")]
|
#[cfg(feature = "disasm")]
|
||||||
|
@ -113,9 +112,6 @@ impl core::fmt::Display for DisasmError<'_> {
|
||||||
"the code contained jumps that dont got neither to a \
|
"the code contained jumps that dont got neither to a \
|
||||||
valid symbol or local insturction"
|
valid symbol or local insturction"
|
||||||
),
|
),
|
||||||
DisasmError::HasDirectInstructionCycles => {
|
|
||||||
writeln!(f, "found instruction that jumps to itself")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +141,6 @@ pub fn disasm<'a>(
|
||||||
|
|
||||||
let mut labels = BTreeMap::<u32, u32>::default();
|
let mut labels = BTreeMap::<u32, u32>::default();
|
||||||
let mut buf = Vec::<instrs::Oper>::new();
|
let mut buf = Vec::<instrs::Oper>::new();
|
||||||
let mut has_cycle = false;
|
|
||||||
let mut has_oob = false;
|
let mut has_oob = false;
|
||||||
|
|
||||||
'_offset_pass: for (&off, &(name, len, kind)) in functions.iter() {
|
'_offset_pass: for (&off, &(name, len, kind)) in functions.iter() {
|
||||||
|
@ -174,8 +169,6 @@ pub fn disasm<'a>(
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
has_cycle |= rel == 0;
|
|
||||||
|
|
||||||
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
||||||
if functions.get(&global_offset).is_some() {
|
if functions.get(&global_offset).is_some() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -287,9 +280,5 @@ pub fn disasm<'a>(
|
||||||
return Err(DisasmError::HasOutOfBoundsJumps);
|
return Err(DisasmError::HasOutOfBoundsJumps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_cycle {
|
|
||||||
return Err(DisasmError::HasDirectInstructionCycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
104
lang/README.md
104
lang/README.md
|
@ -528,99 +528,6 @@ main := fn(): int {
|
||||||
|
|
||||||
### Purely Testing Examples
|
### Purely Testing Examples
|
||||||
|
|
||||||
#### smh_happened
|
|
||||||
```hb
|
|
||||||
render := @use("render.hb")
|
|
||||||
|
|
||||||
main := fn(): void {
|
|
||||||
render.init(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// in module: stn.hb
|
|
||||||
|
|
||||||
string := @use("string.hb")
|
|
||||||
dt := @use("dt.hb")
|
|
||||||
memory := @use("memory.hb")
|
|
||||||
|
|
||||||
// in module: memory.hb
|
|
||||||
|
|
||||||
PAGE_SIZE := 4096
|
|
||||||
MAX_ALLOC := 0xFF
|
|
||||||
|
|
||||||
alloc := fn($Expr: type, num: int): ^Expr {
|
|
||||||
pages := 1 + @bitcast(@sizeof(Expr)) * num / PAGE_SIZE
|
|
||||||
if pages <= MAX_ALLOC {
|
|
||||||
return @bitcast(@inline(request_page, pages))
|
|
||||||
}
|
|
||||||
ptr := @inline(request_page, 0xFF)
|
|
||||||
remaining := pages - MAX_ALLOC
|
|
||||||
loop if remaining <= 0 break else {
|
|
||||||
if remaining < MAX_ALLOC {
|
|
||||||
request_page(remaining)
|
|
||||||
} else {
|
|
||||||
request_page(MAX_ALLOC)
|
|
||||||
}
|
|
||||||
remaining -= MAX_ALLOC
|
|
||||||
}
|
|
||||||
return @bitcast(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
request_page := fn(page_count: u8): ^u8 {
|
|
||||||
msg := "\{00}\{01}xxxxxxxx\0"
|
|
||||||
msg_page_count := msg + 1;
|
|
||||||
*msg_page_count = page_count
|
|
||||||
return @eca(3, 2, msg, 12)
|
|
||||||
}
|
|
||||||
|
|
||||||
// in module: string.hb
|
|
||||||
|
|
||||||
length := fn(ptr: ^u8): uint {
|
|
||||||
len := @as(uint, 0)
|
|
||||||
loop if *(ptr + len) == 0 break else len += 1
|
|
||||||
return len
|
|
||||||
}
|
|
||||||
|
|
||||||
// in module: dt.hb
|
|
||||||
|
|
||||||
.{string} := @use("stn.hb")
|
|
||||||
|
|
||||||
get := fn($Expr: type, query: ^u8): Expr {
|
|
||||||
return @eca(3, 5, query, @inline(string.length, query))
|
|
||||||
}
|
|
||||||
|
|
||||||
// in module: render.hb
|
|
||||||
|
|
||||||
.{dt, memory} := @use("stn.hb")
|
|
||||||
Color := packed struct {b: u8, g: u8, r: u8, a: u8}
|
|
||||||
|
|
||||||
Surface := struct {
|
|
||||||
buf: ^Color,
|
|
||||||
width: int,
|
|
||||||
height: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
new_surface := fn(width: int, height: int): Surface {
|
|
||||||
return .(
|
|
||||||
@inline(memory.alloc, Color, width * height),
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
init := fn(doublebuffer: bool): Surface {
|
|
||||||
framebuffer := dt.get(^Color, "framebuffer/fb0/ptr\0")
|
|
||||||
width := dt.get(int, "framebuffer/fb0/width\0")
|
|
||||||
height := dt.get(int, "framebuffer/fb0/height\0")
|
|
||||||
if doublebuffer {
|
|
||||||
return new_surface(width, height)
|
|
||||||
} else {
|
|
||||||
return .(framebuffer, width, height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### wide_ret
|
#### wide_ret
|
||||||
```hb
|
```hb
|
||||||
OemIdent := struct {
|
OemIdent := struct {
|
||||||
|
@ -1019,6 +926,14 @@ main := fn(arg: int): int {
|
||||||
#### exhaustive_loop_testing
|
#### exhaustive_loop_testing
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
|
loop break
|
||||||
|
|
||||||
|
x := 0
|
||||||
|
loop {
|
||||||
|
x += 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if multiple_breaks(0) != 3 {
|
if multiple_breaks(0) != 3 {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -1043,7 +958,8 @@ main := fn(): int {
|
||||||
return 6
|
return 6
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
loop {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
multiple_breaks := fn(arg: int): int {
|
multiple_breaks := fn(arg: int): int {
|
||||||
|
|
558
lang/src/son.rs
558
lang/src/son.rs
|
@ -1,4 +1,5 @@
|
||||||
use {
|
use {
|
||||||
|
self::var::{Scope, Variable},
|
||||||
crate::{
|
crate::{
|
||||||
ctx_map::CtxEntry,
|
ctx_map::CtxEntry,
|
||||||
ident::Ident,
|
ident::Ident,
|
||||||
|
@ -57,17 +58,17 @@ impl crate::ctx_map::CtxEntry for Nid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(debug_assertions)]
|
||||||
type Trace = std::rc::Rc<std::backtrace::Backtrace>;
|
type Trace = std::rc::Rc<std::backtrace::Backtrace>;
|
||||||
#[cfg(not(test))]
|
#[cfg(not(debug_assertions))]
|
||||||
type Trace = ();
|
type Trace = ();
|
||||||
|
|
||||||
fn trace() -> Trace {
|
fn trace() -> Trace {
|
||||||
#[cfg(test)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
std::rc::Rc::new(std::backtrace::Backtrace::capture())
|
std::rc::Rc::new(std::backtrace::Backtrace::capture())
|
||||||
}
|
}
|
||||||
#[cfg(not(test))]
|
#[cfg(not(debug_assertions))]
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,31 +100,59 @@ impl Nodes {
|
||||||
) -> core::fmt::Result {
|
) -> core::fmt::Result {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
writeln!(out)?;
|
||||||
|
writeln!(out, "digraph G {{")?;
|
||||||
|
writeln!(out, "rankdir=BT;")?;
|
||||||
|
writeln!(out, "concentrate=true;")?;
|
||||||
|
writeln!(out, "compound=true;")?;
|
||||||
|
|
||||||
for (i, node) in self.iter() {
|
for (i, node) in self.iter() {
|
||||||
let color = if self[i].lock_rc != 0 {
|
let color = match () {
|
||||||
"red"
|
_ if self[i].lock_rc != 0 => "red",
|
||||||
} else if self.is_cfg(i) {
|
_ if self[i].outputs.is_empty() => "purple",
|
||||||
"yellow"
|
_ if self[i].is_mem() => "green",
|
||||||
} else {
|
_ if self.is_cfg(i) => "yellow",
|
||||||
"white"
|
_ => "white",
|
||||||
};
|
};
|
||||||
writeln!(
|
|
||||||
out,
|
let mut dest = i;
|
||||||
"node{i}[label=\"{} {}\" color={color}]",
|
let mut index_override = None;
|
||||||
node.kind,
|
|
||||||
ty::Display::new(tys, files, node.ty)
|
if !matches!(node.kind, Kind::Then | Kind::Else) {
|
||||||
)?;
|
if node.ty != ty::Id::VOID {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
" node{i}[label=\"{} {}\" color={color}]",
|
||||||
|
node.kind,
|
||||||
|
ty::Display::new(tys, files, node.ty)
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
writeln!(out, " node{i}[label=\"{}\" color={color}]", node.kind,)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest = node.inputs[0];
|
||||||
|
|
||||||
|
index_override = if node.kind == Kind::Then { Some(0) } else { Some(1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.kind == Kind::If {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (j, &o) in node.outputs.iter().enumerate() {
|
for (j, &o) in node.outputs.iter().enumerate() {
|
||||||
|
let j = index_override.unwrap_or(j);
|
||||||
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" };
|
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" };
|
||||||
let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
||||||
let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" };
|
let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" };
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
"node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]",
|
" node{o} -> node{dest}[color={color} taillabel={index} headlabel={j} {style}]",
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeln!(out, "}}")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +163,19 @@ impl Nodes {
|
||||||
log::info!("{out}");
|
log::info!("{out}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn graphviz_in_browser(&self, tys: &Types, files: &[parser::Ast]) {
|
||||||
|
let out = &mut String::new();
|
||||||
|
_ = self.graphviz_low(tys, files, out);
|
||||||
|
if !std::process::Command::new("brave")
|
||||||
|
.arg(format!("https://dreampuf.github.io/GraphvizOnline/#{out}"))
|
||||||
|
.status()
|
||||||
|
.unwrap()
|
||||||
|
.success()
|
||||||
|
{
|
||||||
|
log::error!("{out}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn gcm(&mut self) {
|
fn gcm(&mut self) {
|
||||||
self.visited.clear(self.values.len());
|
self.visited.clear(self.values.len());
|
||||||
push_up(self);
|
push_up(self);
|
||||||
|
@ -246,6 +288,8 @@ impl Nodes {
|
||||||
self.remove_node_lookup(target);
|
self.remove_node_lookup(target);
|
||||||
self.remove_low(target);
|
self.remove_low(target);
|
||||||
|
|
||||||
|
//std::println!("{target} {}", trace());
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,11 +472,13 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
K::Loop => {
|
K::Loop => {
|
||||||
if self[target].inputs[1] == NEVER {
|
if self[target].inputs[1] == NEVER {
|
||||||
|
self.lock(target);
|
||||||
for o in self[target].outputs.clone() {
|
for o in self[target].outputs.clone() {
|
||||||
if self[o].kind == Kind::Phi {
|
if self[o].kind == Kind::Phi {
|
||||||
self.replace(o, self[o].inputs[1]);
|
self.replace(o, self[o].inputs[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.unlock(target);
|
||||||
return Some(self[target].inputs[0]);
|
return Some(self[target].inputs[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,18 +693,21 @@ impl Nodes {
|
||||||
self[o].kind.is_cfg()
|
self[o].kind.is_cfg()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_final_integrity(&mut self) {
|
fn check_final_integrity(&self, tys: &Types, files: &[parser::Ast]) {
|
||||||
if !cfg!(debug_assertions) {
|
if !cfg!(debug_assertions) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//let mut failed = false;
|
let mut failed = false;
|
||||||
for (_, node) in self.iter() {
|
for (id, node) in self.iter() {
|
||||||
debug_assert_eq!(node.lock_rc, 0, "{:?}", node.kind);
|
if node.lock_rc != 0 {
|
||||||
// if !matches!(node.kind, Kind::Return | Kind::End) && node.outputs.is_empty() {
|
log::error!("{} {} {:?}", node.lock_rc, 0, node.kind);
|
||||||
// log::err!("outputs are empry {i} {:?}", node.kind);
|
failed = true;
|
||||||
// failed = true;
|
}
|
||||||
// }
|
if !matches!(node.kind, Kind::End | Kind::Mem | Kind::Arg) && node.outputs.is_empty() {
|
||||||
|
log::error!("outputs are empry {id} {:?}", node.kind);
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
// let mut allowed_cfgs = 1 + (node.kind == Kind::If) as usize;
|
// let mut allowed_cfgs = 1 + (node.kind == Kind::If) as usize;
|
||||||
// for &o in node.outputs.iter() {
|
// for &o in node.outputs.iter() {
|
||||||
|
@ -695,9 +744,10 @@ impl Nodes {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
//if failed {
|
if failed {
|
||||||
// panic!()
|
self.graphviz_in_browser(tys, files);
|
||||||
//}
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
|
@ -731,50 +781,35 @@ impl Nodes {
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_var(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) {
|
fn load_loop_var(&mut self, index: usize, value: &mut Variable, loops: &mut [Loop]) {
|
||||||
self.load_loop_value(
|
self.load_loop_value(&mut |l| l.scope.iter_mut().nth(index).unwrap(), value, loops);
|
||||||
&mut |l| {
|
|
||||||
l.scope
|
|
||||||
.vars
|
|
||||||
.get_mut(index)
|
|
||||||
.map_or((0, ty::Id::VOID, &mut l.scope.store), |v| (v.id, v.ty, &mut v.value))
|
|
||||||
},
|
|
||||||
value,
|
|
||||||
loops,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) {
|
fn load_loop_store(&mut self, value: &mut Variable, loops: &mut [Loop]) {
|
||||||
self.load_loop_value(&mut |l| (0, ty::Id::VOID, &mut l.scope.store), value, loops);
|
self.load_loop_value(&mut |l| &mut l.scope.store, value, loops);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_value(
|
fn load_loop_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
get_lvalue: &mut impl FnMut(&mut Loop) -> (Ident, ty::Id, &mut Nid),
|
get_lvalue: &mut impl FnMut(&mut Loop) -> &mut Variable,
|
||||||
value: &mut Nid,
|
var: &mut Variable,
|
||||||
loops: &mut [Loop],
|
loops: &mut [Loop],
|
||||||
) {
|
) {
|
||||||
if *value != VOID {
|
if var.value() != VOID {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [loops @ .., loob] = loops else { unreachable!() };
|
let [loops @ .., loob] = loops else { unreachable!() };
|
||||||
let node = loob.node;
|
let node = loob.node;
|
||||||
let (_id, ty, lvalue) = get_lvalue(loob);
|
let lvar = get_lvalue(loob);
|
||||||
|
|
||||||
self.load_loop_value(get_lvalue, lvalue, loops);
|
self.load_loop_value(get_lvalue, lvar, loops);
|
||||||
|
|
||||||
if !self[*lvalue].is_lazy_phi(node) {
|
if !self[lvar.value()].is_lazy_phi(node) {
|
||||||
self.unlock(*value);
|
let inps = [node, lvar.value(), VOID];
|
||||||
let inps = [node, *lvalue, VOID];
|
lvar.set_value(self.new_node_nop(lvar.ty, Kind::Phi, inps), self);
|
||||||
self.unlock(*lvalue);
|
|
||||||
*lvalue = self.new_node_nop(ty, Kind::Phi, inps);
|
|
||||||
self[*lvalue].lock_rc += 2;
|
|
||||||
} else {
|
|
||||||
self.lock(*lvalue);
|
|
||||||
self.unlock(*value);
|
|
||||||
}
|
}
|
||||||
*value = *lvalue;
|
var.set_value(lvar.value(), self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_dominance(&mut self, nd: Nid, min: Nid, check_outputs: bool) {
|
fn check_dominance(&mut self, nd: Nid, min: Nid, check_outputs: bool) {
|
||||||
|
@ -822,30 +857,6 @@ impl Nodes {
|
||||||
self.values.iter_mut().flat_map(Result::as_mut)
|
self.values.iter_mut().flat_map(Result::as_mut)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock_scope(&mut self, scope: &Scope) {
|
|
||||||
self.lock(scope.store);
|
|
||||||
for &load in &scope.loads {
|
|
||||||
self.lock(load);
|
|
||||||
}
|
|
||||||
for var in &scope.vars {
|
|
||||||
self.lock(var.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_remove_scope(&mut self, scope: &Scope) {
|
|
||||||
self.unlock_remove(scope.store);
|
|
||||||
for &load in &scope.loads {
|
|
||||||
self.unlock_remove(load);
|
|
||||||
}
|
|
||||||
for var in &scope.vars {
|
|
||||||
if self[var.value].kind == Kind::Arg {
|
|
||||||
self.unlock(var.value);
|
|
||||||
} else {
|
|
||||||
self.unlock_remove(var.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eliminate_stack_temporaries(&mut self) {
|
fn eliminate_stack_temporaries(&mut self) {
|
||||||
if !cfg!(debug_assertions) {
|
if !cfg!(debug_assertions) {
|
||||||
return;
|
return;
|
||||||
|
@ -1087,6 +1098,10 @@ impl Node {
|
||||||
(self.kind == Kind::Phi && self.inputs[2] == 0)
|
(self.kind == Kind::Phi && self.inputs[2] == 0)
|
||||||
|| matches!(self.kind, Kind::Arg | Kind::Stck)
|
|| matches!(self.kind, Kind::Arg | Kind::Stck)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_mem(&self) -> bool {
|
||||||
|
matches!(self.kind, Kind::Stre | Kind::Load | Kind::Stck)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RallocBRef = u16;
|
type RallocBRef = u16;
|
||||||
|
@ -1102,28 +1117,97 @@ struct Loop {
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
mod var {
|
||||||
struct Variable {
|
use {
|
||||||
id: Ident,
|
super::{Kind, Nid, Nodes},
|
||||||
ty: ty::Id,
|
crate::{ident::Ident, ty},
|
||||||
ptr: bool,
|
std::{panic, vec::Vec},
|
||||||
value: Nid,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
// makes sure value inside is laways locked for this instance of variable
|
||||||
struct Scope {
|
#[derive(Default, Clone)]
|
||||||
vars: Vec<Variable>,
|
pub struct Variable {
|
||||||
loads: Vec<Nid>,
|
pub id: Ident,
|
||||||
store: Nid,
|
pub ty: ty::Id,
|
||||||
}
|
pub ptr: bool,
|
||||||
|
value: Nid,
|
||||||
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Variable {
|
||||||
pub fn iter_elems_mut(&mut self) -> impl Iterator<Item = (Ident, ty::Id, &mut Nid)> {
|
pub fn new(id: Ident, ty: ty::Id, ptr: bool, value: Nid, nodes: &mut Nodes) -> Self {
|
||||||
self.vars.iter_mut().map(|v| (v.id, v.ty, &mut v.value)).chain(core::iter::once((
|
nodes.lock(value);
|
||||||
0,
|
Self { id, ty, ptr, value }
|
||||||
ty::Id::VOID,
|
}
|
||||||
&mut self.store,
|
|
||||||
)))
|
pub fn value(&self) -> Nid {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_value(&mut self, mut new_value: Nid, nodes: &mut Nodes) -> Nid {
|
||||||
|
nodes.unlock(self.value);
|
||||||
|
std::mem::swap(&mut self.value, &mut new_value);
|
||||||
|
nodes.lock(self.value);
|
||||||
|
new_value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dup(&self, nodes: &mut Nodes) -> Self {
|
||||||
|
nodes.lock(self.value);
|
||||||
|
Self { id: self.id, ty: self.ty, ptr: self.ptr, value: self.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(self, nodes: &mut Nodes) {
|
||||||
|
nodes.unlock_remove(self.value);
|
||||||
|
std::mem::forget(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_value_remove(&mut self, new_value: Nid, nodes: &mut Nodes) {
|
||||||
|
let old = self.set_value(new_value, nodes);
|
||||||
|
nodes.remove(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_ignore_arg(self, nodes: &mut Nodes) {
|
||||||
|
if nodes[self.value].kind == Kind::Arg {
|
||||||
|
nodes.unlock(self.value);
|
||||||
|
} else {
|
||||||
|
nodes.unlock_remove(self.value);
|
||||||
|
}
|
||||||
|
std::mem::forget(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Variable {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.ty != ty::Id::UNDECLARED && !std::thread::panicking() {
|
||||||
|
panic!("variable unproperly deinitialized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct Scope {
|
||||||
|
pub vars: Vec<Variable>,
|
||||||
|
pub loads: Vec<Nid>,
|
||||||
|
pub store: Variable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Variable> {
|
||||||
|
self.vars.iter_mut().chain(core::iter::once(&mut self.store))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dup(&self, nodes: &mut Nodes) -> Self {
|
||||||
|
Self {
|
||||||
|
vars: self.vars.iter().map(|v| v.dup(nodes)).collect(),
|
||||||
|
loads: self.loads.iter().copied().inspect(|&l| nodes.lock(l)).collect(),
|
||||||
|
store: self.store.dup(nodes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self, nodes: &mut Nodes) {
|
||||||
|
self.vars.drain(..).for_each(|n| n.remove(nodes));
|
||||||
|
self.loads.drain(..).for_each(|l| _ = nodes.unlock_remove(l));
|
||||||
|
std::mem::take(&mut self.store).remove(nodes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1172,22 +1256,21 @@ impl ItemCtx {
|
||||||
let mem = self.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]);
|
let mem = self.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]);
|
||||||
debug_assert_eq!(mem, MEM);
|
debug_assert_eq!(mem, MEM);
|
||||||
self.nodes.lock(mem);
|
self.nodes.lock(mem);
|
||||||
self.nodes.lock(self.ctrl);
|
self.scope.store = Variable::new(0, ty::Id::VOID, false, ENTRY, &mut self.nodes);
|
||||||
self.scope.store = self.ctrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize(&mut self) {
|
fn finalize(&mut self) {
|
||||||
self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope));
|
self.scope.clear(&mut self.nodes);
|
||||||
self.nodes.unlock(NEVER);
|
self.nodes.unlock(NEVER);
|
||||||
self.nodes.unlock(MEM);
|
self.nodes.unlock(MEM);
|
||||||
self.nodes.eliminate_stack_temporaries();
|
//self.nodes.eliminate_stack_temporaries();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
|
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
|
||||||
crate::emit(&mut self.code, instr);
|
crate::emit(&mut self.code, instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body_code(&mut self, sig: Sig, tys: &Types) -> usize {
|
fn emit_body_code(&mut self, sig: Sig, tys: &Types, files: &[parser::Ast]) -> usize {
|
||||||
let mut nodes = core::mem::take(&mut self.nodes);
|
let mut nodes = core::mem::take(&mut self.nodes);
|
||||||
|
|
||||||
let fuc = Function::new(&mut nodes, tys, sig);
|
let fuc = Function::new(&mut nodes, tys, sig);
|
||||||
|
@ -1205,8 +1288,12 @@ impl ItemCtx {
|
||||||
validate_ssa: cfg!(debug_assertions),
|
validate_ssa: cfg!(debug_assertions),
|
||||||
algorithm: regalloc2::Algorithm::Ion,
|
algorithm: regalloc2::Algorithm::Ion,
|
||||||
};
|
};
|
||||||
regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx)
|
regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx).unwrap_or_else(
|
||||||
.unwrap_or_else(|err| panic!("{err}"));
|
|err| {
|
||||||
|
fuc.nodes.graphviz_in_browser(tys, files);
|
||||||
|
panic!("{err}")
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if self.call_count != 0 {
|
if self.call_count != 0 {
|
||||||
core::mem::swap(
|
core::mem::swap(
|
||||||
|
@ -1487,7 +1574,7 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) {
|
fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) {
|
||||||
self.nodes.check_final_integrity();
|
self.nodes.check_final_integrity(tys, files);
|
||||||
self.nodes.graphviz(tys, files);
|
self.nodes.graphviz(tys, files);
|
||||||
self.nodes.gcm();
|
self.nodes.gcm();
|
||||||
self.nodes.basic_blocks();
|
self.nodes.basic_blocks();
|
||||||
|
@ -1513,7 +1600,7 @@ impl ItemCtx {
|
||||||
self.nodes[MEM].outputs = mems;
|
self.nodes[MEM].outputs = mems;
|
||||||
}
|
}
|
||||||
|
|
||||||
let saved = self.emit_body_code(sig, tys);
|
let saved = self.emit_body_code(sig, tys, files);
|
||||||
|
|
||||||
if let Some(last_ret) = self.ret_relocs.last()
|
if let Some(last_ret) = self.ret_relocs.last()
|
||||||
&& last_ret.offset as usize == self.code.len() - 5
|
&& last_ret.offset as usize == self.code.len() - 5
|
||||||
|
@ -1633,6 +1720,7 @@ impl Pool {
|
||||||
|
|
||||||
fn restore_ci(&mut self, dst: &mut ItemCtx) {
|
fn restore_ci(&mut self, dst: &mut ItemCtx) {
|
||||||
self.used_cis -= 1;
|
self.used_cis -= 1;
|
||||||
|
dst.scope.clear(&mut dst.nodes);
|
||||||
*dst = core::mem::take(&mut self.cis[self.used_cis]);
|
*dst = core::mem::take(&mut self.cis[self.used_cis]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1715,15 +1803,15 @@ impl TypeParser for Codegen<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 {
|
fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 {
|
||||||
let vars = self.ci.scope.vars.clone();
|
let mut scope = std::mem::take(&mut self.ci.scope.vars);
|
||||||
self.pool.push_ci(file, Some(ret), self.tasks.len(), &mut self.ci);
|
self.pool.push_ci(file, Some(ret), self.tasks.len(), &mut self.ci);
|
||||||
self.ci.scope.vars = vars;
|
self.ci.scope.vars = scope;
|
||||||
|
|
||||||
let prev_err_len = self.errors.borrow().len();
|
let prev_err_len = self.errors.borrow().len();
|
||||||
|
|
||||||
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
|
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
|
||||||
|
|
||||||
self.ci.scope.vars = vec![];
|
scope = std::mem::take(&mut self.ci.scope.vars);
|
||||||
self.ci.finalize();
|
self.ci.finalize();
|
||||||
|
|
||||||
if self.errors.borrow().len() == prev_err_len {
|
if self.errors.borrow().len() == prev_err_len {
|
||||||
|
@ -1740,8 +1828,9 @@ impl TypeParser for Codegen<'_> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pool.pop_ci(&mut self.ci);
|
|
||||||
self.complete_call_graph();
|
self.complete_call_graph();
|
||||||
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
self.ci.scope.vars = scope;
|
||||||
|
|
||||||
// TODO: return them back
|
// TODO: return them back
|
||||||
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
||||||
|
@ -1772,6 +1861,7 @@ impl TypeParser for Codegen<'_> {
|
||||||
self.ct.vm.read_reg(reg::RET).0
|
self.ct.vm.read_reg(reg::RET).0
|
||||||
} else {
|
} else {
|
||||||
self.pool.pop_ci(&mut self.ci);
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
self.ci.scope.vars = scope;
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1822,8 +1912,8 @@ impl TypeParser for Codegen<'_> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pool.pop_ci(&mut self.ci);
|
|
||||||
self.complete_call_graph();
|
self.complete_call_graph();
|
||||||
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
|
||||||
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||||
|
|
||||||
|
@ -1879,7 +1969,7 @@ impl TypeParser for Codegen<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_local_ty(&mut self, ident: Ident) -> Option<ty::Id> {
|
fn find_local_ty(&mut self, ident: Ident) -> Option<ty::Id> {
|
||||||
self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value == NEVER)).map(|v| v.ty)
|
self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value() == NEVER)).map(|v| v.ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1907,8 +1997,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let mut vc = Vc::from([VOID, value, region]);
|
let mut vc = Vc::from([VOID, value, region]);
|
||||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
self.ci.nodes.unlock(self.ci.scope.store);
|
if let Some(str) = self.ci.scope.store.value().to_store() {
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
|
||||||
vc.push(str);
|
vc.push(str);
|
||||||
}
|
}
|
||||||
for load in self.ci.scope.loads.drain(..) {
|
for load in self.ci.scope.loads.drain(..) {
|
||||||
|
@ -1920,10 +2009,11 @@ impl<'a> Codegen<'a> {
|
||||||
vc.push(load);
|
vc.push(load);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc);
|
let store = self.ci.nodes.new_node_nop(self.tof(value), Kind::Stre, vc);
|
||||||
self.ci.nodes.lock(store);
|
self.ci.scope.store.set_value(store, &mut self.ci.nodes);
|
||||||
self.ci.scope.store = store;
|
let opted = self.ci.nodes.late_peephole(store);
|
||||||
store
|
self.ci.scope.store.set_value_remove(opted, &mut self.ci.nodes);
|
||||||
|
opted
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
|
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
|
||||||
|
@ -1934,7 +2024,7 @@ impl<'a> Codegen<'a> {
|
||||||
debug_assert!(self.ci.nodes[region].kind != Kind::Stre);
|
debug_assert!(self.ci.nodes[region].kind != Kind::Stre);
|
||||||
let mut vc = Vc::from([VOID, region]);
|
let mut vc = Vc::from([VOID, region]);
|
||||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.value().to_store() {
|
||||||
vc.push(str);
|
vc.push(str);
|
||||||
}
|
}
|
||||||
let load = self.ci.nodes.new_node(ty, Kind::Load, vc);
|
let load = self.ci.nodes.new_node(ty, Kind::Load, vc);
|
||||||
|
@ -2005,7 +2095,7 @@ impl<'a> Codegen<'a> {
|
||||||
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
||||||
{
|
{
|
||||||
let var = &mut self.ci.scope.vars[index];
|
let var = &mut self.ci.scope.vars[index];
|
||||||
self.ci.nodes.load_loop_var(index, &mut var.value, &mut self.ci.loops);
|
self.ci.nodes.load_loop_var(index, var, &mut self.ci.loops);
|
||||||
|
|
||||||
Some(Value::var(index).ty(var.ty))
|
Some(Value::var(index).ty(var.ty))
|
||||||
}
|
}
|
||||||
|
@ -2054,7 +2144,7 @@ impl<'a> Codegen<'a> {
|
||||||
if self.ci.inline_depth == 0 {
|
if self.ci.inline_depth == 0 {
|
||||||
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
||||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.value().to_store() {
|
||||||
inps.push(str);
|
inps.push(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2177,12 +2267,10 @@ impl<'a> Codegen<'a> {
|
||||||
let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize];
|
let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize];
|
||||||
|
|
||||||
if var.ptr {
|
if var.ptr {
|
||||||
let val = var.value;
|
let val = var.value();
|
||||||
self.store_mem(val, value.id);
|
self.store_mem(val, value.id);
|
||||||
} else {
|
} else {
|
||||||
self.ci.nodes.lock(value.id);
|
var.set_value_remove(value.id, &mut self.ci.nodes);
|
||||||
let prev = core::mem::replace(&mut var.value, value.id);
|
|
||||||
self.ci.nodes.unlock_remove(prev);
|
|
||||||
}
|
}
|
||||||
} else if dest.ptr {
|
} else if dest.ptr {
|
||||||
self.store_mem(dest.id, value.id);
|
self.store_mem(dest.id, value.id);
|
||||||
|
@ -2387,7 +2475,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.nodes.unlock(n);
|
self.ci.nodes.unlock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.value().to_store() {
|
||||||
inps.push(str);
|
inps.push(str);
|
||||||
}
|
}
|
||||||
self.ci.scope.loads.retain(|&load| {
|
self.ci.scope.loads.retain(|&load| {
|
||||||
|
@ -2471,7 +2559,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.nodes.unlock(n);
|
self.ci.nodes.unlock(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(str) = self.ci.scope.store.to_store() {
|
if let Some(str) = self.ci.scope.store.value().to_store() {
|
||||||
inps.push(str);
|
inps.push(str);
|
||||||
}
|
}
|
||||||
self.ci.scope.loads.retain(|&load| {
|
self.ci.scope.loads.retain(|&load| {
|
||||||
|
@ -2543,13 +2631,13 @@ impl<'a> Codegen<'a> {
|
||||||
for (arg, carg) in args.iter().zip(cargs) {
|
for (arg, carg) in args.iter().zip(cargs) {
|
||||||
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
||||||
if ty == ty::Id::TYPE {
|
if ty == ty::Id::TYPE {
|
||||||
self.ci.scope.vars.push(Variable {
|
self.ci.scope.vars.push(Variable::new(
|
||||||
id: carg.id,
|
carg.id,
|
||||||
ty: self.tys.ins.args[sig_args.next().unwrap()],
|
self.tys.ins.args[sig_args.next().unwrap()],
|
||||||
ptr: false,
|
false,
|
||||||
value: NEVER,
|
NEVER,
|
||||||
});
|
&mut self.ci.nodes,
|
||||||
self.ci.nodes.lock(NEVER);
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2558,13 +2646,13 @@ impl<'a> Codegen<'a> {
|
||||||
debug_assert_ne!(value.id, 0);
|
debug_assert_ne!(value.id, 0);
|
||||||
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
|
||||||
|
|
||||||
self.ci.scope.vars.push(Variable {
|
self.ci.scope.vars.push(Variable::new(
|
||||||
id: carg.id,
|
carg.id,
|
||||||
ty,
|
ty,
|
||||||
ptr: value.ptr,
|
value.ptr,
|
||||||
value: value.id,
|
value.id,
|
||||||
});
|
&mut self.ci.nodes,
|
||||||
self.ci.nodes.lock(value.id);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev_ret = self.ci.ret.replace(sig.ret);
|
let prev_ret = self.ci.ret.replace(sig.ret);
|
||||||
|
@ -2584,7 +2672,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.file = prev_file;
|
self.ci.file = prev_file;
|
||||||
self.ci.inline_depth -= 1;
|
self.ci.inline_depth -= 1;
|
||||||
for var in self.ci.scope.vars.drain(arg_base..) {
|
for var in self.ci.scope.vars.drain(arg_base..) {
|
||||||
self.ci.nodes.unlock_remove(var.value);
|
var.remove(&mut self.ci.nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, ctrl)| {
|
core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, ctrl)| {
|
||||||
|
@ -2772,7 +2860,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
self.ci.nodes.lock(self.ci.ctrl);
|
self.ci.nodes.lock(self.ci.ctrl);
|
||||||
for var in self.ci.scope.vars.drain(base..) {
|
for var in self.ci.scope.vars.drain(base..) {
|
||||||
self.ci.nodes.unlock_remove(var.value);
|
var.remove(&mut self.ci.nodes);
|
||||||
}
|
}
|
||||||
self.ci.nodes.unlock(self.ci.ctrl);
|
self.ci.nodes.unlock(self.ci.ctrl);
|
||||||
|
|
||||||
|
@ -2784,13 +2872,12 @@ impl<'a> Codegen<'a> {
|
||||||
node: self.ci.ctrl,
|
node: self.ci.ctrl,
|
||||||
ctrl: [Nid::MAX; 2],
|
ctrl: [Nid::MAX; 2],
|
||||||
ctrl_scope: core::array::from_fn(|_| Default::default()),
|
ctrl_scope: core::array::from_fn(|_| Default::default()),
|
||||||
scope: self.ci.scope.clone(),
|
scope: self.ci.scope.dup(&mut self.ci.nodes),
|
||||||
});
|
});
|
||||||
|
|
||||||
for (.., var) in &mut self.ci.scope.iter_elems_mut() {
|
for var in &mut self.ci.scope.iter_mut() {
|
||||||
*var = VOID;
|
var.set_value(VOID, &mut self.ci.nodes);
|
||||||
}
|
}
|
||||||
self.ci.nodes.lock_scope(&self.ci.scope);
|
|
||||||
|
|
||||||
self.expr(body);
|
self.expr(body);
|
||||||
|
|
||||||
|
@ -2808,8 +2895,8 @@ impl<'a> Codegen<'a> {
|
||||||
con,
|
con,
|
||||||
&mut self.ci.scope,
|
&mut self.ci.scope,
|
||||||
&mut cons,
|
&mut cons,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
cons.clear(&mut self.ci.nodes);
|
||||||
self.ci.ctrl = con;
|
self.ci.ctrl = con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2818,15 +2905,15 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||||
|
|
||||||
let idx = self.ci.nodes[node]
|
if let Some(idx) =
|
||||||
.outputs
|
self.ci.nodes[node].outputs.iter().position(|&n| self.ci.nodes.is_cfg(n))
|
||||||
.iter()
|
{
|
||||||
.position(|&n| self.ci.nodes.is_cfg(n))
|
self.ci.nodes[node].outputs.swap(idx, 0);
|
||||||
.unwrap();
|
}
|
||||||
self.ci.nodes[node].outputs.swap(idx, 0);
|
|
||||||
|
|
||||||
if bre == Nid::MAX {
|
if bre == Nid::MAX {
|
||||||
self.ci.ctrl = NEVER;
|
self.ci.ctrl = NEVER;
|
||||||
|
scope.clear(&mut self.ci.nodes);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.ci.ctrl = bre;
|
self.ci.ctrl = bre;
|
||||||
|
@ -2836,51 +2923,44 @@ impl<'a> Codegen<'a> {
|
||||||
debug_assert_eq!(self.ci.scope.vars.len(), scope.vars.len());
|
debug_assert_eq!(self.ci.scope.vars.len(), scope.vars.len());
|
||||||
debug_assert_eq!(self.ci.scope.vars.len(), bres.vars.len());
|
debug_assert_eq!(self.ci.scope.vars.len(), bres.vars.len());
|
||||||
|
|
||||||
for (((.., dest_value), (.., &mut mut scope_value)), (.., &mut loop_value)) in self
|
self.ci.nodes.lock(node);
|
||||||
.ci
|
|
||||||
.scope
|
|
||||||
.iter_elems_mut()
|
|
||||||
.zip(scope.iter_elems_mut())
|
|
||||||
.zip(bres.iter_elems_mut())
|
|
||||||
{
|
|
||||||
self.ci.nodes.unlock(loop_value);
|
|
||||||
|
|
||||||
if self.ci.nodes[scope_value].is_lazy_phi(node) {
|
for ((dest_var, scope_var), loop_var) in
|
||||||
self.ci.nodes.unlock(scope_value);
|
self.ci.scope.iter_mut().zip(scope.iter_mut()).zip(bres.iter_mut())
|
||||||
if loop_value != scope_value {
|
{
|
||||||
scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value);
|
if self.ci.nodes[scope_var.value()].is_lazy_phi(node) {
|
||||||
self.ci.nodes.lock(scope_value);
|
if loop_var.value() != scope_var.value() {
|
||||||
|
scope_var.set_value(
|
||||||
|
self.ci.nodes.modify_input(scope_var.value(), 2, loop_var.value()),
|
||||||
|
&mut self.ci.nodes,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if *dest_value == scope_value {
|
if dest_var.value() == scope_var.value() {
|
||||||
self.ci.nodes.unlock(*dest_value);
|
dest_var.set_value(VOID, &mut self.ci.nodes);
|
||||||
*dest_value = VOID;
|
|
||||||
self.ci.nodes.lock(*dest_value);
|
|
||||||
}
|
}
|
||||||
let phi = &self.ci.nodes[scope_value];
|
let phi = &self.ci.nodes[scope_var.value()];
|
||||||
let prev = phi.inputs[1];
|
let prev = phi.inputs[1];
|
||||||
self.ci.nodes.replace(scope_value, prev);
|
self.ci.nodes.replace(scope_var.value(), prev);
|
||||||
scope_value = prev;
|
scope_var.set_value(prev, &mut self.ci.nodes);
|
||||||
self.ci.nodes.lock(prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *dest_value == VOID {
|
if dest_var.value() == VOID {
|
||||||
self.ci.nodes.unlock(*dest_value);
|
dest_var.set_value(scope_var.value(), &mut self.ci.nodes);
|
||||||
*dest_value = scope_value;
|
|
||||||
self.ci.nodes.lock(*dest_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(!self.ci.nodes[*dest_value].is_lazy_phi(node));
|
debug_assert!(!self.ci.nodes[dest_var.value()].is_lazy_phi(node));
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove(scope_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.loads.iter().for_each(|&n| _ = self.ci.nodes.unlock_remove(n));
|
scope.clear(&mut self.ci.nodes);
|
||||||
bres.loads.iter().for_each(|&n| _ = self.ci.nodes.unlock_remove(n));
|
bres.clear(&mut self.ci.nodes);
|
||||||
|
|
||||||
self.ci.nodes.unlock(self.ci.ctrl);
|
self.ci.nodes.unlock(self.ci.ctrl);
|
||||||
|
self.ci.nodes.unlock(node);
|
||||||
self.ci.nodes.late_peephole(node);
|
let rpl = self.ci.nodes.late_peephole(node);
|
||||||
|
if self.ci.ctrl == node {
|
||||||
|
self.ci.ctrl = rpl;
|
||||||
|
}
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
|
@ -2911,10 +2991,8 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
let orig_store = self.ci.scope.store;
|
let orig_store = self.ci.scope.store.dup(&mut self.ci.nodes);
|
||||||
self.ci.nodes.lock(orig_store);
|
let else_scope = self.ci.scope.dup(&mut self.ci.nodes);
|
||||||
let else_scope = self.ci.scope.clone();
|
|
||||||
self.ci.nodes.lock_scope(&else_scope);
|
|
||||||
|
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node]);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [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);
|
||||||
|
@ -2927,16 +3005,16 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.ctrl
|
self.ci.ctrl
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove(orig_store);
|
orig_store.remove(&mut self.ci.nodes);
|
||||||
|
|
||||||
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
||||||
self.ci.nodes.unlock_remove_scope(&then_scope);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
return None;
|
return None;
|
||||||
} else if lcntrl == Nid::MAX {
|
} else if lcntrl == Nid::MAX {
|
||||||
self.ci.nodes.unlock_remove_scope(&then_scope);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
return Some(Value::VOID);
|
return Some(Value::VOID);
|
||||||
} else if rcntrl == Nid::MAX {
|
} else if rcntrl == Nid::MAX {
|
||||||
self.ci.nodes.unlock_remove_scope(&self.ci.scope);
|
self.ci.scope.clear(&mut self.ci.nodes);
|
||||||
self.ci.scope = then_scope;
|
self.ci.scope = then_scope;
|
||||||
self.ci.ctrl = lcntrl;
|
self.ci.ctrl = lcntrl;
|
||||||
return Some(Value::VOID);
|
return Some(Value::VOID);
|
||||||
|
@ -2950,8 +3028,8 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.ctrl,
|
self.ci.ctrl,
|
||||||
&mut self.ci.scope,
|
&mut self.ci.scope,
|
||||||
&mut then_scope,
|
&mut then_scope,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
|
@ -3029,7 +3107,13 @@ impl<'a> Codegen<'a> {
|
||||||
ty
|
ty
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ci.scope.vars.push(Variable { id: carg.id, ty, ptr: false, value: NEVER });
|
self.ci.scope.vars.push(Variable::new(
|
||||||
|
carg.id,
|
||||||
|
ty,
|
||||||
|
false,
|
||||||
|
NEVER,
|
||||||
|
&mut self.ci.nodes,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(args) = self.tys.pack_args(arg_base) else {
|
let Some(args) = self.tys.pack_args(arg_base) else {
|
||||||
|
@ -3038,7 +3122,7 @@ impl<'a> Codegen<'a> {
|
||||||
};
|
};
|
||||||
let ret = self.ty(ret);
|
let ret = self.ty(ret);
|
||||||
|
|
||||||
self.ci.scope.vars.truncate(base);
|
self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes));
|
||||||
|
|
||||||
let sym = SymKey::FuncInst(*func, args);
|
let sym = SymKey::FuncInst(*func, args);
|
||||||
let ct = |ins: &mut crate::TypeIns| {
|
let ct = |ins: &mut crate::TypeIns| {
|
||||||
|
@ -3064,13 +3148,13 @@ impl<'a> Codegen<'a> {
|
||||||
fn assign_pattern(&mut self, pat: &Expr, right: Value) {
|
fn assign_pattern(&mut self, pat: &Expr, right: Value) {
|
||||||
match *pat {
|
match *pat {
|
||||||
Expr::Ident { id, .. } => {
|
Expr::Ident { id, .. } => {
|
||||||
self.ci.nodes.lock(right.id);
|
self.ci.scope.vars.push(Variable::new(
|
||||||
self.ci.scope.vars.push(Variable {
|
|
||||||
id,
|
id,
|
||||||
value: right.id,
|
right.ty,
|
||||||
ptr: right.ptr,
|
right.ptr,
|
||||||
ty: right.ty,
|
right.id,
|
||||||
});
|
&mut self.ci.nodes,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Expr::Ctor { pos, fields, .. } => {
|
Expr::Ctor { pos, fields, .. } => {
|
||||||
let ty::Kind::Struct(idx) = right.ty.expand() else {
|
let ty::Kind::Struct(idx) = right.ty.expand() else {
|
||||||
|
@ -3114,7 +3198,7 @@ impl<'a> Codegen<'a> {
|
||||||
if core::mem::take(&mut n.var) {
|
if core::mem::take(&mut n.var) {
|
||||||
let id = (u16::MAX - n.id) as usize;
|
let id = (u16::MAX - n.id) as usize;
|
||||||
n.ptr = self.ci.scope.vars[id].ptr;
|
n.ptr = self.ci.scope.vars[id].ptr;
|
||||||
n.id = self.ci.scope.vars[id].value;
|
n.id = self.ci.scope.vars[id].value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3131,9 +3215,11 @@ impl<'a> Codegen<'a> {
|
||||||
if loob.ctrl[id] == Nid::MAX {
|
if loob.ctrl[id] == Nid::MAX {
|
||||||
self.ci.nodes.lock(self.ci.ctrl);
|
self.ci.nodes.lock(self.ci.ctrl);
|
||||||
loob.ctrl[id] = self.ci.ctrl;
|
loob.ctrl[id] = self.ci.ctrl;
|
||||||
loob.ctrl_scope[id] = self.ci.scope.clone();
|
loob.ctrl_scope[id] = self.ci.scope.dup(&mut self.ci.nodes);
|
||||||
loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len());
|
loob.ctrl_scope[id]
|
||||||
self.ci.nodes.lock_scope(&loob.ctrl_scope[id]);
|
.vars
|
||||||
|
.drain(loob.scope.vars.len()..)
|
||||||
|
.for_each(|v| v.remove(&mut self.ci.nodes));
|
||||||
} else {
|
} else {
|
||||||
let reg =
|
let reg =
|
||||||
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]);
|
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]);
|
||||||
|
@ -3145,7 +3231,6 @@ impl<'a> Codegen<'a> {
|
||||||
reg,
|
reg,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
&mut self.ci.scope,
|
&mut self.ci.scope,
|
||||||
false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
loob = self.ci.loops.last_mut().unwrap();
|
loob = self.ci.loops.last_mut().unwrap();
|
||||||
|
@ -3165,20 +3250,16 @@ impl<'a> Codegen<'a> {
|
||||||
ctrl: Nid,
|
ctrl: Nid,
|
||||||
to: &mut Scope,
|
to: &mut Scope,
|
||||||
from: &mut Scope,
|
from: &mut Scope,
|
||||||
drop_from: bool,
|
|
||||||
) {
|
) {
|
||||||
nodes.lock(ctrl);
|
nodes.lock(ctrl);
|
||||||
for (i, ((.., ty, to_value), (.., from_value))) in
|
for (i, (to_value, from_value)) in to.iter_mut().zip(from.iter_mut()).enumerate() {
|
||||||
to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate()
|
if to_value.value() != from_value.value() {
|
||||||
{
|
|
||||||
if to_value != from_value {
|
|
||||||
nodes.load_loop_var(i, from_value, loops);
|
nodes.load_loop_var(i, from_value, loops);
|
||||||
nodes.load_loop_var(i, to_value, loops);
|
nodes.load_loop_var(i, to_value, loops);
|
||||||
if to_value != from_value {
|
if to_value.value() != from_value.value() {
|
||||||
let inps = [ctrl, *from_value, *to_value];
|
let inps = [ctrl, from_value.value(), to_value.value()];
|
||||||
nodes.unlock(*to_value);
|
to_value
|
||||||
*to_value = nodes.new_node(ty, Kind::Phi, inps);
|
.set_value_remove(nodes.new_node(from_value.ty, Kind::Phi, inps), nodes);
|
||||||
nodes.lock(*to_value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3190,9 +3271,6 @@ impl<'a> Codegen<'a> {
|
||||||
nodes.unlock_remove(load);
|
nodes.unlock_remove(load);
|
||||||
}
|
}
|
||||||
|
|
||||||
if drop_from {
|
|
||||||
nodes.unlock_remove_scope(from);
|
|
||||||
}
|
|
||||||
nodes.unlock(ctrl);
|
nodes.unlock(ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3228,23 +3306,23 @@ impl<'a> Codegen<'a> {
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
let ty = self.tys.ins.args[sig_args.next().unwrap()];
|
||||||
if ty == ty::Id::TYPE {
|
if ty == ty::Id::TYPE {
|
||||||
self.ci.scope.vars.push(Variable {
|
self.ci.scope.vars.push(Variable::new(
|
||||||
id: arg.id,
|
arg.id,
|
||||||
ty: self.tys.ins.args[sig_args.next().unwrap()],
|
self.tys.ins.args[sig_args.next().unwrap()],
|
||||||
ptr: false,
|
false,
|
||||||
value: NEVER,
|
NEVER,
|
||||||
});
|
&mut self.ci.nodes,
|
||||||
self.ci.nodes.lock(NEVER);
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut deps = Vc::from([VOID]);
|
let mut deps = Vc::from([VOID]);
|
||||||
if ty.loc(&self.tys) == Loc::Stack {
|
if ty.loc(&self.tys) == Loc::Stack && self.tys.size_of(ty) <= 16 {
|
||||||
deps.push(MEM);
|
deps.push(MEM);
|
||||||
}
|
}
|
||||||
let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, [VOID]);
|
// TODO: whe we not using the deps?
|
||||||
self.ci.nodes.lock(value);
|
let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, deps);
|
||||||
let ptr = ty.loc(&self.tys) == Loc::Stack;
|
let ptr = ty.loc(&self.tys) == Loc::Stack;
|
||||||
self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr });
|
self.ci.scope.vars.push(Variable::new(arg.id, ty, ptr, value, &mut self.ci.nodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
||||||
|
@ -3255,6 +3333,8 @@ impl<'a> Codegen<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes));
|
||||||
|
|
||||||
self.ci.finalize();
|
self.ci.finalize();
|
||||||
|
|
||||||
if self.errors.borrow().is_empty() {
|
if self.errors.borrow().is_empty() {
|
||||||
|
@ -3461,6 +3541,11 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rg(&self, nid: Nid) -> VReg {
|
fn rg(&self, nid: Nid) -> VReg {
|
||||||
|
debug_assert!(
|
||||||
|
!self.nodes.is_cfg(nid) || matches!(self.nodes[nid].kind, Kind::Call { .. }),
|
||||||
|
"{:?}",
|
||||||
|
self.nodes[nid]
|
||||||
|
);
|
||||||
regalloc2::VReg::new(nid as _, regalloc2::RegClass::Int)
|
regalloc2::VReg::new(nid as _, regalloc2::RegClass::Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4137,8 +4222,8 @@ mod tests {
|
||||||
|
|
||||||
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
|
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
|
||||||
_ = log::set_logger(&crate::fs::Logger);
|
_ = log::set_logger(&crate::fs::Logger);
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
//log::set_max_level(log::LevelFilter::Info);
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
// log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
|
||||||
let (ref files, embeds) = crate::test_parse_files(ident, input);
|
let (ref files, embeds) = crate::test_parse_files(ident, input);
|
||||||
let mut codegen = super::Codegen { files, ..Default::default() };
|
let mut codegen = super::Codegen { files, ..Default::default() };
|
||||||
|
@ -4194,7 +4279,6 @@ mod tests {
|
||||||
fb_driver;
|
fb_driver;
|
||||||
|
|
||||||
// Purely Testing Examples;
|
// Purely Testing Examples;
|
||||||
smh_happened;
|
|
||||||
wide_ret;
|
wide_ret;
|
||||||
comptime_min_reg_leak;
|
comptime_min_reg_leak;
|
||||||
different_types;
|
different_types;
|
||||||
|
|
Loading…
Reference in a new issue