diff --git a/lang/README.md b/lang/README.md index 1d8ee6b7..3328a231 100644 --- a/lang/README.md +++ b/lang/README.md @@ -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) diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 24a16e10..c23e4325 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -107,6 +107,7 @@ mod ctx_map { } } + #[derive(Clone)] pub struct Key { 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 { inner: hashbrown::HashMap, (), 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, diff --git a/lang/src/son.rs b/lang/src/son.rs index b0a89990..d56b0fcb 100644 --- a/lang/src/son.rs +++ b/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>, 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, @@ -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>) { + 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(, @bitcast())` 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(, @trunc())` to hint the type", + consider using `@as(, @intcast())` 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(, @eca(...))` 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; diff --git a/lang/src/vc.rs b/lang/src/vc.rs index dae96f79..a2eb5fc3 100644 --- a/lang/src/vc.rs +++ b/lang/src/vc.rs @@ -266,7 +266,7 @@ struct AllocedVc { base: Unique, } -#[derive(Default)] +#[derive(Default, Clone)] pub struct BitSet { data: Vec, } diff --git a/lang/tests/son_tests_different_types.txt b/lang/tests/son_tests_different_types.txt index a29fc93b..10a5a9e3 100644 --- a/lang/tests/son_tests_different_types.txt +++ b/lang/tests/son_tests_different_types.txt @@ -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(()) diff --git a/lang/tests/son_tests_directives.txt b/lang/tests/son_tests_directives.txt new file mode 100644 index 00000000..e69de29b diff --git a/lang/tests/son_tests_pointers.txt b/lang/tests/son_tests_pointers.txt index 69644678..6a62ee7c 100644 --- a/lang/tests/son_tests_pointers.txt +++ b/lang/tests/son_tests_pointers.txt @@ -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(())