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
/depell/src/*.gz
/depell/src/*.wasm
**/*-sv.rs
/bytecode/src/instrs.rs

View file

@ -6,7 +6,7 @@ use {
alloc::{string::String, vec::Vec},
hblang::{
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 = {
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() {
log::error!("{}", ctx.parser.errors.borrow());
return;
}
let mut c = Codegen::new(&files, &mut ctx);
let mut c = Codegen::new(&mut backend, &files, &mut ctx);
c.assemble_comptime()
};

View file

@ -1,7 +1,7 @@
use {
crate::{
parser::{self, Ast, Ctx, FileKind},
son,
son::{self, hbvm::HbvmBackend},
},
alloc::{string::String, vec::Vec},
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();
write!(out, "{ast}").unwrap();
} else {
let mut backend = HbvmBackend::default();
let mut ctx = crate::son::CodegenCtx::default();
*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.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"));
}
if options.dump_asm {
codegen
.disasm(unsafe { std::mem::transmute::<&mut Vec<u8>, &mut String>(out) })
.map_err(|e| io::Error::other(e.to_string()))?;
} else {
codegen.assemble(out);
if options.dump_asm {
let mut disasm = String::new();
codegen.disasm(&mut disasm, out).map_err(|e| io::Error::other(e.to_string()))?;
*out = disasm.into_bytes();
}
}

View file

@ -2,7 +2,7 @@ use {
crate::{
lexer::TokenKind,
parser,
son::{Codegen, CodegenCtx},
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
},
alloc::string::String,
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());
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);
}
}

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)]
pub struct Ident(u32);
@ -567,6 +547,7 @@ mod ty {
};)*
}
#[expect(dead_code)]
impl Id {
$(pub const $name: Self = Kind::Builtin($name).compress();)*
}
@ -758,7 +739,7 @@ pub enum SymKey<'a> {
}
#[derive(Clone, Copy)]
struct Sig {
pub struct Sig {
args: ty::Tuple,
ret: ty::Id,
}
@ -769,10 +750,7 @@ struct Func {
base: Option<ty::Func>,
expr: ExprRef,
sig: Option<Sig>,
offset: Offset,
// TODO: change to indices into common vec
relocs: Vec<TypedReloc>,
code: Vec<u8>,
comp_state: [CompState; 2],
}
impl Default for Func {
@ -783,13 +761,19 @@ impl Default for Func {
base: None,
expr: Default::default(),
sig: None,
offset: u32::MAX,
relocs: Default::default(),
code: Default::default(),
comp_state: Default::default(),
}
}
}
#[derive(Default, PartialEq, Eq)]
enum CompState {
#[default]
Dead,
Queued(usize),
Compiled,
}
#[derive(Clone, Copy)]
struct TypedReloc {
target: ty::Id,
@ -801,7 +785,6 @@ struct Global {
file: FileId,
name: Ident,
ty: ty::Id,
offset: Offset,
data: Vec<u8>,
}
@ -809,7 +792,6 @@ impl Default for Global {
fn default() -> Self {
Self {
ty: Default::default(),
offset: u32::MAX,
data: Default::default(),
file: u32::MAX,
name: Default::default(),
@ -947,9 +929,6 @@ impl IdentInterner {
#[derive(Default)]
struct TypesTmp {
fields: Vec<Field>,
frontier: Vec<ty::Id>,
globals: Vec<ty::Global>,
funcs: Vec<ty::Func>,
args: Vec<ty::Id>,
}
@ -968,6 +947,7 @@ pub struct TypeIns {
struct FTask {
file: FileId,
id: ty::Func,
ct: bool,
}
struct StringRef(ty::Global);
@ -982,7 +962,7 @@ impl ctx_map::CtxEntry for StringRef {
}
#[derive(Default)]
struct Types {
pub struct Types {
syms: ctx_map::CtxMap<ty::Id>,
names: IdentInterner,
strings: ctx_map::CtxMap<StringRef>,
@ -1222,12 +1202,6 @@ impl Types {
&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) {
let mut iter = ParamAlloc(1..12);
let ret = iter.next(ret.into(), self);
@ -1395,9 +1369,6 @@ impl Types {
self.ins.slices.clear();
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.tasks.len(), 0);

View file

@ -1,5 +1,8 @@
use {
self::{hbvm::Comptime, strong_ref::StrongRef},
self::{
hbvm::{Comptime, HbvmBackend},
strong_ref::StrongRef,
},
crate::{
ctx_map::CtxEntry,
debug,
@ -9,11 +12,10 @@ use {
idfl::{self},
CtorField, Expr, FileId, Pos,
},
task,
ty::{self, Arg, ArrayLen, Loc, Tuple},
utils::{BitSet, Vc},
FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Reloc, Sig, StringRef, SymKey,
TypeParser, TypedReloc, Types,
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
SymKey, TypeParser, Types,
},
alloc::{string::String, vec::Vec},
core::{
@ -41,6 +43,38 @@ pub mod hbvm;
type Nid = u16;
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>;
impl crate::ctx_map::CtxEntry for Nid {
@ -71,23 +105,15 @@ macro_rules! inference {
}
#[derive(Clone)]
struct Nodes {
pub struct Nodes {
values: Vec<Result<Node, (Nid, debug::Trace)>>,
visited: BitSet,
free: Nid,
lookup: Lookup,
complete: bool,
}
impl Default for Nodes {
fn default() -> Self {
Self {
values: Default::default(),
free: Nid::MAX,
lookup: Default::default(),
visited: Default::default(),
complete: false,
}
Self { values: Default::default(), free: Nid::MAX, lookup: Default::default() }
}
}
@ -183,15 +209,15 @@ impl Nodes {
}
}
fn push_up_impl(&mut self, node: Nid) {
if !self.visited.set(node) {
fn push_up_impl(&mut self, node: Nid, visited: &mut BitSet) {
if !visited.set(node) {
return;
}
for i in 1..self[node].inputs.len() {
let inp = self[node].inputs[i];
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);
}
fn collect_rpo(&mut self, node: Nid, rpo: &mut Vec<Nid>) {
if !self.is_cfg(node) || !self.visited.set(node) {
fn collect_rpo(&mut self, node: Nid, rpo: &mut Vec<Nid>, visited: &mut BitSet) {
if !self.is_cfg(node) || !visited.set(node) {
return;
}
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);
}
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());
self.collect_rpo(VOID, rpo);
self.collect_rpo(VOID, rpo, visited);
for &node in rpo.iter().rev() {
self.loop_depth(node);
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) {
for i in 0..self[node].outputs.len() {
let usage = self[node].outputs[i];
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!(
self.iter()
.map(|(n, _)| n)
.filter(|&n| !self.visited.get(n)
.filter(|&n| !visited.get(n)
&& !matches!(self[n].kind, Kind::Arg | Kind::Mem | Kind::Loops))
.collect::<Vec<_>>(),
vec![],
"{:?}",
self.iter()
.filter(|&(n, nod)| !self.visited.get(n)
.filter(|&(n, nod)| !visited.get(n)
&& !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops))
.collect::<Vec<_>>()
);
@ -295,20 +321,20 @@ impl Nodes {
}
}
fn push_down(&mut self, node: Nid) {
if !self.visited.set(node) {
fn push_down(&mut self, node: Nid, visited: &mut BitSet) {
if !visited.set(node) {
return;
}
for usage in self[node].outputs.clone() {
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() {
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(
&self,
tys: &Types,
files: &[parser::Ast],
out: &mut String,
) -> core::fmt::Result {
fn graphviz_low(&self, disp: ty::Display, out: &mut String) -> core::fmt::Result {
use core::fmt::Write;
writeln!(out)?;
@ -518,7 +539,7 @@ impl Nodes {
out,
" node{i}[label=\"{i} {} {} {}\" color={color}]",
node.kind,
ty::Display::new(tys, files, node.ty),
disp.rety(node.ty),
node.aclass,
)?;
} else {
@ -545,17 +566,17 @@ impl Nodes {
Ok(())
}
fn graphviz(&self, tys: &Types, files: &[parser::Ast]) {
fn graphviz(&self, disp: ty::Display) {
let out = &mut String::new();
_ = self.graphviz_low(tys, files, out);
_ = self.graphviz_low(disp, 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"))]
{
let out = &mut String::new();
_ = self.graphviz_low(_tys, _files, out);
_ = self.graphviz_low(disp, out);
if !std::process::Command::new("brave")
.arg(format!("https://dreampuf.github.io/GraphvizOnline/#{out}"))
.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.visited.clear(self.values.len());
self.push_up(rpo);
self.visited.clear(self.values.len());
self.push_down(VOID);
visited.clear(self.values.len());
self.push_up(rpo, visited);
visited.clear(self.values.len());
self.push_down(VOID, visited);
}
fn clear(&mut self) {
self.values.clear();
self.lookup.clear();
self.free = Nid::MAX;
self.complete = false;
}
fn new_node_nop(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid {
let node =
Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() };
let node = Node { inputs: inps.into(), kind, ty, ..Default::default() };
if node.kind == Kind::Phi && node.ty != ty::Id::VOID {
debug_assert_ne!(
@ -765,7 +784,7 @@ impl Nodes {
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 {
(self[region].aclass as _, region)
} else {
@ -1336,9 +1355,6 @@ impl Nodes {
#[expect(clippy::format_in_format_args)]
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 {
Kind::Assert { .. } | Kind::Start => unreachable!("{} {out}", self[node].kind),
Kind::End => return Ok(()),
@ -1382,9 +1398,14 @@ impl Nodes {
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();
while self.visited.set(node) {
while visited.set(node) {
match self[node].kind {
Kind::Start => {
writeln!(out, "start: {}", self[node].depth.get())?;
@ -1399,7 +1420,7 @@ impl Nodes {
}
Kind::End => break,
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];
}
Kind::Region => {
@ -1480,8 +1501,8 @@ impl Nodes {
fn basic_blocks(&mut self) {
let mut out = String::new();
self.visited.clear(self.values.len());
self.basic_blocks_low(&mut out, VOID).unwrap();
let mut visited = BitSet::default();
self.basic_blocks_low(&mut out, VOID, &mut visited).unwrap();
log::info!("{out}");
}
@ -1489,7 +1510,7 @@ impl Nodes {
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) {
return;
}
@ -1517,7 +1538,7 @@ impl Nodes {
}
if failed {
self.graphviz_in_browser(tys, files);
self.graphviz_in_browser(disp);
panic!()
}
}
@ -1743,8 +1764,6 @@ pub struct Node {
peep_triggers: Vc,
clobbers: BitSet,
ty: ty::Id,
offset: Offset,
ralloc_backref: RallocBRef,
depth: Cell<IDomDepth>,
lock_rc: LockRc,
loop_depth: LoopDepth,
@ -1963,7 +1982,7 @@ impl Scope {
}
#[derive(Default, Clone)]
struct ItemCtx {
pub struct ItemCtx {
file: FileId,
ret: Option<ty::Id>,
task_base: usize,
@ -1973,25 +1992,19 @@ struct ItemCtx {
inline_ret: Option<(Value, StrongRef, Scope)>,
nodes: Nodes,
ctrl: StrongRef,
call_count: u16,
loops: Vec<Loop>,
scope: Scope,
ret_relocs: Vec<Reloc>,
relocs: Vec<TypedReloc>,
jump_relocs: Vec<(Nid, Reloc)>,
code: Vec<u8>,
}
impl ItemCtx {
fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) {
debug_assert_eq!(self.loops.len(), 0);
debug_assert_eq!(self.scope.vars.len(), 0);
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);
self.call_count = 0;
debug_assert_eq!(self.scope.aclasses.len(), 0);
debug_assert!(self.inline_ret.is_none());
debug_assert_eq!(self.inline_depth, 0);
debug_assert_eq!(self.inline_var_base, 0);
debug_assert_eq!(self.inline_aclass_base, 0);
self.file = file;
self.ret = ret;
@ -2043,21 +2056,21 @@ struct Ctx {
}
impl Ctx {
pub fn with_ty(self, ty: ty::Id) -> Self {
fn with_ty(self, ty: ty::Id) -> Self {
Self { ty: Some(ty) }
}
}
#[derive(Default)]
struct Pool {
pub struct Pool {
cis: Vec<ItemCtx>,
used_cis: usize,
ralloc: Regalloc,
nid_stack: Vec<Nid>,
nid_set: BitSet,
}
impl Pool {
pub fn push_ci(
fn push_ci(
&mut self,
file: FileId,
ret: Option<ty::Id>,
@ -2074,7 +2087,7 @@ impl Pool {
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;
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)]
struct Value {
ty: ty::Id,
@ -2140,20 +2126,20 @@ impl Value {
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 };
pub fn new(id: Nid) -> Self {
fn new(id: Nid) -> Self {
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() }
}
pub fn ptr(id: Nid) -> Self {
fn ptr(id: Nid) -> Self {
Self { id, ptr: true, ..Default::default() }
}
#[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 }
}
}
@ -2164,6 +2150,7 @@ pub struct CodegenCtx {
tys: Types,
pool: Pool,
ct: Comptime,
ct_backend: HbvmBackend,
}
impl CodegenCtx {
@ -2200,10 +2187,16 @@ pub struct Codegen<'a> {
ci: ItemCtx,
pool: &'a mut Pool,
ct: &'a mut Comptime,
ct_backend: &'a mut HbvmBackend,
backend: &'a mut dyn Backend,
}
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 {
files,
errors: Errors(&ctx.parser.errors),
@ -2211,9 +2204,46 @@ impl<'a> Codegen<'a> {
ci: Default::default(),
pool: &mut ctx.pool,
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 {
let mut rets =
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;
}
self.ci.emit_ct_body(self.tys, self.files, Sig { args: Tuple::empty(), ret }, self.pool);
let func = Func {
let fuc = self.tys.ins.funcs.len() as ty::Func;
self.tys.ins.funcs.push(Func {
file,
relocs: mem::take(&mut self.ci.relocs),
code: mem::take(&mut self.ci.code),
sig: Some(Sig { args: Tuple::empty(), ret }),
..Default::default()
};
});
self.ct_backend.emit_ct_body(fuc, &mut self.ci.nodes, self.tys, self.files);
// 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);
self.dump_ct_asm();
let entry =
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)]
{
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);
} else {
log::trace!("{}", vc);
}
}
}
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();
self.ct.run(ret_loc, entry)
}
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!({ self.ci.nodes[region].ty }, ty::Id::VOID, "{:?}", {
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!(
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.ty_display(self.ci.nodes[region].ty)
);
@ -2365,37 +2382,12 @@ impl<'a> Codegen<'a> {
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) {
let state_slot = self.ct.active() as usize;
let fuc = &mut self.tys.ins.funcs[func as usize];
if fuc.offset == u32::MAX {
fuc.offset = task::id(self.tys.tasks.len() as _);
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func }));
if fuc.comp_state[state_slot] == CompState::Dead {
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
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)))
}
Expr::Call { func, args, .. } => {
self.ci.call_count += 1;
let ty = self.ty(func);
let ty::Kind::Func(mut fu) = ty.expand() else {
self.report(
@ -4005,10 +3996,12 @@ impl<'a> Codegen<'a> {
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];
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 ast = &self.files[file as usize];
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));
if self.finalize(prev_err_len) {
self.ci.emit_body(self.tys, self.files, sig, self.pool);
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
let backend = if !cct { &mut *self.backend } else { &mut *self.ct_backend };
backend.emit_body(id, &mut self.ci.nodes, self.tys, self.files);
}
self.pool.pop_ci(&mut self.ci);
@ -4087,6 +4079,7 @@ impl<'a> Codegen<'a> {
use {AssertKind as AK, CondOptRes as CR};
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
let mut to_remove = vec![];
for (id, node) in self.ci.nodes.iter() {
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.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
}
@ -4399,6 +4402,7 @@ impl TypeParser for Codegen<'_> {
}
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);
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci);
self.ci.scope.vars = scope;
@ -4415,6 +4419,7 @@ impl TypeParser for Codegen<'_> {
self.pool.pop_ci(&mut self.ci);
self.ci.scope.vars = scope;
self.ct.deactivate();
res
}
@ -4427,18 +4432,21 @@ impl TypeParser for Codegen<'_> {
}
fn on_reuse(&mut self, existing: ty::Id) {
let state_slot = self.ct.active() as usize;
if let ty::Kind::Func(id) = existing.expand()
&& 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()
{
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();
self.tys.tasks.push(task);
}
}
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;
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.tys.ins.globals[gid as usize].ty = ret;
self.ct.deactivate();
ty.compress()
}
@ -4475,7 +4484,7 @@ impl TypeParser for Codegen<'_> {
#[cfg(test)]
mod tests {
use {
super::CodegenCtx,
super::{hbvm::HbvmBackend, CodegenCtx},
alloc::{string::String, vec::Vec},
core::fmt::Write,
};
@ -4487,7 +4496,8 @@ mod tests {
let mut ctx = CodegenCtx::default();
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.generate(0);
@ -4501,9 +4511,9 @@ mod tests {
}
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 {
writeln!(output, "!!! asm is invalid: {e}").unwrap();
return;

View file

@ -1,10 +1,9 @@
use {
super::{ItemCtx, Nid, Nodes, Pool, RallocBRef, Regalloc, ARG_START, NEVER, VOID},
super::{AssemblySpec, Backend, ItemCtx, Nid, Nodes, RallocBRef, ARG_START, NEVER, VOID},
crate::{
lexer::TokenKind,
parser, reg,
son::{write_reloc, Kind, MEM},
task,
ty::{self, Arg, Loc},
utils::{BitSet, Vc},
HashMap, Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types,
@ -14,139 +13,94 @@ use {
hbbytecode::{self as instrs, *},
};
impl Types {
pub fn assemble(&mut self, to: &mut Vec<u8>) {
to.extend([0u8; HEADER_SIZE]);
binary_prelude(to);
let exe = self.dump_reachable(0, to);
Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, self.ins.funcs[0].offset, 0);
unsafe { *to.as_mut_ptr().cast::<AbleOsExecutableHeader>() = exe }
struct FuncDt {
offset: Offset,
// TODO: change to indices into common vec
relocs: Vec<TypedReloc>,
code: Vec<u8>,
}
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!(),
impl Default for FuncDt {
fn default() -> Self {
Self { offset: u32::MAX, relocs: Default::default(), code: Default::default() }
}
}
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);
struct GlobalDt {
offset: Offset,
}
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);
impl Default for GlobalDt {
fn default() -> Self {
Self { offset: u32::MAX }
}
}
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,
#[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(),
}
}
}
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)
}
#[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 ItemCtx {
impl HbvmBackend {
fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) {
emit(&mut self.code, instr);
}
fn emit_body_code(
&mut self,
nodes: &mut Nodes,
sig: Sig,
tys: &Types,
files: &[parser::Ast],
ralloc: &mut Regalloc,
) -> usize {
let mut nodes = mem::take(&mut self.nodes);
) -> (usize, bool) {
let mut ralloc = mem::take(&mut self.ralloc);
let fuc = Function::new(&mut nodes, tys, sig);
let fuc = Function::new(nodes, tys, sig);
log::info!("{:?}", fuc);
if self.call_count != 0 {
if !fuc.tail {
mem::swap(
&mut ralloc.env.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[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}")
},
);
if self.call_count != 0 {
if !fuc.tail {
mem::swap(
&mut ralloc.env.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)
};
'_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 mut typs = sig.args.args();
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(..) | 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 {
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() {
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) {
let inst = match instr_or_edit {
regalloc2::InstOrEdit::Inst(inst) => inst,
@ -223,6 +182,7 @@ impl ItemCtx {
};
let allocs = ralloc.ctx.output.inst_allocs(inst);
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 (bsize, dsize) = (tys.size_of(base), tys.size_of(dest));
@ -270,7 +230,7 @@ impl ItemCtx {
}
}
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);
self.jump_relocs.push((nid, rel));
self.emit(instrs::jmp(0));
@ -418,7 +378,7 @@ impl ItemCtx {
fuc.nodes[*node.inputs.last().unwrap()].kind,
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));
}
if let Some(PLoc::Reg(r, size)) = ret
@ -428,7 +388,7 @@ impl ItemCtx {
fuc.nodes[*node.inputs.last().unwrap()].kind,
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));
}
}
@ -442,7 +402,7 @@ impl ItemCtx {
}
Kind::Stck => {
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 _));
}
Kind::Load => {
@ -458,7 +418,9 @@ impl ItemCtx {
let size = tys.size_of(node.ty);
if node.ty.loc(tys) != Loc::Stack {
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),
};
self.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
@ -480,7 +442,7 @@ impl ItemCtx {
let nd = &fuc.nodes[region];
let (base, offset, src) = match nd.kind {
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]),
};
@ -507,69 +469,204 @@ impl ItemCtx {
}
}
self.nodes = nodes;
self.ralloc = ralloc;
saved_regs.len()
(saved_regs.len(), fuc.tail)
}
}
pub fn emit_ct_body(
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 }
}
fn assemble_reachable(
&mut self,
tys: &mut Types,
files: &[parser::Ast],
sig: Sig,
pool: &mut Pool,
) {
self.emit_body(tys, files, sig, pool);
self.code.truncate(self.code.len() - instrs::jala(0, 0, 0).0);
self.emit(instrs::tx());
from: ty::Func,
types: &Types,
to: &mut Vec<u8>,
) -> AssemblySpec {
debug_assert!(self.asm.frontier.is_empty());
debug_assert!(self.asm.funcs.is_empty());
debug_assert!(self.asm.globals.is_empty());
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!(),
}
}
pub fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig, pool: &mut Pool) {
self.nodes.check_final_integrity(tys, files);
self.nodes.graphviz(tys, files);
self.nodes.gcm(&mut pool.nid_stack);
self.nodes.basic_blocks();
self.nodes.graphviz(tys, files);
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 _,
}
}
fn disasm<'a>(
&'a self,
mut sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types,
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());
let tail = mem::take(&mut self.call_count) == 0;
'_open_function: {
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
self.emit(instrs::st(reg::RET_ADDR + tail as u8, reg::STACK_PTR, 0, 0));
}
self.offsets.clear();
self.offsets.resize(nodes.values.len(), Offset::MAX);
let mut stack_size = 0;
'_compute_stack: {
let mems = mem::take(&mut self.nodes[MEM].outputs);
let mems = mem::take(&mut nodes[MEM].outputs);
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!(
self.nodes[stck].kind,
nodes[stck].kind,
Kind::Phi | Kind::Return | Kind::Load | Kind::Call { .. } | Kind::Stre
);
continue;
}
stack_size += tys.size_of(self.nodes[stck].ty);
self.nodes[stck].offset = stack_size;
stack_size += tys.size_of(nodes[stck].ty);
self.offsets[stck as usize] = stack_size;
}
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;
}
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()
&& last_ret.offset as usize == self.code.len() - 5
&& self
.jump_relocs
.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.ret_relocs.pop();
@ -577,7 +674,7 @@ impl ItemCtx {
// FIXME: maybe do this incrementally
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);
rel.apply_jump(&mut self.code, offset, 0);
}
@ -592,17 +689,20 @@ impl ItemCtx {
let pushed = (saved as i64 + !tail as i64) * 8;
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) {
(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);
break '_close_function;
}
(0, stack) => {
write_reloc(&mut self.code, 3, -stack, 8);
stripped_prelude_size = instrs::st(0, 0, 0, 0).0;
let end = instrs::addi64(0, 0, 0).0 + instrs::st(0, 0, 0, 0).0;
self.code.drain(instrs::addi64(0, 0, 0).0..end);
stripped_prelude_size = st_len;
let end = add_len + st_len;
self.code.drain(add_len..end);
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, stack as _));
break '_close_function;
}
@ -625,9 +725,22 @@ impl ItemCtx {
if sig.ret != ty::Id::NEVER {
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)]
struct Block {
nid: Nid,
@ -648,6 +761,9 @@ pub struct Function<'a> {
sig: Sig,
nodes: &'a mut Nodes,
tys: &'a Types,
tail: bool,
visited: BitSet,
backrefs: Vec<u16>,
blocks: Vec<Block>,
instrs: Vec<Instr>,
}
@ -670,9 +786,17 @@ impl core::fmt::Debug for Function<'_> {
impl<'a> Function<'a> {
fn new(nodes: &'a mut Nodes, tys: &'a Types, sig: Sig) -> Self {
let mut s =
Self { nodes, tys, sig, blocks: Default::default(), instrs: Default::default() };
s.nodes.visited.clear(s.nodes.values.len());
let mut s = Self {
tys,
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.add_block(0);
s.blocks.pop();
@ -726,7 +850,7 @@ impl<'a> Function<'a> {
fn emit_node(&mut self, nid: Nid, prev: Nid) {
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 idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap();
@ -742,7 +866,7 @@ impl<'a> Function<'a> {
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) => {
for i in node.inputs {
self.bridge(i, nid);
@ -752,7 +876,7 @@ impl<'a> Function<'a> {
(Kind::Region, true) => return,
_ => {}
}
} else if !self.nodes.visited.set(nid) {
} else if !self.visited.set(nid) {
return;
}
@ -763,7 +887,7 @@ impl<'a> Function<'a> {
self.emit_node(node.outputs[0], VOID)
}
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 &[mut then, mut else_] = node.outputs.as_slice() else { unreachable!() };
@ -787,7 +911,7 @@ impl<'a> Function<'a> {
self.emit_node(else_, nid);
}
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 {
for i in node.inputs {
self.bridge(i, nid);
@ -800,7 +924,7 @@ impl<'a> Function<'a> {
}
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);
for o in node.outputs.into_iter().rev() {
self.emit_node(o, nid);
@ -849,7 +973,7 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops);
}
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 mut typs = self.sig.args.args();
@ -882,7 +1006,7 @@ impl<'a> Function<'a> {
}
}
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.reschedule_block(nid, &mut node.outputs);
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])];
self.add_instr(nid, ops);
}
Kind::Call { args, .. } => {
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref;
Kind::Call { args, func } => {
self.tail &= func == ty::ECA;
self.backrefs[nid as usize] = self.backrefs[prev as usize];
let mut ops = vec![];
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) {
if self.nodes[pred].ralloc_backref == u16::MAX
|| self.nodes[succ].ralloc_backref == u16::MAX
{
if self.backrefs[pred as usize] == u16::MAX || self.backrefs[succ as usize] == u16::MAX {
return;
}
self.blocks[self.nodes[pred].ralloc_backref as usize]
self.blocks[self.backrefs[pred as usize] as usize]
.succs
.push(regalloc2::Block::new(self.nodes[succ].ralloc_backref as usize));
self.blocks[self.nodes[succ].ralloc_backref as usize]
.push(regalloc2::Block::new(self.backrefs[succ as usize] as usize));
self.blocks[self.backrefs[succ as usize] as usize]
.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) {
@ -1245,7 +1368,7 @@ impl regalloc2::Function for Function<'_> {
}
impl TokenKind {
pub fn cmp_against(self) -> Option<u64> {
fn cmp_against(self) -> Option<u64> {
Some(match self {
TokenKind::Le | TokenKind::Gt => 1,
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() {
return None;
}
@ -1369,7 +1492,7 @@ impl TokenKind {
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;
Some(match self {
Self::Sub => instrs::neg,
@ -1392,7 +1515,7 @@ fn emit(out: &mut Vec<u8>, (len, instr): EncodedInstr) {
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::tx());
}
@ -1501,6 +1624,7 @@ pub struct Comptime {
pub vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>,
stack: Box<[u8; VM_STACK_SIZE]>,
pub code: Vec<u8>,
depth: usize,
}
impl Comptime {
@ -1544,6 +1668,19 @@ impl Comptime {
pub fn clear(&mut self) {
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 {
@ -1552,7 +1689,7 @@ impl Default for Comptime {
let mut vm = hbvm::Vm::default();
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
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:
ADDI64 r254, r254, -40d
ST r31, r254, 24a, 16h
ADDI64 r254, r254, -56d
ST r31, r254, 24a, 32h
LI64 r32, 1d
ADDI64 r2, r254, 0d
ST r32, r254, 0a, 8h
LI64 r5, 2d
ST r5, r254, 8a, 8h
LI64 r8, 4d
ST r8, r254, 16a, 8h
LI64 r33, 2d
ST r33, r254, 8a, 8h
LI64 r34, 4d
ST r34, r254, 16a, 8h
JAL r31, r0, :pass
ADD64 r1, r1, r32
LD r31, r254, 24a, 16h
ADDI64 r254, r254, 40d
LD r31, r254, 24a, 32h
ADDI64 r254, r254, 56d
JALA r0, r31, 0a
pass:
LD r4, r2, 8a, 8h

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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