fixed the unreachable functions deleting branches

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-17 20:53:13 +01:00
parent 47014c6164
commit 6085177982
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 42 additions and 21 deletions

View file

@ -254,8 +254,7 @@ pub fn disasm<'a>(
|| global_offset > off + len || global_offset > off + len
|| prev || prev
.get(global_offset as usize) .get(global_offset as usize)
.map_or(true, |&b| instr_from_byte(b).is_err()) .map_or(true, |&b| instr_from_byte(b).is_err());
|| prev[global_offset as usize] == 0;
has_oob |= local_has_oob; has_oob |= local_has_oob;
let label = labels.get(&global_offset).unwrap(); let label = labels.get(&global_offset).unwrap();
if local_has_oob { if local_has_oob {

View file

@ -662,10 +662,13 @@ main := fn(): uint {
#### die #### die
```hb ```hb
fun := fn(): never die
main := fn(): never { main := fn(): never {
// simply emmits 'un' instruction that immediately terminates the execution // simply emmits 'un' instruction that immediately terminates the execution
// the expresion has similar properties to 'return' but does not accept a value // the expresion has similar properties to 'return' but does not accept a value
die fun()
} }
``` ```

View file

@ -23,7 +23,7 @@ impl HbvmBackend {
tys: &Types, tys: &Types,
files: &EntSlice<Module, parser::Ast>, files: &EntSlice<Module, parser::Ast>,
) -> (usize, bool) { ) -> (usize, bool) {
let tail = Function::build(nodes, tys, &mut self.ralloc, sig); let tail = FunctionBuilder::build(nodes, tys, &mut self.ralloc, sig);
let strip_load = |value| match nodes[value].kind { let strip_load = |value| match nodes[value].kind {
Kind::Load { .. } if nodes[value].ty.loc(tys) == Loc::Stack => nodes[value].inputs[1], Kind::Load { .. } if nodes[value].ty.loc(tys) == Loc::Stack => nodes[value].inputs[1],
@ -392,8 +392,9 @@ impl HbvmBackend {
todo!("unhandled operator: {op}"); todo!("unhandled operator: {op}");
} }
} }
Kind::Call { args, func } => { Kind::Call { args, func, .. } => {
let (ret, mut parama) = tys.parama(node.ty); let (ret, mut parama) = tys.parama(node.ty);
debug_assert!(node.ty != ty::Id::NEVER || ret.is_none());
if let Some(PLoc::Ref(r, ..)) = ret { if let Some(PLoc::Ref(r, ..)) = ret {
self.emit(instrs::cp(r, atr(*node.inputs.last().unwrap()))) self.emit(instrs::cp(r, atr(*node.inputs.last().unwrap())))
} }
@ -530,7 +531,7 @@ impl HbvmBackend {
} }
} }
struct Function<'a> { struct FunctionBuilder<'a> {
sig: Sig, sig: Sig,
tail: bool, tail: bool,
nodes: &'a Nodes, nodes: &'a Nodes,
@ -538,7 +539,7 @@ struct Function<'a> {
func: &'a mut Res, func: &'a mut Res,
} }
impl core::fmt::Debug for Function<'_> { impl core::fmt::Debug for FunctionBuilder<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for block in &self.func.blocks { for block in &self.func.blocks {
writeln!(f, "{:?}", self.nodes[block.entry].kind)?; writeln!(f, "{:?}", self.nodes[block.entry].kind)?;
@ -551,7 +552,7 @@ impl core::fmt::Debug for Function<'_> {
} }
} }
impl<'a> Function<'a> { impl<'a> FunctionBuilder<'a> {
fn build(nodes: &'a Nodes, tys: &'a Types, func: &'a mut Res, sig: Sig) -> bool { fn build(nodes: &'a Nodes, tys: &'a Types, func: &'a mut Res, sig: Sig) -> bool {
func.blocks.clear(); func.blocks.clear();
func.instrs.clear(); func.instrs.clear();
@ -670,17 +671,21 @@ impl<'a> Function<'a> {
self.emit_node(o); self.emit_node(o);
} }
} }
Kind::Call { func, .. } => { Kind::Call { func, unreachable, .. } => {
self.tail &= func == ty::Func::ECA; self.tail &= func == ty::Func::ECA;
self.add_instr(nid); if unreachable {
self.close_block(nid);
for &o in node.outputs.iter().rev() { self.emit_node(node.outputs[0]);
if self.nodes[o].inputs[0] == nid } else {
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region) self.add_instr(nid);
&& self.nodes[o].inputs[1] == nid) for &o in node.outputs.iter().rev() {
{ if self.nodes[o].inputs[0] == nid
self.emit_node(o); || (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
&& self.nodes[o].inputs[1] == nid)
{
self.emit_node(o);
}
} }
} }
} }

View file

@ -177,8 +177,9 @@ pub fn run_compiler(
if options.dump_asm { if options.dump_asm {
let mut disasm = String::new(); let mut disasm = String::new();
codegen.disasm(&mut disasm, out).map_err(|e| io::Error::other(e.to_string()))?; let err = codegen.disasm(&mut disasm, out).map_err(|e| io::Error::other(e.to_string()));
*out = disasm.into_bytes(); *out = disasm.into_bytes();
err?
} }
} }

View file

@ -97,6 +97,7 @@ impl Nodes {
debug_assert_ne!(next, 0); debug_assert_ne!(next, 0);
if matches!(self[cursor].kind, Kind::Then | Kind::Else) { if matches!(self[cursor].kind, Kind::Then | Kind::Else) {
debug_assert_eq!(self[next].kind, Kind::If); debug_assert_eq!(self[next].kind, Kind::If);
debug_assert_eq!(self[next].ty, ty::Id::VOID);
let other = self[next].outputs[(self[next].outputs[0] == cursor) as usize]; let other = self[next].outputs[(self[next].outputs[0] == cursor) as usize];
self[other].loop_depth.set(depth - 1); self[other].loop_depth.set(depth - 1);
} }
@ -1714,7 +1715,7 @@ impl Nodes {
Kind::BinOp { op } | Kind::UnOp { op } => { Kind::BinOp { op } | Kind::UnOp { op } => {
write!(out, "{:>4}: ", op.name()) write!(out, "{:>4}: ", op.name())
} }
Kind::Call { func, args: _ } => { Kind::Call { func, args: _, unreachable: _ } => {
write!(out, "call: {func} {} ", self[node].depth.get()) write!(out, "call: {func} {} ", self[node].depth.get())
} }
Kind::Global { global } => write!(out, "glob: {global:<5}"), Kind::Global { global } => write!(out, "glob: {global:<5}"),
@ -2109,6 +2110,7 @@ pub enum Kind {
}, },
// [ctrl, ...args] // [ctrl, ...args]
Call { Call {
unreachable: bool,
func: ty::Func, func: ty::Func,
args: ty::Tuple, args: ty::Tuple,
}, },
@ -2163,6 +2165,7 @@ impl Kind {
fn ends_basic_block(&self) -> bool { fn ends_basic_block(&self) -> bool {
matches!(self, Self::Return { .. } | Self::If | Self::End | Self::Die) matches!(self, Self::Return { .. } | Self::If | Self::End | Self::Die)
|| matches!(self, Kind::Call { unreachable: true, .. })
} }
pub fn starts_basic_block(&self) -> bool { pub fn starts_basic_block(&self) -> bool {

View file

@ -1516,7 +1516,11 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get(); inps[0] = self.ci.ctrl.get();
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node_nop(ty, Kind::Call { func: ty::Func::ECA, args }, inps), self.ci.nodes.new_node_nop(
ty,
Kind::Call { func: ty::Func::ECA, args, unreachable: false },
inps,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -2656,13 +2660,19 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get(); inps[0] = self.ci.ctrl.get();
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node_nop(sig.ret, Kind::Call { func: fu, args: sig.args }, inps), self.ci.nodes.new_node_nop(
sig.ret,
Kind::Call { func: fu, args: sig.args, unreachable: sig.ret == ty::Id::NEVER },
inps,
),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.add_clobber_stores(clobbered_aliases); self.add_clobber_stores(clobbered_aliases);
if sig.ret == ty::Id::NEVER { if sig.ret == ty::Id::NEVER {
self.ci.nodes.bind(self.ci.ctrl.get(), NEVER);
self.ci.ctrl.set(NEVER, &mut self.ci.nodes);
return None; return None;
} }