fixing wrong instruction selection

This commit is contained in:
Jakub Doka 2024-11-10 09:17:43 +01:00
parent 823c78bf74
commit 42a713aeae
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 286 additions and 303 deletions

View file

@ -450,7 +450,9 @@ impl Nodes {
return self.idom(from); return self.idom(from);
} }
let index = self[from].inputs.iter().position(|&n| n == target).unwrap(); let index = self[from].inputs.iter().position(|&n| n == target).unwrap_or_else(|| {
panic!("from {from} {:?} target {target} {:?}", self[from], self[target])
});
self[self[from].inputs[0]].inputs[index - 1] self[self[from].inputs[0]].inputs[index - 1]
} }
@ -493,6 +495,8 @@ impl Nodes {
self.load_loop_var(i, from_value, loops); self.load_loop_var(i, from_value, loops);
self.load_loop_var(i, to_value, loops); self.load_loop_var(i, to_value, loops);
if to_value.value() != from_value.value() { if to_value.value() != from_value.value() {
debug_assert!(!to_value.ptr);
debug_assert!(!from_value.ptr);
let inps = [ctrl.get(), from_value.value(), to_value.value()]; let inps = [ctrl.get(), from_value.value(), to_value.value()];
to_value.set_value_remove(self.new_node(from_value.ty, Kind::Phi, inps), self); to_value.set_value_remove(self.new_node(from_value.ty, Kind::Phi, inps), self);
} }
@ -624,6 +628,8 @@ impl Nodes {
node.ty.expand(), node.ty.expand(),
); );
} }
debug_assert!(!matches!(node.ty.expand(), ty::Kind::Struct(_)));
} }
let mut lookup_meta = None; let mut lookup_meta = None;
@ -1036,8 +1042,9 @@ impl Nodes {
if self[lhs].kind == Kind::Stre if self[lhs].kind == Kind::Stre
&& self[rhs].kind == Kind::Stre && self[rhs].kind == Kind::Stre
&& self[lhs].ty == self[rhs].ty && self[lhs].ty == self[rhs].ty
&& !matches!(self[lhs].ty.expand(), ty::Kind::Struct(_))
&& self[lhs].inputs[2] == self[rhs].inputs[2] && self[lhs].inputs[2] == self[rhs].inputs[2]
&& self[lhs].inputs.get(3) == self[rhs].inputs.get(3) && self[lhs].inputs[3] == self[rhs].inputs[3]
{ {
let pick_value = self.new_node(self[lhs].ty, Kind::Phi, [ let pick_value = self.new_node(self[lhs].ty, Kind::Phi, [
ctrl, ctrl,
@ -1154,6 +1161,10 @@ impl Nodes {
} }
} }
if !unidentifed.is_empty() {
break 'eliminate;
}
debug_assert_matches!( debug_assert_matches!(
self[last_store].kind, self[last_store].kind,
Kind::Stre | Kind::Mem, Kind::Stre | Kind::Mem,
@ -1167,10 +1178,6 @@ impl Nodes {
self[first_store] self[first_store]
); );
if !unidentifed.is_empty() {
break 'eliminate;
}
// FIXME: when the loads and stores become parallel we will need to get saved // FIXME: when the loads and stores become parallel we will need to get saved
// differently // differently
let mut prev_store = store; let mut prev_store = store;
@ -1574,10 +1581,14 @@ impl Nodes {
return; return;
} }
debug_assert!(!var.ptr);
let [loops @ .., loob] = loops else { unreachable!() }; let [loops @ .., loob] = loops else { unreachable!() };
let node = loob.node; let node = loob.node;
let lvar = &mut loob.scope.vars[index]; let lvar = &mut loob.scope.vars[index];
debug_assert!(!lvar.ptr);
self.load_loop_var(index, lvar, loops); self.load_loop_var(index, lvar, loops);
if !self[lvar.value()].is_lazy_phi(node) { if !self[lvar.value()].is_lazy_phi(node) {
@ -1634,7 +1645,7 @@ impl Nodes {
} }
} }
fn dominates(&mut self, dominator: Nid, mut dominated: Nid) -> bool { fn dominates(&self, dominator: Nid, mut dominated: Nid) -> bool {
loop { loop {
if dominator == dominated { if dominator == dominated {
break true; break true;
@ -1650,12 +1661,21 @@ impl Nodes {
fn is_data_dep(&self, nid: Nid, n: Nid) -> bool { fn is_data_dep(&self, nid: Nid, n: Nid) -> bool {
match self[n].kind { match self[n].kind {
_ if self.is_cfg(n) && !matches!(self[n].kind, Kind::Call { .. }) => false, Kind::Return => self[n].inputs[1] == nid,
_ if self.is_cfg(n) && !matches!(self[n].kind, Kind::Call { .. } | Kind::If) => false,
Kind::Stre => self[n].inputs[3] != nid, Kind::Stre => self[n].inputs[3] != nid,
Kind::Load => self[n].inputs[2] != nid, Kind::Load => self[n].inputs[2] != nid,
_ => self[n].inputs[0] != nid || self[n].inputs[1..].contains(&nid), _ => self[n].inputs[0] != nid || self[n].inputs[1..].contains(&nid),
} }
} }
fn this_or_delegates<'a>(&'a self, source: Nid, target: &'a Nid) -> (Nid, &'a [Nid]) {
if self[*target].lock_rc == 0 {
(source, core::slice::from_ref(target))
} else {
(*target, self[*target].outputs.as_slice())
}
}
} }
enum CondOptRes { enum CondOptRes {
@ -3509,8 +3529,10 @@ impl<'a> Codegen<'a> {
}); });
for var in self.ci.scope.vars.iter_mut().skip(self.ci.inline_var_base) { for var in self.ci.scope.vars.iter_mut().skip(self.ci.inline_var_base) {
if !var.ptr {
var.set_value(VOID, &mut self.ci.nodes); var.set_value(VOID, &mut self.ci.nodes);
} }
}
for aclass in self.ci.scope.aclasses[..2].iter_mut() { for aclass in self.ci.scope.aclasses[..2].iter_mut() {
aclass.last_store.set(VOID, &mut self.ci.nodes); aclass.last_store.set(VOID, &mut self.ci.nodes);
@ -4612,6 +4634,8 @@ mod tests {
if let Err(e) = err { if let Err(e) = err {
writeln!(output, "!!! asm is invalid: {e}").unwrap(); writeln!(output, "!!! asm is invalid: {e}").unwrap();
} else { } else {
log::info!("================ running {ident} ==============");
log::trace!("{output}");
super::hbvm::test_run_vm(&out, output); super::hbvm::test_run_vm(&out, output);
} }
} }

View file

@ -5,7 +5,7 @@ use {
parser, reg, parser, reg,
son::{debug_assert_matches, write_reloc, Kind, MEM}, son::{debug_assert_matches, write_reloc, Kind, MEM},
ty::{self, Loc, Module}, ty::{self, Loc, Module},
utils::{Ent, EntVec}, utils::{BitSet, Ent, EntVec, Vc},
Offset, Reloc, Size, TypedReloc, Types, Offset, Reloc, Size, TypedReloc, Types,
}, },
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}, alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
@ -332,6 +332,72 @@ impl Backend for HbvmBackend {
} }
impl Nodes { impl Nodes {
fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) {
// NOTE: this code is horible
let from = Some(&from);
let mut buf = Vec::with_capacity(outputs.len());
let mut seen = BitSet::default();
seen.clear(self.values.len());
for &o in outputs.iter() {
if !self.is_cfg(o) {
continue;
}
seen.set(o);
let mut cursor = buf.len();
buf.push(o);
while let Some(&n) = buf.get(cursor) {
for &i in &self[n].inputs[1..] {
if from == self[i].inputs.first()
&& self[i]
.outputs
.iter()
.all(|&o| self[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
for &o in outputs.iter().filter(|&&n| n == i) {
buf.push(o);
}
}
}
cursor += 1;
}
}
for &o in outputs.iter() {
if !seen.set(o) {
continue;
}
let mut cursor = buf.len();
for &o in outputs.iter().filter(|&&n| n == o) {
buf.push(o);
}
while let Some(&n) = buf.get(cursor) {
for &i in &self[n].inputs[1..] {
if from == self[i].inputs.first()
&& self[i]
.outputs
.iter()
.all(|&o| self[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
for &o in outputs.iter().filter(|&&n| n == i) {
buf.push(o);
}
}
}
cursor += 1;
}
}
if outputs.len() != buf.len() {
panic!("{:?} {:?}", outputs, buf);
}
outputs.copy_from_slice(&buf);
}
fn is_never_used(&self, nid: Nid, tys: &Types) -> bool { fn is_never_used(&self, nid: Nid, tys: &Types) -> bool {
let node = &self[nid]; let node = &self[nid];
match node.kind { match node.kind {
@ -485,7 +551,7 @@ impl TokenKind {
Self::Band => return Some(andi), Self::Band => return Some(andi),
Self::Bor => return Some(ori), Self::Bor => return Some(ori),
Self::Xor => return Some(xori), Self::Xor => return Some(xori),
Self::Shr if signed => basic_op!(srui8, srui16, srui32, srui64), Self::Shr if signed => basic_op!(srsi8, srsi16, srsi32, srsi64),
Self::Shr => basic_op!(srui8, srui16, srui32, srui64), Self::Shr => basic_op!(srui8, srui16, srui32, srui64),
Self::Shl => basic_op!(slui8, slui16, slui32, slui64), Self::Shl => basic_op!(slui8, slui16, slui32, slui64),
_ => return None, _ => return None,

View file

@ -6,7 +6,7 @@ use {
reg::{self, Reg}, reg::{self, Reg},
son::{debug_assert_matches, Kind, ARG_START, MEM, VOID}, son::{debug_assert_matches, Kind, ARG_START, MEM, VOID},
ty::{self, Arg, Loc}, ty::{self, Arg, Loc},
utils::{BitSet, Vc}, utils::BitSet,
Offset, PLoc, Reloc, Sig, TypedReloc, Types, Offset, PLoc, Reloc, Sig, TypedReloc, Types,
}, },
alloc::{borrow::ToOwned, vec::Vec}, alloc::{borrow::ToOwned, vec::Vec},
@ -22,9 +22,16 @@ impl HbvmBackend {
tys: &Types, tys: &Types,
files: &[parser::Ast], files: &[parser::Ast],
) -> (usize, bool) { ) -> (usize, bool) {
let mut fuc = Function::new(nodes, tys, sig); let fuc = Function::new(nodes, tys, sig);
log::info!("{fuc:?}"); log::info!("{fuc:?}");
let strip_load = |value| match fuc.nodes[value].kind {
Kind::Load { .. } if fuc.nodes[value].ty.loc(tys) == Loc::Stack => {
fuc.nodes[value].inputs[1]
}
_ => value,
};
let mut res = mem::take(&mut self.ralloc_my); let mut res = mem::take(&mut self.ralloc_my);
Env::new(&fuc, &fuc.func, &mut res).run(); Env::new(&fuc, &fuc.func, &mut res).run();
@ -39,13 +46,27 @@ impl HbvmBackend {
let reg_offset = if fuc.tail { reg::RET + 12 } else { reg::RET_ADDR + 1 }; let reg_offset = if fuc.tail { reg::RET + 12 } else { reg::RET_ADDR + 1 };
res.node_to_reg.iter_mut().filter(|r| **r != 0).for_each(|r| { res.node_to_reg.iter_mut().filter(|r| **r != 0).for_each(|r| {
if *r == u8::MAX {
*r = 0
} else {
*r += reg_offset - 1; *r += reg_offset - 1;
if fuc.tail && *r >= reg::RET_ADDR { if fuc.tail && *r >= reg::RET_ADDR {
*r += 1; *r += 1;
} }
}
}); });
let atr = |allc: Nid| res.node_to_reg[allc as usize]; 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)
);
res.node_to_reg[allc as usize]
};
//for (id, node) in fuc.nodes.iter() { //for (id, node) in fuc.nodes.iter() {
// if node.kind == Kind::Phi { // if node.kind == Kind::Phi {
@ -84,8 +105,6 @@ impl HbvmBackend {
} }
let node = &fuc.nodes[nid]; let node = &fuc.nodes[nid];
let bref = mem::replace(&mut fuc.backrefs[nid as usize], u16::MAX);
let extend = |base: ty::Id, dest: ty::Id, from: Nid, to: Nid| { let extend = |base: ty::Id, dest: ty::Id, from: Nid, to: Nid| {
let (bsize, dsize) = (tys.size_of(base), tys.size_of(dest)); let (bsize, dsize) = (tys.size_of(base), tys.size_of(dest));
debug_assert!(bsize <= 8, "{}", ty::Display::new(tys, files, base)); debug_assert!(bsize <= 8, "{}", ty::Display::new(tys, files, base));
@ -141,36 +160,35 @@ impl HbvmBackend {
cnd, cnd,
)); ));
let rel = Reloc::new(self.code.len(), 3, 2); let rel = Reloc::new(self.code.len(), 3, 2);
debug_assert_eq!(fuc.nodes[node.outputs[0]].kind, Kind::Then);
self.jump_relocs.push((node.outputs[0], rel)); self.jump_relocs.push((node.outputs[0], rel));
self.emit(instrs::jne(atr(cnd), reg::ZERO, 0)); self.emit(instrs::jne(atr(cnd), reg::ZERO, 0));
} }
} }
Kind::Loop | Kind::Region => { Kind::Loop | Kind::Region => {
let mut emit_moves = |index| { let index = node
.inputs
.iter()
.position(|&n| block.entry == fuc.idom_of(n))
.unwrap()
+ 1;
let mut moves = vec![]; let mut moves = vec![];
for &out in node.outputs.iter() { for &out in node.outputs.iter() {
if fuc.nodes[out].is_data_phi() { if fuc.nodes[out].is_data_phi() {
debug_assert_eq!( let src = fuc.nodes[out].inputs[index];
fuc.backrefs[fuc.nodes[out].inputs[index] as usize], if atr(out) != atr(src) {
u16::MAX, moves.push([atr(out), atr(src), 0]);
"{:?}\n{:?}",
node,
fuc.nodes[fuc.nodes[out].inputs[index]]
);
if atr(out) != atr(fuc.nodes[out].inputs[index]) {
if atr(out) == 34 && atr(fuc.nodes[out].inputs[index]) == 32
{
std::dbg!(&node, out, &fuc.nodes[out]);
}
moves.push([
atr(out),
atr(fuc.nodes[out].inputs[index]),
0,
]);
} }
} }
} }
debug_assert_eq!(moves.len(), {
moves.sort_unstable();
moves.dedup();
moves.len()
});
moves.sort_unstable_by(|[aa, ab, _], [ba, bb, _]| { moves.sort_unstable_by(|[aa, ab, _], [ba, bb, _]| {
if aa == bb && ab == ba { if aa == bb && ab == ba {
core::cmp::Ordering::Equal core::cmp::Ordering::Equal
@ -197,40 +215,24 @@ impl HbvmBackend {
self.emit(instrs::swa(dst, src)); self.emit(instrs::swa(dst, src));
} }
} }
};
if (bref != u16::MAX) ^ (node.kind == Kind::Loop) {
let index = (node.kind == Kind::Loop) as usize + 1;
emit_moves(index);
if fuc.block_of(nid) as usize != i + 1 {
let rel = Reloc::new(self.code.len(), 1, 4); let rel = Reloc::new(self.code.len(), 1, 4);
self.jump_relocs.push((nid, rel)); self.jump_relocs.push((nid, rel));
self.emit(instrs::jmp(0)); self.emit(instrs::jmp(0));
} else {
let index = (node.kind != Kind::Loop) as usize + 1;
emit_moves(index);
} }
} }
Kind::Return => { Kind::Return => {
let &[_, mut ret, ..] = node.inputs.as_slice() else { unreachable!() }; let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
match retl { match retl {
None => {} None => {}
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => { Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
self.emit(instrs::cp(r, atr(ret))); self.emit(instrs::cp(r, atr(ret)));
} }
Some(PLoc::Reg(r, size)) | Some(PLoc::WideReg(r, size)) => { Some(PLoc::Reg(r, size)) | Some(PLoc::WideReg(r, size)) => {
ret = match fuc.nodes[ret].kind {
Kind::Load { .. } => fuc.nodes[ret].inputs[1],
_ => ret,
};
self.emit(instrs::ld(r, atr(ret), 0, size)) self.emit(instrs::ld(r, atr(ret), 0, size))
} }
Some(PLoc::Ref(_, size)) => { Some(PLoc::Ref(_, size)) => {
ret = match fuc.nodes[ret].kind {
Kind::Load { .. } => fuc.nodes[ret].inputs[1],
_ => ret,
};
let [src, dst] = [atr(ret), atr(MEM)]; let [src, dst] = [atr(ret), atr(MEM)];
if let Ok(size) = u16::try_from(size) { if let Ok(size) = u16::try_from(size) {
self.emit(instrs::bmc(src, dst, size)); self.emit(instrs::bmc(src, dst, size));
@ -340,10 +342,6 @@ impl HbvmBackend {
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size), PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
PLoc::WideReg(rg, size) => (rg, size), PLoc::WideReg(rg, size) => (rg, size),
PLoc::Ref(r, ..) => { PLoc::Ref(r, ..) => {
arg = match fuc.nodes[arg].kind {
Kind::Load { .. } => fuc.nodes[arg].inputs[1],
_ => arg,
};
self.emit(instrs::cp(r, atr(arg))); self.emit(instrs::cp(r, atr(arg)));
continue; continue;
} }
@ -353,10 +351,6 @@ impl HbvmBackend {
} }
}; };
arg = match fuc.nodes[arg].kind {
Kind::Load { .. } => fuc.nodes[arg].inputs[1],
_ => arg,
};
self.emit(instrs::ld(rg, atr(arg), 0, size)); self.emit(instrs::ld(rg, atr(arg), 0, size));
} }
@ -364,6 +358,10 @@ impl HbvmBackend {
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some() !matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
); );
if let Some(PLoc::Ref(r, ..)) = ret {
self.emit(instrs::cp(r, atr(*node.inputs.last().unwrap())))
}
if func == ty::Func::ECA { if func == ty::Func::ECA {
self.emit(instrs::eca()); self.emit(instrs::eca());
} else { } else {
@ -434,8 +432,9 @@ impl HbvmBackend {
let mut region = node.inputs[2]; let mut region = node.inputs[2];
let mut offset = 0; 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 fuc.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) if matches!(fuc.nodes[region].kind, Kind::BinOp {
&& let Kind::CInt { value } = op: TokenKind::Add | TokenKind::Sub
}) && let Kind::CInt { value } =
fuc.nodes[fuc.nodes[region].inputs[2]].kind fuc.nodes[fuc.nodes[region].inputs[2]].kind
&& node.ty.loc(tys) == Loc::Reg && node.ty.loc(tys) == Loc::Reg
{ {
@ -448,10 +447,7 @@ impl HbvmBackend {
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, value) (reg::STACK_PTR, self.offsets[region as usize] + offset, value)
} }
_ => (atr(region), offset, match fuc.nodes[value].kind { _ => (atr(region), offset, value),
Kind::Load { .. } => fuc.nodes[value].inputs[1],
_ => value,
}),
}; };
match node.ty.loc(tys) { match node.ty.loc(tys) {
@ -507,7 +503,7 @@ impl Function<'_> {
self.nodes.values.len() self.nodes.values.len()
} }
fn uses_of(&self, nid: Nid, buf: &mut Vec<Nid>) { fn uses_of(&self, nid: Nid, buf: &mut Vec<(Nid, Nid)>) {
if self.nodes[nid].kind.is_cfg() && !matches!(self.nodes[nid].kind, Kind::Call { .. }) { if self.nodes[nid].kind.is_cfg() && !matches!(self.nodes[nid].kind, Kind::Call { .. }) {
return; return;
} }
@ -516,9 +512,22 @@ impl Function<'_> {
.outputs .outputs
.iter() .iter()
.filter(|&&n| self.nodes.is_data_dep(nid, n)) .filter(|&&n| self.nodes.is_data_dep(nid, n))
.map(|n| self.nodes.this_or_delegates(nid, n))
.flat_map(|(p, ls)| ls.iter().map(move |l| (p, l)))
.filter(|&(o, &n)| self.nodes.is_data_dep(o, n))
.map(|(p, &n)| (self.use_block(p, n), n))
.inspect(|&(_, n)| debug_assert_eq!(self.nodes[n].lock_rc, 0))
.collect_into(buf); .collect_into(buf);
} }
fn use_block(&self, inst: Nid, uinst: Nid) -> Nid {
let mut block = self.nodes.use_block(inst, uinst);
while !self.nodes[block].kind.starts_basic_block() {
block = self.nodes.idom(block);
}
block
}
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 => {
@ -561,14 +570,6 @@ impl Function<'_> {
} }
nid nid
} }
fn use_block(&self, inst: Nid, uinst: Nid) -> Nid {
let mut block = self.nodes.use_block(inst, uinst);
while !self.nodes[block].kind.starts_basic_block() {
block = self.nodes.idom(block);
}
block
}
} }
impl core::fmt::Debug for Function<'_> { impl core::fmt::Debug for Function<'_> {
@ -654,8 +655,11 @@ impl<'a> Function<'a> {
if let Kind::BinOp { op } = self.nodes[cond].kind if let Kind::BinOp { op } = self.nodes[cond].kind
&& let Some((_, swapped)) = op.cond_op(node.ty) && let Some((_, swapped)) = op.cond_op(node.ty)
&& swapped
{ {
if swapped {
mem::swap(&mut then, &mut else_);
}
} else {
mem::swap(&mut then, &mut else_); mem::swap(&mut then, &mut else_);
} }
@ -666,7 +670,7 @@ impl<'a> Function<'a> {
Kind::Region | Kind::Loop => { Kind::Region | Kind::Loop => {
self.close_block(nid); self.close_block(nid);
self.add_block(nid); self.add_block(nid);
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o); self.emit_node(o);
} }
@ -693,14 +697,14 @@ impl<'a> Function<'a> {
self.add_instr(MEM); self.add_instr(MEM);
} }
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o); self.emit_node(o);
} }
} }
Kind::Then | Kind::Else => { Kind::Then | Kind::Else => {
self.add_block(nid); self.add_block(nid);
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o); self.emit_node(o);
} }
@ -710,7 +714,7 @@ impl<'a> Function<'a> {
self.add_instr(nid); self.add_instr(nid);
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
if self.nodes[o].inputs[0] == nid if self.nodes[o].inputs[0] == nid
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region) || (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
@ -731,72 +735,6 @@ impl<'a> Function<'a> {
Kind::Assert { .. } => unreachable!(), Kind::Assert { .. } => unreachable!(),
} }
} }
fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) {
let from = Some(&from);
let mut buf = Vec::with_capacity(outputs.len());
let mut seen = BitSet::default();
seen.clear(self.nodes.values.len());
for &o in outputs.iter() {
if !self.nodes.is_cfg(o) {
continue;
}
seen.set(o);
let mut cursor = buf.len();
buf.push(o);
while let Some(&n) = buf.get(cursor) {
for &i in &self.nodes[n].inputs[1..] {
if from == self.nodes[i].inputs.first()
&& self.nodes[i]
.outputs
.iter()
.all(|&o| self.nodes[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
buf.push(i);
}
}
cursor += 1;
}
}
for &o in outputs.iter() {
if !seen.set(o) {
continue;
}
let mut cursor = buf.len();
buf.push(o);
while let Some(&n) = buf.get(cursor) {
for &i in &self.nodes[n].inputs[1..] {
if from == self.nodes[i].inputs.first()
&& self.nodes[i]
.outputs
.iter()
.all(|&o| self.nodes[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
buf.push(i);
}
}
cursor += 1;
}
}
debug_assert!(
outputs.len() == buf.len() || outputs.len() == buf.len() + 1,
"{:?} {:?}",
outputs,
buf
);
if buf.len() + 1 == outputs.len() {
outputs.remove(outputs.len() - 1);
}
outputs.copy_from_slice(&buf);
}
} }
pub struct Env<'a> { pub struct Env<'a> {
@ -845,26 +783,37 @@ impl<'a> Env<'a> {
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>) { fn append_bundle(&mut self, inst: Nid, bundle: &mut Bundle, use_buf: &mut Vec<(Nid, Nid)>) {
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 uinst in use_buf.drain(..) { for (cursor, uinst) in use_buf.drain(..) {
let cursor = self.ctx.use_block(inst, uinst);
self.reverse_cfg_dfs(cursor, dom, |_, n, b| { self.reverse_cfg_dfs(cursor, dom, |_, n, b| {
let mut range = b.range.clone(); let mut range = b.range.clone();
debug_assert!(range.start < range.end);
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);
range.end = range.end.min( range.end = range.end.min(
self.ctx self.ctx
.instr_of(uinst) .instr_of(uinst)
.filter(|_| self.ctx.nodes.loop_depth(dom) == self.ctx.nodes.loop_depth(n)) .filter(|_| {
n == cursor
&& self.ctx.nodes.loop_depth(dom)
== self.ctx.nodes.loop_depth(cursor)
})
.map_or(Nid::MAX, |n| n + 1) as usize, .map_or(Nid::MAX, |n| n + 1) as usize,
); );
debug_assert!(range.start < range.end);
bundle.add(range); bundle.add(range);
}); });
} }
if !bundle.taken.contains(&true) {
self.res.node_to_reg[inst as usize] = u8::MAX;
return;
}
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);
@ -888,7 +837,14 @@ impl<'a> Env<'a> {
self.res.dfs_buf.push(from); self.res.dfs_buf.push(from);
self.res.dfs_seem.clear(self.ctx.nodes.values.len()); self.res.dfs_seem.clear(self.ctx.nodes.values.len());
debug_assert!(self.ctx.nodes.dominates(until, from));
while let Some(nid) = self.res.dfs_buf.pop() { while let Some(nid) = self.res.dfs_buf.pop() {
debug_assert!(
self.ctx.nodes.dominates(until, nid),
"{until} {:?}",
self.ctx.nodes[until]
);
each(self, nid, &self.func.blocks[self.ctx.block_of(nid) as usize]); each(self, nid, &self.func.blocks[self.ctx.block_of(nid) as usize]);
if nid == until { if nid == until {
continue; continue;
@ -896,6 +852,9 @@ impl<'a> Env<'a> {
match self.ctx.nodes[nid].kind { match self.ctx.nodes[nid].kind {
Kind::Then | Kind::Else | Kind::Region | Kind::Loop => { Kind::Then | Kind::Else | Kind::Region | Kind::Loop => {
for &n in self.ctx.nodes[nid].inputs.iter() { for &n in self.ctx.nodes[nid].inputs.iter() {
if self.ctx.nodes[n].kind == Kind::Loops {
continue;
}
let d = self.ctx.idom_of(n); let d = self.ctx.idom_of(n);
if self.res.dfs_seem.set(d) { if self.res.dfs_seem.set(d) {
self.res.dfs_buf.push(d); self.res.dfs_buf.push(d);
@ -913,7 +872,7 @@ impl<'a> Env<'a> {
pub struct Res { pub struct Res {
pub bundles: Vec<Bundle>, pub bundles: Vec<Bundle>,
pub node_to_reg: Vec<Reg>, pub node_to_reg: Vec<Reg>,
use_buf: Vec<Nid>, use_buf: Vec<(Nid, Nid)>,
phi_input_buf: Vec<Nid>, phi_input_buf: Vec<Nid>,
dfs_buf: Vec<Nid>, dfs_buf: Vec<Nid>,
dfs_seem: BitSet, dfs_seem: BitSet,

View file

@ -5,7 +5,7 @@ use {
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},
utils::{BitSet, Vc}, utils::BitSet,
HashMap, Offset, PLoc, Reloc, Sig, TypedReloc, Types, HashMap, Offset, PLoc, Reloc, Sig, TypedReloc, Types,
}, },
alloc::{borrow::ToOwned, vec::Vec}, alloc::{borrow::ToOwned, vec::Vec},
@ -616,7 +616,7 @@ impl<'a> Function<'a> {
block.push(self.rg(ph)); block.push(self.rg(ph));
} }
self.blocks[self.backrefs[nid as usize] as usize].params = block; self.blocks[self.backrefs[nid as usize] as usize].params = block;
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o, nid); self.emit_node(o, nid);
} }
@ -680,7 +680,7 @@ impl<'a> Function<'a> {
)]); )]);
} }
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o, nid); self.emit_node(o, nid);
} }
@ -688,7 +688,7 @@ impl<'a> Function<'a> {
Kind::Then | Kind::Else => { Kind::Then | Kind::Else => {
self.backrefs[nid as usize] = self.add_block(nid); self.backrefs[nid as usize] = self.add_block(nid);
self.bridge(prev, nid); self.bridge(prev, nid);
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
self.emit_node(o, nid); self.emit_node(o, nid);
} }
@ -783,7 +783,7 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops); self.add_instr(nid, ops);
self.reschedule_block(nid, &mut node.outputs); self.nodes.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
if self.nodes[o].inputs[0] == nid if self.nodes[o].inputs[0] == nid
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region) || (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
@ -853,72 +853,6 @@ impl<'a> Function<'a> {
.preds .preds
.push(regalloc2::Block::new(self.backrefs[pred as usize] as usize)); .push(regalloc2::Block::new(self.backrefs[pred as usize] as usize));
} }
fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) {
// NOTE: this code is horible
let from = Some(&from);
let mut buf = Vec::with_capacity(outputs.len());
let mut seen = BitSet::default();
seen.clear(self.nodes.values.len());
for &o in outputs.iter() {
if !self.nodes.is_cfg(o) {
continue;
}
seen.set(o);
let mut cursor = buf.len();
buf.push(o);
while let Some(&n) = buf.get(cursor) {
for &i in &self.nodes[n].inputs[1..] {
if from == self.nodes[i].inputs.first()
&& self.nodes[i]
.outputs
.iter()
.all(|&o| self.nodes[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
for &o in outputs.iter().filter(|&&n| n == i) {
buf.push(o);
}
}
}
cursor += 1;
}
}
for &o in outputs.iter() {
if !seen.set(o) {
continue;
}
let mut cursor = buf.len();
for &o in outputs.iter().filter(|&&n| n == o) {
buf.push(o);
}
while let Some(&n) = buf.get(cursor) {
for &i in &self.nodes[n].inputs[1..] {
if from == self.nodes[i].inputs.first()
&& self.nodes[i]
.outputs
.iter()
.all(|&o| self.nodes[o].inputs.first() != from || seen.get(o))
&& seen.set(i)
{
for &o in outputs.iter().filter(|&&n| n == i) {
buf.push(o);
}
}
}
cursor += 1;
}
}
if outputs.len() != buf.len() {
panic!("{:?} {:?}", outputs, buf);
}
outputs.copy_from_slice(&buf);
}
} }
impl regalloc2::Function for Function<'_> { impl regalloc2::Function for Function<'_> {

View file

@ -1,17 +1,17 @@
main: main:
ADDI64 r254, r254, -128d ADDI64 r254, r254, -128d
LI8 r5, 69b LI8 r6, 69b
LI64 r6, 128d LI64 r5, 128d
LI64 r7, 0d LI64 r7, 0d
ADDI64 r4, r254, 0d ADDI64 r4, r254, 0d
2: LD r12, r254, 42a, 1h 2: LD r1, r254, 42a, 1h
JLTU r7, r6, :0 JLTU r7, r5, :0
ANDI r1, r12, 255d ANDI r1, r1, 255d
JMP :1 JMP :1
0: ADDI64 r3, r7, 1d 0: ADDI64 r8, r7, 1d
ADD64 r7, r4, r7 ADD64 r3, r4, r7
ST r5, r7, 0a, 1h ST r6, r3, 0a, 1h
CP r7, r3 CP r7, r8
JMP :2 JMP :2
1: ADDI64 r254, r254, 128d 1: ADDI64 r254, r254, 128d
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -95,8 +95,8 @@ put_filled_rect:
CP r4, r33 CP r4, r33
CP r5, r44 CP r5, r44
ECA ECA
ADD64 r42, r40, r42
SUB64 r41, r41, r40 SUB64 r41, r41, r40
ADD64 r42, r40, r42
SUB64 r39, r39, r32 SUB64 r39, r39, r32
CP r6, r43 CP r6, r43
CP r8, r44 CP r8, r44

View file

@ -1,39 +1,39 @@
main: main:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -32d
LI64 r6, 1d LI64 r7, 1d
LI64 r7, 4d LI64 r6, 4d
LI64 r4, 0d LI64 r4, 0d
ADDI64 r5, r254, 0d ADDI64 r5, r254, 0d
CP r8, r4 CP r8, r4
6: JNE r8, r7, :0 6: JNE r8, r6, :0
LI64 r7, 2d LI64 r6, 2d
CP r8, r4 CP r8, r4
4: LD r1, r254, 0a, 8h 4: LD r1, r254, 0a, 8h
JNE r8, r6, :1 JNE r8, r7, :1
JMP :2 JMP :2
1: MUL64 r10, r8, r7 1: MUL64 r11, r8, r6
ADD64 r8, r8, r6 ADD64 r8, r8, r7
SUB64 r3, r7, r8 SUB64 r9, r6, r8
MUL64 r9, r3, r7 MUL64 r9, r9, r6
CP r2, r4 CP r2, r4
5: JNE r2, r7, :3 5: JNE r2, r6, :3
JMP :4 JMP :4
3: ADD64 r1, r2, r6 3: ADD64 r10, r2, r7
ADD64 r11, r9, r2 ADD64 r12, r9, r2
MULI64 r3, r11, 8d
ADD64 r12, r10, r2
ADD64 r11, r5, r3
MULI64 r12, r12, 8d MULI64 r12, r12, 8d
ADD64 r1, r11, r2
ADD64 r12, r5, r12 ADD64 r12, r5, r12
BMC r11, r12, 8h MULI64 r1, r1, 8d
BMC r12, r11, 8h ADD64 r1, r5, r1
CP r2, r1 BMC r12, r1, 8h
BMC r1, r12, 8h
CP r2, r10
JMP :5 JMP :5
0: ADD64 r11, r8, r6 0: ADD64 r12, r8, r7
MULI64 r10, r8, 8d MULI64 r10, r8, 8d
ADD64 r9, r5, r10 ADD64 r1, r5, r10
ST r8, r9, 0a, 8h ST r8, r1, 0a, 8h
CP r8, r11 CP r8, r12
JMP :6 JMP :6
2: ADDI64 r254, r254, 32d 2: ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -1,27 +1,27 @@
main: main:
ADDI64 r254, r254, -10240d ADDI64 r254, r254, -10240d
LI64 r6, 1d LI64 r7, 1d
LI8 r7, 64b LI8 r8, 64b
LI64 r8, 1024d LI64 r6, 1024d
LI64 r9, 0d LI64 r9, 0d
ADDI64 r5, r254, 0d ADDI64 r5, r254, 0d
4: JLTU r9, r8, :0 4: JLTU r9, r6, :0
LI64 r4, 10d LI64 r6, 10d
CP r7, r6 CP r8, r7
3: LD r9, r254, 2048a, 1h 3: LD r11, r254, 2048a, 1h
JLTU r7, r4, :1 JLTU r8, r6, :1
ANDI r1, r9, 255d ANDI r1, r11, 255d
JMP :2 JMP :2
1: ADD64 r12, r7, r6 1: ADD64 r2, r8, r7
MULI64 r1, r7, 1024d MULI64 r1, r8, 1024d
ADD64 r7, r5, r1 ADD64 r3, r5, r1
BMC r5, r7, 1024h BMC r5, r3, 1024h
CP r7, r12 CP r8, r2
JMP :3 JMP :3
0: ADD64 r1, r9, r6 0: ADD64 r2, r9, r7
ADD64 r10, r5, r9 ADD64 r12, r5, r9
ST r7, r10, 0a, 1h ST r8, r12, 0a, 1h
CP r9, r1 CP r9, r2
JMP :4 JMP :4
2: ADDI64 r254, r254, 10240d 2: ADDI64 r254, r254, 10240d
JALA r0, r31, 0a JALA r0, r31, 0a