implementing directives

This commit is contained in:
Jakub Doka 2024-10-21 18:57:23 +02:00
parent 0298b32e38
commit bc817c4ea2
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
7 changed files with 204 additions and 76 deletions

View file

@ -273,7 +273,7 @@ main := fn(): int {
align_of_Type_in_bytes := @alignof(foo.Type) align_of_Type_in_bytes := @alignof(foo.Type)
hardcoded_pointer := @as(^u8, @bitcast(10)) hardcoded_pointer := @as(^u8, @bitcast(10))
ecall_that_returns_int := @as(int, @eca(1, foo.Type.(10, 20), 5, 6)) 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) return @inline(foo.foo)
} }
@ -357,7 +357,7 @@ fib_iter := fn(n: int): int {
```hb ```hb
main := fn(): int { main := fn(): int {
addr := @as(u16, 0x1FF) 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 _force_stack := &msg
arr := [int].(1, 2, 4) arr := [int].(1, 2, 4)

View file

@ -107,6 +107,7 @@ mod ctx_map {
} }
} }
#[derive(Clone)]
pub struct Key<T> { pub struct Key<T> {
pub value: T, pub value: T,
pub hash: Hash, pub hash: Hash,
@ -125,6 +126,7 @@ mod ctx_map {
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a>; fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a>;
} }
#[derive(Clone)]
pub struct CtxMap<T> { pub struct CtxMap<T> {
inner: hashbrown::HashMap<Key<T>, (), HashBuilder>, inner: hashbrown::HashMap<Key<T>, (), HashBuilder>,
} }
@ -263,6 +265,8 @@ mod ty {
pub type Module = u32; pub type Module = u32;
pub type Slice = u32; pub type Slice = u32;
pub const ECA: Func = Func::MAX;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Tuple(pub u32); pub struct Tuple(pub u32);
@ -702,6 +706,7 @@ impl Default for Func {
} }
} }
#[derive(Clone, Copy)]
struct TypedReloc { struct TypedReloc {
target: ty::Id, target: ty::Id,
reloc: Reloc, reloc: Reloc,

View file

@ -22,6 +22,7 @@ use {
fmt::{self, Debug, Display, Write}, fmt::{self, Debug, Display, Write},
format_args as fa, mem, format_args as fa, mem,
ops::{self}, ops::{self},
usize,
}, },
hashbrown::hash_map, hashbrown::hash_map,
regalloc2::VReg, regalloc2::VReg,
@ -55,6 +56,7 @@ impl crate::ctx_map::CtxEntry for Nid {
} }
} }
#[derive(Clone)]
struct Nodes { struct Nodes {
values: Vec<Result<Node, Nid>>, values: Vec<Result<Node, Nid>>,
visited: BitSet, visited: BitSet,
@ -500,7 +502,7 @@ impl Nodes {
Kind::BinOp { op } | Kind::UnOp { op } => { Kind::BinOp { op } | Kind::UnOp { op } => {
write!(out, "{:>4}: ", op.name()) write!(out, "{:>4}: ", op.name())
} }
Kind::Call { func } => { Kind::Call { func, argc: _ } => {
write!(out, "call: {func} {} ", self[node].depth) write!(out, "call: {func} {} ", self[node].depth)
} }
Kind::Global { global } => write!(out, "glob: {global:<5}"), Kind::Global { global } => write!(out, "glob: {global:<5}"),
@ -886,6 +888,7 @@ pub enum Kind {
// [ctrl, ...args] // [ctrl, ...args]
Call { Call {
func: ty::Func, func: ty::Func,
argc: u32,
}, },
// [ctrl] // [ctrl]
Idk, Idk,
@ -975,6 +978,7 @@ type LoopDepth = u16;
type LockRc = u16; type LockRc = u16;
type IDomDepth = u16; type IDomDepth = u16;
#[derive(Clone)]
struct Loop { struct Loop {
node: Nid, node: Nid,
ctrl: [Nid; 2], ctrl: [Nid; 2],
@ -1007,7 +1011,7 @@ impl Scope {
} }
} }
#[derive(Default)] #[derive(Default, Clone)]
struct ItemCtx { struct ItemCtx {
file: FileId, file: FileId,
ret: Option<ty::Id>, 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 (ret, mut parama) = tys.parama(node.ty);
let mut allocs = allocs.iter(); debug_assert_eq!(
for ti in tys.ins.funcs[func as usize].sig.unwrap().args.range() { allocs.len(),
let ty = tys.ins.args[ti]; 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) { let (rg, size) = match parama.next(ty, tys) {
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size), PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
PLoc::WideReg(rg, size) => (rg, size), PLoc::WideReg(rg, size) => (rg, size),
PLoc::None | PLoc::Ref(..) | PLoc::Reg(..) => continue, 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.emit(instrs::ld(rg, atr(arg), 0, size));
} }
self.relocs.push(TypedReloc {
target: ty::Kind::Func(func).compress(), if func == ty::ECA {
reloc: Reloc::new(self.code.len(), 3, 4), self.emit(instrs::eca());
}); } else {
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); 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 { if let PLoc::WideReg(r, size) = ret {
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset; let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size)); self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
@ -1482,6 +1495,20 @@ impl Pool {
self.used_cis -= 1; self.used_cis -= 1;
core::mem::swap(&mut self.cis[self.used_cis], target); 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 { struct Regalloc {
@ -1566,9 +1593,11 @@ impl TypeParser for Codegen<'_> {
todo!() todo!()
} }
#[expect(unused)]
fn infer_type(&mut self, expr: &Expr) -> ty::Id { 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) { fn on_reuse(&mut self, existing: ty::Id) {
@ -1672,6 +1701,17 @@ impl TypeParser for Codegen<'_> {
} }
impl<'a> Codegen<'a> { 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 { fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
if value == NEVER { if value == NEVER {
return 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); self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
Some(Value::ptr(ptr).ty(elem)) 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], .. } => { Expr::Directive { name: "sizeof", args: [ty], .. } => {
let ty = self.ty(ty); let ty = self.ty(ty);
Some(self.ci.nodes.new_node_lit( Some(self.ci.nodes.new_node_lit(
@ -1988,7 +2033,44 @@ impl<'a> Codegen<'a> {
[VOID], [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)?; let val = self.expr(expr)?;
if !val.ty.is_integer() { if !val.ty.is_integer() {
@ -2006,7 +2088,7 @@ impl<'a> Codegen<'a> {
self.report( self.report(
pos, pos,
"resulting integer cannot be inferred from context, \ "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; return Value::NEVER;
}; };
@ -2031,6 +2113,59 @@ impl<'a> Codegen<'a> {
let ctx = Ctx::default().with_ty(self.ty(ty)); let ctx = Ctx::default().with_ty(self.ty(ty));
self.raw_expr_ctx(expr, ctx) 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, .. } => { Expr::Call { func, args, .. } => {
self.ci.call_count += 1; self.ci.call_count += 1;
let ty = self.ty(func); 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); self.store_mem(VOID, VOID);
@ -3107,21 +3243,19 @@ impl<'a> Function<'a> {
let ops = vec![self.drg(nid), self.urg(node.inputs[1])]; let ops = vec![self.drg(nid), self.urg(node.inputs[1])];
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Call { func } => { Kind::Call { argc, .. } => {
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref;
let mut ops = vec![]; let mut ops = vec![];
let fuc = self.tys.ins.funcs[func as usize].sig.unwrap(); let (ret, mut parama) = self.tys.parama(node.ty);
if self.tys.size_of(fuc.ret) != 0 { if !matches!(ret, PLoc::None) {
ops.push(regalloc2::Operand::reg_fixed_def( ops.push(regalloc2::Operand::reg_fixed_def(
self.rg(nid), self.rg(nid),
regalloc2::PReg::new(1, regalloc2::RegClass::Int), regalloc2::PReg::new(1, regalloc2::RegClass::Int),
)); ));
} }
for &(mut i) in node.inputs[1..][..argc as usize].iter() {
let (ret, mut parama) = self.tys.parama(fuc.ret); let ty = self.nodes[i].ty;
for (ti, &(mut i)) in fuc.args.range().zip(node.inputs[1..].iter()) {
let ty = self.tys.ins.args[ti];
match parama.next(ty, self.tys) { match parama.next(ty, self.tys) {
PLoc::None => {} PLoc::None => {}
PLoc::Reg(r, _) => { PLoc::Reg(r, _) => {
@ -3130,7 +3264,7 @@ impl<'a> Function<'a> {
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int), regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
)); ));
} }
PLoc::WideReg(r, _) => { PLoc::WideReg(..) => {
loop { loop {
match self.nodes[i].kind { match self.nodes[i].kind {
Kind::Stre { .. } => i = self.nodes[i].inputs[2], Kind::Stre { .. } => i = self.nodes[i].inputs[2],
@ -3140,14 +3274,7 @@ impl<'a> Function<'a> {
debug_assert_ne!(i, 0); debug_assert_ne!(i, 0);
} }
debug_assert!(i != 0); debug_assert!(i != 0);
ops.push(regalloc2::Operand::reg_fixed_use( ops.push(self.urg(i));
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),
));
} }
PLoc::Ref(r, _) => { PLoc::Ref(r, _) => {
loop { loop {
@ -3594,8 +3721,9 @@ mod tests {
_ = log::set_logger(&crate::fs::Logger); _ = log::set_logger(&crate::fs::Logger);
log::set_max_level(log::LevelFilter::Info); 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() }; let mut codegen = super::Codegen { files, ..Default::default() };
codegen.push_embeds(embeds);
codegen.generate(); codegen.generate();
@ -3633,7 +3761,7 @@ mod tests {
hex_octal_binary_literals; hex_octal_binary_literals;
//struct_operators; //struct_operators;
global_variables; global_variables;
//directives; directives;
c_strings; c_strings;
struct_patterns; struct_patterns;
arrays; arrays;

View file

@ -266,7 +266,7 @@ struct AllocedVc {
base: Unique<Nid>, base: Unique<Nid>,
} }
#[derive(Default)] #[derive(Default, Clone)]
pub struct BitSet { pub struct BitSet {
data: Vec<usize>, data: Vec<usize>,
} }

View file

@ -15,40 +15,38 @@ main:
ST r3, r254, 12a, 4h ST r3, r254, 12a, 4h
ST r8, r254, 0a, 4h ST r8, r254, 0a, 4h
ST r9, r254, 4a, 4h ST r9, r254, 4a, 4h
LD r1, r254, 0a, 8h LD r12, r254, 0a, 8h
ST r1, r254, 16a, 8h ST r12, r254, 16a, 8h
LD r3, r254, 20a, 4h LD r3, r254, 20a, 4h
ANDI r3, r3, 4294967295d ANDI r3, r3, 4294967295d
ANDI r9, r9, 4294967295d ANDI r9, r9, 4294967295d
JEQ r3, r9, :0 JEQ r3, r9, :0
LI64 r1, 0d LI64 r1, 0d
JMP :1 JMP :1
0: ADDI64 r10, r12, 8d 0: LD r9, r254, 16a, 4h
ADDI64 r10, r10, -4d ANDI r9, r9, 4294967295d
LD r1, r10, 0a, 4h
ANDI r1, r1, 4294967295d
ANDI r8, r8, 4294967295d ANDI r8, r8, 4294967295d
JEQ r1, r8, :2 JEQ r9, r8, :2
LI64 r1, 64d LI64 r1, 64d
JMP :1 JMP :1
2: LD r7, r254, 15a, 1h 2: LD r3, r254, 15a, 1h
ANDI r9, r7, 255d ANDI r5, r3, 255d
LD r6, r254, 14a, 1h LD r2, r254, 14a, 1h
ANDI r8, r6, 255d ANDI r4, r2, 255d
LD r5, r254, 13a, 1h LD r1, r254, 13a, 1h
ANDI r7, r5, 255d ANDI r3, r1, 255d
LD r3, r254, 12a, 1h LD r11, r254, 12a, 1h
ANDI r6, r3, 255d ANDI r2, r11, 255d
LD r4, r254, 20a, 4h LD r12, r254, 20a, 4h
LD r5, r254, 16a, 4h LD r1, r254, 16a, 4h
ADD32 r10, r4, r5 ADD32 r6, r12, r1
ADD32 r11, r10, r6 ADD32 r7, r6, r2
ADD32 r3, r11, r7 ADD32 r11, r7, r3
ADD32 r7, r3, r8 ADD32 r3, r11, r4
ADD32 r11, r7, r9 ADD32 r7, r3, r5
ANDI r1, r11, 4294967295d ANDI r1, r7, 4294967295d
1: ADDI64 r254, r254, 24d 1: ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 529 code size: 507
ret: 512 ret: 512
status: Ok(()) status: Ok(())

View file

View file

@ -1,26 +1,23 @@
drop: drop:
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -32d
ST r31, r254, 8a, 40h ST r31, r254, 8a, 24h
LI64 r32, 1d LI64 r32, 1d
ADDI64 r33, r254, 0d ADDI64 r2, r254, 0d
ADDI64 r34, r33, 8000d
ADDI64 r34, r34, -8000d
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
CP r2, r34
JAL r31, r0, :modify JAL r31, r0, :modify
CP r2, r32 CP r2, r32
JAL r31, r0, :drop JAL r31, r0, :drop
LD r35, r34, 0a, 8h LD r33, r254, 0a, 8h
ADDI64 r1, r35, -2d ADDI64 r1, r33, -2d
LD r31, r254, 8a, 40h LD r31, r254, 8a, 24h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
modify: modify:
LI64 r3, 2d LI64 r3, 2d
ST r3, r2, 0a, 8h ST r3, r2, 0a, 8h
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 212 code size: 187
ret: 0 ret: 0
status: Ok(()) status: Ok(())