making a Backend trait to separate the different backends we will have in the fucture

This commit is contained in:
Jakub Doka 2024-11-05 14:52:30 +01:00
parent 276d1bb0cf
commit 87cb77a553
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
34 changed files with 958 additions and 845 deletions

1
.gitignore vendored
View file

@ -9,4 +9,5 @@ db.sqlite-journal
# assets # assets
/depell/src/*.gz /depell/src/*.gz
/depell/src/*.wasm /depell/src/*.wasm
**/*-sv.rs
/bytecode/src/instrs.rs /bytecode/src/instrs.rs

View file

@ -6,7 +6,7 @@ use {
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
hblang::{ hblang::{
parser::FileId, parser::FileId,
son::{Codegen, CodegenCtx}, son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
}, },
}; };
@ -78,14 +78,15 @@ unsafe fn compile_and_run(mut fuel: usize) {
}; };
let mut ct = { let mut ct = {
Codegen::new(&files, &mut ctx).generate(root as FileId); let mut backend = HbvmBackend::default();
Codegen::new(&mut backend, &files, &mut ctx).generate(root as FileId);
if !ctx.parser.errors.borrow().is_empty() { if !ctx.parser.errors.borrow().is_empty() {
log::error!("{}", ctx.parser.errors.borrow()); log::error!("{}", ctx.parser.errors.borrow());
return; return;
} }
let mut c = Codegen::new(&files, &mut ctx); let mut c = Codegen::new(&mut backend, &files, &mut ctx);
c.assemble_comptime() c.assemble_comptime()
}; };

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
parser::{self, Ast, Ctx, FileKind}, parser::{self, Ast, Ctx, FileKind},
son, son::{self, hbvm::HbvmBackend},
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{fmt::Write, num::NonZeroUsize, ops::Deref}, core::{fmt::Write, num::NonZeroUsize, ops::Deref},
@ -88,9 +88,10 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
let ast = parsed.ast.into_iter().next().unwrap(); let ast = parsed.ast.into_iter().next().unwrap();
write!(out, "{ast}").unwrap(); write!(out, "{ast}").unwrap();
} else { } else {
let mut backend = HbvmBackend::default();
let mut ctx = crate::son::CodegenCtx::default(); let mut ctx = crate::son::CodegenCtx::default();
*ctx.parser.errors.get_mut() = parsed.errors; *ctx.parser.errors.get_mut() = parsed.errors;
let mut codegen = son::Codegen::new(&parsed.ast, &mut ctx); let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
codegen.push_embeds(parsed.embeds); codegen.push_embeds(parsed.embeds);
codegen.generate(0); codegen.generate(0);
@ -100,12 +101,12 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
return Err(std::io::Error::other("compilation faoled")); return Err(std::io::Error::other("compilation faoled"));
} }
codegen.assemble(out);
if options.dump_asm { if options.dump_asm {
codegen let mut disasm = String::new();
.disasm(unsafe { std::mem::transmute::<&mut Vec<u8>, &mut String>(out) }) codegen.disasm(&mut disasm, out).map_err(|e| io::Error::other(e.to_string()))?;
.map_err(|e| io::Error::other(e.to_string()))?; *out = disasm.into_bytes();
} else {
codegen.assemble(out);
} }
} }

View file

@ -2,7 +2,7 @@ use {
crate::{ crate::{
lexer::TokenKind, lexer::TokenKind,
parser, parser,
son::{Codegen, CodegenCtx}, son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
}, },
alloc::string::String, alloc::string::String,
core::{fmt::Write, hash::BuildHasher, ops::Range}, core::{fmt::Write, hash::BuildHasher, ops::Range},
@ -133,7 +133,8 @@ pub fn fuzz(seed_range: Range<u64>) {
assert!(ctx.parser.errors.get_mut().is_empty()); assert!(ctx.parser.errors.get_mut().is_empty());
let mut cdg = Codegen::new(core::slice::from_ref(&parsed), &mut ctx); let mut backend = HbvmBackend::default();
let mut cdg = Codegen::new(&mut backend, core::slice::from_ref(&parsed), &mut ctx);
cdg.generate(0); cdg.generate(0);
} }
} }

View file

@ -219,26 +219,6 @@ mod ctx_map {
} }
} }
mod task {
use super::Offset;
pub fn unpack(offset: Offset) -> Result<Offset, usize> {
if offset >> 31 != 0 {
Err((offset & !(1 << 31)) as usize)
} else {
Ok(offset)
}
}
pub fn is_done(offset: Offset) -> bool {
unpack(offset).is_ok()
}
pub fn id(index: usize) -> Offset {
1 << 31 | index as u32
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
pub struct Ident(u32); pub struct Ident(u32);
@ -567,6 +547,7 @@ mod ty {
};)* };)*
} }
#[expect(dead_code)]
impl Id { impl Id {
$(pub const $name: Self = Kind::Builtin($name).compress();)* $(pub const $name: Self = Kind::Builtin($name).compress();)*
} }
@ -758,7 +739,7 @@ pub enum SymKey<'a> {
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Sig { pub struct Sig {
args: ty::Tuple, args: ty::Tuple,
ret: ty::Id, ret: ty::Id,
} }
@ -769,10 +750,7 @@ struct Func {
base: Option<ty::Func>, base: Option<ty::Func>,
expr: ExprRef, expr: ExprRef,
sig: Option<Sig>, sig: Option<Sig>,
offset: Offset, comp_state: [CompState; 2],
// TODO: change to indices into common vec
relocs: Vec<TypedReloc>,
code: Vec<u8>,
} }
impl Default for Func { impl Default for Func {
@ -783,13 +761,19 @@ impl Default for Func {
base: None, base: None,
expr: Default::default(), expr: Default::default(),
sig: None, sig: None,
offset: u32::MAX, comp_state: Default::default(),
relocs: Default::default(),
code: Default::default(),
} }
} }
} }
#[derive(Default, PartialEq, Eq)]
enum CompState {
#[default]
Dead,
Queued(usize),
Compiled,
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct TypedReloc { struct TypedReloc {
target: ty::Id, target: ty::Id,
@ -801,7 +785,6 @@ struct Global {
file: FileId, file: FileId,
name: Ident, name: Ident,
ty: ty::Id, ty: ty::Id,
offset: Offset,
data: Vec<u8>, data: Vec<u8>,
} }
@ -809,7 +792,6 @@ impl Default for Global {
fn default() -> Self { fn default() -> Self {
Self { Self {
ty: Default::default(), ty: Default::default(),
offset: u32::MAX,
data: Default::default(), data: Default::default(),
file: u32::MAX, file: u32::MAX,
name: Default::default(), name: Default::default(),
@ -947,9 +929,6 @@ impl IdentInterner {
#[derive(Default)] #[derive(Default)]
struct TypesTmp { struct TypesTmp {
fields: Vec<Field>, fields: Vec<Field>,
frontier: Vec<ty::Id>,
globals: Vec<ty::Global>,
funcs: Vec<ty::Func>,
args: Vec<ty::Id>, args: Vec<ty::Id>,
} }
@ -968,6 +947,7 @@ pub struct TypeIns {
struct FTask { struct FTask {
file: FileId, file: FileId,
id: ty::Func, id: ty::Func,
ct: bool,
} }
struct StringRef(ty::Global); struct StringRef(ty::Global);
@ -982,7 +962,7 @@ impl ctx_map::CtxEntry for StringRef {
} }
#[derive(Default)] #[derive(Default)]
struct Types { pub struct Types {
syms: ctx_map::CtxMap<ty::Id>, syms: ctx_map::CtxMap<ty::Id>,
names: IdentInterner, names: IdentInterner,
strings: ctx_map::CtxMap<StringRef>, strings: ctx_map::CtxMap<StringRef>,
@ -1222,12 +1202,6 @@ impl Types {
&self.ins.fields[self.struct_field_range(strct)] &self.ins.fields[self.struct_field_range(strct)]
} }
fn reassemble(&mut self, buf: &mut Vec<u8>) {
self.ins.funcs.iter_mut().for_each(|f| f.offset = u32::MAX);
self.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX);
self.assemble(buf)
}
fn parama(&self, ret: impl Into<ty::Id>) -> (Option<PLoc>, ParamAlloc) { fn parama(&self, ret: impl Into<ty::Id>) -> (Option<PLoc>, ParamAlloc) {
let mut iter = ParamAlloc(1..12); let mut iter = ParamAlloc(1..12);
let ret = iter.next(ret.into(), self); let ret = iter.next(ret.into(), self);
@ -1395,9 +1369,6 @@ impl Types {
self.ins.slices.clear(); self.ins.slices.clear();
debug_assert_eq!(self.tmp.fields.len(), 0); debug_assert_eq!(self.tmp.fields.len(), 0);
debug_assert_eq!(self.tmp.frontier.len(), 0);
debug_assert_eq!(self.tmp.globals.len(), 0);
debug_assert_eq!(self.tmp.funcs.len(), 0);
debug_assert_eq!(self.tmp.args.len(), 0); debug_assert_eq!(self.tmp.args.len(), 0);
debug_assert_eq!(self.tasks.len(), 0); debug_assert_eq!(self.tasks.len(), 0);

View file

@ -1,5 +1,8 @@
use { use {
self::{hbvm::Comptime, strong_ref::StrongRef}, self::{
hbvm::{Comptime, HbvmBackend},
strong_ref::StrongRef,
},
crate::{ crate::{
ctx_map::CtxEntry, ctx_map::CtxEntry,
debug, debug,
@ -9,11 +12,10 @@ use {
idfl::{self}, idfl::{self},
CtorField, Expr, FileId, Pos, CtorField, Expr, FileId, Pos,
}, },
task,
ty::{self, Arg, ArrayLen, Loc, Tuple}, ty::{self, Arg, ArrayLen, Loc, Tuple},
utils::{BitSet, Vc}, utils::{BitSet, Vc},
FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Reloc, Sig, StringRef, SymKey, CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
TypeParser, TypedReloc, Types, SymKey, TypeParser, Types,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{ core::{
@ -41,6 +43,38 @@ pub mod hbvm;
type Nid = u16; type Nid = u16;
type AClassId = i16; type AClassId = i16;
pub struct AssemblySpec {
entry: u64,
code_length: u64,
data_length: u64,
}
pub trait Backend {
fn assemble_reachable(
&mut self,
from: ty::Func,
types: &Types,
to: &mut Vec<u8>,
) -> AssemblySpec;
fn disasm<'a>(
&'a self,
sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types,
files: &'a [parser::Ast],
output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>>;
fn emit_body(&mut self, id: ty::Func, ci: &mut Nodes, tys: &Types, files: &[parser::Ast]);
fn emit_ct_body(&mut self, id: ty::Func, ci: &mut Nodes, tys: &Types, files: &[parser::Ast]) {
self.emit_body(id, ci, tys, files);
}
fn assemble_bin(&mut self, from: ty::Func, types: &Types, to: &mut Vec<u8>) {
self.assemble_reachable(from, types, to);
}
}
type Lookup = crate::ctx_map::CtxMap<Nid>; type Lookup = crate::ctx_map::CtxMap<Nid>;
impl crate::ctx_map::CtxEntry for Nid { impl crate::ctx_map::CtxEntry for Nid {
@ -71,23 +105,15 @@ macro_rules! inference {
} }
#[derive(Clone)] #[derive(Clone)]
struct Nodes { pub struct Nodes {
values: Vec<Result<Node, (Nid, debug::Trace)>>, values: Vec<Result<Node, (Nid, debug::Trace)>>,
visited: BitSet,
free: Nid, free: Nid,
lookup: Lookup, lookup: Lookup,
complete: bool,
} }
impl Default for Nodes { impl Default for Nodes {
fn default() -> Self { fn default() -> Self {
Self { Self { values: Default::default(), free: Nid::MAX, lookup: Default::default() }
values: Default::default(),
free: Nid::MAX,
lookup: Default::default(),
visited: Default::default(),
complete: false,
}
} }
} }
@ -183,15 +209,15 @@ impl Nodes {
} }
} }
fn push_up_impl(&mut self, node: Nid) { fn push_up_impl(&mut self, node: Nid, visited: &mut BitSet) {
if !self.visited.set(node) { if !visited.set(node) {
return; return;
} }
for i in 1..self[node].inputs.len() { for i in 1..self[node].inputs.len() {
let inp = self[node].inputs[i]; let inp = self[node].inputs[i];
if !self[inp].kind.is_pinned() { if !self[inp].kind.is_pinned() {
self.push_up_impl(inp); self.push_up_impl(inp, visited);
} }
} }
@ -230,32 +256,32 @@ impl Nodes {
self[deepest].outputs.push(node); self[deepest].outputs.push(node);
} }
fn collect_rpo(&mut self, node: Nid, rpo: &mut Vec<Nid>) { fn collect_rpo(&mut self, node: Nid, rpo: &mut Vec<Nid>, visited: &mut BitSet) {
if !self.is_cfg(node) || !self.visited.set(node) { if !self.is_cfg(node) || !visited.set(node) {
return; return;
} }
for i in 0..self[node].outputs.len() { for i in 0..self[node].outputs.len() {
self.collect_rpo(self[node].outputs[i], rpo); self.collect_rpo(self[node].outputs[i], rpo, visited);
} }
rpo.push(node); rpo.push(node);
} }
fn push_up(&mut self, rpo: &mut Vec<Nid>) { fn push_up(&mut self, rpo: &mut Vec<Nid>, visited: &mut BitSet) {
debug_assert!(rpo.is_empty()); debug_assert!(rpo.is_empty());
self.collect_rpo(VOID, rpo); self.collect_rpo(VOID, rpo, visited);
for &node in rpo.iter().rev() { for &node in rpo.iter().rev() {
self.loop_depth(node); self.loop_depth(node);
for i in 0..self[node].inputs.len() { for i in 0..self[node].inputs.len() {
self.push_up_impl(self[node].inputs[i]); self.push_up_impl(self[node].inputs[i], visited);
} }
if matches!(self[node].kind, Kind::Loop | Kind::Region) { if matches!(self[node].kind, Kind::Loop | Kind::Region) {
for i in 0..self[node].outputs.len() { for i in 0..self[node].outputs.len() {
let usage = self[node].outputs[i]; let usage = self[node].outputs[i];
if self[usage].kind == Kind::Phi { if self[usage].kind == Kind::Phi {
self.push_up_impl(usage); self.push_up_impl(usage, visited);
} }
} }
} }
@ -264,13 +290,13 @@ impl Nodes {
debug_assert_eq!( debug_assert_eq!(
self.iter() self.iter()
.map(|(n, _)| n) .map(|(n, _)| n)
.filter(|&n| !self.visited.get(n) .filter(|&n| !visited.get(n)
&& !matches!(self[n].kind, Kind::Arg | Kind::Mem | Kind::Loops)) && !matches!(self[n].kind, Kind::Arg | Kind::Mem | Kind::Loops))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
vec![], vec![],
"{:?}", "{:?}",
self.iter() self.iter()
.filter(|&(n, nod)| !self.visited.get(n) .filter(|&(n, nod)| !visited.get(n)
&& !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops)) && !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops))
.collect::<Vec<_>>() .collect::<Vec<_>>()
); );
@ -295,20 +321,20 @@ impl Nodes {
} }
} }
fn push_down(&mut self, node: Nid) { fn push_down(&mut self, node: Nid, visited: &mut BitSet) {
if !self.visited.set(node) { if !visited.set(node) {
return; return;
} }
for usage in self[node].outputs.clone() { for usage in self[node].outputs.clone() {
if self.is_forward_edge(usage, node) && self[node].kind == Kind::Stre { if self.is_forward_edge(usage, node) && self[node].kind == Kind::Stre {
self.push_down(usage); self.push_down(usage, visited);
} }
} }
for usage in self[node].outputs.clone() { for usage in self[node].outputs.clone() {
if self.is_forward_edge(usage, node) { if self.is_forward_edge(usage, node) {
self.push_down(usage); self.push_down(usage, visited);
} }
} }
@ -488,12 +514,7 @@ impl Nodes {
} }
} }
fn graphviz_low( fn graphviz_low(&self, disp: ty::Display, out: &mut String) -> core::fmt::Result {
&self,
tys: &Types,
files: &[parser::Ast],
out: &mut String,
) -> core::fmt::Result {
use core::fmt::Write; use core::fmt::Write;
writeln!(out)?; writeln!(out)?;
@ -518,7 +539,7 @@ impl Nodes {
out, out,
" node{i}[label=\"{i} {} {} {}\" color={color}]", " node{i}[label=\"{i} {} {} {}\" color={color}]",
node.kind, node.kind,
ty::Display::new(tys, files, node.ty), disp.rety(node.ty),
node.aclass, node.aclass,
)?; )?;
} else { } else {
@ -545,17 +566,17 @@ impl Nodes {
Ok(()) Ok(())
} }
fn graphviz(&self, tys: &Types, files: &[parser::Ast]) { fn graphviz(&self, disp: ty::Display) {
let out = &mut String::new(); let out = &mut String::new();
_ = self.graphviz_low(tys, files, out); _ = self.graphviz_low(disp, out);
log::info!("{out}"); log::info!("{out}");
} }
fn graphviz_in_browser(&self, _tys: &Types, _files: &[parser::Ast]) { fn graphviz_in_browser(&self, disp: ty::Display) {
#[cfg(all(debug_assertions, feature = "std"))] #[cfg(all(debug_assertions, feature = "std"))]
{ {
let out = &mut String::new(); let out = &mut String::new();
_ = self.graphviz_low(_tys, _files, out); _ = self.graphviz_low(disp, out);
if !std::process::Command::new("brave") if !std::process::Command::new("brave")
.arg(format!("https://dreampuf.github.io/GraphvizOnline/#{out}")) .arg(format!("https://dreampuf.github.io/GraphvizOnline/#{out}"))
.status() .status()
@ -567,24 +588,22 @@ impl Nodes {
} }
} }
fn gcm(&mut self, rpo: &mut Vec<Nid>) { fn gcm(&mut self, rpo: &mut Vec<Nid>, visited: &mut BitSet) {
self.fix_loops(); self.fix_loops();
self.visited.clear(self.values.len()); visited.clear(self.values.len());
self.push_up(rpo); self.push_up(rpo, visited);
self.visited.clear(self.values.len()); visited.clear(self.values.len());
self.push_down(VOID); self.push_down(VOID, visited);
} }
fn clear(&mut self) { fn clear(&mut self) {
self.values.clear(); self.values.clear();
self.lookup.clear(); self.lookup.clear();
self.free = Nid::MAX; self.free = Nid::MAX;
self.complete = false;
} }
fn new_node_nop(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid { fn new_node_nop(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid {
let node = let node = Node { inputs: inps.into(), kind, ty, ..Default::default() };
Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() };
if node.kind == Kind::Phi && node.ty != ty::Id::VOID { if node.kind == Kind::Phi && node.ty != ty::Id::VOID {
debug_assert_ne!( debug_assert_ne!(
@ -765,7 +784,7 @@ impl Nodes {
stack.iter().skip(prev_len).for_each(|&n| self.lock(n)); stack.iter().skip(prev_len).for_each(|&n| self.lock(n));
} }
pub fn aclass_index(&self, region: Nid) -> (usize, Nid) { fn aclass_index(&self, region: Nid) -> (usize, Nid) {
if self[region].aclass >= 0 { if self[region].aclass >= 0 {
(self[region].aclass as _, region) (self[region].aclass as _, region)
} else { } else {
@ -1336,9 +1355,6 @@ impl Nodes {
#[expect(clippy::format_in_format_args)] #[expect(clippy::format_in_format_args)]
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> core::fmt::Result { fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> core::fmt::Result {
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
write!(out, " {node:>2}-c{:>2}: ", self[node].ralloc_backref)?;
}
match self[node].kind { match self[node].kind {
Kind::Assert { .. } | Kind::Start => unreachable!("{} {out}", self[node].kind), Kind::Assert { .. } | Kind::Start => unreachable!("{} {out}", self[node].kind),
Kind::End => return Ok(()), Kind::End => return Ok(()),
@ -1382,9 +1398,14 @@ impl Nodes {
Ok(()) Ok(())
} }
fn basic_blocks_low(&mut self, out: &mut String, mut node: Nid) -> core::fmt::Result { fn basic_blocks_low(
&mut self,
out: &mut String,
mut node: Nid,
visited: &mut BitSet,
) -> core::fmt::Result {
let iter = |nodes: &Nodes, node| nodes[node].outputs.clone().into_iter().rev(); let iter = |nodes: &Nodes, node| nodes[node].outputs.clone().into_iter().rev();
while self.visited.set(node) { while visited.set(node) {
match self[node].kind { match self[node].kind {
Kind::Start => { Kind::Start => {
writeln!(out, "start: {}", self[node].depth.get())?; writeln!(out, "start: {}", self[node].depth.get())?;
@ -1399,7 +1420,7 @@ impl Nodes {
} }
Kind::End => break, Kind::End => break,
Kind::If => { Kind::If => {
self.basic_blocks_low(out, self[node].outputs[0])?; self.basic_blocks_low(out, self[node].outputs[0], visited)?;
node = self[node].outputs[1]; node = self[node].outputs[1];
} }
Kind::Region => { Kind::Region => {
@ -1480,8 +1501,8 @@ impl Nodes {
fn basic_blocks(&mut self) { fn basic_blocks(&mut self) {
let mut out = String::new(); let mut out = String::new();
self.visited.clear(self.values.len()); let mut visited = BitSet::default();
self.basic_blocks_low(&mut out, VOID).unwrap(); self.basic_blocks_low(&mut out, VOID, &mut visited).unwrap();
log::info!("{out}"); log::info!("{out}");
} }
@ -1489,7 +1510,7 @@ impl Nodes {
self[o].kind.is_cfg() self[o].kind.is_cfg()
} }
fn check_final_integrity(&self, tys: &Types, files: &[parser::Ast]) { fn check_final_integrity(&self, disp: ty::Display) {
if !cfg!(debug_assertions) { if !cfg!(debug_assertions) {
return; return;
} }
@ -1517,7 +1538,7 @@ impl Nodes {
} }
if failed { if failed {
self.graphviz_in_browser(tys, files); self.graphviz_in_browser(disp);
panic!() panic!()
} }
} }
@ -1743,8 +1764,6 @@ pub struct Node {
peep_triggers: Vc, peep_triggers: Vc,
clobbers: BitSet, clobbers: BitSet,
ty: ty::Id, ty: ty::Id,
offset: Offset,
ralloc_backref: RallocBRef,
depth: Cell<IDomDepth>, depth: Cell<IDomDepth>,
lock_rc: LockRc, lock_rc: LockRc,
loop_depth: LoopDepth, loop_depth: LoopDepth,
@ -1963,7 +1982,7 @@ impl Scope {
} }
#[derive(Default, Clone)] #[derive(Default, Clone)]
struct ItemCtx { pub struct ItemCtx {
file: FileId, file: FileId,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
@ -1973,25 +1992,19 @@ struct ItemCtx {
inline_ret: Option<(Value, StrongRef, Scope)>, inline_ret: Option<(Value, StrongRef, Scope)>,
nodes: Nodes, nodes: Nodes,
ctrl: StrongRef, ctrl: StrongRef,
call_count: u16,
loops: Vec<Loop>, loops: Vec<Loop>,
scope: Scope, scope: Scope,
ret_relocs: Vec<Reloc>,
relocs: Vec<TypedReloc>,
jump_relocs: Vec<(Nid, Reloc)>,
code: Vec<u8>,
} }
impl ItemCtx { impl ItemCtx {
fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) { fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) {
debug_assert_eq!(self.loops.len(), 0); debug_assert_eq!(self.loops.len(), 0);
debug_assert_eq!(self.scope.vars.len(), 0); debug_assert_eq!(self.scope.vars.len(), 0);
debug_assert_eq!(self.ret_relocs.len(), 0); debug_assert_eq!(self.scope.aclasses.len(), 0);
debug_assert_eq!(self.relocs.len(), 0); debug_assert!(self.inline_ret.is_none());
debug_assert_eq!(self.jump_relocs.len(), 0); debug_assert_eq!(self.inline_depth, 0);
debug_assert_eq!(self.code.len(), 0); debug_assert_eq!(self.inline_var_base, 0);
debug_assert_eq!(self.inline_aclass_base, 0);
self.call_count = 0;
self.file = file; self.file = file;
self.ret = ret; self.ret = ret;
@ -2043,21 +2056,21 @@ struct Ctx {
} }
impl Ctx { impl Ctx {
pub fn with_ty(self, ty: ty::Id) -> Self { fn with_ty(self, ty: ty::Id) -> Self {
Self { ty: Some(ty) } Self { ty: Some(ty) }
} }
} }
#[derive(Default)] #[derive(Default)]
struct Pool { pub struct Pool {
cis: Vec<ItemCtx>, cis: Vec<ItemCtx>,
used_cis: usize, used_cis: usize,
ralloc: Regalloc,
nid_stack: Vec<Nid>, nid_stack: Vec<Nid>,
nid_set: BitSet,
} }
impl Pool { impl Pool {
pub fn push_ci( fn push_ci(
&mut self, &mut self,
file: FileId, file: FileId,
ret: Option<ty::Id>, ret: Option<ty::Id>,
@ -2074,7 +2087,7 @@ impl Pool {
self.used_cis += 1; self.used_cis += 1;
} }
pub fn pop_ci(&mut self, target: &mut ItemCtx) { fn pop_ci(&mut self, target: &mut ItemCtx) {
self.used_cis -= 1; self.used_cis -= 1;
mem::swap(&mut self.cis[self.used_cis], target); mem::swap(&mut self.cis[self.used_cis], target);
} }
@ -2100,33 +2113,6 @@ impl Pool {
} }
} }
struct Regalloc {
env: regalloc2::MachineEnv,
ctx: regalloc2::Ctx,
}
impl Default for Regalloc {
fn default() -> Self {
Self {
env: regalloc2::MachineEnv {
preferred_regs_by_class: [
(1..13).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
vec![],
vec![],
],
non_preferred_regs_by_class: [
(13..64).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
vec![],
vec![],
],
scratch_by_class: Default::default(),
fixed_stack_slots: Default::default(),
},
ctx: Default::default(),
}
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)] #[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
struct Value { struct Value {
ty: ty::Id, ty: ty::Id,
@ -2140,20 +2126,20 @@ impl Value {
Some(Self { ty: ty::Id::NEVER, var: false, ptr: false, id: NEVER }); Some(Self { ty: ty::Id::NEVER, var: false, ptr: false, id: NEVER });
const VOID: Value = Self { ty: ty::Id::VOID, var: false, ptr: false, id: VOID }; const VOID: Value = Self { ty: ty::Id::VOID, var: false, ptr: false, id: VOID };
pub fn new(id: Nid) -> Self { fn new(id: Nid) -> Self {
Self { id, ..Default::default() } Self { id, ..Default::default() }
} }
pub fn var(id: usize) -> Self { fn var(id: usize) -> Self {
Self { id: u16::MAX - (id as Nid), var: true, ..Default::default() } Self { id: u16::MAX - (id as Nid), var: true, ..Default::default() }
} }
pub fn ptr(id: Nid) -> Self { fn ptr(id: Nid) -> Self {
Self { id, ptr: true, ..Default::default() } Self { id, ptr: true, ..Default::default() }
} }
#[inline(always)] #[inline(always)]
pub fn ty(self, ty: impl Into<ty::Id>) -> Self { fn ty(self, ty: impl Into<ty::Id>) -> Self {
Self { ty: ty.into(), ..self } Self { ty: ty.into(), ..self }
} }
} }
@ -2164,6 +2150,7 @@ pub struct CodegenCtx {
tys: Types, tys: Types,
pool: Pool, pool: Pool,
ct: Comptime, ct: Comptime,
ct_backend: HbvmBackend,
} }
impl CodegenCtx { impl CodegenCtx {
@ -2200,10 +2187,16 @@ pub struct Codegen<'a> {
ci: ItemCtx, ci: ItemCtx,
pool: &'a mut Pool, pool: &'a mut Pool,
ct: &'a mut Comptime, ct: &'a mut Comptime,
ct_backend: &'a mut HbvmBackend,
backend: &'a mut dyn Backend,
} }
impl<'a> Codegen<'a> { impl<'a> Codegen<'a> {
pub fn new(files: &'a [parser::Ast], ctx: &'a mut CodegenCtx) -> Self { pub fn new(
backend: &'a mut dyn Backend,
files: &'a [parser::Ast],
ctx: &'a mut CodegenCtx,
) -> Self {
Self { Self {
files, files,
errors: Errors(&ctx.parser.errors), errors: Errors(&ctx.parser.errors),
@ -2211,9 +2204,46 @@ impl<'a> Codegen<'a> {
ci: Default::default(), ci: Default::default(),
pool: &mut ctx.pool, pool: &mut ctx.pool,
ct: &mut ctx.ct, ct: &mut ctx.ct,
ct_backend: &mut ctx.ct_backend,
backend,
} }
} }
pub fn generate(&mut self, entry: FileId) {
self.find_type(0, entry, entry, Err("main"), self.files);
if self.tys.ins.funcs.is_empty() {
return;
}
self.make_func_reachable(0);
self.complete_call_graph();
}
pub fn assemble_comptime(&mut self) -> Comptime {
self.ct.code.clear();
self.ct_backend.assemble_bin(0, self.tys, &mut self.ct.code);
self.ct.reset();
core::mem::take(self.ct)
}
pub fn assemble(&mut self, buf: &mut Vec<u8>) {
self.backend.assemble_bin(0, self.tys, buf);
}
pub fn disasm(&mut self, output: &mut String, bin: &[u8]) -> Result<(), DisasmError> {
self.backend.disasm(bin, &mut |_| {}, self.tys, self.files, output)
}
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
self.tys.ins.globals = embeds
.into_iter()
.map(|data| Global {
ty: self.tys.make_array(ty::Id::U8, data.len() as _),
data,
..Default::default()
})
.collect();
}
fn emit_and_eval(&mut self, file: FileId, ret: ty::Id, ret_loc: &mut [u8]) -> u64 { fn emit_and_eval(&mut self, file: FileId, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
let mut rets = let mut rets =
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return); self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
@ -2231,46 +2261,33 @@ impl<'a> Codegen<'a> {
return 1; return 1;
} }
self.ci.emit_ct_body(self.tys, self.files, Sig { args: Tuple::empty(), ret }, self.pool); let fuc = self.tys.ins.funcs.len() as ty::Func;
self.tys.ins.funcs.push(Func {
let func = Func {
file, file,
relocs: mem::take(&mut self.ci.relocs), sig: Some(Sig { args: Tuple::empty(), ret }),
code: mem::take(&mut self.ci.code),
..Default::default() ..Default::default()
}; });
self.ct_backend.emit_ct_body(fuc, &mut self.ci.nodes, self.tys, self.files);
// TODO: return them back // TODO: return them back
let fuc = self.tys.ins.funcs.len() as ty::Func;
self.tys.ins.funcs.push(func);
self.tys.dump_reachable(fuc, &mut self.ct.code); let entry =
self.dump_ct_asm(); self.ct_backend.assemble_reachable(fuc, self.tys, &mut self.ct.code).entry as u32;
self.ct.run(ret_loc, self.tys.ins.funcs[fuc as usize].offset)
}
fn dump_ct_asm(&self) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let mut vc = String::new(); let mut vc = String::new();
if let Err(e) = self.tys.disasm(&self.ct.code, self.files, &mut vc, |_| {}) { if let Err(e) =
self.ct_backend.disasm(&self.ct.code, &mut |_| {}, self.tys, self.files, &mut vc)
{
panic!("{e} {}", vc); panic!("{e} {}", vc);
} else { } else {
log::trace!("{}", vc); log::trace!("{}", vc);
} }
} }
}
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) { self.ct.run(ret_loc, entry)
self.tys.ins.globals = embeds
.into_iter()
.map(|data| Global {
ty: self.tys.make_array(ty::Id::U8, data.len() as _),
data,
..Default::default()
})
.collect();
} }
fn new_stack(&mut self, ty: ty::Id) -> Nid { fn new_stack(&mut self, ty: ty::Id) -> Nid {
@ -2348,12 +2365,12 @@ impl<'a> Codegen<'a> {
debug_assert_ne!(region, VOID); debug_assert_ne!(region, VOID);
debug_assert_ne!({ self.ci.nodes[region].ty }, ty::Id::VOID, "{:?}", { debug_assert_ne!({ self.ci.nodes[region].ty }, ty::Id::VOID, "{:?}", {
self.ci.nodes[region].lock_rc = Nid::MAX; self.ci.nodes[region].lock_rc = Nid::MAX;
self.ci.nodes.graphviz_in_browser(self.tys, self.files); self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID));
}); });
debug_assert!( debug_assert!(
self.ci.nodes[region].kind != Kind::Load || self.ci.nodes[region].ty.is_pointer(), self.ci.nodes[region].kind != Kind::Load || self.ci.nodes[region].ty.is_pointer(),
"{:?} {} {}", "{:?} {} {}",
self.ci.nodes.graphviz_in_browser(self.tys, self.files), self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID)),
self.file().path, self.file().path,
self.ty_display(self.ci.nodes[region].ty) self.ty_display(self.ci.nodes[region].ty)
); );
@ -2365,37 +2382,12 @@ impl<'a> Codegen<'a> {
self.ci.nodes.new_node(ty, Kind::Load, vc) self.ci.nodes.new_node(ty, Kind::Load, vc)
} }
pub fn generate(&mut self, entry: FileId) {
self.find_type(0, entry, entry, Err("main"), self.files);
if self.tys.ins.funcs.is_empty() {
return;
}
self.make_func_reachable(0);
self.complete_call_graph();
}
pub fn assemble_comptime(&mut self) -> Comptime {
self.ct.code.clear();
self.tys.reassemble(&mut self.ct.code);
self.ct.reset();
core::mem::take(self.ct)
}
pub fn assemble(&mut self, buf: &mut Vec<u8>) {
self.tys.reassemble(buf);
}
pub fn disasm(&mut self, output: &mut String) -> Result<(), DisasmError> {
let mut bin = Vec::new();
self.assemble(&mut bin);
self.tys.disasm(&bin, self.files, output, |_| {})
}
fn make_func_reachable(&mut self, func: ty::Func) { fn make_func_reachable(&mut self, func: ty::Func) {
let state_slot = self.ct.active() as usize;
let fuc = &mut self.tys.ins.funcs[func as usize]; let fuc = &mut self.tys.ins.funcs[func as usize];
if fuc.offset == u32::MAX { if fuc.comp_state[state_slot] == CompState::Dead {
fuc.offset = task::id(self.tys.tasks.len() as _); fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func })); self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() }));
} }
} }
@ -3072,7 +3064,6 @@ impl<'a> Codegen<'a> {
alt_value.or(Some(Value::new(self.ci.ctrl.get()).ty(ty))) alt_value.or(Some(Value::new(self.ci.ctrl.get()).ty(ty)))
} }
Expr::Call { func, args, .. } => { Expr::Call { func, args, .. } => {
self.ci.call_count += 1;
let ty = self.ty(func); let ty = self.ty(func);
let ty::Kind::Func(mut fu) = ty.expand() else { let ty::Kind::Func(mut fu) = ty.expand() else {
self.report( self.report(
@ -4005,10 +3996,12 @@ impl<'a> Codegen<'a> {
self.errors.borrow().len() == prev_err_len self.errors.borrow().len() == prev_err_len
} }
fn emit_func(&mut self, FTask { file, id }: FTask) { fn emit_func(&mut self, FTask { file, id, ct }: FTask) {
let func = &mut self.tys.ins.funcs[id as usize]; let func = &mut self.tys.ins.funcs[id as usize];
debug_assert_eq!(func.file, file); debug_assert_eq!(func.file, file);
func.offset = u32::MAX - 1; let cct = self.ct.active();
debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled;
let sig = func.sig.expect("to emmit only concrete functions"); let sig = func.sig.expect("to emmit only concrete functions");
let ast = &self.files[file as usize]; let ast = &self.files[file as usize];
let expr = func.expr.get(ast); let expr = func.expr.get(ast);
@ -4075,9 +4068,8 @@ impl<'a> Codegen<'a> {
self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes)); self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes));
if self.finalize(prev_err_len) { if self.finalize(prev_err_len) {
self.ci.emit_body(self.tys, self.files, sig, self.pool); let backend = if !cct { &mut *self.backend } else { &mut *self.ct_backend };
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code); backend.emit_body(id, &mut self.ci.nodes, self.tys, self.files);
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
} }
self.pool.pop_ci(&mut self.ci); self.pool.pop_ci(&mut self.ci);
@ -4087,6 +4079,7 @@ impl<'a> Codegen<'a> {
use {AssertKind as AK, CondOptRes as CR}; use {AssertKind as AK, CondOptRes as CR};
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files); self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
let mut to_remove = vec![]; let mut to_remove = vec![];
for (id, node) in self.ci.nodes.iter() { for (id, node) in self.ci.nodes.iter() {
let Kind::Assert { kind, pos } = node.kind else { continue }; let Kind::Assert { kind, pos } = node.kind else { continue };
@ -4153,7 +4146,17 @@ impl<'a> Codegen<'a> {
self.ci.nodes[n].outputs.iter().map(|&o| &self.ci.nodes[o]).collect::<Vec<_>>(), self.ci.nodes[n].outputs.iter().map(|&o| &self.ci.nodes[o]).collect::<Vec<_>>(),
); );
}); });
self.ci.unlock(); self.ci.unlock();
if self.errors.borrow().len() == prev_err_len {
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.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
self.ci.nodes.basic_blocks();
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
}
self.errors.borrow().len() == prev_err_len self.errors.borrow().len() == prev_err_len
} }
@ -4399,6 +4402,7 @@ impl TypeParser for Codegen<'_> {
} }
fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 { fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 {
self.ct.activate();
let mut scope = mem::take(&mut self.ci.scope.vars); let mut scope = mem::take(&mut self.ci.scope.vars);
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci); self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci);
self.ci.scope.vars = scope; self.ci.scope.vars = scope;
@ -4415,6 +4419,7 @@ impl TypeParser for Codegen<'_> {
self.pool.pop_ci(&mut self.ci); self.pool.pop_ci(&mut self.ci);
self.ci.scope.vars = scope; self.ci.scope.vars = scope;
self.ct.deactivate();
res res
} }
@ -4427,18 +4432,21 @@ impl TypeParser for Codegen<'_> {
} }
fn on_reuse(&mut self, existing: ty::Id) { fn on_reuse(&mut self, existing: ty::Id) {
let state_slot = self.ct.active() as usize;
if let ty::Kind::Func(id) = existing.expand() if let ty::Kind::Func(id) = existing.expand()
&& let func = &mut self.tys.ins.funcs[id as usize] && let func = &mut self.tys.ins.funcs[id as usize]
&& let Err(idx) = task::unpack(func.offset) && let CompState::Queued(idx) = func.comp_state[state_slot]
&& idx < self.tys.tasks.len() && idx < self.tys.tasks.len()
{ {
func.offset = task::id(self.tys.tasks.len()); func.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len());
let task = self.tys.tasks[idx].take(); let task = self.tys.tasks[idx].take();
self.tys.tasks.push(task); self.tys.tasks.push(task);
} }
} }
fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id { fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id {
self.ct.activate();
let gid = self.tys.ins.globals.len() as ty::Global; let gid = self.tys.ins.globals.len() as ty::Global;
self.tys.ins.globals.push(Global { file, name, ..Default::default() }); self.tys.ins.globals.push(Global { file, name, ..Default::default() });
@ -4458,6 +4466,7 @@ impl TypeParser for Codegen<'_> {
self.pool.pop_ci(&mut self.ci); self.pool.pop_ci(&mut self.ci);
self.tys.ins.globals[gid as usize].ty = ret; self.tys.ins.globals[gid as usize].ty = ret;
self.ct.deactivate();
ty.compress() ty.compress()
} }
@ -4475,7 +4484,7 @@ impl TypeParser for Codegen<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use { use {
super::CodegenCtx, super::{hbvm::HbvmBackend, CodegenCtx},
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::fmt::Write, core::fmt::Write,
}; };
@ -4487,7 +4496,8 @@ mod tests {
let mut ctx = CodegenCtx::default(); let mut ctx = CodegenCtx::default();
let (ref files, embeds) = crate::test_parse_files(ident, input, &mut ctx.parser); let (ref files, embeds) = crate::test_parse_files(ident, input, &mut ctx.parser);
let mut codegen = super::Codegen::new(files, &mut ctx); let mut backend = HbvmBackend::default();
let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx);
codegen.push_embeds(embeds); codegen.push_embeds(embeds);
codegen.generate(0); codegen.generate(0);
@ -4501,9 +4511,9 @@ mod tests {
} }
let mut out = Vec::new(); let mut out = Vec::new();
codegen.tys.reassemble(&mut out); codegen.assemble(&mut out);
let err = codegen.tys.disasm(&out, codegen.files, output, |_| {}); let err = codegen.disasm(output, &out);
if let Err(e) = err { if let Err(e) = err {
writeln!(output, "!!! asm is invalid: {e}").unwrap(); writeln!(output, "!!! asm is invalid: {e}").unwrap();
return; return;

View file

@ -1,10 +1,9 @@
use { use {
super::{ItemCtx, Nid, Nodes, Pool, RallocBRef, Regalloc, ARG_START, NEVER, VOID}, super::{AssemblySpec, Backend, ItemCtx, Nid, Nodes, RallocBRef, ARG_START, NEVER, VOID},
crate::{ crate::{
lexer::TokenKind, lexer::TokenKind,
parser, reg, parser, reg,
son::{write_reloc, Kind, MEM}, son::{write_reloc, Kind, MEM},
task,
ty::{self, Arg, Loc}, ty::{self, Arg, Loc},
utils::{BitSet, Vc}, utils::{BitSet, Vc},
HashMap, Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types, HashMap, Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types,
@ -14,139 +13,94 @@ use {
hbbytecode::{self as instrs, *}, hbbytecode::{self as instrs, *},
}; };
impl Types { struct FuncDt {
pub fn assemble(&mut self, to: &mut Vec<u8>) { offset: Offset,
to.extend([0u8; HEADER_SIZE]); // TODO: change to indices into common vec
relocs: Vec<TypedReloc>,
code: Vec<u8>,
}
binary_prelude(to); impl Default for FuncDt {
let exe = self.dump_reachable(0, to); fn default() -> Self {
Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, self.ins.funcs[0].offset, 0); Self { offset: u32::MAX, relocs: Default::default(), code: Default::default() }
unsafe { *to.as_mut_ptr().cast::<AbleOsExecutableHeader>() = exe }
}
pub fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec<u8>) -> AbleOsExecutableHeader {
debug_assert!(self.tmp.frontier.is_empty());
debug_assert!(self.tmp.funcs.is_empty());
debug_assert!(self.tmp.globals.is_empty());
self.tmp.frontier.push(ty::Kind::Func(from).compress());
while let Some(itm) = self.tmp.frontier.pop() {
match itm.expand() {
ty::Kind::Func(func) => {
let fuc = &mut self.ins.funcs[func as usize];
if task::is_done(fuc.offset) {
continue;
}
fuc.offset = 0;
self.tmp.funcs.push(func);
self.tmp.frontier.extend(fuc.relocs.iter().map(|r| r.target));
}
ty::Kind::Global(glob) => {
let glb = &mut self.ins.globals[glob as usize];
if task::is_done(glb.offset) {
continue;
}
glb.offset = 0;
self.tmp.globals.push(glob);
}
_ => unreachable!(),
}
}
for &func in &self.tmp.funcs {
let fuc = &mut self.ins.funcs[func as usize];
fuc.offset = to.len() as _;
debug_assert!(!fuc.code.is_empty());
to.extend(&fuc.code);
}
let code_length = to.len();
for global in self.tmp.globals.drain(..) {
let global = &mut self.ins.globals[global as usize];
global.offset = to.len() as _;
to.extend(&global.data);
}
let data_length = to.len() - code_length;
for func in self.tmp.funcs.drain(..) {
let fuc = &self.ins.funcs[func as usize];
for rel in &fuc.relocs {
let offset = match rel.target.expand() {
ty::Kind::Func(fun) => self.ins.funcs[fun as usize].offset,
ty::Kind::Global(glo) => self.ins.globals[glo as usize].offset,
_ => unreachable!(),
};
rel.reloc.apply_jump(to, offset, fuc.offset);
}
}
AbleOsExecutableHeader {
magic_number: [0x15, 0x91, 0xD2],
executable_version: 0,
code_length: code_length.saturating_sub(HEADER_SIZE) as _,
data_length: data_length as _,
debug_length: 0,
config_length: 0,
metadata_length: 0,
}
}
pub fn disasm<'a>(
&'a self,
mut sluce: &[u8],
files: &'a [parser::Ast],
output: &mut String,
eca_handler: impl FnMut(&mut &[u8]),
) -> Result<(), hbbytecode::DisasmError<'a>> {
use hbbytecode::DisasmItem;
let functions = self
.ins
.funcs
.iter()
.filter(|f| task::is_done(f.offset))
.map(|f| {
let name = if f.file != u32::MAX {
let file = &files[f.file as usize];
file.ident_str(f.name)
} else {
"target_fn"
};
(f.offset, (name, f.code.len() as u32, DisasmItem::Func))
})
.chain(self.ins.globals.iter().filter(|g| task::is_done(g.offset)).map(|g| {
let name = if g.file == u32::MAX {
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else {
let file = &files[g.file as usize];
file.ident_str(g.name)
};
(g.offset, (name, g.data.len() as Size, DisasmItem::Global))
}))
.collect::<BTreeMap<_, _>>();
hbbytecode::disasm(&mut sluce, &functions, output, eca_handler)
} }
} }
impl ItemCtx { struct GlobalDt {
offset: Offset,
}
impl Default for GlobalDt {
fn default() -> Self {
Self { offset: u32::MAX }
}
}
#[derive(Default)]
struct Assembler {
frontier: Vec<ty::Id>,
globals: Vec<ty::Global>,
funcs: Vec<ty::Func>,
}
struct Regalloc {
env: regalloc2::MachineEnv,
ctx: regalloc2::Ctx,
}
impl Default for Regalloc {
fn default() -> Self {
Self {
env: regalloc2::MachineEnv {
preferred_regs_by_class: [
(1..13).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
vec![],
vec![],
],
non_preferred_regs_by_class: [
(13..64).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
vec![],
vec![],
],
scratch_by_class: Default::default(),
fixed_stack_slots: Default::default(),
},
ctx: Default::default(),
}
}
}
#[derive(Default)]
pub struct HbvmBackend {
funcs: Vec<FuncDt>,
globals: Vec<GlobalDt>,
asm: Assembler,
ralloc: Regalloc,
ret_relocs: Vec<Reloc>,
relocs: Vec<TypedReloc>,
jump_relocs: Vec<(Nid, Reloc)>,
code: Vec<u8>,
offsets: Vec<Offset>,
}
impl HbvmBackend {
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) { fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
emit(&mut self.code, instr); emit(&mut self.code, instr);
} }
fn emit_body_code( fn emit_body_code(
&mut self, &mut self,
nodes: &mut Nodes,
sig: Sig, sig: Sig,
tys: &Types, tys: &Types,
files: &[parser::Ast], files: &[parser::Ast],
ralloc: &mut Regalloc, ) -> (usize, bool) {
) -> usize { let mut ralloc = mem::take(&mut self.ralloc);
let mut nodes = mem::take(&mut self.nodes);
let fuc = Function::new(&mut nodes, tys, sig); let fuc = Function::new(nodes, tys, sig);
log::info!("{:?}", fuc); log::info!("{:?}", fuc);
if self.call_count != 0 { if !fuc.tail {
mem::swap( mem::swap(
&mut ralloc.env.preferred_regs_by_class, &mut ralloc.env.preferred_regs_by_class,
&mut ralloc.env.non_preferred_regs_by_class, &mut ralloc.env.non_preferred_regs_by_class,
@ -164,12 +118,12 @@ impl ItemCtx {
fuc.nodes[vreg.vreg() as Nid].lock_rc = Nid::MAX; fuc.nodes[vreg.vreg() as Nid].lock_rc = Nid::MAX;
fuc.nodes[fuc.instrs[inst.index()].nid].lock_rc = Nid::MAX - 1; fuc.nodes[fuc.instrs[inst.index()].nid].lock_rc = Nid::MAX - 1;
} }
fuc.nodes.graphviz_in_browser(tys, files); fuc.nodes.graphviz_in_browser(ty::Display::new(tys, files, ty::Id::VOID));
panic!("{err}") panic!("{err}")
}, },
); );
if self.call_count != 0 { if !fuc.tail {
mem::swap( mem::swap(
&mut ralloc.env.preferred_regs_by_class, &mut ralloc.env.preferred_regs_by_class,
&mut ralloc.env.non_preferred_regs_by_class, &mut ralloc.env.non_preferred_regs_by_class,
@ -187,6 +141,11 @@ impl ItemCtx {
*saved_regs.entry(hvenc).or_insert(would_insert) *saved_regs.entry(hvenc).or_insert(would_insert)
}; };
'_open_function: {
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
self.emit(instrs::st(reg::RET_ADDR + fuc.tail as u8, reg::STACK_PTR, 0, 0));
}
let (retl, mut parama) = tys.parama(sig.ret); let (retl, mut parama) = tys.parama(sig.ret);
let mut typs = sig.args.args(); let mut typs = sig.args.args();
let mut args = fuc.nodes[VOID].outputs[ARG_START..].iter(); let mut args = fuc.nodes[VOID].outputs[ARG_START..].iter();
@ -199,15 +158,15 @@ impl ItemCtx {
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::Reg(..) | PLoc::Ref(..) => continue, PLoc::Reg(..) | PLoc::Ref(..) => continue,
}; };
self.emit(instrs::st(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _, size)); self.emit(instrs::st(rg, reg::STACK_PTR, self.offsets[arg as usize] as _, size));
if fuc.nodes[arg].lock_rc == 0 { if fuc.nodes[arg].lock_rc == 0 {
self.emit(instrs::addi64(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _)); self.emit(instrs::addi64(rg, reg::STACK_PTR, self.offsets[arg as usize] as _));
} }
} }
for (i, block) in fuc.blocks.iter().enumerate() { for (i, block) in fuc.blocks.iter().enumerate() {
let blk = regalloc2::Block(i as _); let blk = regalloc2::Block(i as _);
fuc.nodes[block.nid].offset = self.code.len() as _; self.offsets[block.nid as usize] = self.code.len() as _;
for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&fuc, blk) { for instr_or_edit in ralloc.ctx.output.block_insts_and_edits(&fuc, blk) {
let inst = match instr_or_edit { let inst = match instr_or_edit {
regalloc2::InstOrEdit::Inst(inst) => inst, regalloc2::InstOrEdit::Inst(inst) => inst,
@ -223,6 +182,7 @@ impl ItemCtx {
}; };
let allocs = ralloc.ctx.output.inst_allocs(inst); let allocs = ralloc.ctx.output.inst_allocs(inst);
let node = &fuc.nodes[nid]; let node = &fuc.nodes[nid];
let backref = fuc.backrefs[nid as usize];
let mut extend = |base: ty::Id, dest: ty::Id, from: usize, to: usize| { let mut extend = |base: ty::Id, dest: ty::Id, from: usize, to: usize| {
let (bsize, dsize) = (tys.size_of(base), tys.size_of(dest)); let (bsize, dsize) = (tys.size_of(base), tys.size_of(dest));
@ -270,7 +230,7 @@ impl ItemCtx {
} }
} }
Kind::Loop | Kind::Region => { Kind::Loop | Kind::Region => {
if node.ralloc_backref as usize != i + 1 { if backref 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));
@ -418,7 +378,7 @@ impl ItemCtx {
fuc.nodes[*node.inputs.last().unwrap()].kind, fuc.nodes[*node.inputs.last().unwrap()].kind,
Kind::Stck Kind::Stck
); );
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset; let stck = self.offsets[*node.inputs.last().unwrap() as usize];
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size)); self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
} }
if let Some(PLoc::Reg(r, size)) = ret if let Some(PLoc::Reg(r, size)) = ret
@ -428,7 +388,7 @@ impl ItemCtx {
fuc.nodes[*node.inputs.last().unwrap()].kind, fuc.nodes[*node.inputs.last().unwrap()].kind,
Kind::Stck Kind::Stck
); );
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset; let stck = self.offsets[*node.inputs.last().unwrap() as usize];
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size)); self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
} }
} }
@ -442,7 +402,7 @@ impl ItemCtx {
} }
Kind::Stck => { Kind::Stck => {
let base = reg::STACK_PTR; let base = reg::STACK_PTR;
let offset = fuc.nodes[nid].offset; let offset = self.offsets[nid as usize];
self.emit(instrs::addi64(atr(allocs[0]), base, offset as _)); self.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
} }
Kind::Load => { Kind::Load => {
@ -458,7 +418,9 @@ impl ItemCtx {
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 fuc.nodes[region].kind { let (base, offset) = match fuc.nodes[region].kind {
Kind::Stck => (reg::STACK_PTR, fuc.nodes[region].offset + offset), Kind::Stck => {
(reg::STACK_PTR, self.offsets[region as usize] + offset)
}
_ => (atr(allocs[1]), offset), _ => (atr(allocs[1]), offset),
}; };
self.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _)); self.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
@ -480,7 +442,7 @@ impl ItemCtx {
let nd = &fuc.nodes[region]; let nd = &fuc.nodes[region];
let (base, offset, src) = match nd.kind { let (base, offset, src) = match nd.kind {
Kind::Stck if node.ty.loc(tys) == Loc::Reg => { Kind::Stck if node.ty.loc(tys) == Loc::Reg => {
(reg::STACK_PTR, nd.offset + offset, allocs[0]) (reg::STACK_PTR, self.offsets[region as usize] + offset, allocs[0])
} }
_ => (atr(allocs[0]), offset, allocs[1]), _ => (atr(allocs[0]), offset, allocs[1]),
}; };
@ -507,69 +469,204 @@ impl ItemCtx {
} }
} }
self.nodes = nodes; self.ralloc = ralloc;
saved_regs.len() (saved_regs.len(), fuc.tail)
}
}
impl Backend for HbvmBackend {
fn assemble_bin(&mut self, entry: ty::Func, types: &Types, to: &mut Vec<u8>) {
to.extend([0u8; HEADER_SIZE]);
binary_prelude(to);
let AssemblySpec { code_length, data_length, entry } =
self.assemble_reachable(entry, types, to);
let exe = AbleOsExecutableHeader {
magic_number: [0x15, 0x91, 0xD2],
executable_version: 0,
code_length,
data_length,
debug_length: 0,
config_length: 0,
metadata_length: 0,
};
Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, entry as _, 0);
unsafe { *to.as_mut_ptr().cast::<AbleOsExecutableHeader>() = exe }
} }
pub fn emit_ct_body( fn assemble_reachable(
&mut self, &mut self,
tys: &mut Types, from: ty::Func,
files: &[parser::Ast], types: &Types,
sig: Sig, to: &mut Vec<u8>,
pool: &mut Pool, ) -> AssemblySpec {
) { debug_assert!(self.asm.frontier.is_empty());
self.emit_body(tys, files, sig, pool); debug_assert!(self.asm.funcs.is_empty());
self.code.truncate(self.code.len() - instrs::jala(0, 0, 0).0); debug_assert!(self.asm.globals.is_empty());
self.emit(instrs::tx());
self.globals.resize_with(types.ins.globals.len(), Default::default);
self.asm.frontier.push(ty::Kind::Func(from).compress());
while let Some(itm) = self.asm.frontier.pop() {
match itm.expand() {
ty::Kind::Func(func) => {
let fuc = &mut self.funcs[func as usize];
if fuc.offset != u32::MAX {
continue;
}
fuc.offset = 0;
self.asm.funcs.push(func);
self.asm.frontier.extend(fuc.relocs.iter().map(|r| r.target));
}
ty::Kind::Global(glob) => {
let glb = &mut self.globals[glob as usize];
if glb.offset != u32::MAX {
continue;
}
glb.offset = 0;
self.asm.globals.push(glob);
}
_ => unreachable!(),
}
}
let init_len = to.len();
for &func in &self.asm.funcs {
let fuc = &mut self.funcs[func as usize];
fuc.offset = to.len() as _;
debug_assert!(!fuc.code.is_empty());
to.extend(&fuc.code);
}
let code_length = to.len() - init_len;
for global in self.asm.globals.drain(..) {
self.globals[global as usize].offset = to.len() as _;
to.extend(&types.ins.globals[global as usize].data);
}
let data_length = to.len() - code_length - init_len;
for func in self.asm.funcs.drain(..) {
let fuc = &self.funcs[func as usize];
for rel in &fuc.relocs {
let offset = match rel.target.expand() {
ty::Kind::Func(fun) => self.funcs[fun as usize].offset,
ty::Kind::Global(glo) => self.globals[glo as usize].offset,
_ => unreachable!(),
};
rel.reloc.apply_jump(to, offset, fuc.offset);
}
}
AssemblySpec {
code_length: code_length as _,
data_length: data_length as _,
entry: self.funcs[from as usize].offset as _,
}
} }
pub fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig, pool: &mut Pool) { fn disasm<'a>(
self.nodes.check_final_integrity(tys, files); &'a self,
self.nodes.graphviz(tys, files); mut sluce: &[u8],
self.nodes.gcm(&mut pool.nid_stack); eca_handler: &mut dyn FnMut(&mut &[u8]),
self.nodes.basic_blocks(); types: &'a Types,
self.nodes.graphviz(tys, files); files: &'a [parser::Ast],
output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>> {
use hbbytecode::DisasmItem;
let functions = types
.ins
.funcs
.iter()
.zip(&self.funcs)
.filter(|(_, f)| f.offset != u32::MAX)
.map(|(f, fd)| {
let name = if f.file != u32::MAX {
let file = &files[f.file as usize];
file.ident_str(f.name)
} else {
"target_fn"
};
(fd.offset, (name, fd.code.len() as u32, DisasmItem::Func))
})
.chain(
types
.ins
.globals
.iter()
.zip(&self.globals)
.filter(|(_, g)| g.offset != u32::MAX)
.map(|(g, gd)| {
let name = if g.file == u32::MAX {
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else {
let file = &files[g.file as usize];
file.ident_str(g.name)
};
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
}),
)
.collect::<BTreeMap<_, _>>();
hbbytecode::disasm(&mut sluce, &functions, output, eca_handler)
}
fn emit_ct_body(
&mut self,
id: ty::Func,
nodes: &mut Nodes,
tys: &Types,
files: &[parser::Ast],
) {
self.emit_body(id, nodes, tys, files);
let fd = &mut self.funcs[id as usize];
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
emit(&mut fd.code, instrs::tx());
}
fn emit_body(&mut self, id: ty::Func, nodes: &mut Nodes, tys: &Types, files: &[parser::Ast]) {
let sig = tys.ins.funcs[id as usize].sig.unwrap();
debug_assert!(self.code.is_empty()); debug_assert!(self.code.is_empty());
let tail = mem::take(&mut self.call_count) == 0;
'_open_function: { self.offsets.clear();
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0)); self.offsets.resize(nodes.values.len(), Offset::MAX);
self.emit(instrs::st(reg::RET_ADDR + tail as u8, reg::STACK_PTR, 0, 0));
}
let mut stack_size = 0; let mut stack_size = 0;
'_compute_stack: { '_compute_stack: {
let mems = mem::take(&mut self.nodes[MEM].outputs); let mems = mem::take(&mut nodes[MEM].outputs);
for &stck in mems.iter() { for &stck in mems.iter() {
if !matches!(self.nodes[stck].kind, Kind::Stck | Kind::Arg) { if !matches!(nodes[stck].kind, Kind::Stck | Kind::Arg) {
debug_assert_matches!( debug_assert_matches!(
self.nodes[stck].kind, nodes[stck].kind,
Kind::Phi | Kind::Return | Kind::Load | Kind::Call { .. } | Kind::Stre Kind::Phi | Kind::Return | Kind::Load | Kind::Call { .. } | Kind::Stre
); );
continue; continue;
} }
stack_size += tys.size_of(self.nodes[stck].ty); stack_size += tys.size_of(nodes[stck].ty);
self.nodes[stck].offset = stack_size; self.offsets[stck as usize] = stack_size;
} }
for &stck in mems.iter() { for &stck in mems.iter() {
if !matches!(self.nodes[stck].kind, Kind::Stck | Kind::Arg) { if !matches!(nodes[stck].kind, Kind::Stck | Kind::Arg) {
continue; continue;
} }
self.nodes[stck].offset = stack_size - self.nodes[stck].offset; self.offsets[stck as usize] = stack_size - self.offsets[stck as usize];
} }
self.nodes[MEM].outputs = mems; nodes[MEM].outputs = mems;
} }
let saved = self.emit_body_code(sig, tys, files, &mut pool.ralloc); let (saved, tail) = self.emit_body_code(nodes, sig, tys, files);
if let Some(last_ret) = self.ret_relocs.last() if let Some(last_ret) = self.ret_relocs.last()
&& last_ret.offset as usize == self.code.len() - 5 && last_ret.offset as usize == self.code.len() - 5
&& self && self
.jump_relocs .jump_relocs
.last() .last()
.map_or(true, |&(r, _)| self.nodes[r].offset as usize != self.code.len()) .map_or(true, |&(r, _)| self.offsets[r as usize] as usize != self.code.len())
{ {
self.code.truncate(self.code.len() - 5); self.code.truncate(self.code.len() - 5);
self.ret_relocs.pop(); self.ret_relocs.pop();
@ -577,7 +674,7 @@ impl ItemCtx {
// FIXME: maybe do this incrementally // FIXME: maybe do this incrementally
for (nd, rel) in self.jump_relocs.drain(..) { for (nd, rel) in self.jump_relocs.drain(..) {
let offset = self.nodes[nd].offset; let offset = self.offsets[nd as usize];
//debug_assert!(offset < self.code.len() as u32 - 1); //debug_assert!(offset < self.code.len() as u32 - 1);
rel.apply_jump(&mut self.code, offset, 0); rel.apply_jump(&mut self.code, offset, 0);
} }
@ -592,17 +689,20 @@ impl ItemCtx {
let pushed = (saved as i64 + !tail as i64) * 8; let pushed = (saved as i64 + !tail as i64) * 8;
let stack = stack_size as i64; let stack = stack_size as i64;
let add_len = instrs::addi64(0, 0, 0).0;
let st_len = instrs::st(0, 0, 0, 0).0;
match (pushed, stack) { match (pushed, stack) {
(0, 0) => { (0, 0) => {
stripped_prelude_size = instrs::addi64(0, 0, 0).0 + instrs::st(0, 0, 0, 0).0; stripped_prelude_size = add_len + st_len;
self.code.drain(0..stripped_prelude_size); self.code.drain(0..stripped_prelude_size);
break '_close_function; break '_close_function;
} }
(0, stack) => { (0, stack) => {
write_reloc(&mut self.code, 3, -stack, 8); write_reloc(&mut self.code, 3, -stack, 8);
stripped_prelude_size = instrs::st(0, 0, 0, 0).0; stripped_prelude_size = st_len;
let end = instrs::addi64(0, 0, 0).0 + instrs::st(0, 0, 0, 0).0; let end = add_len + st_len;
self.code.drain(instrs::addi64(0, 0, 0).0..end); self.code.drain(add_len..end);
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, stack as _)); self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, stack as _));
break '_close_function; break '_close_function;
} }
@ -625,9 +725,22 @@ impl ItemCtx {
if sig.ret != ty::Id::NEVER { if sig.ret != ty::Id::NEVER {
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0)); self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
} }
if self.funcs.get(id as usize).is_none() {
self.funcs.resize_with(id as usize + 1, Default::default);
}
self.funcs[id as usize].code = mem::take(&mut self.code);
self.funcs[id as usize].relocs = mem::take(&mut self.relocs);
debug_assert_eq!(self.ret_relocs.len(), 0);
debug_assert_eq!(self.relocs.len(), 0);
debug_assert_eq!(self.jump_relocs.len(), 0);
debug_assert_eq!(self.code.len(), 0);
} }
} }
impl ItemCtx {}
#[derive(Debug)] #[derive(Debug)]
struct Block { struct Block {
nid: Nid, nid: Nid,
@ -648,6 +761,9 @@ pub struct Function<'a> {
sig: Sig, sig: Sig,
nodes: &'a mut Nodes, nodes: &'a mut Nodes,
tys: &'a Types, tys: &'a Types,
tail: bool,
visited: BitSet,
backrefs: Vec<u16>,
blocks: Vec<Block>, blocks: Vec<Block>,
instrs: Vec<Instr>, instrs: Vec<Instr>,
} }
@ -670,9 +786,17 @@ impl core::fmt::Debug for Function<'_> {
impl<'a> Function<'a> { impl<'a> Function<'a> {
fn new(nodes: &'a mut Nodes, tys: &'a Types, sig: Sig) -> Self { fn new(nodes: &'a mut Nodes, tys: &'a Types, sig: Sig) -> Self {
let mut s = let mut s = Self {
Self { nodes, tys, sig, blocks: Default::default(), instrs: Default::default() }; tys,
s.nodes.visited.clear(s.nodes.values.len()); sig,
tail: true,
visited: Default::default(),
backrefs: vec![u16::MAX; nodes.values.len()],
blocks: Default::default(),
instrs: Default::default(),
nodes,
};
s.visited.clear(s.nodes.values.len());
s.emit_node(VOID, VOID); s.emit_node(VOID, VOID);
s.add_block(0); s.add_block(0);
s.blocks.pop(); s.blocks.pop();
@ -726,7 +850,7 @@ impl<'a> Function<'a> {
fn emit_node(&mut self, nid: Nid, prev: Nid) { fn emit_node(&mut self, nid: Nid, prev: Nid) {
if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) { if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) {
let prev_bref = self.nodes[prev].ralloc_backref; let prev_bref = self.backrefs[prev as usize];
let node = self.nodes[nid].clone(); let node = self.nodes[nid].clone();
let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap(); let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap();
@ -742,7 +866,7 @@ impl<'a> Function<'a> {
self.add_instr(nid, vec![]); self.add_instr(nid, vec![]);
match (self.nodes[nid].kind, self.nodes.visited.set(nid)) { match (self.nodes[nid].kind, self.visited.set(nid)) {
(Kind::Loop, false) => { (Kind::Loop, false) => {
for i in node.inputs { for i in node.inputs {
self.bridge(i, nid); self.bridge(i, nid);
@ -752,7 +876,7 @@ impl<'a> Function<'a> {
(Kind::Region, true) => return, (Kind::Region, true) => return,
_ => {} _ => {}
} }
} else if !self.nodes.visited.set(nid) { } else if !self.visited.set(nid) {
return; return;
} }
@ -763,7 +887,7 @@ impl<'a> Function<'a> {
self.emit_node(node.outputs[0], VOID) self.emit_node(node.outputs[0], VOID)
} }
Kind::If => { Kind::If => {
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; self.backrefs[nid as usize] = self.backrefs[prev as usize];
let &[_, cond] = node.inputs.as_slice() else { unreachable!() }; let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
let &[mut then, mut else_] = node.outputs.as_slice() else { unreachable!() }; let &[mut then, mut else_] = node.outputs.as_slice() else { unreachable!() };
@ -787,7 +911,7 @@ impl<'a> Function<'a> {
self.emit_node(else_, nid); self.emit_node(else_, nid);
} }
Kind::Region | Kind::Loop => { Kind::Region | Kind::Loop => {
self.nodes[nid].ralloc_backref = self.add_block(nid); self.backrefs[nid as usize] = self.add_block(nid);
if node.kind == Kind::Region { if node.kind == Kind::Region {
for i in node.inputs { for i in node.inputs {
self.bridge(i, nid); self.bridge(i, nid);
@ -800,7 +924,7 @@ impl<'a> Function<'a> {
} }
block.push(self.rg(ph)); block.push(self.rg(ph));
} }
self.blocks[self.nodes[nid].ralloc_backref as usize].params = block; self.blocks[self.backrefs[nid as usize] as usize].params = block;
self.reschedule_block(nid, &mut node.outputs); self.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);
@ -849,7 +973,7 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Entry => { Kind::Entry => {
self.nodes[nid].ralloc_backref = self.add_block(nid); self.backrefs[nid as usize] = self.add_block(nid);
let (ret, mut parama) = self.tys.parama(self.sig.ret); let (ret, mut parama) = self.tys.parama(self.sig.ret);
let mut typs = self.sig.args.args(); let mut typs = self.sig.args.args();
@ -882,7 +1006,7 @@ impl<'a> Function<'a> {
} }
} }
Kind::Then | Kind::Else => { Kind::Then | Kind::Else => {
self.nodes[nid].ralloc_backref = 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.reschedule_block(nid, &mut node.outputs);
for o in node.outputs.into_iter().rev() { for o in node.outputs.into_iter().rev() {
@ -922,8 +1046,9 @@ impl<'a> Function<'a> {
let ops = vec![self.drg(nid), self.urg(node.inputs[1])]; let ops = vec![self.drg(nid), self.urg(node.inputs[1])];
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Call { args, .. } => { Kind::Call { args, func } => {
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; self.tail &= func == ty::ECA;
self.backrefs[nid as usize] = self.backrefs[prev as usize];
let mut ops = vec![]; let mut ops = vec![];
let (ret, mut parama) = self.tys.parama(node.ty); let (ret, mut parama) = self.tys.parama(node.ty);
@ -1079,17 +1204,15 @@ impl<'a> Function<'a> {
} }
fn bridge(&mut self, pred: u16, succ: u16) { fn bridge(&mut self, pred: u16, succ: u16) {
if self.nodes[pred].ralloc_backref == u16::MAX if self.backrefs[pred as usize] == u16::MAX || self.backrefs[succ as usize] == u16::MAX {
|| self.nodes[succ].ralloc_backref == u16::MAX
{
return; return;
} }
self.blocks[self.nodes[pred].ralloc_backref as usize] self.blocks[self.backrefs[pred as usize] as usize]
.succs .succs
.push(regalloc2::Block::new(self.nodes[succ].ralloc_backref as usize)); .push(regalloc2::Block::new(self.backrefs[succ as usize] as usize));
self.blocks[self.nodes[succ].ralloc_backref as usize] self.blocks[self.backrefs[succ as usize] as usize]
.preds .preds
.push(regalloc2::Block::new(self.nodes[pred].ralloc_backref as usize)); .push(regalloc2::Block::new(self.backrefs[pred as usize] as usize));
} }
fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) { fn reschedule_block(&mut self, from: Nid, outputs: &mut Vc) {
@ -1245,7 +1368,7 @@ impl regalloc2::Function for Function<'_> {
} }
impl TokenKind { impl TokenKind {
pub fn cmp_against(self) -> Option<u64> { fn cmp_against(self) -> Option<u64> {
Some(match self { Some(match self {
TokenKind::Le | TokenKind::Gt => 1, TokenKind::Le | TokenKind::Gt => 1,
TokenKind::Ne | TokenKind::Eq => 0, TokenKind::Ne | TokenKind::Eq => 0,
@ -1254,7 +1377,7 @@ impl TokenKind {
}) })
} }
pub fn float_cmp(self, ty: ty::Id) -> Option<fn(u8, u8, u8) -> EncodedInstr> { fn float_cmp(self, ty: ty::Id) -> Option<fn(u8, u8, u8) -> EncodedInstr> {
if !ty.is_float() { if !ty.is_float() {
return None; return None;
} }
@ -1369,7 +1492,7 @@ impl TokenKind {
Some(ops[size.ilog2() as usize]) Some(ops[size.ilog2() as usize])
} }
pub fn unop(&self, dst: ty::Id, src: ty::Id) -> Option<fn(u8, u8) -> EncodedInstr> { fn unop(&self, dst: ty::Id, src: ty::Id) -> Option<fn(u8, u8) -> EncodedInstr> {
let src_idx = src.simple_size().unwrap().ilog2() as usize - 2; let src_idx = src.simple_size().unwrap().ilog2() as usize - 2;
Some(match self { Some(match self {
Self::Sub => instrs::neg, Self::Sub => instrs::neg,
@ -1392,7 +1515,7 @@ fn emit(out: &mut Vec<u8>, (len, instr): EncodedInstr) {
out.extend_from_slice(&instr[..len]); out.extend_from_slice(&instr[..len]);
} }
pub fn binary_prelude(to: &mut Vec<u8>) { fn binary_prelude(to: &mut Vec<u8>) {
emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
emit(to, instrs::tx()); emit(to, instrs::tx());
} }
@ -1501,6 +1624,7 @@ pub struct Comptime {
pub vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>, pub vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>,
stack: Box<[u8; VM_STACK_SIZE]>, stack: Box<[u8; VM_STACK_SIZE]>,
pub code: Vec<u8>, pub code: Vec<u8>,
depth: usize,
} }
impl Comptime { impl Comptime {
@ -1544,6 +1668,19 @@ impl Comptime {
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.code.clear(); self.code.clear();
} }
#[must_use]
pub fn active(&self) -> bool {
self.depth != 0
}
pub fn activate(&mut self) {
self.depth += 1;
}
pub fn deactivate(&mut self) {
self.depth -= 1;
}
} }
impl Default for Comptime { impl Default for Comptime {
@ -1552,7 +1689,7 @@ impl Default for Comptime {
let mut vm = hbvm::Vm::default(); let mut vm = hbvm::Vm::default();
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 }; let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
vm.write_reg(reg::STACK_PTR, ptr); vm.write_reg(reg::STACK_PTR, ptr);
Self { vm, stack: unsafe { stack.assume_init() }, code: Default::default() } Self { vm, stack: unsafe { stack.assume_init() }, code: Default::default(), depth: 0 }
} }
} }

View file

@ -1,17 +1,17 @@
main: main:
ADDI64 r254, r254, -40d ADDI64 r254, r254, -56d
ST r31, r254, 24a, 16h ST r31, r254, 24a, 32h
LI64 r32, 1d LI64 r32, 1d
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
LI64 r5, 2d LI64 r33, 2d
ST r5, r254, 8a, 8h ST r33, r254, 8a, 8h
LI64 r8, 4d LI64 r34, 4d
ST r8, r254, 16a, 8h ST r34, r254, 16a, 8h
JAL r31, r0, :pass JAL r31, r0, :pass
ADD64 r1, r1, r32 ADD64 r1, r1, r32
LD r31, r254, 24a, 16h LD r31, r254, 24a, 32h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 56d
JALA r0, r31, 0a JALA r0, r31, 0a
pass: pass:
LD r4, r2, 8a, 8h LD r4, r2, 8a, 8h

View file

@ -6,8 +6,7 @@ main:
CP r32, r1 CP r32, r1
LRA r2, r0, :"fff\0" LRA r2, r0, :"fff\0"
JAL r31, r0, :str_len JAL r31, r0, :str_len
CP r10, r32 ADD64 r1, r1, r32
ADD64 r1, r1, r10
LD r31, r254, 0a, 16h LD r31, r254, 0a, 16h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
@ -23,6 +22,6 @@ str_len:
ADDI64 r1, r1, 1d ADDI64 r1, r1, 1d
JMP :2 JMP :2
1: JALA r0, r31, 0a 1: JALA r0, r31, 0a
code size: 219 code size: 216
ret: 16 ret: 16
status: Ok(()) status: Ok(())

View file

@ -2,18 +2,18 @@ cond:
LI64 r1, 0d LI64 r1, 0d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -24d
ST r31, r254, 0a, 8h ST r31, r254, 0a, 24h
JAL r31, r0, :cond JAL r31, r0, :cond
LI64 r5, 0d LI64 r32, 0d
CP r7, r5 CP r33, r32
JNE r1, r7, :0 JNE r1, r33, :0
CP r5, r7 CP r32, r33
CP r1, r5 CP r1, r32
JMP :1 JMP :1
0: LI64 r1, 2d 0: LI64 r1, 2d
1: LD r31, r254, 0a, 8h 1: LD r31, r254, 0a, 24h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 134 code size: 134
ret: 0 ret: 0

View file

@ -30,50 +30,50 @@ infinite_loop:
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -56d ADDI64 r254, r254, -64d
ST r31, r254, 0a, 56h ST r31, r254, 0a, 64h
LI64 r32, 0d LI64 r32, 0d
CP r2, r32 CP r2, r32
JAL r31, r0, :multiple_breaks JAL r31, r0, :multiple_breaks
CP r2, r1 CP r33, r1
LI64 r1, 3d LI64 r1, 3d
JEQ r2, r1, :0 JEQ r33, r1, :0
LI64 r1, 1d LI64 r1, 1d
JMP :1 JMP :1
0: CP r33, r1 0: CP r34, r1
LI64 r34, 4d LI64 r35, 4d
CP r2, r34 CP r2, r35
JAL r31, r0, :multiple_breaks JAL r31, r0, :multiple_breaks
CP r35, r34 CP r36, r35
LI64 r36, 10d LI64 r37, 10d
JEQ r1, r36, :2 JEQ r1, r37, :2
LI64 r1, 2d LI64 r1, 2d
JMP :1 JMP :1
2: CP r2, r32 2: CP r2, r32
JAL r31, r0, :state_change_in_break JAL r31, r0, :state_change_in_break
JEQ r1, r32, :3 JEQ r1, r32, :3
CP r1, r33 CP r1, r34
JMP :1 JMP :1
3: CP r2, r35 3: CP r2, r36
JAL r31, r0, :state_change_in_break JAL r31, r0, :state_change_in_break
JEQ r1, r36, :4 JEQ r1, r37, :4
CP r1, r35 CP r1, r36
JMP :1 JMP :1
4: CP r2, r36 4: CP r2, r37
JAL r31, r0, :continue_and_state_change JAL r31, r0, :continue_and_state_change
JEQ r1, r36, :5 JEQ r1, r37, :5
LI64 r1, 5d LI64 r1, 5d
JMP :1 JMP :1
5: CP r2, r33 5: CP r2, r34
JAL r31, r0, :continue_and_state_change JAL r31, r0, :continue_and_state_change
JEQ r1, r32, :6 JEQ r1, r32, :6
LI64 r1, 6d LI64 r1, 6d
JMP :1 JMP :1
6: CP r37, r32 6: CP r38, r32
JAL r31, r0, :infinite_loop JAL r31, r0, :infinite_loop
CP r1, r37 CP r1, r38
1: LD r31, r254, 0a, 56h 1: LD r31, r254, 0a, 64h
ADDI64 r254, r254, 56d ADDI64 r254, r254, 64d
JALA r0, r31, 0a JALA r0, r31, 0a
multiple_breaks: multiple_breaks:
LI64 r6, 3d LI64 r6, 3d

View file

@ -6,42 +6,40 @@ check_platform:
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -64d
ST r31, r254, 0a, 48h ST r31, r254, 0a, 64h
JAL r31, r0, :check_platform JAL r31, r0, :check_platform
LI64 r32, 0d LI64 r32, 0d
LI64 r33, 30d LI64 r33, 30d
LI64 r34, 100d LI64 r34, 100d
CP r10, r32
CP r35, r32 CP r35, r32
CP r36, r32 CP r36, r32
5: JLTU r10, r33, :0 CP r37, r32
ADDI64 r35, r35, 1d 5: JLTU r35, r33, :0
ADDI64 r36, r36, 1d
CP r2, r32 CP r2, r32
CP r3, r35 CP r3, r36
CP r4, r33 CP r4, r33
JAL r31, r0, :set_pixel JAL r31, r0, :set_pixel
CP r2, r36 JEQ r1, r37, :1
JEQ r1, r2, :1
CP r1, r32 CP r1, r32
JMP :2 JMP :2
1: CP r5, r32 1: CP r38, r32
CP r36, r2 JNE r36, r34, :3
JNE r35, r34, :3 CP r1, r37
CP r1, r36
JMP :2 JMP :2
3: CP r1, r36 3: CP r1, r37
CP r10, r5 CP r35, r38
JMP :4 JMP :4
0: CP r1, r36 0: CP r1, r37
CP r5, r32 CP r38, r32
ADDI64 r1, r1, 1d ADDI64 r1, r1, 1d
ADDI64 r10, r10, 1d ADDI64 r35, r35, 1d
4: CP r32, r5 4: CP r32, r38
CP r36, r1 CP r37, r1
JMP :5 JMP :5
2: LD r31, r254, 0a, 48h 2: LD r31, r254, 0a, 64h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 64d
JALA r0, r31, 0a JALA r0, r31, 0a
set_pixel: set_pixel:
MUL64 r7, r3, r4 MUL64 r7, r3, r4
@ -50,6 +48,6 @@ set_pixel:
x86_fb_ptr: x86_fb_ptr:
LI64 r1, 100d LI64 r1, 100d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 336 code size: 330
ret: 3000 ret: 3000
status: Ok(()) status: Ok(())

View file

@ -12,11 +12,10 @@ main:
CP r32, r1 CP r32, r1
LI64 r2, 20d LI64 r2, 20d
JAL r31, r0, :add_two JAL r31, r0, :add_two
CP r10, r32 ADD64 r1, r1, r32
ADD64 r1, r1, r10
LD r31, r254, 0a, 16h LD r31, r254, 0a, 16h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 155 code size: 152
ret: 33 ret: 33
status: Ok(()) status: Ok(())

View file

@ -5,8 +5,8 @@ add:
ADD32 r1, r2, r3 ADD32 r1, r2, r3
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -24d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 24h
LI32 r3, 2w LI32 r3, 2w
CP r2, r3 CP r2, r3
JAL r31, r0, :add JAL r31, r0, :add
@ -14,12 +14,11 @@ main:
LI64 r3, 3d LI64 r3, 3d
LI64 r2, 1d LI64 r2, 1d
JAL r31, r0, :add JAL r31, r0, :add
CP r2, r32 ANDI r33, r32, 4294967295d
ANDI r11, r2, 4294967295d SUB64 r1, r33, r1
SUB64 r1, r11, r1 LD r31, r254, 0a, 24h
LD r31, r254, 0a, 16h ADDI64 r254, r254, 24d
ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 161 code size: 158
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,17 +1,17 @@
deinit: deinit:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -32d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 32h
CP r32, r2 CP r32, r2
LD r5, r2, 16a, 8h LD r33, r2, 16a, 8h
LI64 r4, 8d LI64 r4, 8d
MUL64 r3, r5, r4 MUL64 r3, r33, r4
CP r5, r32 CP r34, r32
LD r2, r5, 0a, 8h LD r2, r34, 0a, 8h
JAL r31, r0, :free JAL r31, r0, :free
CP r1, r32 CP r1, r32
JAL r31, r0, :new JAL r31, r0, :new
LD r31, r254, 0a, 16h LD r31, r254, 0a, 32h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
free: free:
CP r10, r2 CP r10, r2
@ -23,21 +23,21 @@ free:
ECA ECA
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -56d
ST r31, r254, 24a, 24h ST r31, r254, 24a, 32h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
CP r1, r32 CP r1, r32
JAL r31, r0, :new JAL r31, r0, :new
LI64 r3, 69d LI64 r3, 69d
CP r2, r32 CP r2, r32
JAL r31, r0, :push JAL r31, r0, :push
LD r9, r254, 0a, 8h LD r33, r254, 0a, 8h
LD r33, r9, 0a, 8h LD r34, r33, 0a, 8h
CP r2, r32 CP r2, r32
JAL r31, r0, :deinit JAL r31, r0, :deinit
CP r1, r33 CP r1, r34
LD r31, r254, 24a, 24h LD r31, r254, 24a, 32h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 56d
JALA r0, r31, 0a JALA r0, r31, 0a
malloc: malloc:
CP r9, r2 CP r9, r2
@ -58,69 +58,69 @@ new:
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
push: push:
ADDI64 r254, r254, -72d ADDI64 r254, r254, -192d
ST r31, r254, 0a, 72h ST r31, r254, 0a, 192h
CP r32, r3 CP r32, r3
LI64 r33, 1d LI64 r33, 1d
LD r6, r2, 8a, 8h LD r34, r2, 8a, 8h
LD r8, r2, 16a, 8h LD r35, r2, 16a, 8h
CP r34, r2 CP r36, r2
JNE r8, r6, :0 JNE r35, r34, :0
LI64 r35, 0d LI64 r37, 0d
JNE r8, r35, :1 JNE r35, r37, :1
CP r36, r33 CP r38, r33
JMP :2 JMP :2
1: MULI64 r36, r8, 2d 1: MULI64 r38, r35, 2d
2: LI64 r37, 8d 2: LI64 r39, 8d
MUL64 r2, r36, r37 MUL64 r2, r38, r39
CP r3, r37 CP r3, r39
JAL r31, r0, :malloc JAL r31, r0, :malloc
CP r38, r1 CP r40, r1
CP r39, r34 CP r41, r36
ST r36, r39, 16a, 8h ST r38, r41, 16a, 8h
LI64 r1, 0d LI64 r1, 0d
CP r7, r38 CP r42, r40
JNE r7, r1, :3 JNE r42, r1, :3
JMP :4 JMP :4
3: CP r38, r7 3: CP r40, r42
LD r8, r39, 8a, 8h LD r36, r41, 8a, 8h
MULI64 r10, r8, 8d MULI64 r43, r36, 8d
LD r3, r39, 0a, 8h LD r44, r41, 0a, 8h
ADD64 r7, r3, r10 ADD64 r45, r44, r43
CP r5, r38 CP r46, r40
9: LD r2, r39, 0a, 8h 9: LD r2, r41, 0a, 8h
LD r10, r39, 8a, 8h LD r47, r41, 8a, 8h
JNE r7, r3, :5 JNE r45, r44, :5
JEQ r10, r35, :6 JEQ r47, r37, :6
CP r4, r37 CP r4, r39
MUL64 r3, r10, r4 MUL64 r3, r47, r4
JAL r31, r0, :free JAL r31, r0, :free
CP r6, r38 CP r1, r40
JMP :7 JMP :7
6: CP r6, r38 6: CP r1, r40
7: ST r6, r39, 0a, 8h 7: ST r1, r41, 0a, 8h
JMP :8 JMP :8
5: CP r4, r37 5: CP r1, r40
CP r6, r38 CP r4, r39
ADDI64 r8, r5, 8d ADDI64 r48, r46, 8d
ADDI64 r9, r3, 8d ADDI64 r42, r44, 8d
LD r10, r3, 0a, 8h LD r49, r44, 0a, 8h
ST r10, r5, 0a, 8h ST r49, r46, 0a, 8h
CP r3, r9 CP r44, r42
CP r5, r8 CP r46, r48
JMP :9 JMP :9
0: CP r39, r34 0: CP r41, r36
8: LD r5, r39, 8a, 8h 8: LD r50, r41, 8a, 8h
MULI64 r7, r5, 8d MULI64 r51, r50, 8d
LD r6, r39, 0a, 8h LD r52, r41, 0a, 8h
ADD64 r1, r6, r7 ADD64 r1, r52, r51
CP r3, r32 CP r3, r32
ST r3, r1, 0a, 8h ST r3, r1, 0a, 8h
LD r2, r39, 8a, 8h LD r53, r41, 8a, 8h
ADD64 r3, r2, r33 ADD64 r54, r53, r33
ST r3, r39, 8a, 8h ST r54, r41, 8a, 8h
4: LD r31, r254, 0a, 72h 4: LD r31, r254, 0a, 192h
ADDI64 r254, r254, 72d ADDI64 r254, r254, 192d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 955 code size: 955
ret: 69 ret: 69

View file

@ -4,15 +4,15 @@ clobber:
ST r3, r1, 0a, 8h ST r3, r1, 0a, 8h
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -24d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 24h
LRA r32, r0, :var LRA r32, r0, :var
LI64 r3, 2d LI64 r33, 2d
ST r3, r32, 0a, 8h ST r33, r32, 0a, 8h
JAL r31, r0, :clobber JAL r31, r0, :clobber
LD r1, r32, 0a, 8h LD r1, r32, 0a, 8h
LD r31, r254, 0a, 16h LD r31, r254, 0a, 24h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 166 code size: 166
ret: 0 ret: 0

View file

@ -1,22 +1,21 @@
fib: fib:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -40d
ST r31, r254, 0a, 32h ST r31, r254, 0a, 40h
LI64 r1, 1d LI64 r1, 1d
LI64 r32, 2d LI64 r32, 2d
JGTU r2, r32, :0 JGTU r2, r32, :0
JMP :1 JMP :1
0: CP r6, r2 0: CP r33, r2
SUB64 r2, r6, r1 SUB64 r2, r33, r1
CP r33, r6 CP r34, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r2, r33 CP r2, r34
CP r34, r1 CP r35, r1
SUB64 r2, r2, r32 SUB64 r2, r2, r32
JAL r31, r0, :fib JAL r31, r0, :fib
CP r8, r34 ADD64 r1, r1, r35
ADD64 r1, r1, r8 1: LD r31, r254, 0a, 40h
1: LD r31, r254, 0a, 32h ADDI64 r254, r254, 40d
ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -8d
@ -26,6 +25,6 @@ main:
LD r31, r254, 0a, 8h LD r31, r254, 0a, 8h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 214 code size: 211
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -1,22 +1,21 @@
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -32d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 32h
JAL r31, r0, :scalar_values JAL r31, r0, :scalar_values
LI64 r3, 0d LI64 r32, 0d
CP r8, r3 CP r33, r32
JEQ r1, r8, :0 JEQ r1, r33, :0
LI64 r1, 1d LI64 r1, 1d
JMP :1 JMP :1
0: CP r32, r8 0: JAL r31, r0, :structs
JAL r31, r0, :structs CP r34, r33
CP r3, r32 JEQ r1, r34, :2
JEQ r1, r3, :2
JAL r31, r0, :structs JAL r31, r0, :structs
JMP :1 JMP :1
2: CP r1, r3 2: CP r1, r34
CP r32, r3 CP r33, r34
1: LD r31, r254, 0a, 16h 1: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
scalar_values: scalar_values:
LI64 r1, 0d LI64 r1, 0d
@ -35,6 +34,6 @@ structs:
SUB64 r1, r1, r10 SUB64 r1, r1, r10
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 310 code size: 307
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,32 +1,32 @@
main: main:
ADDI64 r254, r254, -66d ADDI64 r254, r254, -106d
ST r31, r254, 58a, 8h ST r31, r254, 58a, 48h
ADDI64 r3, r254, 33d ADDI64 r32, r254, 33d
ADDI64 r2, r254, 34d ADDI64 r2, r254, 34d
ADDI64 r6, r254, 1d ADDI64 r6, r254, 1d
LI64 r9, 0d LI64 r33, 0d
ADDI64 r4, r254, 17d ADDI64 r4, r254, 17d
ST r3, r254, 34a, 8h ST r32, r254, 34a, 8h
LI64 r10, 100d LI64 r34, 100d
ADDI64 r7, r254, 0d ADDI64 r7, r254, 0d
LI8 r5, 1b LI8 r35, 1b
ST r9, r254, 1a, 8h ST r33, r254, 1a, 8h
ST r9, r254, 17a, 8h ST r33, r254, 17a, 8h
ST r10, r254, 42a, 8h ST r34, r254, 42a, 8h
LI8 r3, 0b LI8 r36, 0b
ST r5, r254, 0a, 1h ST r35, r254, 0a, 1h
ST r9, r254, 9a, 8h ST r33, r254, 9a, 8h
ST r9, r254, 25a, 8h ST r33, r254, 25a, 8h
ST r10, r254, 50a, 8h ST r34, r254, 50a, 8h
ST r3, r254, 33a, 1h ST r36, r254, 33a, 1h
CP r3, r4 CP r3, r4
CP r5, r6 CP r5, r6
LD r3, r3, 0a, 16h LD r3, r3, 0a, 16h
LD r5, r5, 0a, 16h LD r5, r5, 0a, 16h
LD r7, r7, 0a, 1h LD r7, r7, 0a, 1h
JAL r31, r0, :put_filled_rect JAL r31, r0, :put_filled_rect
LD r31, r254, 58a, 8h LD r31, r254, 58a, 48h
ADDI64 r254, r254, 66d ADDI64 r254, r254, 106d
JALA r0, r31, 0a JALA r0, r31, 0a
put_filled_rect: put_filled_rect:
ADDI64 r254, r254, -212d ADDI64 r254, r254, -212d

View file

@ -1,16 +1,16 @@
main: main:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -32d
ST r31, r254, 16a, 8h ST r31, r254, 16a, 16h
ADDI64 r3, r254, 0d ADDI64 r3, r254, 0d
ADDI64 r2, r254, 8d ADDI64 r2, r254, 8d
LI64 r4, 0d LI64 r32, 0d
ST r4, r254, 0a, 8h ST r32, r254, 0a, 8h
ST r4, r254, 8a, 8h ST r32, r254, 8a, 8h
LI64 r4, 1024d LI64 r4, 1024d
JAL r31, r0, :set JAL r31, r0, :set
ANDI r1, r1, 4294967295d ANDI r1, r1, 4294967295d
LD r31, r254, 16a, 8h LD r31, r254, 16a, 16h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
set: set:
CP r1, r4 CP r1, r4

View file

@ -1,23 +1,23 @@
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -32d
ST r31, r254, 0a, 16h ST r31, r254, 0a, 32h
JAL r31, r0, :opaque JAL r31, r0, :opaque
CP r32, r1 CP r32, r1
JAL r31, r0, :opaque JAL r31, r0, :opaque
LI64 r6, 0d LI64 r33, 0d
CP r1, r32 CP r1, r32
JNE r1, r6, :0 JNE r1, r33, :0
CP r32, r1 CP r32, r1
LI64 r1, 0d LI64 r1, 0d
CP r3, r32 CP r34, r32
JMP :1 JMP :1
0: CP r3, r1 0: CP r34, r1
LD r1, r3, 0a, 8h LD r1, r34, 0a, 8h
1: JEQ r3, r6, :2 1: JEQ r34, r33, :2
LD r1, r3, 0a, 8h LD r1, r34, 0a, 8h
JMP :2 JMP :2
2: LD r31, r254, 0a, 16h 2: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
opaque: opaque:
LI64 r1, 0d LI64 r1, 0d

View file

@ -4,22 +4,22 @@ get_ptr:
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -40d
ST r31, r254, 0a, 8h ST r31, r254, 0a, 40h
JAL r31, r0, :get_ptr JAL r31, r0, :get_ptr
LI64 r3, 0d LI64 r32, 0d
JNE r1, r3, :0 JNE r1, r32, :0
LI64 r1, 0d LI64 r1, 0d
JMP :1 JMP :1
0: LI64 r10, 10d 0: LI64 r33, 10d
CP r2, r1 CP r34, r1
2: LD r1, r2, 0a, 8h 2: LD r1, r34, 0a, 8h
JEQ r1, r10, :1 JEQ r1, r33, :1
ADDI64 r3, r1, 1d ADDI64 r35, r1, 1d
ST r3, r2, 0a, 8h ST r35, r34, 0a, 8h
JMP :2 JMP :2
1: LD r31, r254, 0a, 8h 1: LD r31, r254, 0a, 40h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 208 code size: 208
ret: 10 ret: 10

View file

@ -2,77 +2,77 @@ decide:
LI8 r1, 1b LI8 r1, 1b
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -136d ADDI64 r254, r254, -224d
ST r31, r254, 80a, 56h ST r31, r254, 80a, 144h
JAL r31, r0, :decide JAL r31, r0, :decide
LI64 r4, 0d LI64 r32, 0d
ADDI64 r2, r254, 72d ADDI64 r2, r254, 72d
CP r32, r2 CP r33, r2
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :0 JNE r1, r0, :0
CP r33, r4 CP r34, r32
JMP :1 JMP :1
0: CP r33, r32 0: CP r34, r33
1: JNE r33, r4, :2 1: JNE r34, r32, :2
LI64 r1, 9001d LI64 r1, 9001d
JMP :3 JMP :3
2: JAL r31, r0, :decide 2: JAL r31, r0, :decide
LI8 r34, 0b LI8 r35, 0b
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :4 JNE r1, r0, :4
LI8 r8, 1b LI8 r36, 1b
ST r8, r254, 56a, 1h ST r36, r254, 56a, 1h
LD r9, r33, 0a, 8h LD r36, r34, 0a, 8h
ST r9, r254, 64a, 8h ST r36, r254, 64a, 8h
JMP :5 JMP :5
4: ST r34, r254, 56a, 1h 4: ST r35, r254, 56a, 1h
5: LD r6, r254, 56a, 1h 5: LD r37, r254, 56a, 1h
ANDI r6, r6, 255d ANDI r37, r37, 255d
ANDI r34, r34, 255d ANDI r35, r35, 255d
JEQ r6, r34, :6 JEQ r37, r35, :6
LI64 r1, 42d LI64 r1, 42d
JMP :3 JMP :3
6: JAL r31, r0, :decide 6: JAL r31, r0, :decide
LI32 r2, 0w LI32 r38, 0w
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :7 JNE r1, r0, :7
CP r35, r2 CP r39, r38
JMP :8 JMP :8
7: LI32 r35, 8388609w 7: LI32 r39, 8388609w
8: ANDI r35, r35, 4294967295d 8: ANDI r39, r39, 4294967295d
ANDI r2, r2, 4294967295d ANDI r38, r38, 4294967295d
JNE r35, r2, :9 JNE r39, r38, :9
LI64 r1, 69d LI64 r1, 69d
JMP :3 JMP :3
9: ADDI64 r3, r254, 40d 9: ADDI64 r3, r254, 40d
CP r36, r3 CP r40, r3
JAL r31, r0, :new_foo JAL r31, r0, :new_foo
ST r1, r254, 40a, 16h ST r1, r254, 40a, 16h
LI64 r37, 0d LI64 r32, 0d
LD r7, r254, 40a, 8h LD r41, r254, 40a, 8h
JNE r7, r37, :10 JNE r41, r32, :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, r36 CP r3, r40
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 r6, r254, 0d ADDI64 r42, r254, 0d
JAL r31, r0, :no_foo JAL r31, r0, :no_foo
ST r1, r254, 0a, 16h ST r1, r254, 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
CP r2, r32 CP r2, r33
JMP :12 JMP :12
11: CP r2, r32 11: CP r2, r33
ST r2, r254, 0a, 8h ST r2, r254, 0a, 8h
LI64 r12, 1d LI64 r43, 1d
ST r12, r254, 8a, 8h ST r43, r254, 8a, 8h
ST r12, r254, 72a, 8h ST r43, r254, 72a, 8h
12: LD r6, r254, 0a, 8h 12: LD r44, r254, 0a, 8h
JNE r6, r37, :13 JNE r44, r32, :13
LI64 r1, 34d LI64 r1, 34d
JMP :3 JMP :3
13: ADDI64 r1, r254, 16d 13: ADDI64 r1, r254, 16d
@ -81,19 +81,19 @@ main:
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :14 JNE r1, r0, :14
JMP :15 JMP :15
14: ST r34, r254, 16a, 1h 14: ST r35, r254, 16a, 1h
15: LD r10, r254, 16a, 1h 15: LD r45, r254, 16a, 1h
ANDI r10, r10, 255d ANDI r45, r45, 255d
ANDI r34, r34, 255d ANDI r35, r35, 255d
JEQ r10, r34, :16 JEQ r45, r35, :16
LI64 r1, 420d LI64 r1, 420d
JMP :3 JMP :3
16: LD r4, r254, 0a, 8h 16: LD r46, r254, 0a, 8h
LD r6, r4, 0a, 8h LD r47, r46, 0a, 8h
ANDI r8, r35, 65535d ANDI r48, r39, 65535d
SUB64 r1, r8, r6 SUB64 r1, r48, r47
3: LD r31, r254, 80a, 56h 3: LD r31, r254, 80a, 144h
ADDI64 r254, r254, 136d ADDI64 r254, r254, 224d
JALA r0, r31, 0a JALA r0, r31, 0a
new_bar: new_bar:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -24d

View file

@ -2,14 +2,14 @@ inb:
CP r1, r2 CP r1, r2
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -32d
ST r31, r254, 0a, 24h ST r31, r254, 0a, 32h
LI64 r32, 0d LI64 r32, 0d
LI64 r33, 100d LI64 r33, 100d
4: CP r2, r33 4: CP r2, r33
JAL r31, r0, :inb JAL r31, r0, :inb
ANDI r7, r1, 2d ANDI r34, r1, 2d
JNE r7, r32, :0 JNE r34, r32, :0
LI64 r2, 96d LI64 r2, 96d
CP r3, r32 CP r3, r32
JAL r31, r0, :outb JAL r31, r0, :outb
@ -20,8 +20,8 @@ main:
JMP :2 JMP :2
1: JMP :3 1: JMP :3
0: JMP :4 0: JMP :4
2: LD r31, r254, 0a, 24h 2: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
outb: outb:
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -1,23 +1,23 @@
main: main:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -104d
ST r31, r254, 40a, 8h ST r31, r254, 40a, 64h
LI64 r4, 4d LI64 r32, 4d
ADDI64 r3, r254, 24d ADDI64 r33, r254, 24d
ADDI64 r6, r254, 0d ADDI64 r34, r254, 0d
ST r4, r254, 24a, 8h ST r32, r254, 24a, 8h
LI64 r5, 1d LI64 r35, 1d
ST r5, r254, 32a, 8h ST r35, r254, 32a, 8h
ST r5, r254, 16a, 8h ST r35, r254, 16a, 8h
BMC r3, r6, 16h BMC r33, r34, 16h
JAL r31, r0, :opaque JAL r31, r0, :opaque
ST r1, r254, 0a, 16h ST r1, r254, 0a, 16h
LD r4, r254, 8a, 8h LD r36, r254, 8a, 8h
LD r6, r254, 16a, 8h LD r37, r254, 16a, 8h
ADD64 r8, r6, r4 ADD64 r38, r37, r36
LD r6, r254, 0a, 8h LD r37, r254, 0a, 8h
SUB64 r1, r6, r8 SUB64 r1, r37, r38
LD r31, r254, 40a, 8h LD r31, r254, 40a, 64h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 104d
JALA r0, r31, 0a JALA r0, r31, 0a
opaque: opaque:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -16d

View file

@ -3,17 +3,17 @@ clobber:
ST r3, r2, 0a, 8h ST r3, r2, 0a, 8h
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -40d
ST r31, r254, 8a, 8h ST r31, r254, 8a, 32h
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
LI64 r3, 2d LI64 r32, 2d
ST r3, r254, 0a, 8h ST r32, r254, 0a, 8h
JAL r31, r0, :clobber JAL r31, r0, :clobber
LD r8, r254, 0a, 8h LD r33, r254, 0a, 8h
LI64 r9, 4d LI64 r34, 4d
SUB64 r1, r9, r8 SUB64 r1, r34, r33
LD r31, r254, 8a, 8h LD r31, r254, 8a, 32h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 169 code size: 169
ret: 0 ret: 0

View file

@ -1,18 +1,18 @@
drop: drop:
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -32d
ST r31, r254, 8a, 16h ST r31, r254, 8a, 24h
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
LI64 r32, 1d LI64 r32, 1d
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
JAL r31, r0, :modify JAL r31, r0, :modify
CP r2, r32 CP r2, r32
JAL r31, r0, :drop JAL r31, r0, :drop
LD r8, r254, 0a, 8h LD r33, r254, 0a, 8h
ADDI64 r1, r8, -2d ADDI64 r1, r33, -2d
LD r31, r254, 8a, 16h LD r31, r254, 8a, 24h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
modify: modify:
LI64 r3, 2d LI64 r3, 2d

View file

@ -1,6 +1,6 @@
create_back_buffer: create_back_buffer:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -56d
ST r31, r254, 0a, 48h ST r31, r254, 0a, 56h
LI64 r32, 255d LI64 r32, 255d
JGTS r2, r32, :0 JGTS r2, r32, :0
JAL r31, r0, :request_page JAL r31, r0, :request_page
@ -9,23 +9,23 @@ create_back_buffer:
LI8 r34, 255b LI8 r34, 255b
CP r2, r34 CP r2, r34
JAL r31, r0, :request_page JAL r31, r0, :request_page
CP r35, r1 LI64 r35, 0d
LI64 r36, 0d
CP r2, r33 CP r2, r33
SUB64 r33, r2, r32 SUB64 r36, r2, r32
5: JGTS r33, r36, :2 5: JGTS r36, r35, :2
CP r1, r35
JMP :1 JMP :1
2: JLTS r33, r32, :3 2: CP r37, r1
JLTS r36, r32, :3
CP r2, r34 CP r2, r34
JAL r31, r0, :request_page JAL r31, r0, :request_page
JMP :4 JMP :4
3: CP r2, r33 3: CP r2, r36
JAL r31, r0, :request_page JAL r31, r0, :request_page
4: SUB64 r33, r33, r32 4: SUB64 r36, r36, r32
CP r1, r37
JMP :5 JMP :5
1: LD r31, r254, 0a, 48h 1: LD r31, r254, 0a, 56h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 56d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -8d ADDI64 r254, r254, -8d

View file

@ -1,22 +1,22 @@
main: main:
ADDI64 r254, r254, -12d ADDI64 r254, r254, -100d
ST r31, r254, 4a, 8h ST r31, r254, 4a, 96h
ADDI64 r2, r254, 0d ADDI64 r32, r254, 0d
JAL r31, r0, :random_color JAL r31, r0, :random_color
ST r1, r254, 0a, 4h ST r1, r254, 0a, 4h
LD r5, r254, 0a, 1h LD r33, r254, 0a, 1h
LD r8, r254, 1a, 1h LD r34, r254, 1a, 1h
LD r12, r254, 2a, 1h LD r35, r254, 2a, 1h
ANDI r9, r5, 255d ANDI r36, r33, 255d
ANDI r1, r8, 255d ANDI r37, r34, 255d
LD r6, r254, 3a, 1h LD r38, r254, 3a, 1h
ANDI r5, r12, 255d ANDI r39, r35, 255d
ADD64 r4, r1, r9 ADD64 r40, r37, r36
ANDI r10, r6, 255d ANDI r41, r38, 255d
ADD64 r9, r4, r5 ADD64 r42, r40, r39
ADD64 r1, r9, r10 ADD64 r1, r42, r41
LD r31, r254, 4a, 8h LD r31, r254, 4a, 96h
ADDI64 r254, r254, 12d ADDI64 r254, r254, 100d
JALA r0, r31, 0a JALA r0, r31, 0a
random_color: random_color:
LRA r1, r0, :white LRA r1, r0, :white

View file

@ -1,25 +1,25 @@
main: main:
ADDI64 r254, r254, -12d ADDI64 r254, r254, -36d
ST r31, r254, 4a, 8h ST r31, r254, 4a, 32h
LRA r1, r0, :white LRA r32, r0, :white
ADDI64 r4, r254, 0d ADDI64 r33, r254, 0d
LD r2, r1, 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, r254, 0a, 4h
LD r9, r254, 0a, 1h LD r34, r254, 0a, 1h
ANDI r1, r9, 255d ANDI r1, r34, 255d
LD r31, r254, 4a, 8h LD r31, r254, 4a, 32h
ADDI64 r254, r254, 12d ADDI64 r254, r254, 36d
JALA r0, r31, 0a JALA r0, r31, 0a
u32_to_color: u32_to_color:
ADDI64 r254, r254, -12d ADDI64 r254, r254, -20d
ST r31, r254, 4a, 8h ST r31, r254, 4a, 16h
JAL r31, r0, :u32_to_u32 JAL r31, r0, :u32_to_u32
ADDI64 r5, r254, 0d ADDI64 r32, r254, 0d
ST r1, r254, 0a, 4h ST r1, r254, 0a, 4h
LD r1, r5, 0a, 4h LD r1, r32, 0a, 4h
LD r31, r254, 4a, 8h LD r31, r254, 4a, 16h
ADDI64 r254, r254, 12d ADDI64 r254, r254, 20d
JALA r0, r31, 0a JALA r0, r31, 0a
u32_to_u32: u32_to_u32:
CP r1, r2 CP r1, r2

View file

@ -4,15 +4,14 @@ fib:
CP r32, r2 CP r32, r2
LI64 r33, 2d LI64 r33, 2d
JLTU r2, r33, :0 JLTU r2, r33, :0
CP r6, r32 CP r34, r32
ADDI64 r2, r6, -1d ADDI64 r2, r34, -1d
JAL r31, r0, :fib JAL r31, r0, :fib
CP r2, r32 CP r2, r32
CP r34, r1 CP r34, r1
SUB64 r2, r2, r33 SUB64 r2, r2, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r6, r34 ADD64 r1, r1, r34
ADD64 r1, r1, r6
JMP :1 JMP :1
0: CP r1, r32 0: CP r1, r32
1: LD r31, r254, 0a, 32h 1: LD r31, r254, 0a, 32h
@ -41,11 +40,10 @@ main:
CP r2, r32 CP r2, r32
CP r33, r1 CP r33, r1
JAL r31, r0, :fib_iter JAL r31, r0, :fib_iter
CP r9, r33 SUB64 r1, r33, r1
SUB64 r1, r9, r1
LD r31, r254, 0a, 24h LD r31, r254, 0a, 24h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 306 code size: 300
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -10,28 +10,28 @@ foo:
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -56d ADDI64 r254, r254, -128d
ST r31, r254, 48a, 8h ST r31, r254, 48a, 80h
ADDI64 r2, r254, 32d ADDI64 r32, r254, 32d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 32a, 16h ST r1, r254, 32a, 16h
ADDI64 r7, r254, 16d ADDI64 r33, r254, 16d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 16a, 16h ST r1, r254, 16a, 16h
ADDI64 r2, r254, 0d ADDI64 r34, r254, 0d
JAL r31, r0, :foo JAL r31, r0, :foo
ST r1, r254, 0a, 16h ST r1, r254, 0a, 16h
LD r1, r254, 24a, 4h LD r35, r254, 24a, 4h
LD r7, r254, 12a, 4h LD r36, r254, 12a, 4h
ANDI r4, r1, 4294967295d ANDI r37, r35, 4294967295d
LD r1, r254, 32a, 8h LD r35, r254, 32a, 8h
ANDI r11, r7, 4294967295d ANDI r38, r36, 4294967295d
ADD64 r8, r1, r4 ADD64 r39, r35, r37
ADD64 r2, r8, r11 ADD64 r40, r39, r38
LI64 r3, 7d LI64 r34, 7d
SUB64 r1, r3, r2 SUB64 r1, r34, r40
LD r31, r254, 48a, 8h LD r31, r254, 48a, 80h
ADDI64 r254, r254, 56d ADDI64 r254, r254, 128d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 355 code size: 355
ret: 0 ret: 0

View file

@ -1,24 +1,24 @@
main: main:
ADDI64 r254, r254, -56d ADDI64 r254, r254, -72d
ST r31, r254, 32a, 24h ST r31, r254, 32a, 40h
LI64 r2, 4d LI64 r32, 4d
ADDI64 r4, r254, 16d ADDI64 r4, r254, 16d
ST r2, r254, 16a, 8h ST r32, r254, 16a, 8h
LI64 r32, 3d LI64 r33, 3d
ST r32, r254, 24a, 8h ST r33, r254, 24a, 8h
ADDI64 r33, r254, 0d ADDI64 r34, r254, 0d
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, r254, 0a, 16h
LD r2, r254, 8a, 8h LD r35, r254, 8a, 8h
JNE r2, r32, :0 JNE r35, r33, :0
CP r2, r33 CP r2, r34
JAL r31, r0, :pass JAL r31, r0, :pass
JMP :1 JMP :1
0: LI64 r1, 0d 0: LI64 r1, 0d
1: LD r31, r254, 32a, 24h 1: LD r31, r254, 32a, 40h
ADDI64 r254, r254, 56d ADDI64 r254, r254, 72d
JALA r0, r31, 0a JALA r0, r31, 0a
odher_pass: odher_pass:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -16d

View file

@ -1,47 +1,47 @@
main: main:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -56d
ST r31, r254, 16a, 8h ST r31, r254, 16a, 40h
ADDI64 r3, r254, 0d ADDI64 r32, r254, 0d
LI64 r4, 0d LI64 r4, 0d
CP r3, r4 CP r3, r4
JAL r31, r0, :maina JAL r31, r0, :maina
ST r1, r254, 0a, 16h ST r1, r254, 0a, 16h
LD r8, r254, 12a, 1h LD r33, r254, 12a, 1h
LD r9, r254, 3a, 1h LD r34, r254, 3a, 1h
SUB8 r11, r9, r8 SUB8 r35, r34, r33
ANDI r1, r11, 255d ANDI r1, r35, 255d
LD r31, r254, 16a, 8h LD r31, r254, 16a, 40h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 56d
JALA r0, r31, 0a JALA r0, r31, 0a
maina: maina:
ADDI64 r254, r254, -28d ADDI64 r254, r254, -68d
ST r31, r254, 20a, 8h ST r31, r254, 20a, 48h
ADDI64 r5, r254, 16d ADDI64 r32, r254, 16d
JAL r31, r0, :small_struct JAL r31, r0, :small_struct
ST r1, r254, 16a, 4h ST r1, r254, 16a, 4h
LI8 r9, 0b LI8 r33, 0b
ADDI64 r1, r254, 0d ADDI64 r34, r254, 0d
ST r9, r254, 0a, 1h ST r33, r254, 0a, 1h
ST r9, r254, 1a, 1h ST r33, r254, 1a, 1h
ST r9, r254, 2a, 1h ST r33, r254, 2a, 1h
LI8 r3, 3b LI8 r35, 3b
ST r3, r254, 3a, 1h ST r35, r254, 3a, 1h
LI8 r6, 1b LI8 r36, 1b
ST r6, r254, 4a, 1h ST r36, r254, 4a, 1h
ST r9, r254, 5a, 1h ST r33, r254, 5a, 1h
ST r9, r254, 6a, 1h ST r33, r254, 6a, 1h
ST r9, r254, 7a, 1h ST r33, r254, 7a, 1h
ST r9, r254, 8a, 1h ST r33, r254, 8a, 1h
ST r9, r254, 9a, 1h ST r33, r254, 9a, 1h
ST r9, r254, 10a, 1h ST r33, r254, 10a, 1h
ST r3, r254, 11a, 1h ST r35, r254, 11a, 1h
ST r6, r254, 12a, 1h ST r36, r254, 12a, 1h
ST r9, r254, 13a, 1h ST r33, r254, 13a, 1h
ST r9, r254, 14a, 1h ST r33, r254, 14a, 1h
ST r9, r254, 15a, 1h ST r33, r254, 15a, 1h
LD r1, r1, 0a, 16h LD r1, r34, 0a, 16h
LD r31, r254, 20a, 8h LD r31, r254, 20a, 48h
ADDI64 r254, r254, 28d ADDI64 r254, r254, 68d
JALA r0, r31, 0a JALA r0, r31, 0a
small_struct: small_struct:
ADDI64 r254, r254, -4d ADDI64 r254, r254, -4d