POC for removeing needless stack offset computes when only value is used
TBD: there are far more cases where this will apply Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
00f6729d31
commit
48a0c8d0b9
|
@ -3,8 +3,8 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser,
|
parser,
|
||||||
son::{Kind, Nid, Node, Nodes, MEM, VOID},
|
son::{Kind, Nid, Nodes, MEM},
|
||||||
ty::{self, Arg, Loc, Module, Offset, Sig, Size, Types},
|
ty::{self, Loc, Module, Offset, Size, Types},
|
||||||
utils::{EntSlice, EntVec},
|
utils::{EntSlice, EntVec},
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||||
|
@ -417,7 +417,7 @@ impl Nodes {
|
||||||
Kind::BinOp { op: TokenKind::Add | TokenKind::Sub } => {
|
Kind::BinOp { op: TokenKind::Add | TokenKind::Sub } => {
|
||||||
self.is_locked(node.inputs[1])
|
self.is_locked(node.inputs[1])
|
||||||
|| (self.is_const(node.inputs[2])
|
|| (self.is_const(node.inputs[2])
|
||||||
&& node.outputs.iter().all(|&n| self[n].uses_direct_offset_of(nid, tys)))
|
&& node.outputs.iter().all(|&n| self.uses_direct_offset_of(n, nid, tys)))
|
||||||
}
|
}
|
||||||
Kind::BinOp { op } => {
|
Kind::BinOp { op } => {
|
||||||
op.cond_op(self[node.inputs[1]].ty).is_some()
|
op.cond_op(self[node.inputs[1]].ty).is_some()
|
||||||
|
@ -425,7 +425,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
Kind::Stck if tys.size_of(node.ty) == 0 => true,
|
Kind::Stck if tys.size_of(node.ty) == 0 => true,
|
||||||
Kind::Stck | Kind::Arg => node.outputs.iter().all(|&n| {
|
Kind::Stck | Kind::Arg => node.outputs.iter().all(|&n| {
|
||||||
self[n].uses_direct_offset_of(nid, tys)
|
self.uses_direct_offset_of(n, nid, tys)
|
||||||
|| (matches!(self[n].kind, Kind::BinOp { op: TokenKind::Add })
|
|| (matches!(self[n].kind, Kind::BinOp { op: TokenKind::Add })
|
||||||
&& self.is_never_used(n, tys))
|
&& self.is_never_used(n, tys))
|
||||||
}),
|
}),
|
||||||
|
@ -433,18 +433,17 @@ impl Nodes {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct InstrCtx<'a> {
|
fn uses_direct_offset_of(&self, user: Nid, target: Nid, tys: &Types) -> bool {
|
||||||
nid: Nid,
|
let node = &self[user];
|
||||||
sig: Sig,
|
((node.kind == Kind::Stre && node.inputs[2] == target)
|
||||||
is_last_block: bool,
|
|| (node.kind == Kind::Load && node.inputs[1] == target))
|
||||||
is_next_block: bool,
|
&& (node.ty.loc(tys) == Loc::Reg
|
||||||
retl: Option<PLoc>,
|
// this means the struct is actually loaded into a register so no BMC needed
|
||||||
allocs: &'a [u8],
|
|| (node.kind == Kind::Load
|
||||||
nodes: &'a Nodes,
|
&& !matches!(tys.parama(node.ty).0, Some(PLoc::Ref(..)))
|
||||||
tys: &'a Types,
|
&& node.outputs.iter().all(|&o| self[o].kind.is_call())))
|
||||||
files: &'a EntSlice<Module, parser::Ast>,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HbvmBackend {
|
impl HbvmBackend {
|
||||||
|
@ -477,253 +476,6 @@ impl HbvmBackend {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_instr(
|
|
||||||
&mut self,
|
|
||||||
InstrCtx {
|
|
||||||
nid,
|
|
||||||
sig,
|
|
||||||
is_last_block,
|
|
||||||
is_next_block,
|
|
||||||
allocs,
|
|
||||||
nodes,
|
|
||||||
tys,
|
|
||||||
files,
|
|
||||||
retl,
|
|
||||||
}: InstrCtx,
|
|
||||||
) {
|
|
||||||
let node = &nodes[nid];
|
|
||||||
|
|
||||||
match node.kind {
|
|
||||||
Kind::If => {
|
|
||||||
let &[_, cnd] = node.inputs.as_slice() else { unreachable!() };
|
|
||||||
if let Some((op, swapped)) = nodes.cond_op(cnd) {
|
|
||||||
let &[lhs, rhs] = allocs else { unreachable!() };
|
|
||||||
let &[_, lh, rh] = nodes[cnd].inputs.as_slice() else { unreachable!() };
|
|
||||||
|
|
||||||
self.extend(nodes[lh].ty, nodes[lh].ty.extend(), lhs, tys, files);
|
|
||||||
self.extend(nodes[rh].ty, nodes[rh].ty.extend(), rhs, tys, files);
|
|
||||||
|
|
||||||
let rel = Reloc::new(self.code.len(), 3, 2);
|
|
||||||
self.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
|
||||||
self.emit(op(lhs, rhs, 0));
|
|
||||||
} else {
|
|
||||||
debug_assert_eq!(nodes[node.outputs[0]].kind, Kind::Then);
|
|
||||||
self.extend(nodes[cnd].ty, nodes[cnd].ty.extend(), allocs[0], tys, files);
|
|
||||||
let rel = Reloc::new(self.code.len(), 3, 2);
|
|
||||||
self.jump_relocs.push((node.outputs[0], rel));
|
|
||||||
self.emit(instrs::jne(allocs[0], reg::ZERO, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Loop | Kind::Region => {
|
|
||||||
if !is_next_block {
|
|
||||||
let rel = Reloc::new(self.code.len(), 1, 4);
|
|
||||||
self.jump_relocs.push((nid, rel));
|
|
||||||
self.emit(instrs::jmp(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Return { .. } => {
|
|
||||||
match retl {
|
|
||||||
Some(PLoc::Reg(r, size)) if sig.ret.loc(tys) == Loc::Stack => {
|
|
||||||
self.emit(instrs::ld(r, allocs[0], 0, size))
|
|
||||||
}
|
|
||||||
None | Some(PLoc::Reg(..)) => {}
|
|
||||||
Some(PLoc::WideReg(r, size)) => self.emit(instrs::ld(r, allocs[0], 0, size)),
|
|
||||||
Some(PLoc::Ref(_, size)) => {
|
|
||||||
let [src, dst] = [allocs[0], allocs[1]];
|
|
||||||
if let Ok(size) = u16::try_from(size) {
|
|
||||||
self.emit(instrs::bmc(src, dst, size));
|
|
||||||
} else {
|
|
||||||
for _ in 0..size / u16::MAX as u32 {
|
|
||||||
self.emit(instrs::bmc(src, dst, u16::MAX));
|
|
||||||
self.emit(instrs::addi64(src, src, u16::MAX as _));
|
|
||||||
self.emit(instrs::addi64(dst, dst, u16::MAX as _));
|
|
||||||
}
|
|
||||||
self.emit(instrs::bmc(src, dst, size as u16));
|
|
||||||
self.emit(instrs::addi64(src, src, size.wrapping_neg() as _));
|
|
||||||
self.emit(instrs::addi64(dst, dst, size.wrapping_neg() as _));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !is_last_block {
|
|
||||||
let rel = Reloc::new(self.code.len(), 1, 4);
|
|
||||||
self.ret_relocs.push(rel);
|
|
||||||
self.emit(instrs::jmp(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Die => {
|
|
||||||
self.emit(instrs::un());
|
|
||||||
}
|
|
||||||
Kind::CInt { value: 0 } => self.emit(instrs::cp(allocs[0], reg::ZERO)),
|
|
||||||
Kind::CInt { value } if node.ty == ty::Id::F32 => {
|
|
||||||
self.emit(instrs::li32(allocs[0], (f64::from_bits(value as _) as f32).to_bits()));
|
|
||||||
}
|
|
||||||
Kind::CInt { value } => self.emit(match tys.size_of(node.ty) {
|
|
||||||
1 => instrs::li8(allocs[0], value as _),
|
|
||||||
2 => instrs::li16(allocs[0], value as _),
|
|
||||||
4 => instrs::li32(allocs[0], value as _),
|
|
||||||
_ => instrs::li64(allocs[0], value as _),
|
|
||||||
}),
|
|
||||||
Kind::UnOp { op } => {
|
|
||||||
let op = op
|
|
||||||
.unop(
|
|
||||||
node.ty,
|
|
||||||
tys.inner_of(nodes[node.inputs[1]].ty).unwrap_or(nodes[node.inputs[1]].ty),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"TODO: unary operator not supported: {op} {} {}",
|
|
||||||
ty::Display::new(tys, files, node.ty),
|
|
||||||
ty::Display::new(
|
|
||||||
tys,
|
|
||||||
files,
|
|
||||||
tys.inner_of(nodes[node.inputs[1]].ty)
|
|
||||||
.unwrap_or(nodes[node.inputs[1]].ty)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let &[dst, oper] = allocs else { unreachable!() };
|
|
||||||
self.emit(op(dst, oper));
|
|
||||||
}
|
|
||||||
Kind::BinOp { op } => {
|
|
||||||
let &[.., rh] = node.inputs.as_slice() else { unreachable!() };
|
|
||||||
|
|
||||||
if let Kind::CInt { value } = nodes[rh].kind
|
|
||||||
&& nodes.is_locked(rh)
|
|
||||||
&& let Some(op) = op.imm_binop(node.ty)
|
|
||||||
{
|
|
||||||
let &[dst, lhs] = allocs else { unreachable!() };
|
|
||||||
self.emit(op(dst, lhs, value as _));
|
|
||||||
} else if let Some(against) = op.cmp_against() {
|
|
||||||
let op_ty = nodes[rh].ty;
|
|
||||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
|
||||||
if let Some(op) = op.float_cmp(op_ty) {
|
|
||||||
self.emit(op(dst, lhs, rhs));
|
|
||||||
} else if op_ty.is_float() && matches!(op, TokenKind::Le | TokenKind::Ge) {
|
|
||||||
let op = match op {
|
|
||||||
TokenKind::Le => TokenKind::Gt,
|
|
||||||
TokenKind::Ge => TokenKind::Lt,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let op_fn = op.float_cmp(op_ty).unwrap();
|
|
||||||
self.emit(op_fn(dst, lhs, rhs));
|
|
||||||
self.emit(instrs::not(dst, dst));
|
|
||||||
} else {
|
|
||||||
let op_fn = if op_ty.is_signed() { instrs::cmps } else { instrs::cmpu };
|
|
||||||
self.emit(op_fn(dst, lhs, rhs));
|
|
||||||
self.emit(instrs::cmpui(dst, dst, against));
|
|
||||||
if matches!(op, TokenKind::Eq | TokenKind::Lt | TokenKind::Gt) {
|
|
||||||
self.emit(instrs::not(dst, dst));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(op) = op.binop(node.ty) {
|
|
||||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
|
||||||
self.emit(op(dst, lhs, rhs));
|
|
||||||
} else {
|
|
||||||
todo!("unhandled operator: {op}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Call { args, func } => {
|
|
||||||
let (ret, mut parama) = tys.parama(node.ty);
|
|
||||||
let has_ret = ret.is_some() as usize;
|
|
||||||
let mut args = args.args();
|
|
||||||
let mut allocs = allocs[has_ret..].iter();
|
|
||||||
while let Some(arg) = args.next(tys) {
|
|
||||||
let Arg::Value(ty) = arg else { continue };
|
|
||||||
let Some(loc) = parama.next(ty, tys) else { continue };
|
|
||||||
|
|
||||||
let &arg = allocs.next().unwrap();
|
|
||||||
let (rg, size) = match loc {
|
|
||||||
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
|
|
||||||
PLoc::WideReg(rg, size) => (rg, size),
|
|
||||||
PLoc::Ref(..) | PLoc::Reg(..) => continue,
|
|
||||||
};
|
|
||||||
if size > 8 {
|
|
||||||
allocs.next().unwrap();
|
|
||||||
}
|
|
||||||
self.emit(instrs::ld(rg, arg, 0, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert!(!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some());
|
|
||||||
|
|
||||||
if func == ty::Func::ECA {
|
|
||||||
self.emit(instrs::eca());
|
|
||||||
} else {
|
|
||||||
self.relocs.push(TypedReloc {
|
|
||||||
target: func.into(),
|
|
||||||
reloc: Reloc::new(self.code.len(), 3, 4),
|
|
||||||
});
|
|
||||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.ty.loc(tys) == Loc::Stack
|
|
||||||
&& let Some(PLoc::Reg(r, size) | PLoc::WideReg(r, size)) = ret
|
|
||||||
{
|
|
||||||
self.emit(instrs::st(r, *allocs.last().unwrap(), 0, size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Global { global } => {
|
|
||||||
let reloc = Reloc::new(self.code.len(), 3, 4);
|
|
||||||
self.relocs.push(TypedReloc { target: global.into(), reloc });
|
|
||||||
self.emit(instrs::lra(allocs[0], 0, 0));
|
|
||||||
}
|
|
||||||
Kind::Stck => {
|
|
||||||
let base = reg::STACK_PTR;
|
|
||||||
let offset = self.offsets[nid as usize];
|
|
||||||
self.emit(instrs::addi64(allocs[0], base, offset as _));
|
|
||||||
}
|
|
||||||
Kind::Load => {
|
|
||||||
let (region, offset) = nodes.strip_offset(node.inputs[1], node.ty, tys);
|
|
||||||
let size = tys.size_of(node.ty);
|
|
||||||
if node.ty.loc(tys) != Loc::Stack {
|
|
||||||
let (base, offset) = match nodes[region].kind {
|
|
||||||
Kind::Stck => (reg::STACK_PTR, self.offsets[region as usize] + offset),
|
|
||||||
_ => (allocs[1], offset),
|
|
||||||
};
|
|
||||||
self.emit(instrs::ld(allocs[0], base, offset as _, size as _));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::Stre if node.inputs[1] == VOID => {}
|
|
||||||
Kind::Stre => {
|
|
||||||
let (region, offset) = nodes.strip_offset(node.inputs[2], node.ty, tys);
|
|
||||||
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
|
|
||||||
let (base, offset, src) = match nodes[region].kind {
|
|
||||||
Kind::Stck if node.ty.loc(tys) == Loc::Reg => {
|
|
||||||
(reg::STACK_PTR, self.offsets[region as usize] + offset, allocs[0])
|
|
||||||
}
|
|
||||||
_ => ((allocs[0]), offset, allocs[1]),
|
|
||||||
};
|
|
||||||
|
|
||||||
match node.ty.loc(tys) {
|
|
||||||
Loc::Reg => self.emit(instrs::st(src, base, offset as _, size)),
|
|
||||||
Loc::Stack => {
|
|
||||||
debug_assert_eq!(offset, 0);
|
|
||||||
self.emit(instrs::bmc(src, base, size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e @ (Kind::Start
|
|
||||||
| Kind::Assert { .. }
|
|
||||||
| Kind::Entry
|
|
||||||
| Kind::Mem
|
|
||||||
| Kind::End
|
|
||||||
| Kind::Loops
|
|
||||||
| Kind::Then
|
|
||||||
| Kind::Else
|
|
||||||
| Kind::Phi
|
|
||||||
| Kind::Arg
|
|
||||||
| Kind::Join) => unreachable!("{e:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node {
|
|
||||||
fn uses_direct_offset_of(&self, nid: Nid, tys: &Types) -> bool {
|
|
||||||
((self.kind == Kind::Stre && self.inputs[2] == nid)
|
|
||||||
|| (self.kind == Kind::Load && self.inputs[1] == nid))
|
|
||||||
&& self.ty.loc(tys) == Loc::Reg
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CondRet = Option<(fn(u8, u8, i16) -> EncodedInstr, bool)>;
|
type CondRet = Option<(fn(u8, u8, i16) -> EncodedInstr, bool)>;
|
||||||
|
|
|
@ -2,15 +2,16 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::hbvm::{
|
backend::hbvm::{
|
||||||
reg::{self, Reg},
|
reg::{self, Reg},
|
||||||
HbvmBackend, Nid, Nodes, PLoc,
|
HbvmBackend, Nid, Nodes, PLoc, Reloc, TypedReloc,
|
||||||
},
|
},
|
||||||
|
lexer::TokenKind,
|
||||||
parser, quad_sort,
|
parser, quad_sort,
|
||||||
son::{Kind, ARG_START, MEM, VOID},
|
son::{Kind, ARG_START, MEM, VOID},
|
||||||
ty::{self, Arg, Loc, Module, Sig, Types},
|
ty::{self, Arg, Loc, Module, Offset, Sig, Types},
|
||||||
utils::{BitSet, EntSlice},
|
utils::{BitSet, EntSlice},
|
||||||
},
|
},
|
||||||
alloc::{borrow::ToOwned, vec::Vec},
|
alloc::{borrow::ToOwned, vec::Vec},
|
||||||
core::{assert_matches::debug_assert_matches, mem, ops::Range},
|
core::{assert_matches::debug_assert_matches, mem, ops::Range, usize},
|
||||||
hbbytecode::{self as instrs},
|
hbbytecode::{self as instrs},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ impl HbvmBackend {
|
||||||
|
|
||||||
let mut res = mem::take(&mut self.ralloc);
|
let mut res = mem::take(&mut self.ralloc);
|
||||||
|
|
||||||
Regalloc::run(nodes, &mut res);
|
Regalloc::run(nodes, tys, &mut res);
|
||||||
|
|
||||||
'_open_function: {
|
'_open_function: {
|
||||||
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
||||||
|
@ -106,8 +107,7 @@ impl HbvmBackend {
|
||||||
let node = &nodes[nid];
|
let node = &nodes[nid];
|
||||||
alloc_buf.clear();
|
alloc_buf.clear();
|
||||||
|
|
||||||
let atr = |allc: Nid| {
|
let assert_alloc_use = |allc: Nid| {
|
||||||
let allc = strip_load(allc);
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
nodes.is_unlocked(allc),
|
nodes.is_unlocked(allc),
|
||||||
"{:?} {}",
|
"{:?} {}",
|
||||||
|
@ -125,18 +125,46 @@ impl HbvmBackend {
|
||||||
nodes[nid],
|
nodes[nid],
|
||||||
nodes[allc]
|
nodes[allc]
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let atr = |allc: Nid| {
|
||||||
|
let allc = strip_load(allc);
|
||||||
|
assert_alloc_use(allc);
|
||||||
res.node_to_reg[allc as usize]
|
res.node_to_reg[allc as usize]
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut is_next_block = false;
|
let offset_atr = |allc: Nid, offsets: &[Offset]| {
|
||||||
|
let allc = strip_load(allc);
|
||||||
|
if nodes.is_locked(allc) && nodes[allc].kind == Kind::Stck {
|
||||||
|
return (reg::STACK_PTR, offsets[allc as usize] as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_alloc_use(allc);
|
||||||
|
(res.node_to_reg[allc as usize], 0)
|
||||||
|
};
|
||||||
|
|
||||||
match node.kind {
|
match node.kind {
|
||||||
|
Kind::Mem => self.emit(instrs::cp(atr(MEM), reg::RET)),
|
||||||
|
Kind::Arg => {}
|
||||||
Kind::If => {
|
Kind::If => {
|
||||||
let &[_, cnd] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, cnd] = node.inputs.as_slice() else { unreachable!() };
|
||||||
if nodes.cond_op(cnd).is_some() {
|
if let Some((op, swapped)) = nodes.cond_op(cnd) {
|
||||||
let &[_, lh, rh] = nodes[cnd].inputs.as_slice() else { unreachable!() };
|
let &[_, lh, rh] = nodes[cnd].inputs.as_slice() else { unreachable!() };
|
||||||
alloc_buf.extend([atr(lh), atr(rh)]);
|
let [lhs, rhs] = [atr(lh), atr(rh)];
|
||||||
|
|
||||||
|
self.extend(nodes[lh].ty, nodes[lh].ty.extend(), lhs, tys, files);
|
||||||
|
self.extend(nodes[rh].ty, nodes[rh].ty.extend(), rhs, tys, files);
|
||||||
|
|
||||||
|
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||||
|
self.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
||||||
|
self.emit(op(lhs, rhs, 0));
|
||||||
} else {
|
} else {
|
||||||
alloc_buf.push(atr(cnd));
|
let cd = atr(cnd);
|
||||||
|
debug_assert_eq!(nodes[node.outputs[0]].kind, Kind::Then);
|
||||||
|
self.extend(nodes[cnd].ty, nodes[cnd].ty.extend(), cd, tys, files);
|
||||||
|
let rel = Reloc::new(self.code.len(), 3, 2);
|
||||||
|
self.jump_relocs.push((node.outputs[0], rel));
|
||||||
|
self.emit(instrs::jne(cd, reg::ZERO, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Loop | Kind::Region => {
|
Kind::Loop | Kind::Region => {
|
||||||
|
@ -217,39 +245,132 @@ impl HbvmBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is_next_block = res.backrefs[nid as usize] as usize == i + 1;
|
if res.backrefs[nid as usize] as usize != i + 1 {
|
||||||
|
let rel = Reloc::new(self.code.len(), 1, 4);
|
||||||
|
self.jump_relocs.push((nid, rel));
|
||||||
|
self.emit(instrs::jmp(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Kind::Return { .. } => {
|
Kind::Return { .. } => {
|
||||||
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
|
let &[_, ret, ..] = node.inputs.as_slice() else { unreachable!() };
|
||||||
match retl {
|
match retl {
|
||||||
Some(PLoc::Reg(r, _)) if sig.ret.loc(tys) == Loc::Reg => {
|
None => {}
|
||||||
|
Some(PLoc::Reg(r, size)) if sig.ret.loc(tys) == Loc::Stack => {
|
||||||
|
// TODO: handle the stack load
|
||||||
|
self.emit(instrs::ld(r, atr(ret), 0, size))
|
||||||
|
}
|
||||||
|
Some(PLoc::WideReg(r, size)) => {
|
||||||
|
// TODO: handle the stack load
|
||||||
|
self.emit(instrs::ld(r, atr(ret), 0, size))
|
||||||
|
}
|
||||||
|
Some(PLoc::Reg(r, _)) => {
|
||||||
alloc_buf.push(atr(ret));
|
alloc_buf.push(atr(ret));
|
||||||
self.emit(instrs::cp(r, atr(ret)));
|
self.emit(instrs::cp(r, atr(ret)));
|
||||||
}
|
}
|
||||||
Some(PLoc::Ref(..)) => alloc_buf.extend([atr(ret), atr(MEM)]),
|
Some(PLoc::Ref(_, size)) => {
|
||||||
Some(_) => alloc_buf.push(atr(ret)),
|
let [src, dst] = [atr(ret), atr(MEM)];
|
||||||
None => {}
|
if let Ok(size) = u16::try_from(size) {
|
||||||
|
self.emit(instrs::bmc(src, dst, size));
|
||||||
|
} else {
|
||||||
|
for _ in 0..size / u16::MAX as u32 {
|
||||||
|
self.emit(instrs::bmc(src, dst, u16::MAX));
|
||||||
|
self.emit(instrs::addi64(src, src, u16::MAX as _));
|
||||||
|
self.emit(instrs::addi64(dst, dst, u16::MAX as _));
|
||||||
|
}
|
||||||
|
self.emit(instrs::bmc(src, dst, size as u16));
|
||||||
|
self.emit(instrs::addi64(src, src, size.wrapping_neg() as _));
|
||||||
|
self.emit(instrs::addi64(dst, dst, size.wrapping_neg() as _));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i != res.blocks.len() - 1 {
|
||||||
|
let rel = Reloc::new(self.code.len(), 1, 4);
|
||||||
|
self.ret_relocs.push(rel);
|
||||||
|
self.emit(instrs::jmp(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Die => {}
|
Kind::Die => {
|
||||||
Kind::CInt { .. } => alloc_buf.push(atr(nid)),
|
self.emit(instrs::un());
|
||||||
Kind::UnOp { .. } => alloc_buf.extend([atr(nid), atr(node.inputs[1])]),
|
}
|
||||||
|
Kind::CInt { value: 0 } => self.emit(instrs::cp(atr(nid), reg::ZERO)),
|
||||||
|
Kind::CInt { value } if node.ty == ty::Id::F32 => {
|
||||||
|
self.emit(instrs::li32(
|
||||||
|
atr(nid),
|
||||||
|
(f64::from_bits(value as _) as f32).to_bits(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Kind::CInt { value } => self.emit(match tys.size_of(node.ty) {
|
||||||
|
1 => instrs::li8(atr(nid), value as _),
|
||||||
|
2 => instrs::li16(atr(nid), value as _),
|
||||||
|
4 => instrs::li32(atr(nid), value as _),
|
||||||
|
_ => instrs::li64(atr(nid), value as _),
|
||||||
|
}),
|
||||||
|
Kind::UnOp { op } => {
|
||||||
|
let op = op
|
||||||
|
.unop(
|
||||||
|
node.ty,
|
||||||
|
tys.inner_of(nodes[node.inputs[1]].ty)
|
||||||
|
.unwrap_or(nodes[node.inputs[1]].ty),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"TODO: unary operator not supported: {op} {} {}",
|
||||||
|
ty::Display::new(tys, files, node.ty),
|
||||||
|
ty::Display::new(
|
||||||
|
tys,
|
||||||
|
files,
|
||||||
|
tys.inner_of(nodes[node.inputs[1]].ty)
|
||||||
|
.unwrap_or(nodes[node.inputs[1]].ty)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
self.emit(op(atr(nid), atr(node.inputs[1])));
|
||||||
|
}
|
||||||
Kind::BinOp { op } => {
|
Kind::BinOp { op } => {
|
||||||
let &[.., lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
let &[.., lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||||
|
|
||||||
if let Kind::CInt { .. } = nodes[rhs].kind
|
if let Kind::CInt { value } = nodes[rhs].kind
|
||||||
&& nodes.is_locked(rhs)
|
&& nodes.is_locked(rhs)
|
||||||
&& op.imm_binop(node.ty).is_some()
|
&& let Some(op) = op.imm_binop(node.ty)
|
||||||
{
|
{
|
||||||
alloc_buf.extend([atr(nid), atr(lhs)]);
|
self.emit(op(atr(nid), atr(lhs), value as _));
|
||||||
|
} else if let Some(against) = op.cmp_against() {
|
||||||
|
let op_ty = nodes[rhs].ty;
|
||||||
|
let [dst, lhs, rhs] = [atr(nid), atr(lhs), atr(rhs)];
|
||||||
|
if let Some(op) = op.float_cmp(op_ty) {
|
||||||
|
self.emit(op(dst, lhs, rhs));
|
||||||
|
} else if op_ty.is_float()
|
||||||
|
&& matches!(op, TokenKind::Le | TokenKind::Ge)
|
||||||
|
{
|
||||||
|
let op = match op {
|
||||||
|
TokenKind::Le => TokenKind::Gt,
|
||||||
|
TokenKind::Ge => TokenKind::Lt,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let op_fn = op.float_cmp(op_ty).unwrap();
|
||||||
|
self.emit(op_fn(dst, lhs, rhs));
|
||||||
|
self.emit(instrs::not(dst, dst));
|
||||||
|
} else {
|
||||||
|
let op_fn =
|
||||||
|
if op_ty.is_signed() { instrs::cmps } else { instrs::cmpu };
|
||||||
|
self.emit(op_fn(dst, lhs, rhs));
|
||||||
|
self.emit(instrs::cmpui(dst, dst, against));
|
||||||
|
if matches!(op, TokenKind::Eq | TokenKind::Lt | TokenKind::Gt) {
|
||||||
|
self.emit(instrs::not(dst, dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(op) = op.binop(node.ty) {
|
||||||
|
let [dst, lhs, rhs] = [atr(nid), atr(lhs), atr(rhs)];
|
||||||
|
self.emit(op(dst, lhs, rhs));
|
||||||
} else {
|
} else {
|
||||||
alloc_buf.extend([atr(nid), atr(lhs), atr(rhs)]);
|
todo!("unhandled operator: {op}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Call { args, .. } => {
|
Kind::Call { args, func } => {
|
||||||
let (ret, mut parama) = tys.parama(node.ty);
|
let (ret, mut parama) = tys.parama(node.ty);
|
||||||
if ret.is_some() {
|
if let Some(PLoc::Ref(r, ..)) = ret {
|
||||||
alloc_buf.push(atr(nid));
|
self.emit(instrs::cp(r, atr(*node.inputs.last().unwrap())))
|
||||||
}
|
}
|
||||||
let mut args = args.args();
|
let mut args = args.args();
|
||||||
let mut allocs = node.inputs[1..].iter();
|
let mut allocs = node.inputs[1..].iter();
|
||||||
|
@ -257,68 +378,90 @@ impl HbvmBackend {
|
||||||
let Arg::Value(ty) = arg else { continue };
|
let Arg::Value(ty) = arg else { continue };
|
||||||
let Some(loc) = parama.next(ty, tys) else { continue };
|
let Some(loc) = parama.next(ty, tys) else { continue };
|
||||||
|
|
||||||
let arg = *allocs.next().unwrap();
|
let &arg = allocs.next().unwrap();
|
||||||
alloc_buf.push(atr(arg));
|
let (rg, size) = match loc {
|
||||||
match loc {
|
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
|
||||||
PLoc::Reg(..) if ty.loc(tys) == Loc::Stack => {}
|
PLoc::WideReg(rg, size) => (rg, size),
|
||||||
PLoc::WideReg(..) => alloc_buf.push(0),
|
PLoc::Ref(r, ..) | PLoc::Reg(r, ..) => {
|
||||||
PLoc::Reg(r, ..) | PLoc::Ref(r, ..) => {
|
self.emit(instrs::cp(r, atr(arg)));
|
||||||
self.emit(instrs::cp(r, atr(arg)))
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (src, off) = offset_atr(arg, &self.offsets);
|
||||||
|
self.emit(instrs::ld(rg, src, off, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.ty.loc(tys) == Loc::Stack {
|
if func == ty::Func::ECA {
|
||||||
alloc_buf.push(atr(*node.inputs.last().unwrap()));
|
self.emit(instrs::eca());
|
||||||
|
} else {
|
||||||
|
self.relocs.push(TypedReloc {
|
||||||
|
target: func.into(),
|
||||||
|
reloc: Reloc::new(self.code.len(), 3, 4),
|
||||||
|
});
|
||||||
|
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(PLoc::Ref(r, ..)) = ret {
|
if node.ty.loc(tys) == Loc::Stack
|
||||||
self.emit(instrs::cp(r, *alloc_buf.last().unwrap()))
|
&& let Some(PLoc::Reg(r, size) | PLoc::WideReg(r, size)) = ret
|
||||||
|
{
|
||||||
|
self.emit(instrs::st(r, atr(*node.inputs.last().unwrap()), 0, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Stck | Kind::Global { .. } => alloc_buf.push(atr(nid)),
|
Kind::Global { global } => {
|
||||||
|
let reloc = Reloc::new(self.code.len(), 3, 4);
|
||||||
|
self.relocs.push(TypedReloc { target: global.into(), reloc });
|
||||||
|
self.emit(instrs::lra(atr(nid), 0, 0));
|
||||||
|
}
|
||||||
|
Kind::Stck => {
|
||||||
|
let base = reg::STACK_PTR;
|
||||||
|
let offset = self.offsets[nid as usize];
|
||||||
|
self.emit(instrs::addi64(atr(nid), base, offset as _));
|
||||||
|
}
|
||||||
Kind::Load => {
|
Kind::Load => {
|
||||||
let (region, _) = nodes.strip_offset(node.inputs[1], node.ty, tys);
|
let (region, offset) = nodes.strip_offset(node.inputs[1], node.ty, tys);
|
||||||
|
let size = tys.size_of(node.ty);
|
||||||
if node.ty.loc(tys) != Loc::Stack {
|
if node.ty.loc(tys) != Loc::Stack {
|
||||||
alloc_buf.push(atr(nid));
|
let (base, offset) = match nodes[region].kind {
|
||||||
match nodes[region].kind {
|
Kind::Stck => {
|
||||||
Kind::Stck => {}
|
(reg::STACK_PTR, self.offsets[region as usize] + offset)
|
||||||
_ => alloc_buf.push(atr(region)),
|
}
|
||||||
}
|
_ => (atr(region), offset),
|
||||||
|
};
|
||||||
|
self.emit(instrs::ld(atr(nid), base, offset as _, size as _));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Stre if node.inputs[1] == VOID => {}
|
|
||||||
Kind::Stre => {
|
Kind::Stre => {
|
||||||
let (region, _) = nodes.strip_offset(node.inputs[2], node.ty, tys);
|
debug_assert_ne!(node.inputs[1], VOID);
|
||||||
match nodes[region].kind {
|
let (region, offset) = nodes.strip_offset(node.inputs[2], node.ty, tys);
|
||||||
Kind::Stck if node.ty.loc(tys) == Loc::Reg => {
|
let size = u16::try_from(tys.size_of(node.ty)).expect("TODO");
|
||||||
alloc_buf.push(atr(node.inputs[1]))
|
let (base, offset, src) = match nodes[region].kind {
|
||||||
|
Kind::Stck if node.ty.loc(tys) == Loc::Reg => (
|
||||||
|
reg::STACK_PTR,
|
||||||
|
self.offsets[region as usize] + offset,
|
||||||
|
atr(node.inputs[1]),
|
||||||
|
),
|
||||||
|
_ => (atr(region), offset, atr(node.inputs[1])),
|
||||||
|
};
|
||||||
|
|
||||||
|
match node.ty.loc(tys) {
|
||||||
|
Loc::Reg => self.emit(instrs::st(src, base, offset as _, size)),
|
||||||
|
Loc::Stack => {
|
||||||
|
debug_assert_eq!(offset, 0);
|
||||||
|
self.emit(instrs::bmc(src, base, size))
|
||||||
}
|
}
|
||||||
_ => alloc_buf.extend([atr(region), atr(node.inputs[1])]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Mem => {
|
e @ (Kind::Start
|
||||||
self.emit(instrs::cp(atr(MEM), reg::RET));
|
| Kind::Assert { .. }
|
||||||
continue;
|
| Kind::Entry
|
||||||
}
|
| Kind::End
|
||||||
Kind::Arg => {
|
| Kind::Loops
|
||||||
continue;
|
| Kind::Then
|
||||||
}
|
| Kind::Else
|
||||||
_ => {}
|
| Kind::Phi
|
||||||
|
| Kind::Join) => unreachable!("{e:?}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_instr(super::InstrCtx {
|
|
||||||
nid,
|
|
||||||
sig,
|
|
||||||
is_next_block,
|
|
||||||
is_last_block: i == res.blocks.len() - 1,
|
|
||||||
retl,
|
|
||||||
allocs: &alloc_buf,
|
|
||||||
nodes,
|
|
||||||
tys,
|
|
||||||
files,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Kind::Call { .. } = node.kind {
|
if let Kind::Call { .. } = node.kind {
|
||||||
let (ret, ..) = tys.parama(node.ty);
|
let (ret, ..) = tys.parama(node.ty);
|
||||||
|
|
||||||
|
@ -537,6 +680,37 @@ impl Nodes {
|
||||||
self.len()
|
self.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_data_dep(&self, val: Nid, user: Nid, #[expect(unused)] types: &Types) -> bool {
|
||||||
|
match self[user].kind {
|
||||||
|
Kind::Return { .. } => self[user].inputs[1] == val,
|
||||||
|
_ if self.is_cfg(user) && !matches!(self[user].kind, Kind::Call { .. } | Kind::If) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Kind::Join => false,
|
||||||
|
Kind::Stre => {
|
||||||
|
debug_assert_eq!(
|
||||||
|
self[user].inputs[4..]
|
||||||
|
.iter()
|
||||||
|
.filter(|&&v| self[v].kind != Kind::Load)
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![]
|
||||||
|
);
|
||||||
|
debug_assert_matches!(
|
||||||
|
self[self[user].inputs[3]].kind,
|
||||||
|
Kind::Stre | Kind::Mem | Kind::Phi
|
||||||
|
);
|
||||||
|
self[user].inputs.iter().position(|&v| v == val).is_some_and(|v| v < 3)
|
||||||
|
}
|
||||||
|
//Kind::Call { .. } => {
|
||||||
|
// self[val].kind != Kind::Load
|
||||||
|
// || matches!(types.parama(self[val].ty).0, Some(PLoc::Ref(..)))
|
||||||
|
//}
|
||||||
|
Kind::Load => self[user].inputs[2] != val,
|
||||||
|
_ => self[user].inputs[0] != val || self[user].inputs[1..].contains(&val),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn use_block_of(&self, inst: Nid, uinst: Nid) -> Nid {
|
fn use_block_of(&self, inst: Nid, uinst: Nid) -> Nid {
|
||||||
let mut block = self.use_block(inst, uinst, None);
|
let mut block = self.use_block(inst, uinst, None);
|
||||||
while !self[block].kind.starts_basic_block() {
|
while !self[block].kind.starts_basic_block() {
|
||||||
|
@ -568,7 +742,11 @@ impl Nodes {
|
||||||
nid
|
nid
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uses_of(&self, nid: Nid) -> impl Iterator<Item = (Nid, Nid)> + use<'_> {
|
fn uses_of<'a>(
|
||||||
|
&'a self,
|
||||||
|
nid: Nid,
|
||||||
|
types: &'a Types,
|
||||||
|
) -> impl Iterator<Item = (Nid, Nid)> + use<'a> {
|
||||||
if self[nid].kind.is_cfg() && !matches!(self[nid].kind, Kind::Call { .. }) {
|
if self[nid].kind.is_cfg() && !matches!(self[nid].kind, Kind::Call { .. }) {
|
||||||
return None.into_iter().flatten();
|
return None.into_iter().flatten();
|
||||||
}
|
}
|
||||||
|
@ -577,10 +755,10 @@ impl Nodes {
|
||||||
self[nid]
|
self[nid]
|
||||||
.outputs
|
.outputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |&&n| self.is_data_dep(nid, n))
|
.filter(move |&&n| self.is_data_dep(nid, n, types))
|
||||||
.map(move |n| self.this_or_delegates(nid, n))
|
.map(move |n| self.this_or_delegates(nid, n))
|
||||||
.flat_map(|(p, ls)| ls.iter().map(move |l| (p, l)))
|
.flat_map(|(p, ls)| ls.iter().map(move |l| (p, l)))
|
||||||
.filter(|&(o, &n)| self.is_data_dep(o, n))
|
.filter(|&(o, &n)| self.is_data_dep(o, n, types))
|
||||||
.map(|(p, &n)| (self.use_block_of(p, n), n))
|
.map(|(p, &n)| (self.use_block_of(p, n), n))
|
||||||
.inspect(|&(_, n)| debug_assert!(self.is_unlocked(n))),
|
.inspect(|&(_, n)| debug_assert!(self.is_unlocked(n))),
|
||||||
)
|
)
|
||||||
|
@ -591,6 +769,7 @@ impl Nodes {
|
||||||
|
|
||||||
struct Regalloc<'a> {
|
struct Regalloc<'a> {
|
||||||
nodes: &'a Nodes,
|
nodes: &'a Nodes,
|
||||||
|
tys: &'a Types,
|
||||||
res: &'a mut Res,
|
res: &'a mut Res,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,8 +787,8 @@ impl<'a> Regalloc<'a> {
|
||||||
self.res.backrefs[nid as usize]
|
self.res.backrefs[nid as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(ctx: &'a Nodes, res: &'a mut Res) {
|
fn run(ctx: &'a Nodes, tys: &'a Types, res: &'a mut Res) {
|
||||||
Self { nodes: ctx, res }.run_low();
|
Self { nodes: ctx, tys, res }.run_low();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_low(&mut self) {
|
fn run_low(&mut self) {
|
||||||
|
@ -657,7 +836,7 @@ impl<'a> Regalloc<'a> {
|
||||||
fn collect_bundle(&mut self, inst: Nid, into: &mut Bundle) {
|
fn collect_bundle(&mut self, inst: Nid, into: &mut Bundle) {
|
||||||
let dom = self.nodes.idom_of(inst);
|
let dom = self.nodes.idom_of(inst);
|
||||||
self.res.dfs_seem.clear(self.nodes.len());
|
self.res.dfs_seem.clear(self.nodes.len());
|
||||||
for (cursor, uinst) in self.nodes.uses_of(inst) {
|
for (cursor, uinst) in self.nodes.uses_of(inst, self.tys) {
|
||||||
if !self.res.dfs_seem.set(uinst) {
|
if !self.res.dfs_seem.set(uinst) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1898,7 +1898,7 @@ impl Nodes {
|
||||||
log::info!("{out}");
|
log::info!("{out}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_cfg(&self, o: Nid) -> bool {
|
pub fn is_cfg(&self, o: Nid) -> bool {
|
||||||
self[o].kind.is_cfg()
|
self[o].kind.is_cfg()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2054,33 +2054,6 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_data_dep(&self, val: Nid, user: Nid) -> bool {
|
|
||||||
match self[user].kind {
|
|
||||||
Kind::Return { .. } => self[user].inputs[1] == val,
|
|
||||||
_ if self.is_cfg(user) && !matches!(self[user].kind, Kind::Call { .. } | Kind::If) => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
Kind::Join => false,
|
|
||||||
Kind::Stre => {
|
|
||||||
debug_assert_eq!(
|
|
||||||
self[user].inputs[4..]
|
|
||||||
.iter()
|
|
||||||
.filter(|&&v| self[v].kind != Kind::Load)
|
|
||||||
.copied()
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
vec![]
|
|
||||||
);
|
|
||||||
debug_assert_matches!(
|
|
||||||
self[self[user].inputs[3]].kind,
|
|
||||||
Kind::Stre | Kind::Mem | Kind::Phi
|
|
||||||
);
|
|
||||||
self[user].inputs.iter().position(|&v| v == val).is_some_and(|v| v < 3)
|
|
||||||
}
|
|
||||||
Kind::Load => self[user].inputs[2] != val,
|
|
||||||
_ => self[user].inputs[0] != val || self[user].inputs[1..].contains(&val),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn this_or_delegates<'a>(&'a self, source: Nid, target: &'a Nid) -> (Nid, &'a [Nid]) {
|
pub fn this_or_delegates<'a>(&'a self, source: Nid, target: &'a Nid) -> (Nid, &'a [Nid]) {
|
||||||
if self.is_unlocked(*target) {
|
if self.is_unlocked(*target) {
|
||||||
(source, core::slice::from_ref(target))
|
(source, core::slice::from_ref(target))
|
||||||
|
@ -2193,7 +2166,7 @@ pub enum Kind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kind {
|
impl Kind {
|
||||||
fn is_call(&self) -> bool {
|
pub fn is_call(&self) -> bool {
|
||||||
matches!(self, Kind::Call { .. })
|
matches!(self, Kind::Call { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -16d
|
ADDI64 r254, r254, -16d
|
||||||
LI64 r13, 10d
|
LI64 r13, 10d
|
||||||
ADDI64 r14, r254, 0d
|
|
||||||
ST r13, r254, 0a, 8h
|
ST r13, r254, 0a, 8h
|
||||||
LI64 r13, 20d
|
LI64 r13, 20d
|
||||||
ST r13, r254, 8a, 8h
|
ST r13, r254, 8a, 8h
|
||||||
LI64 r13, 6d
|
LI64 r13, 6d
|
||||||
LI64 r15, 5d
|
LI64 r14, 5d
|
||||||
LI64 r16, 1d
|
LI64 r15, 1d
|
||||||
CP r2, r16
|
CP r2, r15
|
||||||
CP r5, r15
|
LD r3, r254, 0a, 16h
|
||||||
|
CP r5, r14
|
||||||
CP r6, r13
|
CP r6, r13
|
||||||
LD r3, r14, 0a, 16h
|
|
||||||
ECA
|
ECA
|
||||||
CP r1, r0
|
CP r1, r0
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
ev: Ecall
|
ev: Ecall
|
||||||
code size: 154
|
code size: 143
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -122d
|
ADDI64 r254, r254, -98d
|
||||||
ST r31, r254, 58a, 64h
|
ST r31, r254, 58a, 40h
|
||||||
ADDI64 r32, r254, 33d
|
ADDI64 r32, r254, 33d
|
||||||
ADDI64 r33, r254, 34d
|
ADDI64 r33, r254, 34d
|
||||||
ADDI64 r34, r254, 1d
|
|
||||||
ADDI64 r35, r254, 17d
|
|
||||||
ST r32, r254, 34a, 8h
|
ST r32, r254, 34a, 8h
|
||||||
LI64 r36, 100d
|
LI64 r34, 100d
|
||||||
ADDI64 r37, r254, 0d
|
LI8 r35, 1b
|
||||||
LI8 r38, 1b
|
|
||||||
ST r0, r254, 1a, 8h
|
ST r0, r254, 1a, 8h
|
||||||
ST r0, r254, 17a, 8h
|
ST r0, r254, 17a, 8h
|
||||||
ST r36, r254, 42a, 8h
|
ST r34, r254, 42a, 8h
|
||||||
ST r38, r254, 0a, 1h
|
ST r35, r254, 0a, 1h
|
||||||
ST r0, r254, 9a, 8h
|
ST r0, r254, 9a, 8h
|
||||||
ST r0, r254, 25a, 8h
|
ST r0, r254, 25a, 8h
|
||||||
ST r36, r254, 50a, 8h
|
ST r34, r254, 50a, 8h
|
||||||
ST r0, r254, 33a, 1h
|
ST r0, r254, 33a, 1h
|
||||||
CP r2, r33
|
CP r2, r33
|
||||||
LD r3, r35, 0a, 16h
|
LD r3, r254, 17a, 16h
|
||||||
LD r5, r34, 0a, 16h
|
LD r5, r254, 1a, 16h
|
||||||
LD r7, r37, 0a, 1h
|
LD r7, r254, 0a, 1h
|
||||||
JAL r31, r0, :put_filled_rect
|
JAL r31, r0, :put_filled_rect
|
||||||
LD r31, r254, 58a, 64h
|
LD r31, r254, 58a, 40h
|
||||||
ADDI64 r254, r254, 122d
|
ADDI64 r254, r254, 98d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
put_filled_rect:
|
put_filled_rect:
|
||||||
ADDI64 r254, r254, -108d
|
ADDI64 r254, r254, -108d
|
||||||
|
@ -99,6 +96,6 @@ put_filled_rect:
|
||||||
JMP :3
|
JMP :3
|
||||||
2: ADDI64 r254, r254, 108d
|
2: ADDI64 r254, r254, 108d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 875
|
code size: 842
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -13,14 +13,14 @@ main:
|
||||||
ADDI64 r254, r254, -120d
|
ADDI64 r254, r254, -120d
|
||||||
ST r31, r254, 72a, 48h
|
ST r31, r254, 72a, 48h
|
||||||
ADDI64 r32, r254, 48d
|
ADDI64 r32, r254, 48d
|
||||||
CP r2, r0
|
|
||||||
CP r1, r32
|
CP r1, r32
|
||||||
|
CP r2, r0
|
||||||
JAL r31, r0, :decide
|
JAL r31, r0, :decide
|
||||||
ADDI64 r34, r254, 24d
|
ADDI64 r34, r254, 24d
|
||||||
BMC r32, r34, 24h
|
BMC r32, r34, 24h
|
||||||
LI64 r35, 1d
|
LI64 r35, 1d
|
||||||
CP r2, r35
|
|
||||||
CP r1, r34
|
CP r1, r34
|
||||||
|
CP r2, r35
|
||||||
JAL r31, r0, :decide
|
JAL r31, r0, :decide
|
||||||
ADDI64 r36, r254, 0d
|
ADDI64 r36, r254, 0d
|
||||||
BMC r32, r36, 24h
|
BMC r32, r36, 24h
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -72d
|
ADDI64 r254, r254, -72d
|
||||||
ST r31, r254, 32a, 40h
|
ST r31, r254, 32a, 40h
|
||||||
ADDI64 r32, r254, 8d
|
LRA r32, r0, :"Goodbye, World!\0"
|
||||||
LRA r33, r0, :"Goodbye, World!\0"
|
LRA r33, r0, :"Hello, World!\0"
|
||||||
ADDI64 r34, r254, 24d
|
ST r32, r254, 8a, 8h
|
||||||
LRA r35, r0, :"Hello, World!\0"
|
ST r33, r254, 24a, 8h
|
||||||
ST r33, r254, 8a, 8h
|
LD r2, r254, 24a, 8h
|
||||||
ST r35, r254, 24a, 8h
|
LD r3, r254, 8a, 8h
|
||||||
LD r2, r34, 0a, 8h
|
|
||||||
LD r3, r32, 0a, 8h
|
|
||||||
JAL r31, r0, :print
|
JAL r31, r0, :print
|
||||||
ADDI64 r32, r254, 0d
|
ADDI64 r34, r254, 0d
|
||||||
ADDI64 r34, r254, 16d
|
ADDI64 r35, r254, 16d
|
||||||
ST r33, r254, 0a, 8h
|
ST r32, r254, 0a, 8h
|
||||||
ST r35, r254, 16a, 8h
|
ST r33, r254, 16a, 8h
|
||||||
CP r2, r34
|
CP r2, r35
|
||||||
CP r3, r32
|
CP r3, r34
|
||||||
JAL r31, r0, :print2
|
JAL r31, r0, :print2
|
||||||
LD r31, r254, 32a, 40h
|
LD r31, r254, 32a, 40h
|
||||||
ADDI64 r254, r254, 72d
|
ADDI64 r254, r254, 72d
|
||||||
|
@ -56,6 +54,6 @@ Hello, World!
|
||||||
Goodbye, World!
|
Goodbye, World!
|
||||||
Hello, World!
|
Hello, World!
|
||||||
Goodbye, World!
|
Goodbye, World!
|
||||||
code size: 457
|
code size: 435
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -59,8 +59,8 @@ main:
|
||||||
CP r1, r32
|
CP r1, r32
|
||||||
JMP :3
|
JMP :3
|
||||||
10: LRA r36, r0, :"foo\0"
|
10: LRA r36, r0, :"foo\0"
|
||||||
CP r4, r36
|
|
||||||
LD r2, r33, 0a, 16h
|
LD r2, r33, 0a, 16h
|
||||||
|
CP r4, r36
|
||||||
JAL r31, r0, :use_foo
|
JAL r31, r0, :use_foo
|
||||||
ADDI64 r33, r254, 0d
|
ADDI64 r33, r254, 0d
|
||||||
JAL r31, r0, :no_foo
|
JAL r31, r0, :no_foo
|
||||||
|
@ -78,8 +78,8 @@ main:
|
||||||
CP r1, r32
|
CP r1, r32
|
||||||
JMP :3
|
JMP :3
|
||||||
13: ADDI64 r35, r254, 16d
|
13: ADDI64 r35, r254, 16d
|
||||||
CP r2, r34
|
|
||||||
CP r1, r35
|
CP r1, r35
|
||||||
|
CP r2, r34
|
||||||
JAL r31, r0, :new_bar
|
JAL r31, r0, :new_bar
|
||||||
JAL r31, r0, :decide
|
JAL r31, r0, :decide
|
||||||
CP r34, r1
|
CP r34, r1
|
||||||
|
|
|
@ -2,17 +2,16 @@ main:
|
||||||
ADDI64 r254, r254, -64d
|
ADDI64 r254, r254, -64d
|
||||||
ST r31, r254, 32a, 32h
|
ST r31, r254, 32a, 32h
|
||||||
LI64 r32, 4d
|
LI64 r32, 4d
|
||||||
ADDI64 r33, r254, 16d
|
|
||||||
ST r32, r254, 16a, 8h
|
ST r32, r254, 16a, 8h
|
||||||
LI64 r32, 3d
|
LI64 r32, 3d
|
||||||
ST r32, r254, 24a, 8h
|
ST r32, r254, 24a, 8h
|
||||||
ADDI64 r34, r254, 0d
|
ADDI64 r33, r254, 0d
|
||||||
LD r3, r33, 0a, 16h
|
LD r3, r254, 16a, 16h
|
||||||
JAL r31, r0, :odher_pass
|
JAL r31, r0, :odher_pass
|
||||||
ST r1, r34, 0a, 16h
|
ST r1, r33, 0a, 16h
|
||||||
LD r33, r254, 8a, 8h
|
LD r34, r254, 8a, 8h
|
||||||
JNE r33, r32, :0
|
JNE r34, r32, :0
|
||||||
CP r2, r34
|
CP r2, r33
|
||||||
JAL r31, r0, :pass
|
JAL r31, r0, :pass
|
||||||
CP r32, r1
|
CP r32, r1
|
||||||
CP r1, r32
|
CP r1, r32
|
||||||
|
@ -34,6 +33,6 @@ pass:
|
||||||
LD r13, r13, 0a, 8h
|
LD r13, r13, 0a, 8h
|
||||||
CP r1, r13
|
CP r1, r13
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 313
|
code size: 302
|
||||||
ret: 4
|
ret: 4
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
Loading…
Reference in a new issue