fixing function destinations

This commit is contained in:
Jakub Doka 2024-11-14 20:25:52 +01:00
parent d01e31b203
commit 981c17ff19
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
22 changed files with 340 additions and 174 deletions

View file

@ -646,6 +646,41 @@ main := fn(): uint {
### Purely Testing Examples ### Purely Testing Examples
#### different_function_destinations
```hb
Stru := struct {a: uint, b: uint}
new_stru := fn(): Stru return .(0, 0)
glob_stru := Stru.(1, 1)
main := fn(): uint {
glob_stru = new_stru()
if glob_stru.a != 0 return 300
glob_stru = .(1, 1)
glob_stru = @inline(new_stru)
if glob_stru.a != 0 return 200
glob_stru = .(1, 1)
strus := [Stru].(glob_stru, glob_stru, glob_stru)
i := 0
loop if i == 3 break else {
strus[i] = new_stru()
i += 1
}
if strus[2].a != 0 return 100
strus = [Stru].(glob_stru, glob_stru, glob_stru)
i = 0
loop if i == 3 break else {
strus[i] = @inline(new_stru)
i += 1
}
if strus[2].a != 0 return 10
return 0
}
```
#### triggering_store_in_divergent_branch #### triggering_store_in_divergent_branch
```hb ```hb
opaque := fn(): uint { opaque := fn(): uint {

View file

@ -1,4 +1,5 @@
#![feature( #![feature(
iter_array_chunks,
assert_matches, assert_matches,
let_chains, let_chains,
if_let_guard, if_let_guard,

View file

@ -125,52 +125,34 @@ impl Default for Nodes {
impl Nodes { impl Nodes {
fn loop_depth(&self, target: Nid) -> LoopDepth { fn loop_depth(&self, target: Nid) -> LoopDepth {
if self[target].loop_depth.get() != 0 {
return self[target].loop_depth.get();
}
self[target].loop_depth.set(match self[target].kind { self[target].loop_depth.set(match self[target].kind {
Kind::Entry | Kind::Then | Kind::Else | Kind::Call { .. } | Kind::Return | Kind::If => { Kind::Region | Kind::Entry | Kind::Then | Kind::Else | Kind::Call { .. } | Kind::If => {
let dpth = self.loop_depth(self[target].inputs[0]);
if self[target].loop_depth.get() != 0 { if self[target].loop_depth.get() != 0 {
return self[target].loop_depth.get(); return self[target].loop_depth.get();
} }
dpth self.loop_depth(self[target].inputs[0])
}
Kind::Region => {
let l = self.loop_depth(self[target].inputs[0]);
let r = self.loop_depth(self[target].inputs[1]);
debug_assert_eq!(l, r);
l
} }
Kind::Loop => { Kind::Loop => {
let depth = Self::loop_depth(self, self[target].inputs[0]) + 1; if self[target].loop_depth.get() == self.loop_depth(self[target].inputs[0]) + 1 {
return self[target].loop_depth.get();
}
let depth = self.loop_depth(self[target].inputs[0]) + 1;
self[target].loop_depth.set(depth); self[target].loop_depth.set(depth);
let mut cursor = self[target].inputs[1]; let mut cursor = self[target].inputs[1];
while cursor != target { while cursor != target {
self[cursor].loop_depth.set(depth); self[cursor].loop_depth.set(depth);
let next = if self[cursor].kind == Kind::Region { let next = self.idom(cursor);
self.loop_depth(self[cursor].inputs[0]); debug_assert_ne!(next, 0);
self[cursor].inputs[1]
} else {
self.idom(cursor)
};
debug_assert_ne!(next, VOID);
if matches!(self[cursor].kind, Kind::Then | Kind::Else) { if matches!(self[cursor].kind, Kind::Then | Kind::Else) {
let other = *self[next] debug_assert_eq!(self[next].kind, Kind::If);
.outputs let other = self[next].outputs[(self[next].outputs[0] == cursor) as usize];
.iter()
.find(|&&n| self[n].kind != self[cursor].kind)
.unwrap();
if self[other].loop_depth.get() == 0 {
self[other].loop_depth.set(depth - 1); self[other].loop_depth.set(depth - 1);
} }
}
cursor = next; cursor = next;
} }
depth depth
} }
Kind::Start | Kind::End | Kind::Die => 1, Kind::Start | Kind::End | Kind::Die | Kind::Return => 1,
u => unreachable!("{u:?}"), u => unreachable!("{u:?}"),
}); });
@ -194,23 +176,24 @@ impl Nodes {
self[target].depth.get() self[target].depth.get()
} }
fn fix_loops(&mut self) { fn fix_loops(&mut self, stack: &mut Vec<Nid>, seen: &mut BitSet) {
'o: for l in self[LOOPS].outputs.clone() { debug_assert!(stack.is_empty());
let mut cursor = self[l].inputs[1];
let depth = self.loop_depth(cursor); stack.push(NEVER);
while cursor != l {
if self[cursor].kind == Kind::If while let Some(node) = stack.pop() {
&& self[cursor].outputs.iter().any(|&b| self.loop_depth(b) < depth) if seen.set(node) && self.is_cfg(node) {
{ stack.extend(self[node].inputs.iter());
continue 'o;
} }
cursor = self.idom(cursor);
} }
for l in self[LOOPS].outputs.clone() {
if !seen.get(l) {
self[l].outputs.push(NEVER); self[l].outputs.push(NEVER);
self[NEVER].inputs.push(l); self[NEVER].inputs.push(l);
} }
} }
}
fn push_up_impl(&mut self, node: Nid, visited: &mut BitSet) { fn push_up_impl(&mut self, node: Nid, visited: &mut BitSet) {
if !visited.set(node) { if !visited.set(node) {
@ -599,7 +582,8 @@ impl Nodes {
} }
fn gcm(&mut self, rpo: &mut Vec<Nid>, visited: &mut BitSet) { fn gcm(&mut self, rpo: &mut Vec<Nid>, visited: &mut BitSet) {
self.fix_loops(); visited.clear(self.values.len());
self.fix_loops(rpo, visited);
visited.clear(self.values.len()); visited.clear(self.values.len());
self.push_up(rpo, visited); self.push_up(rpo, visited);
visited.clear(self.values.len()); visited.clear(self.values.len());
@ -947,6 +931,10 @@ impl Nodes {
} }
} }
K::If => { K::If => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
if self[target].ty == ty::Id::VOID { if self[target].ty == ty::Id::VOID {
match self.try_opt_cond(target) { match self.try_opt_cond(target) {
CondOptRes::Unknown => {} CondOptRes::Unknown => {}
@ -962,6 +950,10 @@ impl Nodes {
} }
} }
K::Then => { K::Then => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE { if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE {
return Some(NEVER); return Some(NEVER);
} else if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE { } else if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE {
@ -969,6 +961,10 @@ impl Nodes {
} }
} }
K::Else => { K::Else => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE { if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE {
return Some(NEVER); return Some(NEVER);
} else if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE { } else if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE {
@ -1354,6 +1350,7 @@ impl Nodes {
return Some(self[target].inputs[0]); return Some(self[target].inputs[0]);
} }
} }
_ if self.is_cfg(target) && self.idom(target) == NEVER => panic!(),
_ => {} _ => {}
} }
@ -1665,6 +1662,40 @@ impl Nodes {
} }
} }
fn check_loop_depth_integrity(&self, disp: ty::Display) {
if !cfg!(debug_assertions) {
return;
}
let mut failed = false;
for &loob in self[LOOPS].outputs.iter() {
let mut stack = vec![self[loob].inputs[1]];
let mut seen = BitSet::default();
seen.set(loob);
let depth = self.loop_depth(loob);
while let Some(nid) = stack.pop() {
if seen.set(nid) {
if depth > self.loop_depth(nid) {
failed = true;
log::error!("{depth} {} {nid} {:?}", self.loop_depth(nid), self[nid]);
}
match self[nid].kind {
Kind::Loop | Kind::Region => {
stack.extend(&self[nid].inputs[..2]);
}
_ => stack.push(self[nid].inputs[0]),
}
}
}
}
if failed {
self.graphviz_in_browser(disp);
panic!()
}
}
fn load_loop_var(&mut self, index: usize, var: &mut Variable, loops: &mut [Loop]) { fn load_loop_var(&mut self, index: usize, var: &mut Variable, loops: &mut [Loop]) {
if var.value() != VOID { if var.value() != VOID {
return; return;
@ -1748,14 +1779,16 @@ impl Nodes {
} }
} }
fn is_data_dep(&self, nid: Nid, n: Nid) -> bool { fn is_data_dep(&self, val: Nid, user: Nid) -> bool {
match self[n].kind { match self[user].kind {
Kind::Return => self[n].inputs[1] == nid, Kind::Return => self[user].inputs[1] == val,
_ if self.is_cfg(n) && !matches!(self[n].kind, Kind::Call { .. } | Kind::If) => false, _ if self.is_cfg(user) && !matches!(self[user].kind, Kind::Call { .. } | Kind::If) => {
false
}
Kind::Join => false, Kind::Join => false,
Kind::Stre => self[n].inputs[3] != nid, Kind::Stre => self[user].inputs[3] != val,
Kind::Load => self[n].inputs[2] != nid, Kind::Load => self[user].inputs[2] != val,
_ => self[n].inputs[0] != nid || self[n].inputs[1..].contains(&nid), _ => self[user].inputs[0] != val || self[user].inputs[1..].contains(&val),
} }
} }
@ -4426,6 +4459,7 @@ impl<'a> Codegen<'a> {
self.ci.nodes.check_final_integrity(self.ty_display(ty::Id::VOID)); self.ci.nodes.check_final_integrity(self.ty_display(ty::Id::VOID));
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID)); self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set); self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
self.ci.nodes.check_loop_depth_integrity(self.ty_display(ty::Id::VOID));
self.ci.nodes.basic_blocks(); self.ci.nodes.basic_blocks();
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID)); self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
} else { } else {
@ -4844,6 +4878,7 @@ mod tests {
fb_driver; fb_driver;
// Purely Testing Examples; // Purely Testing Examples;
different_function_destinations;
triggering_store_in_divergent_branch; triggering_store_in_divergent_branch;
wrong_dead_code_elimination; wrong_dead_code_elimination;
memory_swap; memory_swap;

View file

@ -336,6 +336,18 @@ impl Backend for HbvmBackend {
} }
impl Nodes { impl Nodes {
fn strip_offset(&self, region: Nid, ty: ty::Id, tys: &Types) -> (Nid, Offset) {
if matches!(self[region].kind, Kind::BinOp { op: TokenKind::Add | TokenKind::Sub })
&& self[region].lock_rc != 0
&& let Kind::CInt { value } = self[self[region].inputs[2]].kind
&& ty.loc(tys) == Loc::Reg
{
(self[region].inputs[1], value as _)
} else {
(region, 0)
}
}
fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) { fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) {
// NOTE: this code is horible // NOTE: this code is horible
let fromc = Some(&from); let fromc = Some(&from);
@ -638,17 +650,10 @@ impl HbvmBackend {
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
} }
if let Some(PLoc::WideReg(r, size)) = ret { if node.ty.loc(tys) == Loc::Stack
debug_assert_eq!(nodes[*node.inputs.last().unwrap()].kind, Kind::Stck); && let Some(PLoc::Reg(r, size) | PLoc::WideReg(r, size)) = ret
let stck = self.offsets[*node.inputs.last().unwrap() as usize];
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
}
if let Some(PLoc::Reg(r, size)) = ret
&& node.ty.loc(tys) == Loc::Stack
{ {
debug_assert_eq!(nodes[*node.inputs.last().unwrap()].kind, Kind::Stck); self.emit(instrs::st(r, *allocs.last().unwrap(), 0, size));
let stck = self.offsets[*node.inputs.last().unwrap() as usize];
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
} }
} }
Kind::Global { global } => { Kind::Global { global } => {
@ -662,14 +667,7 @@ impl HbvmBackend {
self.emit(instrs::addi64(allocs[0], base, offset as _)); self.emit(instrs::addi64(allocs[0], base, offset as _));
} }
Kind::Load => { Kind::Load => {
let mut region = node.inputs[1]; let (region, offset) = nodes.strip_offset(node.inputs[1], node.ty, tys);
let mut offset = 0;
if nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& let Kind::CInt { value } = nodes[nodes[region].inputs[2]].kind
{
region = nodes[region].inputs[1];
offset = value as Offset;
}
let size = tys.size_of(node.ty); let size = tys.size_of(node.ty);
if node.ty.loc(tys) != Loc::Stack { if node.ty.loc(tys) != Loc::Stack {
let (base, offset) = match nodes[region].kind { let (base, offset) = match nodes[region].kind {
@ -681,16 +679,8 @@ impl HbvmBackend {
} }
Kind::Stre if node.inputs[1] == VOID => {} Kind::Stre if node.inputs[1] == VOID => {}
Kind::Stre => { Kind::Stre => {
let mut region = node.inputs[2]; let (region, offset) = nodes.strip_offset(node.inputs[2], node.ty, tys);
let mut offset = 0;
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO"); let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
if nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& let Kind::CInt { value } = nodes[nodes[region].inputs[2]].kind
&& node.ty.loc(tys) == Loc::Reg
{
region = nodes[region].inputs[1];
offset = value as Offset;
}
let (base, offset, src) = match nodes[region].kind { let (base, offset, src) = match nodes[region].kind {
Kind::Stck if node.ty.loc(tys) == Loc::Reg => { Kind::Stck if node.ty.loc(tys) == Loc::Reg => {
(reg::STACK_PTR, self.offsets[region as usize] + offset, allocs[0]) (reg::STACK_PTR, self.offsets[region as usize] + offset, allocs[0])

View file

@ -1,7 +1,6 @@
use { use {
super::{HbvmBackend, Nid, Nodes}, super::{HbvmBackend, Nid, Nodes},
crate::{ crate::{
lexer::TokenKind,
parser, parser,
reg::{self, Reg}, reg::{self, Reg},
son::{debug_assert_matches, Kind, ARG_START, MEM, VOID}, son::{debug_assert_matches, Kind, ARG_START, MEM, VOID},
@ -10,7 +9,8 @@ use {
PLoc, Sig, Types, PLoc, Sig, Types,
}, },
alloc::{borrow::ToOwned, vec::Vec}, alloc::{borrow::ToOwned, vec::Vec},
core::{mem, ops::Range}, core::{cell::RefCell, mem, ops::Range},
hashbrown::HashSet,
hbbytecode::{self as instrs}, hbbytecode::{self as instrs},
}; };
@ -101,6 +101,28 @@ impl HbvmBackend {
let node = &fuc.nodes[nid]; let node = &fuc.nodes[nid];
alloc_buf.clear(); alloc_buf.clear();
let atr = |allc: Nid| {
let allc = strip_load(allc);
debug_assert_eq!(
fuc.nodes[allc].lock_rc,
0,
"{:?} {}",
fuc.nodes[allc],
ty::Display::new(tys, files, fuc.nodes[allc].ty)
);
debug_assert!(
fuc.marked.borrow().contains(&(allc, nid))
|| nid == allc
|| fuc.nodes.is_hard_zero(allc)
|| allc == MEM
|| matches!(node.kind, Kind::Loop | Kind::Region),
"{nid} {:?}\n{allc} {:?}",
fuc.nodes[nid],
fuc.nodes[allc]
);
res.node_to_reg[allc as usize]
};
let mut is_next_block = false; let mut is_next_block = false;
match node.kind { match node.kind {
Kind::If => { Kind::If => {
@ -170,13 +192,14 @@ impl HbvmBackend {
} }
Kind::Return => { Kind::Return => {
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() }; let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
alloc_buf.push(atr(ret));
match retl { match retl {
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => { Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
alloc_buf.push(atr(ret));
self.emit(instrs::cp(r, atr(ret))); self.emit(instrs::cp(r, atr(ret)));
} }
Some(PLoc::Ref(..)) => alloc_buf.push(atr(MEM)), Some(PLoc::Ref(..)) => alloc_buf.extend([atr(ret), atr(MEM)]),
_ => {} Some(_) => alloc_buf.push(atr(ret)),
None => {}
} }
} }
Kind::Die => self.emit(instrs::un()), Kind::Die => self.emit(instrs::un()),
@ -224,12 +247,7 @@ impl HbvmBackend {
} }
Kind::Stck | Kind::Global { .. } => alloc_buf.push(atr(nid)), Kind::Stck | Kind::Global { .. } => alloc_buf.push(atr(nid)),
Kind::Load => { Kind::Load => {
let mut region = node.inputs[1]; let (region, _) = fuc.nodes.strip_offset(node.inputs[1], node.ty, tys);
if fuc.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& let Kind::CInt { .. } = fuc.nodes[fuc.nodes[region].inputs[2]].kind
{
region = fuc.nodes[region].inputs[1];
}
if node.ty.loc(tys) != Loc::Stack { if node.ty.loc(tys) != Loc::Stack {
alloc_buf.push(atr(nid)); alloc_buf.push(atr(nid));
match fuc.nodes[region].kind { match fuc.nodes[region].kind {
@ -240,14 +258,7 @@ impl HbvmBackend {
} }
Kind::Stre if node.inputs[1] == VOID => {} Kind::Stre if node.inputs[1] == VOID => {}
Kind::Stre => { Kind::Stre => {
let mut region = node.inputs[2]; let (region, _) = fuc.nodes.strip_offset(node.inputs[2], node.ty, tys);
if matches!(fuc.nodes[region].kind, Kind::BinOp {
op: TokenKind::Add | TokenKind::Sub
}) && let Kind::CInt { .. } = fuc.nodes[fuc.nodes[region].inputs[2]].kind
&& node.ty.loc(tys) == Loc::Reg
{
region = fuc.nodes[region].inputs[1];
}
match fuc.nodes[region].kind { match fuc.nodes[region].kind {
Kind::Stck if node.ty.loc(tys) == Loc::Reg => { Kind::Stck if node.ty.loc(tys) == Loc::Reg => {
alloc_buf.push(atr(node.inputs[1])) alloc_buf.push(atr(node.inputs[1]))
@ -313,6 +324,7 @@ pub struct Function<'a> {
tys: &'a Types, tys: &'a Types,
visited: BitSet, visited: BitSet,
func: Func, func: Func,
marked: RefCell<HashSet<(Nid, Nid), crate::FnvBuildHasher>>,
} }
impl Function<'_> { impl Function<'_> {
@ -334,6 +346,7 @@ impl Function<'_> {
.filter(|&(o, &n)| self.nodes.is_data_dep(o, n)) .filter(|&(o, &n)| self.nodes.is_data_dep(o, n))
.map(|(p, &n)| (self.use_block(p, n), n)) .map(|(p, &n)| (self.use_block(p, n), n))
.inspect(|&(_, n)| debug_assert_eq!(self.nodes[n].lock_rc, 0)) .inspect(|&(_, n)| debug_assert_eq!(self.nodes[n].lock_rc, 0))
.inspect(|&(_, n)| _ = self.marked.borrow_mut().insert((nid, n)))
.collect_into(buf); .collect_into(buf);
} }
@ -347,20 +360,11 @@ impl Function<'_> {
fn phi_inputs_of(&self, nid: Nid, buf: &mut Vec<Nid>) { fn phi_inputs_of(&self, nid: Nid, buf: &mut Vec<Nid>) {
match self.nodes[nid].kind { match self.nodes[nid].kind {
Kind::Region => { Kind::Region | Kind::Loop => {
for &inp in self.nodes[nid].outputs.as_slice() { for &inp in self.nodes[nid].outputs.as_slice() {
if self.nodes[inp].is_data_phi() { if self.nodes[inp].is_data_phi() {
buf.push(inp);
buf.extend(&self.nodes[inp].inputs[1..]); buf.extend(&self.nodes[inp].inputs[1..]);
buf.push(inp);
}
}
}
Kind::Loop => {
for &inp in self.nodes[nid].outputs.as_slice() {
if self.nodes[inp].is_data_phi() {
buf.push(self.nodes[inp].inputs[1]);
buf.push(inp);
buf.push(self.nodes[inp].inputs[2]);
} }
} }
} }
@ -412,6 +416,7 @@ impl<'a> Function<'a> {
sig, sig,
visited: Default::default(), visited: Default::default(),
func: Default::default(), func: Default::default(),
marked: Default::default(),
}; };
s.visited.clear(s.nodes.values.len()); s.visited.clear(s.nodes.values.len());
s.emit_node(VOID); s.emit_node(VOID);
@ -580,13 +585,25 @@ impl<'a> Env<'a> {
let mut use_buf = mem::take(&mut self.res.use_buf); let mut use_buf = mem::take(&mut self.res.use_buf);
let mut phi_input_buf = mem::take(&mut self.res.phi_input_buf); let mut phi_input_buf = mem::take(&mut self.res.phi_input_buf);
for block in &self.func.blocks { for block in self.func.blocks.iter().rev() {
self.ctx.phi_inputs_of(block.entry, &mut phi_input_buf); self.ctx.phi_inputs_of(block.entry, &mut phi_input_buf);
for param in phi_input_buf.drain(..) { for [a, rest @ ..] in phi_input_buf.drain(..).array_chunks::<3>() {
if !visited.set(param) { if visited.set(a) {
self.append_bundle(a, &mut bundle, &mut use_buf, None);
}
for r in rest {
if !visited.set(r) {
continue; continue;
} }
self.append_bundle(param, &mut bundle, &mut use_buf);
self.append_bundle(
r,
&mut bundle,
&mut use_buf,
Some(self.res.node_to_reg[a as usize] as usize - 1),
);
}
} }
} }
self.res.phi_input_buf = phi_input_buf; self.res.phi_input_buf = phi_input_buf;
@ -595,13 +612,19 @@ impl<'a> Env<'a> {
if visited.get(inst) || inst == 0 { if visited.get(inst) || inst == 0 {
continue; continue;
} }
self.append_bundle(inst, &mut bundle, &mut use_buf); self.append_bundle(inst, &mut bundle, &mut use_buf, None);
} }
self.res.use_buf = use_buf; self.res.use_buf = use_buf;
} }
fn append_bundle(&mut self, inst: Nid, bundle: &mut Bundle, use_buf: &mut Vec<(Nid, Nid)>) { fn append_bundle(
&mut self,
inst: Nid,
bundle: &mut Bundle,
use_buf: &mut Vec<(Nid, Nid)>,
prefered: Option<usize>,
) {
let dom = self.ctx.idom_of(inst); let dom = self.ctx.idom_of(inst);
self.ctx.uses_of(inst, use_buf); self.ctx.uses_of(inst, use_buf);
for (cursor, uinst) in use_buf.drain(..) { for (cursor, uinst) in use_buf.drain(..) {
@ -611,7 +634,7 @@ impl<'a> Env<'a> {
range.start = range.start =
range.start.max(self.ctx.instr_of(inst).map_or(0, |n| n + 1) as usize); range.start.max(self.ctx.instr_of(inst).map_or(0, |n| n + 1) as usize);
debug_assert!(range.start < range.end, "{:?}", range); debug_assert!(range.start < range.end, "{:?}", range);
range.end = range.end.min( let new = range.end.min(
self.ctx self.ctx
.instr_of(uinst) .instr_of(uinst)
.filter(|_| { .filter(|_| {
@ -621,6 +644,8 @@ impl<'a> Env<'a> {
}) })
.map_or(Nid::MAX, |n| n + 1) as usize, .map_or(Nid::MAX, |n| n + 1) as usize,
); );
range.end = new;
debug_assert!(range.start < range.end); debug_assert!(range.start < range.end);
bundle.add(range); bundle.add(range);
@ -632,6 +657,13 @@ impl<'a> Env<'a> {
return; return;
} }
if let Some(prefered) = prefered
&& !self.res.bundles[prefered].overlaps(bundle)
{
self.res.bundles[prefered].merge(bundle);
bundle.clear();
self.res.node_to_reg[inst as usize] = prefered as Reg + 1;
} else {
match self.res.bundles.iter_mut().enumerate().find(|(_, b)| !b.overlaps(bundle)) { match self.res.bundles.iter_mut().enumerate().find(|(_, b)| !b.overlaps(bundle)) {
Some((i, other)) => { Some((i, other)) => {
other.merge(bundle); other.merge(bundle);
@ -639,11 +671,14 @@ impl<'a> Env<'a> {
self.res.node_to_reg[inst as usize] = i as Reg + 1; self.res.node_to_reg[inst as usize] = i as Reg + 1;
} }
None => { None => {
self.res.bundles.push(mem::replace(bundle, Bundle::new(self.func.instrs.len()))); self.res
.bundles
.push(mem::replace(bundle, Bundle::new(self.func.instrs.len())));
self.res.node_to_reg[inst as usize] = self.res.bundles.len() as Reg; self.res.node_to_reg[inst as usize] = self.res.bundles.len() as Reg;
} }
} }
} }
}
fn reverse_cfg_dfs( fn reverse_cfg_dfs(
&mut self, &mut self,

View file

@ -1,7 +1,6 @@
use { use {
super::{HbvmBackend, Nid, Nodes}, super::{HbvmBackend, Nid, Nodes},
crate::{ crate::{
lexer::TokenKind,
parser, reg, parser, reg,
son::{debug_assert_matches, Kind, ARG_START, MEM, NEVER, VOID}, son::{debug_assert_matches, Kind, ARG_START, MEM, NEVER, VOID},
ty::{self, Arg, Loc}, ty::{self, Arg, Loc},
@ -540,6 +539,8 @@ impl<'a> Function<'a> {
self.rg(*node.inputs.last().unwrap()), self.rg(*node.inputs.last().unwrap()),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int), regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
)); ));
} else if node.ty.loc(self.tys) == Loc::Stack {
ops.push(self.urg(*node.inputs.last().unwrap()));
} }
self.add_instr(nid, ops); self.add_instr(nid, ops);
@ -565,13 +566,7 @@ impl<'a> Function<'a> {
Kind::Assert { .. } => unreachable!(), Kind::Assert { .. } => unreachable!(),
Kind::End | Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops | Kind::Join => {} Kind::End | Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops | Kind::Join => {}
Kind::Load { .. } => { Kind::Load { .. } => {
let mut region = node.inputs[1]; let (region, _) = self.nodes.strip_offset(node.inputs[1], node.ty, self.tys);
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& self.nodes.is_const(self.nodes[region].inputs[2])
&& node.ty.loc(self.tys) == Loc::Reg
{
region = self.nodes[region].inputs[1]
}
let ops = match self.nodes[region].kind { let ops = match self.nodes[region].kind {
Kind::Stck => vec![self.drg(nid)], Kind::Stck => vec![self.drg(nid)],
_ => vec![self.drg(nid), self.urg(region)], _ => vec![self.drg(nid), self.urg(region)],
@ -580,13 +575,7 @@ impl<'a> Function<'a> {
} }
Kind::Stre => { Kind::Stre => {
debug_assert_ne!(self.tys.size_of(node.ty), 0); debug_assert_ne!(self.tys.size_of(node.ty), 0);
let mut region = node.inputs[2]; let (region, _) = self.nodes.strip_offset(node.inputs[2], node.ty, self.tys);
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& self.nodes.is_const(self.nodes[region].inputs[2])
&& node.ty.loc(self.tys) == Loc::Reg
{
region = self.nodes[region].inputs[1]
}
let ops = match self.nodes[region].kind { let ops = match self.nodes[region].kind {
_ if node.ty.loc(self.tys) == Loc::Stack => { _ if node.ty.loc(self.tys) == Loc::Stack => {
if self.nodes[node.inputs[1]].kind == Kind::Arg { if self.nodes[node.inputs[1]].kind == Kind::Arg {

View file

@ -0,0 +1,82 @@
main:
ADDI64 r254, r254, -208d
ST r31, r254, 80a, 128h
LRA r32, r0, :glob_stru
JAL r31, r0, :new_stru
ST r1, r32, 0a, 16h
CP r1, r0
LD r33, r32, 0a, 8h
JEQ r33, r1, :0
LI64 r1, 300d
JMP :1
0: LI64 r34, 1d
ST r34, r32, 0a, 8h
ST r34, r32, 8a, 8h
ST r1, r32, 0a, 8h
LD r35, r32, 0a, 8h
JEQ r35, r1, :2
LI64 r1, 200d
JMP :1
2: CP r36, r1
LI64 r37, 3d
ST r34, r32, 0a, 8h
ST r34, r32, 8a, 8h
ADDI64 r38, r254, 16d
ST r34, r254, 16a, 8h
ST r34, r254, 24a, 8h
ST r34, r254, 32a, 8h
ST r34, r254, 40a, 8h
ST r34, r254, 48a, 8h
ST r34, r254, 56a, 8h
CP r39, r36
8: JNE r39, r37, :3
LD r40, r254, 48a, 8h
CP r1, r36
JEQ r40, r1, :4
LI64 r1, 100d
JMP :1
4: ST r1, r254, 0a, 8h
ST r1, r254, 8a, 8h
ST r1, r254, 64a, 8h
ST r1, r254, 72a, 8h
ST r34, r254, 16a, 8h
ST r34, r254, 24a, 8h
ST r34, r254, 32a, 8h
ST r34, r254, 40a, 8h
ST r34, r254, 48a, 8h
ST r34, r254, 56a, 8h
CP r41, r1
7: LD r42, r254, 48a, 8h
JNE r41, r37, :5
JEQ r42, r1, :6
LI64 r1, 10d
JMP :1
6: JMP :1
5: ADD64 r43, r41, r34
MULI64 r44, r41, 16d
ADD64 r45, r38, r44
ST r1, r45, 0a, 8h
ST r1, r45, 8a, 8h
CP r36, r1
CP r41, r43
JMP :7
3: MULI64 r46, r39, 16d
ADD64 r43, r38, r46
JAL r31, r0, :new_stru
ST r1, r43, 0a, 16h
ADD64 r39, r39, r34
JMP :8
1: LD r31, r254, 80a, 128h
ADDI64 r254, r254, 208d
JALA r0, r31, 0a
new_stru:
ADDI64 r254, r254, -16d
ADDI64 r3, r254, 0d
ST r0, r254, 0a, 8h
ST r0, r254, 8a, 8h
LD r1, r3, 0a, 16h
ADDI64 r254, r254, 16d
JALA r0, r31, 0a
code size: 759
ret: 0
status: Ok(())

View file

@ -1,16 +1,16 @@
continue_and_state_change: continue_and_state_change:
LI64 r9, 3d CP r1, r0
LI64 r10, 4d LI64 r10, 3d
LI64 r11, 2d LI64 r11, 4d
LI64 r12, 10d LI64 r12, 2d
6: JLTU r2, r12, :0 LI64 r3, 10d
6: JLTU r2, r3, :0
CP r1, r2 CP r1, r2
JMP :1 JMP :1
0: JNE r2, r11, :2 0: JNE r2, r12, :2
CP r2, r10 CP r2, r11
JMP :3 JMP :3
2: JNE r2, r9, :4 2: JNE r2, r10, :4
CP r1, r0
1: JMP :5 1: JMP :5
4: ADDI64 r2, r2, 1d 4: ADDI64 r2, r2, 1d
3: JMP :6 3: JMP :6

View file

@ -3,7 +3,7 @@ main:
ST r31, r254, 6a, 24h ST r31, r254, 6a, 24h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
2: JAL r31, r0, :return_fn 2: JAL r31, r0, :return_fn
ST r1, r254, 0a, 6h ST r1, r32, 0a, 6h
LD r33, r254, 0a, 1h LD r33, r254, 0a, 1h
ANDI r33, r33, 255d ANDI r33, r33, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d

View file

@ -4,7 +4,7 @@ foo:
ADDI64 r32, r254, 64d ADDI64 r32, r254, 64d
LRA r3, r0, :some_file LRA r3, r0, :some_file
JAL r31, r0, :get JAL r31, r0, :get
ST r1, r254, 64a, 16h ST r1, r32, 0a, 16h
LD r33, r254, 64a, 1h LD r33, r254, 64a, 1h
ANDI r33, r33, 255d ANDI r33, r33, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d
@ -60,7 +60,7 @@ main:
ST r31, r254, 16a, 24h ST r31, r254, 16a, 24h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 0a, 16h ST r1, r32, 0a, 16h
LD r33, r254, 0a, 1h LD r33, r254, 0a, 1h
ANDI r33, r33, 255d ANDI r33, r33, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d

View file

@ -7,7 +7,7 @@ main:
JAL r31, r0, :returner_bn JAL r31, r0, :returner_bn
ADDI64 r33, r254, 0d ADDI64 r33, r254, 0d
JAL r31, r0, :returner_cn JAL r31, r0, :returner_cn
ST r1, r254, 0a, 2h ST r1, r33, 0a, 2h
LD r34, r254, 2a, 1h LD r34, r254, 2a, 1h
CP r1, r32 CP r1, r32
CMPU r35, r1, r0 CMPU r35, r1, r0

View file

@ -45,22 +45,21 @@ main:
JNE r40, r39, :9 JNE r40, r39, :9
LI64 r1, 69d LI64 r1, 69d
JMP :3 JMP :3
9: ADDI64 r3, r254, 40d 9: ADDI64 r41, r254, 40d
CP r41, r3
JAL r31, r0, :new_foo JAL r31, r0, :new_foo
ST r1, r254, 40a, 16h ST r1, r41, 0a, 16h
CP r3, r41
LD r42, r254, 40a, 8h LD r42, r254, 40a, 8h
JNE r42, r0, :10 JNE r42, r0, :10
LI64 r1, 999d LI64 r1, 999d
JMP :3 JMP :3
10: LRA r4, r0, :"foo\0" 10: LRA r4, r0, :"foo\0"
CP r3, r41
CP r2, r3 CP r2, r3
LD r2, r2, 0a, 16h LD r2, r2, 0a, 16h
JAL r31, r0, :use_foo JAL r31, r0, :use_foo
ADDI64 r43, r254, 0d ADDI64 r43, r254, 0d
JAL r31, r0, :no_foo JAL r31, r0, :no_foo
ST r1, r254, 0a, 16h ST r1, r43, 0a, 16h
JAL r31, r0, :decide JAL r31, r0, :decide
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :11 JNE r1, r0, :11
@ -126,6 +125,6 @@ use_foo:
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 1100 code size: 1097
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,12 +1,12 @@
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -16d
ADDI64 r4, r254, 0d ADDI64 r7, r254, 0d
CP r3, r0 CP r3, r0
CP r4, r0 CP r4, r0
CP r5, r0 CP r5, r0
CP r6, r0 CP r6, r0
ECA ECA
ST r1, r254, 0a, 16h ST r1, r7, 0a, 16h
LD r7, r254, 0a, 1h LD r7, r254, 0a, 1h
ANDI r7, r7, 255d ANDI r7, r7, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d

View file

@ -8,7 +8,7 @@ main:
ST r34, r254, 0a, 8h ST r34, r254, 0a, 8h
ST r33, r254, 8a, 8h ST r33, r254, 8a, 8h
JAL r31, r0, :opaque JAL r31, r0, :opaque
ST r1, r254, 0a, 16h ST r1, r32, 0a, 16h
LD r35, r254, 8a, 8h LD r35, r254, 8a, 8h
LD r36, r254, 16a, 8h LD r36, r254, 16a, 8h
ADD64 r37, r36, r35 ADD64 r37, r36, r35

View file

@ -3,7 +3,7 @@ main:
ST r31, r254, 4a, 96h ST r31, r254, 4a, 96h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
JAL r31, r0, :random_color JAL r31, r0, :random_color
ST r1, r254, 0a, 4h ST r1, r32, 0a, 4h
LD r33, r254, 0a, 1h LD r33, r254, 0a, 1h
LD r34, r254, 1a, 1h LD r34, r254, 1a, 1h
LD r35, r254, 2a, 1h LD r35, r254, 2a, 1h

View file

@ -14,7 +14,7 @@ main:
ST r31, r254, 16a, 24h ST r31, r254, 16a, 24h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
JAL r31, r0, :get_format JAL r31, r0, :get_format
ST r1, r254, 0a, 16h ST r1, r32, 0a, 16h
LD r33, r254, 0a, 1h LD r33, r254, 0a, 1h
ANDI r33, r33, 255d ANDI r33, r33, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d

View file

@ -16,7 +16,7 @@ main:
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
CP r3, r0 CP r3, r0
JAL r31, r0, :constructor JAL r31, r0, :constructor
ST r1, r254, 0a, 16h ST r1, r32, 0a, 16h
LD r31, r254, 16a, 16h LD r31, r254, 16a, 16h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -5,7 +5,7 @@ main:
ADDI64 r33, r254, 0d ADDI64 r33, r254, 0d
LD r2, r32, 0a, 4h LD r2, r32, 0a, 4h
JAL r31, r0, :u32_to_color JAL r31, r0, :u32_to_color
ST r1, r254, 0a, 4h ST r1, r33, 0a, 4h
LD r34, r254, 0a, 1h LD r34, r254, 0a, 1h
ANDI r1, r34, 255d ANDI r1, r34, 255d
LD r31, r254, 4a, 32h LD r31, r254, 4a, 32h

View file

@ -21,7 +21,7 @@ main:
CP r34, r1 CP r34, r1
ADDI64 r35, r254, 0d ADDI64 r35, r254, 0d
JAL r31, r0, :optional JAL r31, r0, :optional
ST r1, r254, 0a, 16h ST r1, r35, 0a, 16h
LD r36, r254, 0a, 1h LD r36, r254, 0a, 1h
ANDI r36, r36, 255d ANDI r36, r36, 255d
ANDI r0, r0, 255d ANDI r0, r0, 255d

View file

@ -14,13 +14,13 @@ main:
ST r31, r254, 48a, 80h ST r31, r254, 48a, 80h
ADDI64 r32, r254, 32d ADDI64 r32, r254, 32d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 32a, 16h ST r1, r32, 0a, 16h
ADDI64 r33, r254, 16d ADDI64 r33, r254, 16d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 16a, 16h ST r1, r33, 0a, 16h
ADDI64 r34, r254, 0d ADDI64 r34, r254, 0d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 0a, 16h ST r1, r34, 0a, 16h
LD r35, r254, 24a, 4h LD r35, r254, 24a, 4h
LD r36, r254, 12a, 4h LD r36, r254, 12a, 4h
ANDI r37, r35, 4294967295d ANDI r37, r35, 4294967295d

View file

@ -10,7 +10,7 @@ main:
CP r3, r4 CP r3, r4
LD r3, r3, 0a, 16h LD r3, r3, 0a, 16h
JAL r31, r0, :odher_pass JAL r31, r0, :odher_pass
ST r1, r254, 0a, 16h ST r1, r34, 0a, 16h
LD r35, r254, 8a, 8h LD r35, r254, 8a, 8h
JNE r35, r33, :0 JNE r35, r33, :0
CP r2, r34 CP r2, r34

View file

@ -5,7 +5,7 @@ main:
CP r4, r0 CP r4, r0
CP r3, r4 CP r3, r4
JAL r31, r0, :maina JAL r31, r0, :maina
ST r1, r254, 0a, 16h ST r1, r32, 0a, 16h
LD r33, r254, 12a, 1h LD r33, r254, 12a, 1h
LD r34, r254, 3a, 1h LD r34, r254, 3a, 1h
SUB8 r35, r34, r33 SUB8 r35, r34, r33
@ -18,7 +18,7 @@ maina:
ST r31, r254, 20a, 40h ST r31, r254, 20a, 40h
ADDI64 r32, r254, 16d ADDI64 r32, r254, 16d
JAL r31, r0, :small_struct JAL r31, r0, :small_struct
ST r1, r254, 16a, 4h ST r1, r32, 0a, 4h
ADDI64 r33, r254, 0d ADDI64 r33, r254, 0d
ST r0, r254, 0a, 1h ST r0, r254, 0a, 1h
ST r0, r254, 1a, 1h ST r0, r254, 1a, 1h