forked from AbleOS/holey-bytes
implementing directives
This commit is contained in:
parent
0298b32e38
commit
bc817c4ea2
|
@ -273,7 +273,7 @@ main := fn(): int {
|
|||
align_of_Type_in_bytes := @alignof(foo.Type)
|
||||
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||
ecall_that_returns_int := @as(int, @eca(1, foo.Type.(10, 20), 5, 6))
|
||||
embedded_array := @as([u8; 15], @embed("text.txt"))
|
||||
embedded_array := @as(^[u8; 15], @embed("text.txt"))
|
||||
return @inline(foo.foo)
|
||||
}
|
||||
|
||||
|
@ -357,7 +357,7 @@ fib_iter := fn(n: int): int {
|
|||
```hb
|
||||
main := fn(): int {
|
||||
addr := @as(u16, 0x1FF)
|
||||
msg := [u8].(0, 0, @trunc(addr), @trunc(addr >> 8))
|
||||
msg := [u8].(0, 0, @intcast(addr), @intcast(addr >> 8))
|
||||
_force_stack := &msg
|
||||
|
||||
arr := [int].(1, 2, 4)
|
||||
|
|
|
@ -107,6 +107,7 @@ mod ctx_map {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Key<T> {
|
||||
pub value: T,
|
||||
pub hash: Hash,
|
||||
|
@ -125,6 +126,7 @@ mod ctx_map {
|
|||
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtxMap<T> {
|
||||
inner: hashbrown::HashMap<Key<T>, (), HashBuilder>,
|
||||
}
|
||||
|
@ -263,6 +265,8 @@ mod ty {
|
|||
pub type Module = u32;
|
||||
pub type Slice = u32;
|
||||
|
||||
pub const ECA: Func = Func::MAX;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Tuple(pub u32);
|
||||
|
||||
|
@ -702,6 +706,7 @@ impl Default for Func {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct TypedReloc {
|
||||
target: ty::Id,
|
||||
reloc: Reloc,
|
||||
|
|
204
lang/src/son.rs
204
lang/src/son.rs
|
@ -22,6 +22,7 @@ use {
|
|||
fmt::{self, Debug, Display, Write},
|
||||
format_args as fa, mem,
|
||||
ops::{self},
|
||||
usize,
|
||||
},
|
||||
hashbrown::hash_map,
|
||||
regalloc2::VReg,
|
||||
|
@ -55,6 +56,7 @@ impl crate::ctx_map::CtxEntry for Nid {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Nodes {
|
||||
values: Vec<Result<Node, Nid>>,
|
||||
visited: BitSet,
|
||||
|
@ -500,7 +502,7 @@ impl Nodes {
|
|||
Kind::BinOp { op } | Kind::UnOp { op } => {
|
||||
write!(out, "{:>4}: ", op.name())
|
||||
}
|
||||
Kind::Call { func } => {
|
||||
Kind::Call { func, argc: _ } => {
|
||||
write!(out, "call: {func} {} ", self[node].depth)
|
||||
}
|
||||
Kind::Global { global } => write!(out, "glob: {global:<5}"),
|
||||
|
@ -886,6 +888,7 @@ pub enum Kind {
|
|||
// [ctrl, ...args]
|
||||
Call {
|
||||
func: ty::Func,
|
||||
argc: u32,
|
||||
},
|
||||
// [ctrl]
|
||||
Idk,
|
||||
|
@ -975,6 +978,7 @@ type LoopDepth = u16;
|
|||
type LockRc = u16;
|
||||
type IDomDepth = u16;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Loop {
|
||||
node: Nid,
|
||||
ctrl: [Nid; 2],
|
||||
|
@ -1007,7 +1011,7 @@ impl Scope {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
struct ItemCtx {
|
||||
file: FileId,
|
||||
ret: Option<ty::Id>,
|
||||
|
@ -1247,27 +1251,36 @@ impl ItemCtx {
|
|||
}
|
||||
}
|
||||
}
|
||||
Kind::Call { func } => {
|
||||
Kind::Call { argc, func } => {
|
||||
std::dbg!(node.ty.simple_size());
|
||||
let (ret, mut parama) = tys.parama(node.ty);
|
||||
let mut allocs = allocs.iter();
|
||||
for ti in tys.ins.funcs[func as usize].sig.unwrap().args.range() {
|
||||
let ty = tys.ins.args[ti];
|
||||
debug_assert_eq!(
|
||||
allocs.len(),
|
||||
argc as usize
|
||||
+ !matches!(ret, PLoc::Reg(..) | PLoc::None) as usize
|
||||
+ !matches!(ret, PLoc::None) as usize
|
||||
);
|
||||
for (&i, &arg) in node.inputs[1..][..argc as usize].iter().zip(&allocs[1..])
|
||||
{
|
||||
let ty = fuc.nodes[i].ty;
|
||||
let (rg, size) = match parama.next(ty, tys) {
|
||||
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
|
||||
PLoc::WideReg(rg, size) => (rg, size),
|
||||
PLoc::None | PLoc::Ref(..) | PLoc::Reg(..) => continue,
|
||||
};
|
||||
let &arg = allocs.next().unwrap();
|
||||
if size > 8 {
|
||||
allocs.next().unwrap();
|
||||
}
|
||||
self.emit(instrs::ld(rg, atr(arg), 0, size));
|
||||
}
|
||||
self.relocs.push(TypedReloc {
|
||||
target: ty::Kind::Func(func).compress(),
|
||||
reloc: Reloc::new(self.code.len(), 3, 4),
|
||||
});
|
||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||
|
||||
if func == ty::ECA {
|
||||
self.emit(instrs::eca());
|
||||
} else {
|
||||
self.relocs.push(TypedReloc {
|
||||
target: ty::Kind::Func(func).compress(),
|
||||
reloc: Reloc::new(self.code.len(), 3, 4),
|
||||
});
|
||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||
}
|
||||
|
||||
if let PLoc::WideReg(r, size) = ret {
|
||||
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
|
||||
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
|
||||
|
@ -1482,6 +1495,20 @@ impl Pool {
|
|||
self.used_cis -= 1;
|
||||
core::mem::swap(&mut self.cis[self.used_cis], target);
|
||||
}
|
||||
|
||||
fn save_ci(&mut self, ci: &ItemCtx) {
|
||||
if let Some(slot) = self.cis.get_mut(self.used_cis) {
|
||||
slot.clone_from(ci);
|
||||
} else {
|
||||
self.cis.push(ci.clone());
|
||||
}
|
||||
self.used_cis += 1;
|
||||
}
|
||||
|
||||
fn restore_ci(&mut self, dst: &mut ItemCtx) {
|
||||
self.used_cis -= 1;
|
||||
*dst = core::mem::take(&mut self.cis[self.used_cis]);
|
||||
}
|
||||
}
|
||||
|
||||
struct Regalloc {
|
||||
|
@ -1566,9 +1593,11 @@ impl TypeParser for Codegen<'_> {
|
|||
todo!()
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
fn infer_type(&mut self, expr: &Expr) -> ty::Id {
|
||||
todo!()
|
||||
self.pool.save_ci(&self.ci);
|
||||
let ty = self.expr(expr).map_or(ty::Id::NEVER, |v| v.ty);
|
||||
self.pool.restore_ci(&mut self.ci);
|
||||
ty
|
||||
}
|
||||
|
||||
fn on_reuse(&mut self, existing: ty::Id) {
|
||||
|
@ -1672,6 +1701,17 @@ impl TypeParser for Codegen<'_> {
|
|||
}
|
||||
|
||||
impl<'a> Codegen<'a> {
|
||||
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 store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
||||
if value == NEVER {
|
||||
return NEVER;
|
||||
|
@ -1980,6 +2020,11 @@ impl<'a> Codegen<'a> {
|
|||
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
|
||||
Some(Value::ptr(ptr).ty(elem))
|
||||
}
|
||||
Expr::Embed { id, .. } => {
|
||||
let glob = &self.tys.ins.globals[id as usize];
|
||||
let ty = self.tys.make_ptr(glob.ty);
|
||||
Some(self.ci.nodes.new_node_lit(ty, Kind::Global { global: id }, [VOID]))
|
||||
}
|
||||
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
||||
let ty = self.ty(ty);
|
||||
Some(self.ci.nodes.new_node_lit(
|
||||
|
@ -1988,7 +2033,44 @@ impl<'a> Codegen<'a> {
|
|||
[VOID],
|
||||
))
|
||||
}
|
||||
Expr::Directive { name: "trunc", args: [expr], pos } => {
|
||||
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
||||
let ty = self.ty(ty);
|
||||
Some(self.ci.nodes.new_node_lit(
|
||||
ty::Id::INT,
|
||||
Kind::CInt { value: self.tys.align_of(ty) as _ },
|
||||
[VOID],
|
||||
))
|
||||
}
|
||||
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
||||
let mut val = self.raw_expr(val)?;
|
||||
self.strip_var(&mut val);
|
||||
|
||||
let Some(ty) = ctx.ty else {
|
||||
self.report(
|
||||
pos,
|
||||
"resulting type cannot be inferred from context, \
|
||||
consider using `@as(<ty>, @bitcast(<expr>))` to hint the type",
|
||||
);
|
||||
return Value::NEVER;
|
||||
};
|
||||
|
||||
let (got, expected) = (self.tys.size_of(val.ty), self.tys.size_of(ty));
|
||||
if got != expected {
|
||||
self.report(
|
||||
pos,
|
||||
fa!(
|
||||
"cast from '{}' to '{}' is not supported, \
|
||||
sizes dont match ({got} != {expected})",
|
||||
self.ty_display(val.ty),
|
||||
self.ty_display(ty)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
val.ty = ty;
|
||||
Some(val)
|
||||
}
|
||||
Expr::Directive { name: "intcast", args: [expr], pos } => {
|
||||
let val = self.expr(expr)?;
|
||||
|
||||
if !val.ty.is_integer() {
|
||||
|
@ -2006,7 +2088,7 @@ impl<'a> Codegen<'a> {
|
|||
self.report(
|
||||
pos,
|
||||
"resulting integer cannot be inferred from context, \
|
||||
consider using `@as(<int_ty>, @trunc(<expr>))` to hint the type",
|
||||
consider using `@as(<int_ty>, @intcast(<expr>))` to hint the type",
|
||||
);
|
||||
return Value::NEVER;
|
||||
};
|
||||
|
@ -2031,6 +2113,59 @@ impl<'a> Codegen<'a> {
|
|||
let ctx = Ctx::default().with_ty(self.ty(ty));
|
||||
self.raw_expr_ctx(expr, ctx)
|
||||
}
|
||||
Expr::Directive { pos, name: "eca", args } => {
|
||||
let Some(ty) = ctx.ty else {
|
||||
self.report(
|
||||
pos,
|
||||
"return type cannot be inferred from context, \
|
||||
consider using `@as(<return_ty>, @eca(<expr>...))` to hint the type",
|
||||
);
|
||||
return Value::NEVER;
|
||||
};
|
||||
|
||||
let mut inps = Vc::from([self.ci.ctrl]);
|
||||
for arg in args {
|
||||
let value = self.expr(arg)?;
|
||||
debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre);
|
||||
self.ci.nodes.lock(value.id);
|
||||
inps.push(value.id);
|
||||
}
|
||||
|
||||
for &n in inps.iter().skip(1) {
|
||||
self.ci.nodes.unlock(n);
|
||||
}
|
||||
|
||||
if let Some(str) = self.ci.scope.store.to_store() {
|
||||
inps.push(str);
|
||||
}
|
||||
self.ci.scope.loads.retain(|&load| {
|
||||
if inps.contains(&load) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.ci.nodes.unlock_remove(load) {
|
||||
inps.push(load);
|
||||
}
|
||||
|
||||
false
|
||||
});
|
||||
|
||||
let alt_value = match ty.loc(&self.tys) {
|
||||
Loc::Reg => None,
|
||||
Loc::Stack => {
|
||||
let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]);
|
||||
inps.push(stck);
|
||||
Some(Value::ptr(stck).ty(ty))
|
||||
}
|
||||
};
|
||||
|
||||
let argc = args.len() as u32;
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty, Kind::Call { func: ty::ECA, argc }, inps);
|
||||
|
||||
self.store_mem(VOID, VOID);
|
||||
|
||||
alt_value.or(Some(Value::new(self.ci.ctrl).ty(ty)))
|
||||
}
|
||||
Expr::Call { func, args, .. } => {
|
||||
self.ci.call_count += 1;
|
||||
let ty = self.ty(func);
|
||||
|
@ -2100,7 +2235,8 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fu }, inps);
|
||||
let argc = args.len() as u32;
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fu, argc }, inps);
|
||||
|
||||
self.store_mem(VOID, VOID);
|
||||
|
||||
|
@ -3107,21 +3243,19 @@ impl<'a> Function<'a> {
|
|||
let ops = vec![self.drg(nid), self.urg(node.inputs[1])];
|
||||
self.add_instr(nid, ops);
|
||||
}
|
||||
Kind::Call { func } => {
|
||||
Kind::Call { argc, .. } => {
|
||||
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref;
|
||||
let mut ops = vec![];
|
||||
|
||||
let fuc = self.tys.ins.funcs[func as usize].sig.unwrap();
|
||||
if self.tys.size_of(fuc.ret) != 0 {
|
||||
let (ret, mut parama) = self.tys.parama(node.ty);
|
||||
if !matches!(ret, PLoc::None) {
|
||||
ops.push(regalloc2::Operand::reg_fixed_def(
|
||||
self.rg(nid),
|
||||
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
|
||||
));
|
||||
}
|
||||
|
||||
let (ret, mut parama) = self.tys.parama(fuc.ret);
|
||||
for (ti, &(mut i)) in fuc.args.range().zip(node.inputs[1..].iter()) {
|
||||
let ty = self.tys.ins.args[ti];
|
||||
for &(mut i) in node.inputs[1..][..argc as usize].iter() {
|
||||
let ty = self.nodes[i].ty;
|
||||
match parama.next(ty, self.tys) {
|
||||
PLoc::None => {}
|
||||
PLoc::Reg(r, _) => {
|
||||
|
@ -3130,7 +3264,7 @@ impl<'a> Function<'a> {
|
|||
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
|
||||
));
|
||||
}
|
||||
PLoc::WideReg(r, _) => {
|
||||
PLoc::WideReg(..) => {
|
||||
loop {
|
||||
match self.nodes[i].kind {
|
||||
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
||||
|
@ -3140,14 +3274,7 @@ impl<'a> Function<'a> {
|
|||
debug_assert_ne!(i, 0);
|
||||
}
|
||||
debug_assert!(i != 0);
|
||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||
self.rg(i),
|
||||
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
|
||||
));
|
||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||
self.rg(i),
|
||||
regalloc2::PReg::new(r as usize + 1, regalloc2::RegClass::Int),
|
||||
));
|
||||
ops.push(self.urg(i));
|
||||
}
|
||||
PLoc::Ref(r, _) => {
|
||||
loop {
|
||||
|
@ -3594,8 +3721,9 @@ mod tests {
|
|||
_ = log::set_logger(&crate::fs::Logger);
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
|
||||
let (ref files, _embeds) = crate::test_parse_files(ident, input);
|
||||
let (ref files, embeds) = crate::test_parse_files(ident, input);
|
||||
let mut codegen = super::Codegen { files, ..Default::default() };
|
||||
codegen.push_embeds(embeds);
|
||||
|
||||
codegen.generate();
|
||||
|
||||
|
@ -3633,7 +3761,7 @@ mod tests {
|
|||
hex_octal_binary_literals;
|
||||
//struct_operators;
|
||||
global_variables;
|
||||
//directives;
|
||||
directives;
|
||||
c_strings;
|
||||
struct_patterns;
|
||||
arrays;
|
||||
|
|
|
@ -266,7 +266,7 @@ struct AllocedVc {
|
|||
base: Unique<Nid>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct BitSet {
|
||||
data: Vec<usize>,
|
||||
}
|
||||
|
|
|
@ -15,40 +15,38 @@ main:
|
|||
ST r3, r254, 12a, 4h
|
||||
ST r8, r254, 0a, 4h
|
||||
ST r9, r254, 4a, 4h
|
||||
LD r1, r254, 0a, 8h
|
||||
ST r1, r254, 16a, 8h
|
||||
LD r12, r254, 0a, 8h
|
||||
ST r12, r254, 16a, 8h
|
||||
LD r3, r254, 20a, 4h
|
||||
ANDI r3, r3, 4294967295d
|
||||
ANDI r9, r9, 4294967295d
|
||||
JEQ r3, r9, :0
|
||||
LI64 r1, 0d
|
||||
JMP :1
|
||||
0: ADDI64 r10, r12, 8d
|
||||
ADDI64 r10, r10, -4d
|
||||
LD r1, r10, 0a, 4h
|
||||
ANDI r1, r1, 4294967295d
|
||||
0: LD r9, r254, 16a, 4h
|
||||
ANDI r9, r9, 4294967295d
|
||||
ANDI r8, r8, 4294967295d
|
||||
JEQ r1, r8, :2
|
||||
JEQ r9, r8, :2
|
||||
LI64 r1, 64d
|
||||
JMP :1
|
||||
2: LD r7, r254, 15a, 1h
|
||||
ANDI r9, r7, 255d
|
||||
LD r6, r254, 14a, 1h
|
||||
ANDI r8, r6, 255d
|
||||
LD r5, r254, 13a, 1h
|
||||
ANDI r7, r5, 255d
|
||||
LD r3, r254, 12a, 1h
|
||||
ANDI r6, r3, 255d
|
||||
LD r4, r254, 20a, 4h
|
||||
LD r5, r254, 16a, 4h
|
||||
ADD32 r10, r4, r5
|
||||
ADD32 r11, r10, r6
|
||||
ADD32 r3, r11, r7
|
||||
ADD32 r7, r3, r8
|
||||
ADD32 r11, r7, r9
|
||||
ANDI r1, r11, 4294967295d
|
||||
2: LD r3, r254, 15a, 1h
|
||||
ANDI r5, r3, 255d
|
||||
LD r2, r254, 14a, 1h
|
||||
ANDI r4, r2, 255d
|
||||
LD r1, r254, 13a, 1h
|
||||
ANDI r3, r1, 255d
|
||||
LD r11, r254, 12a, 1h
|
||||
ANDI r2, r11, 255d
|
||||
LD r12, r254, 20a, 4h
|
||||
LD r1, r254, 16a, 4h
|
||||
ADD32 r6, r12, r1
|
||||
ADD32 r7, r6, r2
|
||||
ADD32 r11, r7, r3
|
||||
ADD32 r3, r11, r4
|
||||
ADD32 r7, r3, r5
|
||||
ANDI r1, r7, 4294967295d
|
||||
1: ADDI64 r254, r254, 24d
|
||||
JALA r0, r31, 0a
|
||||
code size: 529
|
||||
code size: 507
|
||||
ret: 512
|
||||
status: Ok(())
|
||||
|
|
0
lang/tests/son_tests_directives.txt
Normal file
0
lang/tests/son_tests_directives.txt
Normal file
|
@ -1,26 +1,23 @@
|
|||
drop:
|
||||
JALA r0, r31, 0a
|
||||
main:
|
||||
ADDI64 r254, r254, -48d
|
||||
ST r31, r254, 8a, 40h
|
||||
ADDI64 r254, r254, -32d
|
||||
ST r31, r254, 8a, 24h
|
||||
LI64 r32, 1d
|
||||
ADDI64 r33, r254, 0d
|
||||
ADDI64 r34, r33, 8000d
|
||||
ADDI64 r34, r34, -8000d
|
||||
ADDI64 r2, r254, 0d
|
||||
ST r32, r254, 0a, 8h
|
||||
CP r2, r34
|
||||
JAL r31, r0, :modify
|
||||
CP r2, r32
|
||||
JAL r31, r0, :drop
|
||||
LD r35, r34, 0a, 8h
|
||||
ADDI64 r1, r35, -2d
|
||||
LD r31, r254, 8a, 40h
|
||||
ADDI64 r254, r254, 48d
|
||||
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
|
||||
ST r3, r2, 0a, 8h
|
||||
JALA r0, r31, 0a
|
||||
code size: 212
|
||||
code size: 187
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
Loading…
Reference in a new issue