forked from AbleOS/holey-bytes
add new ableos path resolver, separate platform independent code
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
d368ac023b
commit
19aca050ed
|
@ -2,3 +2,4 @@
|
||||||
--fmt-stdout - dont write the formatted file but print it
|
--fmt-stdout - dont write the formatted file but print it
|
||||||
--dump-asm - output assembly instead of raw code, (the assembly is more for debugging the compiler)
|
--dump-asm - output assembly instead of raw code, (the assembly is more for debugging the compiler)
|
||||||
--threads <1...> - number of extra threads compiler can use [default: 0]
|
--threads <1...> - number of extra threads compiler can use [default: 0]
|
||||||
|
--path-resolver <name> - choose between builtin path resolvers, options are: ableos
|
||||||
|
|
|
@ -41,13 +41,16 @@ pub struct Options<'a> {
|
||||||
pub fmt: bool,
|
pub fmt: bool,
|
||||||
pub fmt_stdout: bool,
|
pub fmt_stdout: bool,
|
||||||
pub dump_asm: bool,
|
pub dump_asm: bool,
|
||||||
pub in_house_regalloc: bool,
|
|
||||||
pub extra_threads: usize,
|
pub extra_threads: usize,
|
||||||
pub resolver: Option<PathResolver<'a>>,
|
pub resolver: Option<PathResolver<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options<'static> {
|
impl<'a> Options<'a> {
|
||||||
pub fn from_args(args: &[&str], out: &mut Vec<u8>) -> std::io::Result<Self> {
|
pub fn from_args(
|
||||||
|
args: &[&str],
|
||||||
|
out: &mut Vec<u8>,
|
||||||
|
resolvers: &'a [(&str, PathResolver)],
|
||||||
|
) -> std::io::Result<Self> {
|
||||||
if args.contains(&"--help") || args.contains(&"-h") {
|
if args.contains(&"--help") || args.contains(&"-h") {
|
||||||
writeln!(out, "Usage: hbc [OPTIONS...] <FILE>")?;
|
writeln!(out, "Usage: hbc [OPTIONS...] <FILE>")?;
|
||||||
writeln!(out, include_str!("../command-help.txt"))?;
|
writeln!(out, include_str!("../command-help.txt"))?;
|
||||||
|
@ -58,7 +61,6 @@ impl Options<'static> {
|
||||||
fmt: args.contains(&"--fmt"),
|
fmt: args.contains(&"--fmt"),
|
||||||
fmt_stdout: args.contains(&"--fmt-stdout"),
|
fmt_stdout: args.contains(&"--fmt-stdout"),
|
||||||
dump_asm: args.contains(&"--dump-asm"),
|
dump_asm: args.contains(&"--dump-asm"),
|
||||||
in_house_regalloc: args.contains(&"--in-house-regalloc"),
|
|
||||||
extra_threads: args
|
extra_threads: args
|
||||||
.iter()
|
.iter()
|
||||||
.position(|&a| a == "--threads")
|
.position(|&a| a == "--threads")
|
||||||
|
@ -72,7 +74,27 @@ impl Options<'static> {
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.map_or(1, NonZeroUsize::get)
|
.map_or(1, NonZeroUsize::get)
|
||||||
- 1,
|
- 1,
|
||||||
..Default::default()
|
resolver: args
|
||||||
|
.iter()
|
||||||
|
.position(|&a| a == "--path-resolver")
|
||||||
|
.map(|i| {
|
||||||
|
resolvers.iter().find(|&&(n, _)| args[i + 1] == n).map(|&(_, r)| r).ok_or_else(
|
||||||
|
|| {
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"--path-resolver can only be one of: {}",
|
||||||
|
resolvers
|
||||||
|
.iter()
|
||||||
|
.map(|&(n, _)| n)
|
||||||
|
.intersperse(", ")
|
||||||
|
.collect::<String>()
|
||||||
|
)
|
||||||
|
.err()
|
||||||
|
.unwrap_or(std::io::ErrorKind::Other.into())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.transpose()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +129,6 @@ pub fn run_compiler(
|
||||||
write!(out, "{}", &parsed.ast[0])?;
|
write!(out, "{}", &parsed.ast[0])?;
|
||||||
} else {
|
} else {
|
||||||
let mut backend = HbvmBackend::default();
|
let mut backend = HbvmBackend::default();
|
||||||
backend.use_in_house_regalloc = options.in_house_regalloc;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -100,15 +100,6 @@ mod debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod reg {
|
|
||||||
pub const STACK_PTR: Reg = 254;
|
|
||||||
pub const ZERO: Reg = 0;
|
|
||||||
pub const RET: Reg = 1;
|
|
||||||
pub const RET_ADDR: Reg = 31;
|
|
||||||
|
|
||||||
pub type Reg = u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod ctx_map {
|
mod ctx_map {
|
||||||
use core::hash::BuildHasher;
|
use core::hash::BuildHasher;
|
||||||
|
|
||||||
|
@ -841,12 +832,6 @@ enum CompState {
|
||||||
Compiled,
|
Compiled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct TypedReloc {
|
|
||||||
target: ty::Id,
|
|
||||||
reloc: Reloc,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct Global {
|
struct Global {
|
||||||
file: Module,
|
file: Module,
|
||||||
|
@ -863,33 +848,6 @@ pub struct Const {
|
||||||
parent: ty::Id,
|
parent: ty::Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
struct Reloc {
|
|
||||||
offset: Offset,
|
|
||||||
sub_offset: u8,
|
|
||||||
width: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reloc {
|
|
||||||
fn new(offset: usize, sub_offset: u8, width: u8) -> Self {
|
|
||||||
Self { offset: offset as u32, sub_offset, width }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_jump(mut self, code: &mut [u8], to: u32, from: u32) -> i64 {
|
|
||||||
self.offset += from;
|
|
||||||
let offset = to as i64 - self.offset as i64;
|
|
||||||
self.write_offset(code, offset);
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_offset(&self, code: &mut [u8], offset: i64) {
|
|
||||||
let bytes = offset.to_ne_bytes();
|
|
||||||
let slice = &mut code[self.offset as usize + self.sub_offset as usize..];
|
|
||||||
slice[..self.width as usize].copy_from_slice(&bytes[..self.width as usize]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct EnumField {
|
struct EnumField {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
}
|
}
|
||||||
|
@ -941,26 +899,6 @@ impl Array {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum PLoc {
|
|
||||||
Reg(u8, u16),
|
|
||||||
WideReg(u8, u16),
|
|
||||||
Ref(u8, u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ParamAlloc(Range<u8>);
|
|
||||||
|
|
||||||
impl ParamAlloc {
|
|
||||||
pub fn next(&mut self, ty: ty::Id, tys: &Types) -> Option<PLoc> {
|
|
||||||
Some(match tys.size_of(ty) {
|
|
||||||
0 => return None,
|
|
||||||
size @ 1..=8 => PLoc::Reg(self.0.next().unwrap(), size as _),
|
|
||||||
size @ 9..=16 => PLoc::WideReg(self.0.next_chunk::<2>().unwrap()[0], size as _),
|
|
||||||
size @ 17.. => PLoc::Ref(self.0.next().unwrap(), size),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ctx_map::CtxEntry for Ident {
|
impl ctx_map::CtxEntry for Ident {
|
||||||
type Ctx = str;
|
type Ctx = str;
|
||||||
type Key<'a> = &'a str;
|
type Key<'a> = &'a str;
|
||||||
|
@ -1109,13 +1047,6 @@ impl Types {
|
||||||
start..end
|
start..end
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parama(&self, ret: impl Into<ty::Id>) -> (Option<PLoc>, ParamAlloc) {
|
|
||||||
let mut iter = ParamAlloc(1..12);
|
|
||||||
let ret = iter.next(ret.into(), self);
|
|
||||||
iter.0.start += ret.is_none() as u8;
|
|
||||||
(ret, iter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
||||||
self.make_generic_ty(Opt { base }, |ins| &mut ins.opts, |e| SymKey::Optional(e))
|
self.make_generic_ty(Opt { base }, |ins| &mut ins.opts, |e| SymKey::Optional(e))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,43 @@
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
fn main() {
|
fn main() {
|
||||||
use std::io::Write;
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
static ABLEOS_PATH_RESOLVER: hblang::PathResolver =
|
||||||
|
&|mut path: &str, mut from: &str, tmp: &mut PathBuf| {
|
||||||
|
tmp.clear();
|
||||||
|
|
||||||
|
path = match path {
|
||||||
|
"stn" => {
|
||||||
|
from = "";
|
||||||
|
"./sysdata/libraries/stn/src/lib.hb"
|
||||||
|
}
|
||||||
|
_ => path,
|
||||||
|
};
|
||||||
|
|
||||||
|
match path.split_once(':') {
|
||||||
|
Some(("lib", p)) => tmp.extend(["./sysdata/libraries", p, "src/lib.hb"]),
|
||||||
|
Some(("stn", p)) => {
|
||||||
|
tmp.extend(["./sysdata/libraries/stn/src", &(p.to_owned() + ".hb")])
|
||||||
|
}
|
||||||
|
Some(("sysdata", p)) => tmp.extend(["./sysdata", p]),
|
||||||
|
None => match Path::new(from).parent() {
|
||||||
|
Some(parent) => tmp.extend([parent, Path::new(path)]),
|
||||||
|
None => tmp.push(path),
|
||||||
|
},
|
||||||
|
_ => panic!("path: '{path}' is invalid: unexpected ':'"),
|
||||||
|
};
|
||||||
|
tmp.canonicalize()
|
||||||
|
.map_err(|source| hblang::CantLoadFile { path: std::mem::take(tmp), source })
|
||||||
|
};
|
||||||
|
|
||||||
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
|
fn run(out: &mut Vec<u8>, warnings: &mut String) -> std::io::Result<()> {
|
||||||
let args = std::env::args().collect::<Vec<_>>();
|
let args = std::env::args().collect::<Vec<_>>();
|
||||||
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
let args = args.iter().map(String::as_str).collect::<Vec<_>>();
|
||||||
|
let resolvers = &[("ableos", ABLEOS_PATH_RESOLVER)];
|
||||||
let opts = hblang::Options::from_args(&args, out)?;
|
let opts = hblang::Options::from_args(&args, out, resolvers)?;
|
||||||
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
|
let file = args.iter().filter(|a| !a.starts_with('-')).nth(1).copied().unwrap_or("main.hb");
|
||||||
|
|
||||||
hblang::run_compiler(file, opts, out, warnings)
|
hblang::run_compiler(file, opts, out, warnings)
|
||||||
|
|
122
lang/src/son.rs
122
lang/src/son.rs
|
@ -297,6 +297,120 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn schedule_inside_blocks(
|
||||||
|
&mut self,
|
||||||
|
cfg_nodes: &mut Vec<Nid>,
|
||||||
|
buf: &mut Vec<Nid>,
|
||||||
|
seen: &mut BitSet,
|
||||||
|
) {
|
||||||
|
debug_assert!(cfg_nodes.is_empty());
|
||||||
|
debug_assert!(buf.is_empty());
|
||||||
|
cfg_nodes.extend(
|
||||||
|
self.iter()
|
||||||
|
// skip VOID and NEVER
|
||||||
|
.skip(2)
|
||||||
|
.filter(|(_, n)| n.kind.is_cfg() && !n.kind.ends_basic_block())
|
||||||
|
.map(|(n, _)| n),
|
||||||
|
);
|
||||||
|
|
||||||
|
for &block in &*cfg_nodes {
|
||||||
|
seen.clear(self.values.len());
|
||||||
|
let mut outputs = mem::take(&mut self[block].outputs);
|
||||||
|
self.reschedule_block(block, &mut outputs, buf, seen);
|
||||||
|
self[block].outputs = outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_nodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reschedule_block(
|
||||||
|
&self,
|
||||||
|
from: Nid,
|
||||||
|
outputs: &mut [Nid],
|
||||||
|
buf: &mut Vec<Nid>,
|
||||||
|
seen: &mut BitSet,
|
||||||
|
) {
|
||||||
|
debug_assert!(buf.is_empty());
|
||||||
|
|
||||||
|
// NOTE: this code is horible
|
||||||
|
let fromc = Some(&from);
|
||||||
|
|
||||||
|
let cfg_idx = outputs.iter().position(|&n| self.is_cfg(n)).unwrap();
|
||||||
|
outputs.swap(cfg_idx, 0);
|
||||||
|
for &o in outputs.iter() {
|
||||||
|
if (!self.is_cfg(o)
|
||||||
|
&& self[o].outputs.iter().any(|&oi| {
|
||||||
|
self[oi].kind != Kind::Phi && self[oi].inputs.first() == fromc && !seen.get(oi)
|
||||||
|
}))
|
||||||
|
|| !seen.set(o)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut cursor = buf.len();
|
||||||
|
for &o in outputs.iter().filter(|&&n| n == o) {
|
||||||
|
buf.push(o);
|
||||||
|
}
|
||||||
|
while let Some(&n) = buf.get(cursor) {
|
||||||
|
for &i in &self[n].inputs[1..] {
|
||||||
|
if fromc == self[i].inputs.first()
|
||||||
|
&& self[i].outputs.iter().all(|&o| {
|
||||||
|
self[o].kind == Kind::Phi
|
||||||
|
|| self[o].inputs.first() != fromc
|
||||||
|
|| seen.get(o)
|
||||||
|
})
|
||||||
|
&& seen.set(i)
|
||||||
|
{
|
||||||
|
for &o in outputs.iter().filter(|&&n| n == i) {
|
||||||
|
buf.push(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
outputs.iter().filter(|&&n| !seen.get(n)).copied().collect::<Vec<_>>(),
|
||||||
|
vec![],
|
||||||
|
"{:?} {from:?} {:?}",
|
||||||
|
outputs
|
||||||
|
.iter()
|
||||||
|
.filter(|&&n| !seen.get(n))
|
||||||
|
.copied()
|
||||||
|
.map(|n| (n, &self[n]))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
self[from]
|
||||||
|
);
|
||||||
|
|
||||||
|
let bf = &buf;
|
||||||
|
debug_assert_eq!(
|
||||||
|
bf.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, &b)| !self[b].kind.is_pinned())
|
||||||
|
.flat_map(|(i, &b)| self[b]
|
||||||
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.filter(|&&b| !self[b].kind.is_pinned())
|
||||||
|
.filter_map(move |&inp| bf
|
||||||
|
.iter()
|
||||||
|
.position(|&n| inp == n)
|
||||||
|
.filter(|&j| i > j)
|
||||||
|
.map(|j| (bf[i], bf[j]))))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![],
|
||||||
|
"{:?}",
|
||||||
|
bf
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert!(self.is_cfg(bf[0]) || self[bf[0]].kind == Kind::Phi, "{:?}", self[bf[0]]);
|
||||||
|
|
||||||
|
if outputs.len() != buf.len() {
|
||||||
|
panic!("{:?} {:?}", outputs, buf);
|
||||||
|
}
|
||||||
|
outputs.copy_from_slice(buf);
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn push_down(
|
fn push_down(
|
||||||
&self,
|
&self,
|
||||||
node: Nid,
|
node: Nid,
|
||||||
|
@ -623,6 +737,9 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.clear();
|
scratch.clear();
|
||||||
|
|
||||||
|
visited.clear(self.values.len());
|
||||||
|
self.schedule_inside_blocks(bind_buf, scratch, visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
|
@ -2410,11 +2527,6 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_reloc(doce: &mut [u8], offset: usize, value: i64, size: u16) {
|
|
||||||
let value = value.to_ne_bytes();
|
|
||||||
doce[offset..offset + size as usize].copy_from_slice(&value[..size as usize]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct Ctx {
|
struct Ctx {
|
||||||
ty: Option<ty::Id>,
|
ty: Option<ty::Id>,
|
||||||
|
|
|
@ -3,19 +3,66 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser,
|
parser,
|
||||||
reg::{self, Reg},
|
son::{debug_assert_matches, Kind, MEM},
|
||||||
son::{debug_assert_matches, write_reloc, Kind, MEM},
|
|
||||||
ty::{self, Arg, Loc, Module},
|
ty::{self, Arg, Loc, Module},
|
||||||
utils::{BitSet, Ent, EntVec, Vc},
|
utils::{Ent, EntVec},
|
||||||
Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types,
|
Offset, Sig, Size, Types,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||||
core::mem,
|
core::{mem, ops::Range},
|
||||||
hbbytecode::{self as instrs, *},
|
hbbytecode::{self as instrs, *},
|
||||||
|
reg::Reg,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod regalloc;
|
mod regalloc;
|
||||||
|
|
||||||
|
mod reg {
|
||||||
|
pub const STACK_PTR: Reg = 254;
|
||||||
|
pub const ZERO: Reg = 0;
|
||||||
|
pub const RET: Reg = 1;
|
||||||
|
pub const RET_ADDR: Reg = 31;
|
||||||
|
|
||||||
|
pub type Reg = u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_reloc(doce: &mut [u8], offset: usize, value: i64, size: u16) {
|
||||||
|
let value = value.to_ne_bytes();
|
||||||
|
doce[offset..offset + size as usize].copy_from_slice(&value[..size as usize]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct TypedReloc {
|
||||||
|
target: ty::Id,
|
||||||
|
reloc: Reloc,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct Reloc {
|
||||||
|
offset: Offset,
|
||||||
|
sub_offset: u8,
|
||||||
|
width: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reloc {
|
||||||
|
fn new(offset: usize, sub_offset: u8, width: u8) -> Self {
|
||||||
|
Self { offset: offset as u32, sub_offset, width }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_jump(mut self, code: &mut [u8], to: u32, from: u32) -> i64 {
|
||||||
|
self.offset += from;
|
||||||
|
let offset = to as i64 - self.offset as i64;
|
||||||
|
self.write_offset(code, offset);
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_offset(&self, code: &mut [u8], offset: i64) {
|
||||||
|
let bytes = offset.to_ne_bytes();
|
||||||
|
let slice = &mut code[self.offset as usize + self.sub_offset as usize..];
|
||||||
|
slice[..self.width as usize].copy_from_slice(&bytes[..self.width as usize]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct FuncDt {
|
struct FuncDt {
|
||||||
offset: Offset,
|
offset: Offset,
|
||||||
// TODO: change to indices into common vec
|
// TODO: change to indices into common vec
|
||||||
|
@ -48,8 +95,6 @@ struct Assembler {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct HbvmBackend {
|
pub struct HbvmBackend {
|
||||||
pub use_in_house_regalloc: bool,
|
|
||||||
|
|
||||||
funcs: EntVec<ty::Func, FuncDt>,
|
funcs: EntVec<ty::Func, FuncDt>,
|
||||||
globals: EntVec<ty::Global, GlobalDt>,
|
globals: EntVec<ty::Global, GlobalDt>,
|
||||||
asm: Assembler,
|
asm: Assembler,
|
||||||
|
@ -355,89 +400,6 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reschedule_block(&self, from: Nid, outputs: &mut Vc) {
|
|
||||||
// NOTE: this code is horible
|
|
||||||
let fromc = Some(&from);
|
|
||||||
let mut buf = Vec::with_capacity(outputs.len());
|
|
||||||
let mut seen = BitSet::default();
|
|
||||||
seen.clear(self.values.len());
|
|
||||||
|
|
||||||
let cfg_idx = outputs.iter().position(|&n| self.is_cfg(n)).unwrap();
|
|
||||||
outputs.swap(cfg_idx, 0);
|
|
||||||
|
|
||||||
for &o in outputs.iter() {
|
|
||||||
if (!self.is_cfg(o)
|
|
||||||
&& self[o].outputs.iter().any(|&oi| {
|
|
||||||
self[oi].kind != Kind::Phi && self[oi].inputs.first() == fromc && !seen.get(oi)
|
|
||||||
}))
|
|
||||||
|| !seen.set(o)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut cursor = buf.len();
|
|
||||||
for &o in outputs.iter().filter(|&&n| n == o) {
|
|
||||||
buf.push(o);
|
|
||||||
}
|
|
||||||
while let Some(&n) = buf.get(cursor) {
|
|
||||||
for &i in &self[n].inputs[1..] {
|
|
||||||
if fromc == self[i].inputs.first()
|
|
||||||
&& self[i].outputs.iter().all(|&o| {
|
|
||||||
self[o].kind == Kind::Phi
|
|
||||||
|| self[o].inputs.first() != fromc
|
|
||||||
|| seen.get(o)
|
|
||||||
})
|
|
||||||
&& seen.set(i)
|
|
||||||
{
|
|
||||||
for &o in outputs.iter().filter(|&&n| n == i) {
|
|
||||||
buf.push(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert_eq!(
|
|
||||||
outputs.iter().filter(|&&n| !seen.get(n)).copied().collect::<Vec<_>>(),
|
|
||||||
vec![],
|
|
||||||
"{:?} {from:?} {:?}",
|
|
||||||
outputs
|
|
||||||
.iter()
|
|
||||||
.filter(|&&n| !seen.get(n))
|
|
||||||
.copied()
|
|
||||||
.map(|n| (n, &self[n]))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
self[from]
|
|
||||||
);
|
|
||||||
|
|
||||||
let bf = &buf;
|
|
||||||
debug_assert_eq!(
|
|
||||||
bf.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, &b)| !self[b].kind.is_pinned())
|
|
||||||
.flat_map(|(i, &b)| self[b]
|
|
||||||
.inputs
|
|
||||||
.iter()
|
|
||||||
.filter(|&&b| !self[b].kind.is_pinned())
|
|
||||||
.filter_map(move |&inp| bf
|
|
||||||
.iter()
|
|
||||||
.position(|&n| inp == n)
|
|
||||||
.filter(|&j| i > j)
|
|
||||||
.map(|j| (bf[i], bf[j]))))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
vec![],
|
|
||||||
"{:?}",
|
|
||||||
bf
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_assert!(self.is_cfg(bf[0]) || self[bf[0]].kind == Kind::Phi, "{:?}", self[bf[0]]);
|
|
||||||
|
|
||||||
if outputs.len() != buf.len() {
|
|
||||||
panic!("{:?} {:?}", outputs, buf);
|
|
||||||
}
|
|
||||||
outputs.copy_from_slice(&buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_never_used(&self, nid: Nid, tys: &Types) -> bool {
|
fn is_never_used(&self, nid: Nid, tys: &Types) -> bool {
|
||||||
let node = &self[nid];
|
let node = &self[nid];
|
||||||
match node.kind {
|
match node.kind {
|
||||||
|
@ -919,6 +881,35 @@ impl TokenKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum PLoc {
|
||||||
|
Reg(Reg, u16),
|
||||||
|
WideReg(Reg, u16),
|
||||||
|
Ref(Reg, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParamAlloc(Range<Reg>);
|
||||||
|
|
||||||
|
impl ParamAlloc {
|
||||||
|
pub fn next(&mut self, ty: ty::Id, tys: &Types) -> Option<PLoc> {
|
||||||
|
Some(match tys.size_of(ty) {
|
||||||
|
0 => return None,
|
||||||
|
size @ 1..=8 => PLoc::Reg(self.0.next().unwrap(), size as _),
|
||||||
|
size @ 9..=16 => PLoc::WideReg(self.0.next_chunk::<2>().unwrap()[0], size as _),
|
||||||
|
size @ 17.. => PLoc::Ref(self.0.next().unwrap(), size),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Types {
|
||||||
|
fn parama(&self, ret: ty::Id) -> (Option<PLoc>, ParamAlloc) {
|
||||||
|
let mut iter = ParamAlloc(1..12);
|
||||||
|
let ret = iter.next(ret, self);
|
||||||
|
iter.0.start += ret.is_none() as u8;
|
||||||
|
(ret, iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type EncodedInstr = (usize, [u8; instrs::MAX_SIZE]);
|
type EncodedInstr = (usize, [u8; instrs::MAX_SIZE]);
|
||||||
fn emit(out: &mut Vec<u8>, (len, instr): EncodedInstr) {
|
fn emit(out: &mut Vec<u8>, (len, instr): EncodedInstr) {
|
||||||
out.extend_from_slice(&instr[..len]);
|
out.extend_from_slice(&instr[..len]);
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use {
|
use {
|
||||||
super::{HbvmBackend, Nid, Nodes},
|
|
||||||
crate::{
|
crate::{
|
||||||
parser,
|
parser,
|
||||||
reg::{self, Reg},
|
son::{
|
||||||
son::{debug_assert_matches, Kind, ARG_START, MEM, VOID},
|
debug_assert_matches,
|
||||||
|
hbvm::{reg, reg::Reg, HbvmBackend, Nid, Nodes, PLoc},
|
||||||
|
Kind, ARG_START, MEM, VOID,
|
||||||
|
},
|
||||||
ty::{self, Arg, Loc},
|
ty::{self, Arg, Loc},
|
||||||
utils::BitSet,
|
utils::BitSet,
|
||||||
PLoc, Sig, Types,
|
Sig, Types,
|
||||||
},
|
},
|
||||||
alloc::{borrow::ToOwned, vec::Vec},
|
alloc::{borrow::ToOwned, vec::Vec},
|
||||||
core::{mem, ops::Range},
|
core::{mem, ops::Range},
|
||||||
|
@ -415,7 +417,7 @@ impl<'a> Function<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut node = self.nodes[nid].clone();
|
let node = &self.nodes[nid];
|
||||||
match node.kind {
|
match node.kind {
|
||||||
Kind::Start => {
|
Kind::Start => {
|
||||||
debug_assert_matches!(self.nodes[node.outputs[0]].kind, Kind::Entry);
|
debug_assert_matches!(self.nodes[node.outputs[0]].kind, Kind::Entry);
|
||||||
|
@ -441,8 +443,7 @@ impl<'a> Function<'a> {
|
||||||
Kind::Region | Kind::Loop => {
|
Kind::Region | Kind::Loop => {
|
||||||
self.close_block(nid);
|
self.close_block(nid);
|
||||||
self.add_block(nid);
|
self.add_block(nid);
|
||||||
self.nodes.reschedule_block(nid, &mut node.outputs);
|
for &o in node.outputs.iter().rev() {
|
||||||
for o in node.outputs.into_iter().rev() {
|
|
||||||
self.emit_node(o);
|
self.emit_node(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,15 +470,13 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.nodes.reschedule_block(nid, &mut node.outputs);
|
for &o in node.outputs.iter().rev() {
|
||||||
for o in node.outputs.into_iter().rev() {
|
|
||||||
self.emit_node(o);
|
self.emit_node(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Then | Kind::Else => {
|
Kind::Then | Kind::Else => {
|
||||||
self.add_block(nid);
|
self.add_block(nid);
|
||||||
self.nodes.reschedule_block(nid, &mut node.outputs);
|
for &o in node.outputs.iter().rev() {
|
||||||
for o in node.outputs.into_iter().rev() {
|
|
||||||
self.emit_node(o);
|
self.emit_node(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,8 +485,7 @@ impl<'a> Function<'a> {
|
||||||
|
|
||||||
self.add_instr(nid);
|
self.add_instr(nid);
|
||||||
|
|
||||||
self.nodes.reschedule_block(nid, &mut node.outputs);
|
for &o in node.outputs.iter().rev() {
|
||||||
for o in node.outputs.into_iter().rev() {
|
|
||||||
if self.nodes[o].inputs[0] == nid
|
if self.nodes[o].inputs[0] == nid
|
||||||
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
|
|| (matches!(self.nodes[o].kind, Kind::Loop | Kind::Region)
|
||||||
&& self.nodes[o].inputs[1] == nid)
|
&& self.nodes[o].inputs[1] == nid)
|
||||||
|
|
|
@ -15,16 +15,16 @@ main:
|
||||||
ADDI64 r254, r254, 24d
|
ADDI64 r254, r254, 24d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
str_len:
|
str_len:
|
||||||
CP r15, r2
|
CP r13, r2
|
||||||
CP r14, r0
|
CP r15, r0
|
||||||
CP r13, r14
|
CP r14, r15
|
||||||
2: LD r16, r15, 0a, 1h
|
2: LD r16, r13, 0a, 1h
|
||||||
ANDI r16, r16, 255d
|
ANDI r16, r16, 255d
|
||||||
JNE r16, r14, :0
|
JNE r16, r15, :0
|
||||||
CP r1, r13
|
CP r1, r14
|
||||||
JMP :1
|
JMP :1
|
||||||
0: ADDI64 r15, r15, 1d
|
0: ADDI64 r13, r13, 1d
|
||||||
ADDI64 r13, r13, 1d
|
ADDI64 r14, r14, 1d
|
||||||
JMP :2
|
JMP :2
|
||||||
1: JALA r0, r31, 0a
|
1: JALA r0, r31, 0a
|
||||||
code size: 216
|
code size: 216
|
||||||
|
|
|
@ -11,29 +11,29 @@ main:
|
||||||
ADDI64 r254, r254, -56d
|
ADDI64 r254, r254, -56d
|
||||||
ST r31, r254, 0a, 56h
|
ST r31, r254, 0a, 56h
|
||||||
JAL r31, r0, :check_platform
|
JAL r31, r0, :check_platform
|
||||||
CP r33, r0
|
CP r35, r0
|
||||||
LI64 r36, 30d
|
LI64 r36, 30d
|
||||||
LI64 r37, 100d
|
LI64 r37, 100d
|
||||||
CP r35, r33
|
CP r34, r35
|
||||||
CP r34, r33
|
CP r33, r35
|
||||||
CP r32, r33
|
CP r32, r35
|
||||||
5: JLTU r32, r36, :0
|
5: JLTU r34, r36, :0
|
||||||
ADDI64 r34, r34, 1d
|
ADDI64 r32, r32, 1d
|
||||||
CP r2, r33
|
CP r2, r35
|
||||||
CP r3, r34
|
CP r3, r32
|
||||||
CP r4, r36
|
CP r4, r36
|
||||||
JAL r31, r0, :set_pixel
|
JAL r31, r0, :set_pixel
|
||||||
CP r32, r1
|
CP r34, r1
|
||||||
JEQ r32, r35, :1
|
JEQ r34, r33, :1
|
||||||
CP r1, r33
|
|
||||||
JMP :2
|
|
||||||
1: JNE r34, r37, :3
|
|
||||||
CP r1, r35
|
CP r1, r35
|
||||||
JMP :2
|
JMP :2
|
||||||
3: CP r32, r33
|
1: JNE r32, r37, :3
|
||||||
|
CP r1, r33
|
||||||
|
JMP :2
|
||||||
|
3: CP r34, r35
|
||||||
JMP :4
|
JMP :4
|
||||||
0: ADDI64 r35, r35, 1d
|
0: ADDI64 r33, r33, 1d
|
||||||
ADDI64 r32, r32, 1d
|
ADDI64 r34, r34, 1d
|
||||||
4: JMP :5
|
4: JMP :5
|
||||||
2: LD r31, r254, 0a, 56h
|
2: LD r31, r254, 0a, 56h
|
||||||
ADDI64 r254, r254, 56d
|
ADDI64 r254, r254, 56d
|
||||||
|
|
|
@ -10,21 +10,21 @@ main:
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
sqrt:
|
sqrt:
|
||||||
CP r13, r2
|
CP r14, r2
|
||||||
LI64 r16, 15d
|
LI64 r16, 15d
|
||||||
LI64 r15, 32768d
|
LI64 r15, 32768d
|
||||||
CP r17, r0
|
CP r17, r0
|
||||||
CP r14, r17
|
CP r13, r17
|
||||||
3: JNE r15, r17, :0
|
3: JNE r15, r17, :0
|
||||||
CP r1, r14
|
CP r1, r13
|
||||||
JMP :1
|
JMP :1
|
||||||
0: SLUI64 r18, r14, 1b
|
0: SLUI64 r18, r13, 1b
|
||||||
ADDI64 r16, r16, -1d
|
ADDI64 r16, r16, -1d
|
||||||
ADD64 r18, r18, r15
|
ADD64 r18, r18, r15
|
||||||
SLU64 r18, r18, r16
|
SLU64 r18, r18, r16
|
||||||
JLTU r13, r18, :2
|
JLTU r14, r18, :2
|
||||||
SUB64 r13, r13, r18
|
SUB64 r14, r14, r18
|
||||||
ADD64 r14, r15, r14
|
ADD64 r13, r15, r13
|
||||||
JMP :2
|
JMP :2
|
||||||
2: SRUI64 r15, r15, 1b
|
2: SRUI64 r15, r15, 1b
|
||||||
JMP :3
|
JMP :3
|
||||||
|
|
Loading…
Reference in a new issue