making tests more robust for no reason
This commit is contained in:
parent
9e0e0242aa
commit
00ad474881
|
@ -8,7 +8,7 @@ use {
|
||||||
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
|
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
|
||||||
HashMap,
|
HashMap,
|
||||||
},
|
},
|
||||||
std::{ops::Range, rc::Rc},
|
std::{ops::Range, rc::Rc, u32},
|
||||||
};
|
};
|
||||||
|
|
||||||
type Offset = u32;
|
type Offset = u32;
|
||||||
|
@ -517,29 +517,11 @@ struct Reloc {
|
||||||
offset: Offset,
|
offset: Offset,
|
||||||
sub_offset: u8,
|
sub_offset: u8,
|
||||||
width: u8,
|
width: u8,
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
shifted: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reloc {
|
impl Reloc {
|
||||||
fn new(offset: u32, sub_offset: u8, width: u8) -> Self {
|
fn new(offset: u32, sub_offset: u8, width: u8) -> Self {
|
||||||
Self {
|
Self { offset, sub_offset, width }
|
||||||
offset,
|
|
||||||
sub_offset,
|
|
||||||
width,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
shifted: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shifted(offset: u32, sub_offset: u8, width: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
offset,
|
|
||||||
sub_offset,
|
|
||||||
width,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
shifted: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_stack_offset(&self, code: &mut [u8], stack: &stack::Alloc) {
|
fn apply_stack_offset(&self, code: &mut [u8], stack: &stack::Alloc) {
|
||||||
|
@ -556,14 +538,14 @@ impl Reloc {
|
||||||
((id >> 32) as u32, id as u32)
|
((id >> 32) as u32, id as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_jump(&self, code: &mut [u8], to: u32) {
|
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;
|
let offset = to as i64 - self.offset as i64;
|
||||||
self.write_offset(code, offset);
|
self.write_offset(code, offset);
|
||||||
|
offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_offset(&self, code: &mut [u8], offset: i64) {
|
fn write_offset(&self, code: &mut [u8], offset: i64) {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
assert!(self.shifted);
|
|
||||||
let bytes = offset.to_ne_bytes();
|
let bytes = offset.to_ne_bytes();
|
||||||
let slice = &mut code[self.offset as usize + self.sub_offset as usize..];
|
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]);
|
slice[..self.width as usize].copy_from_slice(&bytes[..self.width as usize]);
|
||||||
|
@ -766,21 +748,10 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize(&mut self, output: &mut Output) {
|
fn finalize(&mut self, output: &mut Output) {
|
||||||
let len = output.code.len() as Offset;
|
|
||||||
let base = self.snap.code as Offset;
|
let base = self.snap.code as Offset;
|
||||||
for reloc in output.reloc_iter_mut(&self.snap).chain(&mut self.ret_relocs) {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
if std::mem::replace(&mut reloc.shifted, true) {
|
|
||||||
panic!("reloc visited twice");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reloc.offset += base;
|
|
||||||
debug_assert!(reloc.offset < len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(last_ret) = self.ret_relocs.last()
|
if let Some(last_ret) = self.ret_relocs.last()
|
||||||
&& last_ret.offset as usize == output.code.len() - 5
|
&& (last_ret.offset + base) as usize == output.code.len() - 5
|
||||||
{
|
{
|
||||||
output.code.truncate(output.code.len() - 5);
|
output.code.truncate(output.code.len() - 5);
|
||||||
self.ret_relocs.pop();
|
self.ret_relocs.pop();
|
||||||
|
@ -794,7 +765,8 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
for rel in self.ret_relocs.drain(..) {
|
for rel in self.ret_relocs.drain(..) {
|
||||||
rel.apply_jump(&mut output.code, len);
|
let off = rel.apply_jump(&mut output.code, len, base);
|
||||||
|
debug_assert!(off > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finalize_frame(output);
|
self.finalize_frame(output);
|
||||||
|
@ -872,6 +844,8 @@ struct Global {
|
||||||
offset: Offset,
|
offset: Offset,
|
||||||
ty: ty::Id,
|
ty: ty::Id,
|
||||||
runtime: bool,
|
runtime: bool,
|
||||||
|
_file: FileId,
|
||||||
|
_name: Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Field {
|
struct Field {
|
||||||
|
@ -918,6 +892,25 @@ struct Types {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Types {
|
impl Types {
|
||||||
|
pub fn offset_of_item(&self, item: ty::Kind, ct_hint: Option<u32>) -> Option<Offset> {
|
||||||
|
task::unpack(match item {
|
||||||
|
ty::Kind::Func(f) => self.funcs[f as usize].offset,
|
||||||
|
ty::Kind::Global(g) => self.globals[g as usize].offset,
|
||||||
|
ty::Kind::Builtin(u32::MAX) => ct_hint?,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_runtime_item(&self, item: ty::Kind) -> bool {
|
||||||
|
match item {
|
||||||
|
ty::Kind::Func(f) => self.funcs[f as usize].runtime,
|
||||||
|
ty::Kind::Global(f) => self.globals[f as usize].runtime,
|
||||||
|
ty::Kind::Builtin(u32::MAX) => false,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parama(&self, ret: impl Into<ty::Id>) -> ParamAlloc {
|
fn parama(&self, ret: impl Into<ty::Id>) -> ParamAlloc {
|
||||||
ParamAlloc(2 + (9..=16).contains(&self.size_of(ret.into())) as u8..12)
|
ParamAlloc(2 + (9..=16).contains(&self.size_of(ret.into())) as u8..12)
|
||||||
}
|
}
|
||||||
|
@ -1053,8 +1046,7 @@ struct FTask {
|
||||||
pub struct Snapshot {
|
pub struct Snapshot {
|
||||||
code: usize,
|
code: usize,
|
||||||
string_data: usize,
|
string_data: usize,
|
||||||
funcs: usize,
|
relocs: usize,
|
||||||
globals: usize,
|
|
||||||
strings: usize,
|
strings: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1062,26 +1054,29 @@ impl Snapshot {
|
||||||
fn _sub(&mut self, other: &Self) {
|
fn _sub(&mut self, other: &Self) {
|
||||||
self.code -= other.code;
|
self.code -= other.code;
|
||||||
self.string_data -= other.string_data;
|
self.string_data -= other.string_data;
|
||||||
self.funcs -= other.funcs;
|
self.relocs -= other.relocs;
|
||||||
self.globals -= other.globals;
|
|
||||||
self.strings -= other.strings;
|
self.strings -= other.strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _add(&mut self, other: &Self) {
|
fn _add(&mut self, other: &Self) {
|
||||||
self.code += other.code;
|
self.code += other.code;
|
||||||
self.string_data += other.string_data;
|
self.string_data += other.string_data;
|
||||||
self.funcs += other.funcs;
|
self.relocs += other.relocs;
|
||||||
self.globals += other.globals;
|
|
||||||
self.strings += other.strings;
|
self.strings += other.strings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct OutReloc {
|
||||||
|
from: ty::Kind,
|
||||||
|
to: ty::Kind,
|
||||||
|
rel: Reloc,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Output {
|
struct Output {
|
||||||
code: Vec<u8>,
|
code: Vec<u8>,
|
||||||
string_data: Vec<u8>,
|
string_data: Vec<u8>,
|
||||||
funcs: Vec<(ty::Func, Reloc)>,
|
relocs: Vec<OutReloc>,
|
||||||
globals: Vec<(ty::Global, Reloc)>,
|
|
||||||
strings: Vec<StringReloc>,
|
strings: Vec<StringReloc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1118,14 +1113,6 @@ impl Output {
|
||||||
self.emit(tx());
|
self.emit(tx());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reloc_iter_mut(&mut self, snap: &Snapshot) -> impl Iterator<Item = &mut Reloc> {
|
|
||||||
self.globals[snap.globals..]
|
|
||||||
.iter_mut()
|
|
||||||
.chain(&mut self.funcs[snap.funcs..])
|
|
||||||
.map(|(_, rel)| rel)
|
|
||||||
.chain(self.strings[snap.strings..].iter_mut().map(|rl| &mut rl.reloc))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append(&mut self, val: &mut Self) {
|
fn append(&mut self, val: &mut Self) {
|
||||||
val.pop(self, &Snapshot::default());
|
val.pop(self, &Snapshot::default());
|
||||||
}
|
}
|
||||||
|
@ -1135,26 +1122,7 @@ impl Output {
|
||||||
|
|
||||||
stash.code.extend(self.code.drain(snap.code..));
|
stash.code.extend(self.code.drain(snap.code..));
|
||||||
stash.string_data.extend(self.string_data.drain(snap.string_data..));
|
stash.string_data.extend(self.string_data.drain(snap.string_data..));
|
||||||
stash.funcs.extend(self.funcs.drain(snap.funcs..).inspect(|(_, rel)| {
|
stash.relocs.extend(self.relocs.drain(snap.relocs..));
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
assert!(!rel.shifted);
|
|
||||||
debug_assert!(
|
|
||||||
rel.offset as usize + init_code < stash.code.len(),
|
|
||||||
"{} {} {}",
|
|
||||||
rel.offset,
|
|
||||||
init_code,
|
|
||||||
stash.code.len()
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
stash.globals.extend(self.globals.drain(snap.globals..).inspect(|(_, rel)| {
|
|
||||||
log::dbg!(
|
|
||||||
"reloc: {rel:?} {init_code} {} {} {}",
|
|
||||||
stash.code.len(),
|
|
||||||
self.code.len(),
|
|
||||||
snap.code
|
|
||||||
);
|
|
||||||
debug_assert!(rel.offset as usize + init_code < stash.code.len())
|
|
||||||
}));
|
|
||||||
stash.strings.extend(self.strings.drain(snap.strings..).inspect(|str| {
|
stash.strings.extend(self.strings.drain(snap.strings..).inspect(|str| {
|
||||||
debug_assert!(str.reloc.offset as usize + init_code < stash.code.len())
|
debug_assert!(str.reloc.offset as usize + init_code < stash.code.len())
|
||||||
}));
|
}));
|
||||||
|
@ -1163,13 +1131,13 @@ impl Output {
|
||||||
fn trunc(&mut self, snap: &Snapshot) {
|
fn trunc(&mut self, snap: &Snapshot) {
|
||||||
self.code.truncate(snap.code);
|
self.code.truncate(snap.code);
|
||||||
self.string_data.truncate(snap.string_data);
|
self.string_data.truncate(snap.string_data);
|
||||||
self.globals.truncate(snap.globals);
|
self.relocs.truncate(snap.relocs);
|
||||||
self.funcs.truncate(snap.funcs);
|
|
||||||
self.strings.truncate(snap.strings);
|
self.strings.truncate(snap.strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_trap(&mut self, kind: trap::Trap) {
|
fn write_trap(&mut self, kind: trap::Trap) {
|
||||||
self.emit(eca());
|
self.emit(eca());
|
||||||
|
self.code.push(255);
|
||||||
self.code.extend(kind.as_slice());
|
self.code.extend(kind.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,8 +1145,7 @@ impl Output {
|
||||||
Snapshot {
|
Snapshot {
|
||||||
code: self.code.len(),
|
code: self.code.len(),
|
||||||
string_data: self.string_data.len(),
|
string_data: self.string_data.len(),
|
||||||
funcs: self.funcs.len(),
|
relocs: self.relocs.len(),
|
||||||
globals: self.globals.len(),
|
|
||||||
strings: self.strings.len(),
|
strings: self.strings.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1283,7 +1250,7 @@ impl hbvm::mem::Memory for LoggedMem {
|
||||||
const VM_STACK_SIZE: usize = 1024 * 1024 * 2;
|
const VM_STACK_SIZE: usize = 1024 * 1024 * 2;
|
||||||
|
|
||||||
struct Comptime {
|
struct Comptime {
|
||||||
vm: hbvm::Vm<LoggedMem, 0>,
|
vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
_stack: Box<[u8; VM_STACK_SIZE]>,
|
_stack: Box<[u8; VM_STACK_SIZE]>,
|
||||||
}
|
}
|
||||||
|
@ -1293,7 +1260,6 @@ impl Default for Comptime {
|
||||||
let mut stack = Box::<[u8; VM_STACK_SIZE]>::new_uninit();
|
let mut stack = Box::<[u8; VM_STACK_SIZE]>::new_uninit();
|
||||||
let mut vm = hbvm::Vm::default();
|
let mut vm = hbvm::Vm::default();
|
||||||
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
||||||
log::dbg!("stack_ptr: {:x}", ptr);
|
|
||||||
vm.write_reg(STACK_PTR, ptr);
|
vm.write_reg(STACK_PTR, ptr);
|
||||||
Self { vm, depth: 0, _stack: unsafe { stack.assume_init() } }
|
Self { vm, depth: 0, _stack: unsafe { stack.assume_init() } }
|
||||||
}
|
}
|
||||||
|
@ -1371,10 +1337,10 @@ mod trap {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StringReloc {
|
struct StringReloc {
|
||||||
|
// TODO: change to ty::Id
|
||||||
|
from: ty::Kind,
|
||||||
reloc: Reloc,
|
reloc: Reloc,
|
||||||
range: std::ops::Range<u32>,
|
range: std::ops::Range<u32>,
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
shifted: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -1399,8 +1365,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&mut self, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
pub fn dump(&mut self, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
||||||
let reloc = Reloc::shifted(0, 3, 4);
|
Reloc::new(0, 3, 4).apply_jump(&mut self.output.code, self.tys.funcs[0].offset, 0);
|
||||||
self.output.funcs.push((0, reloc));
|
|
||||||
self.link();
|
self.link();
|
||||||
out.write_all(&self.output.code)
|
out.write_all(&self.output.code)
|
||||||
}
|
}
|
||||||
|
@ -1567,13 +1532,8 @@ impl Codegen {
|
||||||
self.ci.ret_relocs.pop();
|
self.ci.ret_relocs.pop();
|
||||||
}
|
}
|
||||||
let len = self.output.code.len() as u32;
|
let len = self.output.code.len() as u32;
|
||||||
for mut rel in self.ci.ret_relocs.drain(ret_reloc_base..) {
|
for rel in self.ci.ret_relocs.drain(ret_reloc_base..) {
|
||||||
rel.offset += self.ci.snap.code as u32;
|
rel.apply_jump(&mut self.output.code, len, self.ci.snap.code as u32);
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
rel.shifted = true;
|
|
||||||
}
|
|
||||||
rel.apply_jump(&mut self.output.code, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(Value { ty: sig.ret, loc });
|
return Some(Value { ty: sig.ret, loc });
|
||||||
|
@ -1736,12 +1696,7 @@ impl Codegen {
|
||||||
|
|
||||||
let range = start as _..self.output.string_data.len() as _;
|
let range = start as _..self.output.string_data.len() as _;
|
||||||
let reloc = Reloc::new(self.local_offset() as _, 3, 4);
|
let reloc = Reloc::new(self.local_offset() as _, 3, 4);
|
||||||
self.output.strings.push(StringReloc {
|
self.output.strings.push(StringReloc { from: self.ci.id, reloc, range });
|
||||||
reloc,
|
|
||||||
range,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
shifted: false,
|
|
||||||
});
|
|
||||||
let reg = self.ci.regs.allocate();
|
let reg = self.ci.regs.allocate();
|
||||||
self.output.emit(instrs::lra(reg.get(), 0, 0));
|
self.output.emit(instrs::lra(reg.get(), 0, 0));
|
||||||
Some(Value::new(self.tys.make_ptr(ty::U8.into()), reg))
|
Some(Value::new(self.tys.make_ptr(ty::U8.into()), reg))
|
||||||
|
@ -1945,16 +1900,18 @@ impl Codegen {
|
||||||
self.ci.free_loc(value);
|
self.ci.free_loc(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::dbg!("call ctx: {ctx:?}");
|
|
||||||
|
|
||||||
let loc = self.alloc_ret(sig.ret, ctx, false);
|
let loc = self.alloc_ret(sig.ret, ctx, false);
|
||||||
|
|
||||||
if should_momize {
|
if should_momize {
|
||||||
self.output.write_trap(trap::Trap::MomizedCall(trap::MomizedCall { func }));
|
self.output.write_trap(trap::Trap::MomizedCall(trap::MomizedCall { func }));
|
||||||
}
|
}
|
||||||
|
|
||||||
let reloc = Reloc::new(self.local_offset(), 3, 4);
|
let rel = Reloc::new(self.local_offset(), 3, 4);
|
||||||
self.output.funcs.push((func, reloc));
|
self.output.relocs.push(OutReloc {
|
||||||
|
from: self.ci.id,
|
||||||
|
to: ty::Kind::Func(func),
|
||||||
|
rel,
|
||||||
|
});
|
||||||
self.output.emit(jal(RET_ADDR, ZERO, 0));
|
self.output.emit(jal(RET_ADDR, ZERO, 0));
|
||||||
self.make_func_reachable(func);
|
self.make_func_reachable(func);
|
||||||
|
|
||||||
|
@ -2027,7 +1984,6 @@ impl Codegen {
|
||||||
loc: Loc::ct(value as u64),
|
loc: Loc::ct(value as u64),
|
||||||
}),
|
}),
|
||||||
E::If { cond, then, else_, .. } => {
|
E::If { cond, then, else_, .. } => {
|
||||||
log::dbg!("if-cond");
|
|
||||||
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
|
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
|
||||||
let reg = self.loc_to_reg(&cond.loc, 1);
|
let reg = self.loc_to_reg(&cond.loc, 1);
|
||||||
let jump_offset = self.local_offset();
|
let jump_offset = self.local_offset();
|
||||||
|
@ -2035,14 +1991,12 @@ impl Codegen {
|
||||||
self.ci.free_loc(cond.loc);
|
self.ci.free_loc(cond.loc);
|
||||||
self.ci.regs.free(reg);
|
self.ci.regs.free(reg);
|
||||||
|
|
||||||
log::dbg!("if-then");
|
|
||||||
let then_unreachable = self.expr(then).is_none();
|
let then_unreachable = self.expr(then).is_none();
|
||||||
let mut else_unreachable = false;
|
let mut else_unreachable = false;
|
||||||
|
|
||||||
let mut jump = self.local_offset() as i64 - jump_offset as i64;
|
let mut jump = self.local_offset() as i64 - jump_offset as i64;
|
||||||
|
|
||||||
if let Some(else_) = else_ {
|
if let Some(else_) = else_ {
|
||||||
log::dbg!("if-else");
|
|
||||||
let else_jump_offset = self.local_offset();
|
let else_jump_offset = self.local_offset();
|
||||||
if !then_unreachable {
|
if !then_unreachable {
|
||||||
self.output.emit(jmp(0));
|
self.output.emit(jmp(0));
|
||||||
|
@ -2053,19 +2007,15 @@ impl Codegen {
|
||||||
|
|
||||||
if !then_unreachable {
|
if !then_unreachable {
|
||||||
let jump = self.local_offset() as i64 - else_jump_offset as i64;
|
let jump = self.local_offset() as i64 - else_jump_offset as i64;
|
||||||
log::dbg!("if-else-jump: {}", jump);
|
|
||||||
write_reloc(self.local_code(), else_jump_offset as usize + 1, jump, 4);
|
write_reloc(self.local_code(), else_jump_offset as usize + 1, jump, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log::dbg!("if-then-jump: {}", jump);
|
|
||||||
write_reloc(self.local_code(), jump_offset as usize + 3, jump, 2);
|
write_reloc(self.local_code(), jump_offset as usize + 3, jump, 2);
|
||||||
|
|
||||||
(!then_unreachable || !else_unreachable).then_some(Value::void())
|
(!then_unreachable || !else_unreachable).then_some(Value::void())
|
||||||
}
|
}
|
||||||
E::Loop { body, .. } => 'a: {
|
E::Loop { body, .. } => 'a: {
|
||||||
log::dbg!("loop");
|
|
||||||
|
|
||||||
let loop_start = self.local_offset();
|
let loop_start = self.local_offset();
|
||||||
self.ci.loops.push(Loop {
|
self.ci.loops.push(Loop {
|
||||||
var_count: self.ci.vars.len() as _,
|
var_count: self.ci.vars.len() as _,
|
||||||
|
@ -2074,18 +2024,19 @@ impl Codegen {
|
||||||
});
|
});
|
||||||
let body_unreachable = self.expr(body).is_none();
|
let body_unreachable = self.expr(body).is_none();
|
||||||
|
|
||||||
log::dbg!("loop-end");
|
|
||||||
if !body_unreachable {
|
if !body_unreachable {
|
||||||
let loop_end = self.local_offset();
|
let loop_end = self.local_offset();
|
||||||
self.output.emit(jmp(loop_start as i32 - loop_end as i32));
|
self.output.emit(jmp(loop_start as i32 - loop_end as i32));
|
||||||
}
|
}
|
||||||
|
|
||||||
let loop_end = self.local_offset();
|
let loop_end = self.output.code.len() as u32;
|
||||||
|
|
||||||
let loopa = self.ci.loops.pop().unwrap();
|
let loopa = self.ci.loops.pop().unwrap();
|
||||||
let is_unreachable = loopa.reloc_base == self.ci.loop_relocs.len() as u32;
|
let is_unreachable = loopa.reloc_base == self.ci.loop_relocs.len() as u32;
|
||||||
for reloc in self.ci.loop_relocs.drain(loopa.reloc_base as usize..) {
|
for reloc in self.ci.loop_relocs.drain(loopa.reloc_base as usize..) {
|
||||||
reloc.apply_jump(&mut self.output.code[self.ci.snap.code..], loop_end);
|
let off =
|
||||||
|
reloc.apply_jump(&mut self.output.code, loop_end, self.ci.snap.code as _);
|
||||||
|
debug_assert!(off > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vars = std::mem::take(&mut self.ci.vars);
|
let mut vars = std::mem::take(&mut self.ci.vars);
|
||||||
|
@ -2095,14 +2046,13 @@ impl Codegen {
|
||||||
self.ci.vars = vars;
|
self.ci.vars = vars;
|
||||||
|
|
||||||
if is_unreachable {
|
if is_unreachable {
|
||||||
log::dbg!("infinite loop");
|
|
||||||
break 'a None;
|
break 'a None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Value::void())
|
Some(Value::void())
|
||||||
}
|
}
|
||||||
E::Break { .. } => {
|
E::Break { .. } => {
|
||||||
self.ci.loop_relocs.push(Reloc::shifted(self.local_offset(), 1, 4));
|
self.ci.loop_relocs.push(Reloc::new(self.local_offset(), 1, 4));
|
||||||
self.output.emit(jmp(0));
|
self.output.emit(jmp(0));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -2147,7 +2097,6 @@ impl Codegen {
|
||||||
let lsize = self.tys.size_of(left.ty);
|
let lsize = self.tys.size_of(left.ty);
|
||||||
|
|
||||||
let lhs = self.loc_to_reg(left.loc, lsize);
|
let lhs = self.loc_to_reg(left.loc, lsize);
|
||||||
log::dbg!("{expr}");
|
|
||||||
let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?;
|
let right = self.expr_ctx(right, Ctx::default().with_ty(left.ty))?;
|
||||||
let rsize = self.tys.size_of(right.ty);
|
let rsize = self.tys.size_of(right.ty);
|
||||||
|
|
||||||
|
@ -2261,7 +2210,6 @@ impl Codegen {
|
||||||
|
|
||||||
for (arg, carg) in args.iter().zip(cargs) {
|
for (arg, carg) in args.iter().zip(cargs) {
|
||||||
let ty = self.ty(&carg.ty);
|
let ty = self.ty(&carg.ty);
|
||||||
log::dbg!("arg: {}", self.ty_display(ty));
|
|
||||||
self.tys.args.push(ty);
|
self.tys.args.push(ty);
|
||||||
let sym = parser::find_symbol(&fast.symbols, carg.id);
|
let sym = parser::find_symbol(&fast.symbols, carg.id);
|
||||||
let loc = if sym.flags & idfl::COMPTIME == 0 {
|
let loc = if sym.flags & idfl::COMPTIME == 0 {
|
||||||
|
@ -2315,7 +2263,7 @@ impl Codegen {
|
||||||
fn eval_const_low(&mut self, expr: &Expr, mut ty: Option<ty::Id>) -> (u64, ty::Id) {
|
fn eval_const_low(&mut self, expr: &Expr, mut ty: Option<ty::Id>) -> (u64, ty::Id) {
|
||||||
let mut ci = ItemCtx {
|
let mut ci = ItemCtx {
|
||||||
file: self.ci.file,
|
file: self.ci.file,
|
||||||
id: self.ci.id,
|
id: ty::Kind::Builtin(u32::MAX),
|
||||||
ret: ty,
|
ret: ty,
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
..self.pool.cis.pop().unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
@ -2341,8 +2289,6 @@ impl Codegen {
|
||||||
|
|
||||||
s.push_stash(stash);
|
s.push_stash(stash);
|
||||||
|
|
||||||
s.dunp_imported_fns();
|
|
||||||
|
|
||||||
prev.vars.append(&mut s.ci.vars);
|
prev.vars.append(&mut s.ci.vars);
|
||||||
s.ci.finalize(&mut s.output);
|
s.ci.finalize(&mut s.output);
|
||||||
s.output.emit(tx());
|
s.output.emit(tx());
|
||||||
|
@ -2587,11 +2533,11 @@ impl Codegen {
|
||||||
fn handle_global(&mut self, id: ty::Global) -> Option<Value> {
|
fn handle_global(&mut self, id: ty::Global) -> Option<Value> {
|
||||||
let ptr = self.ci.regs.allocate();
|
let ptr = self.ci.regs.allocate();
|
||||||
|
|
||||||
let reloc = Reloc::new(self.local_offset(), 3, 4);
|
let rel = Reloc::new(self.local_offset(), 3, 4);
|
||||||
let global = &mut self.tys.globals[id as usize];
|
let global = &mut self.tys.globals[id as usize];
|
||||||
self.output.globals.push((id, reloc));
|
self.output.relocs.push(OutReloc { from: self.ci.id, to: ty::Kind::Global(id), rel });
|
||||||
log::dbg!("{}", self.output.globals.len() - self.ci.snap.globals);
|
|
||||||
self.output.emit(instrs::lra(ptr.get(), 0, 0));
|
self.output.emit(instrs::lra(ptr.get(), 0, 0));
|
||||||
|
global.runtime |= !self.ct.active();
|
||||||
|
|
||||||
Some(Value { ty: global.ty, loc: Loc::reg(ptr).into_derefed() })
|
Some(Value { ty: global.ty, loc: Loc::reg(ptr).into_derefed() })
|
||||||
}
|
}
|
||||||
|
@ -2626,6 +2572,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_call_graph_low(&mut self) {
|
fn complete_call_graph_low(&mut self) {
|
||||||
|
let prev_strings = self.output.strings.len();
|
||||||
while self.ci.task_base < self.tasks.len()
|
while self.ci.task_base < self.tasks.len()
|
||||||
&& let Some(task_slot) = self.tasks.pop()
|
&& let Some(task_slot) = self.tasks.pop()
|
||||||
{
|
{
|
||||||
|
@ -2636,13 +2583,8 @@ impl Codegen {
|
||||||
let base = self.output.code.len() as u32;
|
let base = self.output.code.len() as u32;
|
||||||
let prev_data_len = self.output.string_data.len();
|
let prev_data_len = self.output.string_data.len();
|
||||||
self.output.code.append(&mut self.output.string_data);
|
self.output.code.append(&mut self.output.string_data);
|
||||||
for srel in self.output.strings.iter_mut() {
|
// we drain these when linking
|
||||||
#[cfg(debug_assertions)]
|
for srel in self.output.strings.iter_mut().skip(prev_strings) {
|
||||||
{
|
|
||||||
if std::mem::replace(&mut srel.shifted, true) {
|
|
||||||
panic!("str reloc visited twice");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_assert!(srel.range.end <= prev_data_len as u32);
|
debug_assert!(srel.range.end <= prev_data_len as u32);
|
||||||
debug_assert!(srel.range.start <= srel.range.end);
|
debug_assert!(srel.range.start <= srel.range.end);
|
||||||
srel.range.start += base;
|
srel.range.start += base;
|
||||||
|
@ -2669,7 +2611,7 @@ impl Codegen {
|
||||||
self.ci.snap = self.output.snap();
|
self.ci.snap = self.output.snap();
|
||||||
|
|
||||||
let Expr::BinOp {
|
let Expr::BinOp {
|
||||||
left: Expr::Ident { name, .. },
|
left: Expr::Ident { .. },
|
||||||
op: TokenKind::Decl,
|
op: TokenKind::Decl,
|
||||||
right: &Expr::Closure { body, args, .. },
|
right: &Expr::Closure { body, args, .. },
|
||||||
} = expr
|
} = expr
|
||||||
|
@ -2677,11 +2619,8 @@ impl Codegen {
|
||||||
unreachable!("{expr}")
|
unreachable!("{expr}")
|
||||||
};
|
};
|
||||||
|
|
||||||
log::dbg!("fn: {}", name);
|
|
||||||
|
|
||||||
self.output.emit_prelude();
|
self.output.emit_prelude();
|
||||||
|
|
||||||
log::dbg!("fn-args");
|
|
||||||
let mut parama = self.tys.parama(sig.ret);
|
let mut parama = self.tys.parama(sig.ret);
|
||||||
let mut sig_args = sig.args.range();
|
let mut sig_args = sig.args.range();
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
|
@ -2702,7 +2641,6 @@ impl Codegen {
|
||||||
self.ci.ret_reg = reg::Id::RET;
|
self.ci.ret_reg = reg::Id::RET;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::dbg!("fn-body");
|
|
||||||
if self.expr(body).is_some() {
|
if self.expr(body).is_some() {
|
||||||
self.report(body.pos(), "expected all paths in the fucntion to return");
|
self.report(body.pos(), "expected all paths in the fucntion to return");
|
||||||
}
|
}
|
||||||
|
@ -2711,9 +2649,6 @@ impl Codegen {
|
||||||
self.ci.free_loc(vars.value.loc);
|
self.ci.free_loc(vars.value.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::dbg!("fn-prelude, stack: {:x}", self.ci.stack.max_height);
|
|
||||||
|
|
||||||
log::dbg!("fn-relocs");
|
|
||||||
self.ci.finalize(&mut self.output);
|
self.ci.finalize(&mut self.output);
|
||||||
self.output.emit(jala(ZERO, RET_ADDR, 0));
|
self.output.emit(jala(ZERO, RET_ADDR, 0));
|
||||||
self.ci.regs.free(std::mem::take(&mut self.ci.ret_reg));
|
self.ci.regs.free(std::mem::take(&mut self.ci.ret_reg));
|
||||||
|
@ -2927,32 +2862,31 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_reloc(&mut self, stack: &stack::Id, off: Offset, sub_offset: u8) -> u64 {
|
fn stack_reloc(&mut self, stack: &stack::Id, off: Offset, sub_offset: u8) -> u64 {
|
||||||
log::dbg!("whaaaaatahack: {:b}", stack.repr());
|
|
||||||
let offset = self.local_offset();
|
let offset = self.local_offset();
|
||||||
self.ci.stack_relocs.push(Reloc::shifted(offset, sub_offset, 8));
|
self.ci.stack_relocs.push(Reloc::new(offset, sub_offset, 8));
|
||||||
Reloc::pack_srel(stack, off)
|
Reloc::pack_srel(stack, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link(&mut self) {
|
fn link(&mut self) {
|
||||||
// FIXME: this will cause problems relating snapshots
|
let ct_hint = self.ct.active().then_some(self.ci.snap.code as u32);
|
||||||
|
|
||||||
self.output.funcs.retain(|&(f, rel)| {
|
for reloc in &self.output.relocs {
|
||||||
_ = task::unpack(self.tys.funcs[f as usize].offset)
|
if !self.tys.is_runtime_item(reloc.from) && !self.ct.active() {
|
||||||
.map(|off| rel.apply_jump(&mut self.output.code, off));
|
continue;
|
||||||
true
|
}
|
||||||
});
|
|
||||||
|
|
||||||
self.output.globals.retain(|&(g, rel)| {
|
let Some(to_offset) = self.tys.offset_of_item(reloc.to, ct_hint) else {
|
||||||
_ = task::unpack(self.tys.globals[g as usize].offset)
|
continue;
|
||||||
.map(|off| rel.apply_jump(&mut self.output.code, off));
|
};
|
||||||
true
|
|
||||||
});
|
let from_offset = self.tys.offset_of_item(reloc.from, ct_hint).unwrap();
|
||||||
|
reloc.rel.apply_jump(&mut self.output.code, to_offset, from_offset);
|
||||||
|
}
|
||||||
|
|
||||||
//self.compress_strings();
|
//self.compress_strings();
|
||||||
for srel in self.output.strings.drain(..) {
|
for reloc in self.output.strings.iter() {
|
||||||
#[cfg(debug_assertions)]
|
let from_offset = self.tys.offset_of_item(reloc.from, ct_hint).unwrap();
|
||||||
assert!(srel.shifted);
|
reloc.reloc.apply_jump(&mut self.output.code, reloc.range.start, from_offset);
|
||||||
srel.reloc.apply_jump(&mut self.output.code, srel.range.start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2990,9 +2924,17 @@ impl Codegen {
|
||||||
ty::Id::from(self.eval_const(expr, ty::TYPE))
|
ty::Id::from(self.eval_const(expr, ty::TYPE))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_trap(addr: u64) -> Option<&'static trap::Trap> {
|
||||||
|
// TODO: make this debug only
|
||||||
|
if unsafe { *(addr as *const u8) } != 255 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(unsafe { &*((addr + 1) as *const trap::Trap) })
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_ecall(&mut self) {
|
fn handle_ecall(&mut self) {
|
||||||
let trap = unsafe { &*(self.ct.vm.pc.get() as *const trap::Trap) };
|
let trap = Self::read_trap(self.ct.vm.pc.get()).unwrap();
|
||||||
self.ct.vm.pc = self.ct.vm.pc.wrapping_add(trap.size());
|
self.ct.vm.pc = self.ct.vm.pc.wrapping_add(trap.size() + 1);
|
||||||
|
|
||||||
let mut extra_jump = 0;
|
let mut extra_jump = 0;
|
||||||
let mut local_pc = (self.ct.vm.pc.get() as usize - self.output.code.as_ptr() as usize)
|
let mut local_pc = (self.ct.vm.pc.get() as usize - self.output.code.as_ptr() as usize)
|
||||||
|
@ -3063,8 +3005,6 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::dbg!("foo: {expr}");
|
|
||||||
|
|
||||||
if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) {
|
if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) {
|
||||||
if let ty::Kind::Func(id) = existing.expand()
|
if let ty::Kind::Func(id) = existing.expand()
|
||||||
&& let func = &mut self.tys.funcs[id as usize]
|
&& let func = &mut self.tys.funcs[id as usize]
|
||||||
|
@ -3100,7 +3040,6 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = self.pack_args(pos, arg_base);
|
let args = self.pack_args(pos, arg_base);
|
||||||
log::dbg!("eval ret");
|
|
||||||
let ret = self.ty(ret);
|
let ret = self.ty(ret);
|
||||||
|
|
||||||
Some(Sig { args, ret })
|
Some(Sig { args, ret })
|
||||||
|
@ -3131,17 +3070,20 @@ impl Codegen {
|
||||||
offset: u32::MAX,
|
offset: u32::MAX,
|
||||||
ty: Default::default(),
|
ty: Default::default(),
|
||||||
runtime: false,
|
runtime: false,
|
||||||
|
_file: file,
|
||||||
|
_name: ident,
|
||||||
});
|
});
|
||||||
|
|
||||||
let ci = ItemCtx {
|
let ci = ItemCtx {
|
||||||
file,
|
file,
|
||||||
id: ty::Kind::Global(gid),
|
id: ty::Kind::Builtin(u32::MAX),
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
..self.pool.cis.pop().unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = left.find_pattern_path(ident, right, |expr| {
|
_ = left.find_pattern_path(ident, right, |expr| {
|
||||||
self.tys.globals[gid as usize] =
|
self.tys.globals[gid as usize] = self
|
||||||
self.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr))).into_ok();
|
.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr, file, ident)))
|
||||||
|
.into_ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
ty::Kind::Global(gid)
|
ty::Kind::Global(gid)
|
||||||
|
@ -3162,7 +3104,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_global(&mut self, expr: &Expr) -> Global {
|
fn generate_global(&mut self, expr: &Expr, file: FileId, name: Ident) -> Global {
|
||||||
self.output.emit_prelude();
|
self.output.emit_prelude();
|
||||||
|
|
||||||
let ret = self.ci.regs.allocate();
|
let ret = self.ci.regs.allocate();
|
||||||
|
@ -3190,16 +3132,7 @@ impl Codegen {
|
||||||
|
|
||||||
self.ci.free_loc(ret.loc);
|
self.ci.free_loc(ret.loc);
|
||||||
|
|
||||||
Global { ty: ret.ty, offset: offset as _, runtime: false }
|
Global { ty: ret.ty, offset: offset as _, runtime: false, _file: file, _name: name }
|
||||||
}
|
|
||||||
|
|
||||||
fn dunp_imported_fns(&mut self) {
|
|
||||||
for &(f, _) in &self.output.funcs[self.ci.snap.funcs..] {
|
|
||||||
let fnball = self.tys.funcs[f as usize];
|
|
||||||
let file = self.files[fnball.file as usize].clone();
|
|
||||||
let expr = fnball.expr.get(&file).unwrap();
|
|
||||||
log::dbg!("{expr}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_stash(&mut self) -> Output {
|
fn pop_stash(&mut self) -> Output {
|
||||||
|
@ -3248,9 +3181,14 @@ impl Codegen {
|
||||||
|
|
||||||
self.link();
|
self.link();
|
||||||
self.output.trunc(&Snapshot { code: self.output.code.len(), ..self.ci.snap });
|
self.output.trunc(&Snapshot { code: self.output.code.len(), ..self.ci.snap });
|
||||||
log::dbg!("{} {}", self.output.code.len(), self.ci.snap.code);
|
|
||||||
let entry = &mut self.output.code[self.ci.snap.code] as *mut _ as _;
|
let entry = &mut self.output.code[self.ci.snap.code] as *mut _ as _;
|
||||||
let prev_pc = std::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry));
|
let prev_pc = std::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry));
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
{
|
||||||
|
self.disasm(&mut String::new());
|
||||||
|
}
|
||||||
|
|
||||||
self.run_vm();
|
self.run_vm();
|
||||||
self.ct.vm.pc = prev_pc;
|
self.ct.vm.pc = prev_pc;
|
||||||
}
|
}
|
||||||
|
@ -3266,6 +3204,85 @@ impl Codegen {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn disasm(&mut self, output: &mut String) {
|
||||||
|
use crate::DisasmItem;
|
||||||
|
let mut sluce = self.output.code.as_slice();
|
||||||
|
let functions = self
|
||||||
|
.ct
|
||||||
|
.active()
|
||||||
|
.then_some((
|
||||||
|
self.ci.snap.code as u32,
|
||||||
|
(
|
||||||
|
"target_fn",
|
||||||
|
(self.output.code.len() - self.ci.snap.code) as u32,
|
||||||
|
DisasmItem::Func,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.into_iter()
|
||||||
|
.chain(
|
||||||
|
self.tys
|
||||||
|
.funcs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(i, f)| {
|
||||||
|
task::unpack(f.offset).is_ok()
|
||||||
|
&& (f.runtime || self.ct.active())
|
||||||
|
&& self.is_fully_linked(i as ty::Func)
|
||||||
|
})
|
||||||
|
.map(|(_, f)| {
|
||||||
|
let file = &self.files[f.file as usize];
|
||||||
|
let Expr::BinOp { left: &Expr::Ident { name, .. }, .. } =
|
||||||
|
f.expr.get(file).unwrap()
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
(f.offset, (name, f.size, DisasmItem::Func))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
self.tys
|
||||||
|
.globals
|
||||||
|
.iter()
|
||||||
|
.filter(|g| task::unpack(g.offset).is_ok() && (g.runtime || self.ct.active()))
|
||||||
|
.map(|g| {
|
||||||
|
let file = &self.files[g._file as usize];
|
||||||
|
|
||||||
|
(
|
||||||
|
g.offset,
|
||||||
|
(file.ident_str(g._name), self.tys.size_of(g.ty), DisasmItem::Global),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
self.output
|
||||||
|
.strings
|
||||||
|
.iter()
|
||||||
|
.map(|s| (s.range.start, ("string", s.range.len() as _, DisasmItem::Global))),
|
||||||
|
)
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
if crate::disasm(&mut sluce, &functions, output, |bin| {
|
||||||
|
if self.ct.active()
|
||||||
|
&& let Some(trap) = Self::read_trap(bin.as_ptr() as u64)
|
||||||
|
{
|
||||||
|
bin.take(..trap.size() + 1).unwrap();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
panic!("{} {:?}", output, sluce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn is_fully_linked(&self, func: ty::Func) -> bool {
|
||||||
|
self.output
|
||||||
|
.relocs
|
||||||
|
.iter()
|
||||||
|
.filter(|r| r.from == ty::Kind::Func(func))
|
||||||
|
.all(|r| self.tys.offset_of_item(r.to, None).is_some())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_vm(&mut self) {
|
fn run_vm(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.ct.vm.run().unwrap() {
|
match self.ct.vm.run().unwrap() {
|
||||||
|
@ -3333,8 +3350,7 @@ impl Codegen {
|
||||||
Snapshot {
|
Snapshot {
|
||||||
code: self.output.code.len() - self.ci.snap.code,
|
code: self.output.code.len() - self.ci.snap.code,
|
||||||
string_data: self.output.string_data.len() - self.ci.snap.string_data,
|
string_data: self.output.string_data.len() - self.ci.snap.string_data,
|
||||||
funcs: self.output.funcs.len() - self.ci.snap.funcs,
|
relocs: self.output.relocs.len() - self.ci.snap.relocs,
|
||||||
globals: self.output.globals.len() - self.ci.snap.globals,
|
|
||||||
strings: self.output.strings.len() - self.ci.snap.strings,
|
strings: self.output.strings.len() - self.ci.snap.strings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3342,8 +3358,7 @@ impl Codegen {
|
||||||
fn pop_local_snap(&mut self, snap: Snapshot) {
|
fn pop_local_snap(&mut self, snap: Snapshot) {
|
||||||
self.output.code.truncate(snap.code + self.ci.snap.code);
|
self.output.code.truncate(snap.code + self.ci.snap.code);
|
||||||
self.output.string_data.truncate(snap.string_data + self.ci.snap.string_data);
|
self.output.string_data.truncate(snap.string_data + self.ci.snap.string_data);
|
||||||
self.output.funcs.truncate(snap.funcs + self.ci.snap.funcs);
|
self.output.relocs.truncate(snap.relocs + self.ci.snap.relocs);
|
||||||
self.output.globals.truncate(snap.globals + self.ci.snap.globals);
|
|
||||||
self.output.strings.truncate(snap.strings + self.ci.snap.strings);
|
self.output.strings.truncate(snap.strings + self.ci.snap.strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3366,11 +3381,7 @@ impl Codegen {
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
super::parser,
|
super::parser,
|
||||||
crate::{
|
crate::{codegen::LoggedMem, log, parser::FileId},
|
||||||
codegen::LoggedMem,
|
|
||||||
log,
|
|
||||||
parser::{Expr, FileId},
|
|
||||||
},
|
|
||||||
std::io,
|
std::io,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3434,24 +3445,7 @@ mod tests {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
codegen.dump(&mut out).unwrap();
|
codegen.dump(&mut out).unwrap();
|
||||||
|
|
||||||
let mut sluce = out.as_slice();
|
codegen.disasm(output);
|
||||||
let functions = codegen
|
|
||||||
.tys
|
|
||||||
.funcs
|
|
||||||
.iter()
|
|
||||||
.filter(|f| f.offset != u32::MAX && f.runtime)
|
|
||||||
.map(|f| {
|
|
||||||
let file = &codegen.files[f.file as usize];
|
|
||||||
let Expr::BinOp { left: &Expr::Ident { name, .. }, .. } = f.expr.get(file).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
(f.offset, (name, f.size))
|
|
||||||
})
|
|
||||||
.collect::<crate::HashMap<_, _>>();
|
|
||||||
if crate::disasm(&mut sluce, &functions, output).is_err() {
|
|
||||||
panic!("{} {:?}", output, sluce);
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ use {
|
||||||
parser::Ast,
|
parser::Ast,
|
||||||
std::{
|
std::{
|
||||||
collections::{hash_map, VecDeque},
|
collections::{hash_map, VecDeque},
|
||||||
|
default,
|
||||||
io::{self, Read},
|
io::{self, Read},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
|
@ -129,11 +130,20 @@ unsafe fn encode<T>(instr: T) -> (usize, [u8; instrs::MAX_SIZE]) {
|
||||||
std::ptr::write(buf.as_mut_ptr() as *mut T, instr);
|
std::ptr::write(buf.as_mut_ptr() as *mut T, instr);
|
||||||
(std::mem::size_of::<T>(), buf)
|
(std::mem::size_of::<T>(), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum DisasmItem {
|
||||||
|
Func,
|
||||||
|
Global,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn disasm(
|
fn disasm(
|
||||||
binary: &mut &[u8],
|
binary: &mut &[u8],
|
||||||
functions: &HashMap<u32, (&str, u32)>,
|
functions: &HashMap<u32, (&str, u32, DisasmItem)>,
|
||||||
out: &mut String,
|
out: &mut String,
|
||||||
|
mut eca_handler: impl FnMut(&mut &[u8]),
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
use self::instrs::Instr;
|
use self::instrs::Instr;
|
||||||
|
|
||||||
|
@ -146,11 +156,18 @@ fn disasm(
|
||||||
|
|
||||||
let mut labels = HashMap::<u32, u32>::default();
|
let mut labels = HashMap::<u32, u32>::default();
|
||||||
let mut buf = Vec::<instrs::Oper>::new();
|
let mut buf = Vec::<instrs::Oper>::new();
|
||||||
|
let mut has_cycle = false;
|
||||||
|
let mut has_oob = false;
|
||||||
|
|
||||||
|
'_offset_pass: for (&off, &(_name, len, kind)) in functions.iter() {
|
||||||
|
if matches!(kind, DisasmItem::Global) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
'_offset_pass: for (&off, &(_name, len)) in functions.iter() {
|
|
||||||
let prev = *binary;
|
let prev = *binary;
|
||||||
|
|
||||||
binary.take(..off as usize).unwrap();
|
binary.take(..off as usize).unwrap();
|
||||||
|
|
||||||
let mut label_count = 0;
|
let mut label_count = 0;
|
||||||
while let Some(&byte) = binary.first() {
|
while let Some(&byte) = binary.first() {
|
||||||
let inst = instr_from_byte(byte)?;
|
let inst = instr_from_byte(byte)?;
|
||||||
|
@ -167,18 +184,27 @@ fn disasm(
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
has_cycle |= rel == 0;
|
||||||
|
|
||||||
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
||||||
if functions.get(&global_offset).is_some() {
|
if functions.get(&global_offset).is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
label_count += labels.try_insert(global_offset, label_count).is_ok() as u32;
|
label_count += labels.try_insert(global_offset, label_count).is_ok() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matches!(inst, Instr::ECA) {
|
||||||
|
eca_handler(binary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*binary = prev;
|
*binary = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
'_dump: for (&off, &(name, len)) in functions.iter() {
|
'_dump: for (&off, &(name, len, kind)) in functions.iter() {
|
||||||
|
if matches!(kind, DisasmItem::Global) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let prev = *binary;
|
let prev = *binary;
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -224,20 +250,37 @@ fn disasm(
|
||||||
};
|
};
|
||||||
|
|
||||||
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
let global_offset: u32 = (offset + rel).try_into().unwrap();
|
||||||
if let Some(&(name, _)) = functions.get(&global_offset) {
|
if let Some(&(name, ..)) = functions.get(&global_offset) {
|
||||||
write!(out, ":{name}")?;
|
write!(out, ":{name}")?;
|
||||||
} else {
|
} else {
|
||||||
|
let local_has_oob = global_offset < off
|
||||||
|
|| global_offset > off + len
|
||||||
|
|| instr_from_byte(prev[global_offset as usize]).is_err()
|
||||||
|
|| prev[global_offset as usize] == 0;
|
||||||
|
has_oob |= local_has_oob;
|
||||||
let label = labels.get(&global_offset).unwrap();
|
let label = labels.get(&global_offset).unwrap();
|
||||||
|
if local_has_oob {
|
||||||
|
write!(out, "!!!!!!!!!{rel}")?;
|
||||||
|
} else {
|
||||||
write!(out, ":{label}")?;
|
write!(out, ":{label}")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writeln!(out)?;
|
writeln!(out)?;
|
||||||
|
|
||||||
|
if matches!(inst, Instr::ECA) {
|
||||||
|
eca_handler(binary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*binary = prev;
|
*binary = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if has_oob || has_cycle {
|
||||||
|
return Err(std::fmt::Error);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -24d
|
ADDI64 r254, r254, -24d
|
||||||
ST r31, r254, 0a, 24h
|
ST r31, r254, 0a, 24h
|
||||||
LRA r32, r0, :0
|
LRA r32, r0, :string
|
||||||
CP r2, r32
|
CP r2, r32
|
||||||
JAL r31, r0, :str_len
|
JAL r31, r0, :str_len
|
||||||
CP r32, r1
|
CP r32, r1
|
||||||
LRA r33, r0, :1
|
LRA r33, r0, :string
|
||||||
CP r2, r33
|
CP r2, r33
|
||||||
JAL r31, r0, :str_len
|
JAL r31, r0, :str_len
|
||||||
CP r33, r1
|
CP r33, r1
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -16d
|
ADDI64 r254, r254, -16d
|
||||||
ST r31, r254, 0a, 16h
|
ST r31, r254, 0a, 16h
|
||||||
LRA r32, r0, :0
|
LRA r32, r0, :a
|
||||||
LD r1, r32, 0a, 8h
|
LD r1, r32, 0a, 8h
|
||||||
LD r31, r254, 0a, 16h
|
LD r31, r254, 0a, 16h
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -16d
|
ADDI64 r254, r254, -16d
|
||||||
ST r31, r254, 0a, 16h
|
ST r31, r254, 0a, 16h
|
||||||
LRA r32, r0, :0
|
LRA r32, r0, :a
|
||||||
LD r1, r32, 0a, 8h
|
LD r1, r32, 0a, 8h
|
||||||
LD r31, r254, 0a, 16h
|
LD r31, r254, 0a, 16h
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
new:
|
free:
|
||||||
ADDI64 r254, r254, -24d
|
ADDI64 r254, r254, -40d
|
||||||
ST r31, r254, 0a, 24h
|
ST r31, r254, 0a, 40h
|
||||||
CP r32, r1
|
CP r32, r2
|
||||||
LI64 r33, 0d
|
CP r33, r3
|
||||||
ST r33, r32, 0a, 8h
|
CP r34, r4
|
||||||
LI64 r33, 0d
|
LRA r35, r0, :FREE_SYS_CALL
|
||||||
ST r33, r32, 8a, 8h
|
LD r2, r35, 0a, 8h
|
||||||
LI64 r33, 0d
|
CP r3, r32
|
||||||
ST r33, r32, 16a, 8h
|
CP r4, r33
|
||||||
LD r31, r254, 0a, 24h
|
CP r5, r34
|
||||||
ADDI64 r254, r254, 24d
|
ECA
|
||||||
|
LD r31, r254, 0a, 40h
|
||||||
|
ADDI64 r254, r254, 40d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
push:
|
push:
|
||||||
ADDI64 r254, r254, -88d
|
ADDI64 r254, r254, -88d
|
||||||
|
@ -98,6 +100,19 @@ push:
|
||||||
4: LD r31, r254, 0a, 88h
|
4: LD r31, r254, 0a, 88h
|
||||||
ADDI64 r254, r254, 88d
|
ADDI64 r254, r254, 88d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
|
new:
|
||||||
|
ADDI64 r254, r254, -24d
|
||||||
|
ST r31, r254, 0a, 24h
|
||||||
|
CP r32, r1
|
||||||
|
LI64 r33, 0d
|
||||||
|
ST r33, r32, 0a, 8h
|
||||||
|
LI64 r33, 0d
|
||||||
|
ST r33, r32, 8a, 8h
|
||||||
|
LI64 r33, 0d
|
||||||
|
ST r33, r32, 16a, 8h
|
||||||
|
LD r31, r254, 0a, 24h
|
||||||
|
ADDI64 r254, r254, 24d
|
||||||
|
JALA r0, r31, 0a
|
||||||
deinit:
|
deinit:
|
||||||
ADDI64 r254, r254, -24d
|
ADDI64 r254, r254, -24d
|
||||||
ST r31, r254, 0a, 24h
|
ST r31, r254, 0a, 24h
|
||||||
|
@ -118,7 +133,7 @@ malloc:
|
||||||
ST r31, r254, 0a, 32h
|
ST r31, r254, 0a, 32h
|
||||||
CP r32, r2
|
CP r32, r2
|
||||||
CP r33, r3
|
CP r33, r3
|
||||||
LRA r34, r0, :0
|
LRA r34, r0, :MALLOC_SYS_CALL
|
||||||
LD r2, r34, 0a, 8h
|
LD r2, r34, 0a, 8h
|
||||||
CP r3, r32
|
CP r3, r32
|
||||||
CP r4, r33
|
CP r4, r33
|
||||||
|
@ -126,21 +141,6 @@ malloc:
|
||||||
LD r31, r254, 0a, 32h
|
LD r31, r254, 0a, 32h
|
||||||
ADDI64 r254, r254, 32d
|
ADDI64 r254, r254, 32d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
free:
|
|
||||||
ADDI64 r254, r254, -40d
|
|
||||||
ST r31, r254, 0a, 40h
|
|
||||||
CP r32, r2
|
|
||||||
CP r33, r3
|
|
||||||
CP r34, r4
|
|
||||||
LRA r35, r0, :0
|
|
||||||
LD r2, r35, 0a, 8h
|
|
||||||
CP r3, r32
|
|
||||||
CP r4, r33
|
|
||||||
CP r5, r34
|
|
||||||
ECA
|
|
||||||
LD r31, r254, 0a, 40h
|
|
||||||
ADDI64 r254, r254, 40d
|
|
||||||
JALA r0, r31, 0a
|
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -72d
|
ADDI64 r254, r254, -72d
|
||||||
ST r31, r254, 48a, 24h
|
ST r31, r254, 48a, 24h
|
||||||
|
@ -162,6 +162,6 @@ main:
|
||||||
LD r31, r254, 48a, 24h
|
LD r31, r254, 48a, 24h
|
||||||
ADDI64 r254, r254, 72d
|
ADDI64 r254, r254, 72d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 1469
|
code size: 1470
|
||||||
ret: 69
|
ret: 69
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -16d
|
ADDI64 r254, r254, -16d
|
||||||
ST r31, r254, 0a, 16h
|
ST r31, r254, 0a, 16h
|
||||||
LRA r32, r0, :0
|
LRA r32, r0, :complex_global_var
|
||||||
LD r1, r32, 0a, 8h
|
LD r1, r32, 0a, 8h
|
||||||
LD r31, r254, 0a, 16h
|
LD r31, r254, 0a, 16h
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
|
|
Loading…
Reference in a new issue