better somehow

This commit is contained in:
Jakub Doka 2024-10-22 22:57:40 +02:00
parent 6977cb218c
commit f013e90936
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
3 changed files with 331 additions and 342 deletions

View file

@ -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(())
} }

View file

@ -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 {

View file

@ -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;