// Expect retcode = 0 // IR -> C99 后端(P1a 子集)。 // // 设计:每个 IR ref 一个 C 局部变量(C 编译器 -O2 会做 mem2reg),标签用 goto; // 类型直接由 IR 的 tid 决定,生成期无运行时分发。 // // 每个非 extern 函数的 C 名为 `spl_f`;extern 函数直接用其 SPL 名 // (由 runtime 提供)。暂不支持聚合/切片/全局数据。 type .{ .Vec } = @import("utils/vec.spl"); type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .append_usize, .append_i64, .append_u64 } = @import("utils/fmt.spl"); type TypeTable = @import("./type_table.spl"); type LayoutM = @import("./layout.spl"); type .{ .Layout } = @import("./layout.spl"); type AttrM = @import("./attr.spl"); type .{ .Attr } = @import("./attr.spl"); type IrM = @import("./ir.spl"); type .{ .Ir, .IrFunc, .IrEntry } = @import("./ir.spl"); type Ir2C = @self; ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer, gdata_n: usize, failed: bool, fn usize_at(v: *Vec, i: usize): usize { ret (v.data as *usize)[i]; } fn put(self: *Ir2C, s: []u8) { match ByteBuffer.append(self.out, s) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_byte(self: *Ir2C, b: u8) { match ByteBuffer.append_byte(self.out, b) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_u(self: *Ir2C, v: usize) { match append_usize(self.out, v, 10, false) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_i(self: *Ir2C, v: i64) { match append_i64(self.out, v, 10, false) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_u64(self: *Ir2C, v: u64) { match append_u64(self.out, v, 10, false) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_bv(self: *Ir2C, v: ByteView) { match ByteBuffer.append(self.out, ByteView.as_slice(v)) { .Ok => {}, .Err(error) => { self.failed = true; }, } } fn put_unsupported(self: *Ir2C, what: []u8) { self.failed = true; put(self, "/* unsupported: "); put(self, what); put(self, " */\n"); } // ---- 类型查询 ---- fn info_of(self: *Ir2C, tid: usize): *LayoutM.LayoutInfo { ret LayoutM.info_of(self.layout, tid); } fn type_size(self: *Ir2C, tid: usize): usize { var info = info_of(self, tid); if info == null { ret 0; } ret (info.size_bits + 7) / 8; } fn type_align(self: *Ir2C, tid: usize): usize { var info = info_of(self, tid); if info == null { ret 1; } var a = info.align_bits / 8; if a == 0 { a = 1; } ret a; } fn is_aggregate(self: *Ir2C, tid: usize): bool { var te = TypeTable.node(self.ty, tid); if te == null { ret false; } match te.node { .Array => { ret true; }, .Struct => { ret true; }, .Union => { ret true; }, .Enum => { ret true; }, .Shape => { ret true; }, _ => {}, } ret false; } fn tid_is_signed(self: *Ir2C, tid: usize): bool { var te = TypeTable.node(self.ty, tid); if te == null { ret false; } match te.node { .Int(x) => { ret x.is_signed; }, _ => {}, } ret false; } fn tid_int_bits(self: *Ir2C, tid: usize): usize { var te = TypeTable.node(self.ty, tid); if te == null { ret 0; } match te.node { .Int(x) => { ret x.bits; }, _ => {}, } ret 0; } fn tid_is_bool(self: *Ir2C, tid: usize): bool { var te = TypeTable.node(self.ty, tid); if te == null { ret false; } match te.node { .Bool => { ret true; }, _ => {}, } ret false; } fn tid_is_unit(self: *Ir2C, tid: usize): bool { if tid == 0 { ret true; } var te = TypeTable.node(self.ty, tid); if te == null { ret true; } match te.node { .Unit => { ret true; }, _ => {}, } ret false; } fn fn_ret_type(self: *Ir2C, fn_tid: usize): usize { var te = TypeTable.node(self.ty, fn_tid); if te == null { ret 0; } match te.node { .Fn(f) => { ret f.ret_type; }, _ => {}, } ret 0; } // ---- C 类型 ---- fn put_type(self: *Ir2C, tid: usize): bool { var te = TypeTable.node(self.ty, tid); if te == null { ret false; } match te.node { .Unit => { put(self, "void"); ret true; }, .Never => { put(self, "void"); ret true; }, .Bool => { put(self, "u8"); ret true; }, .Int(x) => { if x.bits == 8 { if x.is_signed { put(self, "i8"); } else { put(self, "u8"); } } else if x.bits == 16 { if x.is_signed { put(self, "i16"); } else { put(self, "u16"); } } else if x.bits == 32 { if x.is_signed { put(self, "i32"); } else { put(self, "u32"); } } else { if x.is_signed { put(self, "i64"); } else { put(self, "u64"); } } ret true; }, .Float(x) => { if x.bits == 32 { put(self, "float"); } else { put(self, "double"); } ret true; }, .Ptr(x) => { put(self, "void*"); ret true; }, .Fn(f) => { put(self, "void*"); ret true; }, // 聚合值统一以「指向存储的指针」表示 .Array => { put(self, "void*"); ret true; }, .Struct => { put(self, "void*"); ret true; }, .Union => { put(self, "void*"); ret true; }, .Enum => { put(self, "void*"); ret true; }, .Shape => { put(self, "void*"); ret true; }, _ => {}, } ret false; } fn fn_is_extern(self: *Ir2C, f: *IrFunc): bool { var i: usize = 0; while i < f.attrs.len { var a = AttrM.node(self.attr, usize_at(&f.attrs, i)); if a != null { var info = AttrM.info_at(self.attr, a.info_index); if info != null { if ByteView.eq(info.name, ByteView.from_slice("extern")) { ret true; } } } i = i + 1; } ret false; } fn c_fn_name(self: *Ir2C, fid: usize) { var f = IrM.func(self.ir, fid); if f != null && fn_is_extern(self, f) { put_bv(self, f.name); ret; } put(self, "f"); put_u(self, fid); } // ---- 常量解析 ---- fn const_node(self: *Ir2C, f: *IrFunc, ref: usize): usize { if ref == 0 || ref >= f.nodes.len { ret 0; } var n = (f.nodes.data as *IrEntry) + ref; match n.body { .Const(c) => { match c.lit { .Int(v) => { ret v; }, .Char(v) => { ret v as usize; }, .Ptr(v) => { ret v; }, _ => {}, } }, _ => {}, } ret 0; } // ---- 聚合字段 ---- fn field_tid(self: *Ir2C, tid: usize, idx: usize): usize { var te = TypeTable.node(self.ty, tid); if te == null { ret 0; } match te.node { .Enum(agg) => { if idx == 0 { ret agg.tag_type; } var vidx = idx - 1; if vidx < agg.variants.len { var m = TypeTable.member_at(&agg.variants, vidx); if m != null { ret m.type_id; } } ret 0; }, .Struct(agg) => { if idx < agg.variants.len { var m = TypeTable.member_at(&agg.variants, idx); if m != null { ret m.type_id; } } ret 0; }, .Union(agg) => { if idx < agg.variants.len { var m = TypeTable.member_at(&agg.variants, idx); if m != null { ret m.type_id; } } ret 0; }, .Shape(agg) => { if idx < agg.variants.len { var m = TypeTable.member_at(&agg.variants, idx); if m != null { ret m.type_id; } } ret 0; }, .Array(a) => { ret a.element; }, _ => {}, } ret 0; } fn field_off(self: *Ir2C, tid: usize, idx: usize): usize { var te = TypeTable.node(self.ty, tid); if te == null { ret 0; } match te.node { .Array(a) => { ret idx * type_size(self, a.element); }, _ => {}, } var info = info_of(self, tid); if info == null || idx >= info.field_bit_offsets.len { ret 0; } ret usize_at(&info.field_bit_offsets, idx) / 8; } // 聚合值统一表示为「指向存储的指针」:声明一个 8 字节对齐的缓冲并把指针存入 v。 fn emit_agg_local(self: *Ir2C, ref: usize, tid: usize) { var size = type_size(self, tid); var words = (size + 7) / 8; if words == 0 { words = 1; } put(self, "u64 s"); put_u(self, ref); put(self, "["); put_u(self, words); put(self, "]; void* v"); put_u(self, ref); put(self, " = (void*)s"); put_u(self, ref); put(self, ";\n"); } fn emit_agg_construct(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .AggConstruct(a) => { if !is_aggregate(self, a.tid) { put_unsupported(self, "agg construct non-agg"); ret; } bind_agg(self, ref); var i: usize = 0; while i < a.fields.len { var fref = usize_at(&a.fields, i); var ftid = field_tid(self, a.tid, i); var foff = field_off(self, a.tid, i); if ftid != 0 { if is_aggregate(self, ftid) { var fsz = type_size(self, ftid); put(self, "memcpy((u8*)v"); put_u(self, ref); put(self, " + "); put_u(self, foff); put(self, ", v"); put_u(self, fref); put(self, ", "); put_u(self, fsz); put(self, ");\n"); } else { put(self, "*("); put_type(self, ftid); put(self, "*)((u8*)v"); put_u(self, ref); put(self, " + "); put_u(self, foff); put(self, ") = v"); put_u(self, fref); put(self, ";\n"); } } i = i + 1; } }, _ => {}, } } fn emit_agg_extract(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .AggExtract(a) => { var foff = field_off(self, a.tid, a.field_idx); if is_aggregate(self, a.field_tid) { var fsz = type_size(self, a.field_tid); bind_agg(self, ref); put(self, "memcpy(v"); put_u(self, ref); put(self, ", (u8*)v"); put_u(self, a.val); put(self, " + "); put_u(self, foff); put(self, ", "); put_u(self, fsz); put(self, ");\n"); } else { put(self, "v"); put_u(self, ref); put(self, " = *("); put_type(self, a.field_tid); put(self, "*)((u8*)v"); put_u(self, a.val); put(self, " + "); put_u(self, foff); put(self, ");\n"); } }, _ => {}, } } fn emit_agg_insert(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .AggInsert(a) => { bind_agg(self, ref); var sz = type_size(self, a.tid); put(self, "memcpy(v"); put_u(self, ref); put(self, ", v"); put_u(self, a.agg); put(self, ", "); put_u(self, sz); put(self, ");\n"); var ftid = field_tid(self, a.tid, a.field_idx); var foff = field_off(self, a.tid, a.field_idx); if ftid != 0 { if is_aggregate(self, ftid) { var fsz = type_size(self, ftid); put(self, "memcpy((u8*)v"); put_u(self, ref); put(self, " + "); put_u(self, foff); put(self, ", v"); put_u(self, a.field); put(self, ", "); put_u(self, fsz); put(self, ");\n"); } else { put(self, "*("); put_type(self, ftid); put(self, "*)((u8*)v"); put_u(self, ref); put(self, " + "); put_u(self, foff); put(self, ") = v"); put_u(self, a.field); put(self, ";\n"); } } }, _ => {}, } } // ---- 节点发射 ---- fn emit_arith(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .Arith(a) => { put(self, "v"); put_u(self, ref); put(self, " = "); match n.kind { .ArithAdd => { put(self, "(v"); put_u(self, a.left); put(self, " + v"); put_u(self, a.right); put(self, ")"); }, .ArithSub => { put(self, "(v"); put_u(self, a.left); put(self, " - v"); put_u(self, a.right); put(self, ")"); }, .ArithMul => { put(self, "(v"); put_u(self, a.left); put(self, " * v"); put_u(self, a.right); put(self, ")"); }, .ArithDiv => { put(self, "(v"); put_u(self, a.left); put(self, " / v"); put_u(self, a.right); put(self, ")"); }, .ArithRem => { put(self, "(v"); put_u(self, a.left); put(self, " % v"); put_u(self, a.right); put(self, ")"); }, .ArithAnd => { put(self, "(v"); put_u(self, a.left); put(self, " & v"); put_u(self, a.right); put(self, ")"); }, .ArithOr => { put(self, "(v"); put_u(self, a.left); put(self, " | v"); put_u(self, a.right); put(self, ")"); }, .ArithXor => { put(self, "(v"); put_u(self, a.left); put(self, " ^ v"); put_u(self, a.right); put(self, ")"); }, .ArithShl => { put(self, "(v"); put_u(self, a.left); put(self, " << v"); put_u(self, a.right); put(self, ")"); }, .ArithShr => { put(self, "(v"); put_u(self, a.left); put(self, " >> v"); put_u(self, a.right); put(self, ")"); }, .ArithNeg => { put(self, "(-v"); put_u(self, a.left); put(self, ")"); }, .ArithNot => { if tid_is_bool(self, a.tid) { put(self, "(!v"); } else { put(self, "(~v"); } put_u(self, a.left); put(self, ")"); }, .ArithAbs => { put(self, "(v"); put_u(self, a.left); put(self, " < 0 ? -v"); put_u(self, a.left); put(self, " : v"); put_u(self, a.left); put(self, ")"); }, _ => { put(self, "0"); }, } put(self, ";\n"); }, _ => {}, } } fn emit_cmp(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .Cmp(c) => { put(self, "v"); put_u(self, ref); put(self, " = (v"); put_u(self, c.a); match n.kind { .CmpEq => { put(self, " == v"); }, .CmpNe => { put(self, " != v"); }, .CmpLt => { put(self, " < v"); }, .CmpLe => { put(self, " <= v"); }, .CmpGt => { put(self, " > v"); }, .CmpGe => { put(self, " >= v"); }, _ => { put(self, " == v"); }, } put_u(self, c.b); put(self, ");\n"); }, _ => {}, } } fn emit_cast(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .Cast(c) => { put(self, "v"); put_u(self, ref); put(self, " = "); var from_is_ptr = false; var from_is_bool = false; var to_is_ptr = false; var te = TypeTable.node(self.ty, c.from_tid); if te != null { match te.node { .Ptr(p) => { from_is_ptr = true; }, .Bool => { from_is_bool = true; }, _ => {}, } } var tte = TypeTable.node(self.ty, c.to_tid); if tte != null { match tte.node { .Ptr(p) => { to_is_ptr = true; }, _ => {} } } if to_is_ptr { put(self, "(void*)(usize)v"); put_u(self, c.val); } else if from_is_ptr { put(self, "(usize)v"); put_u(self, c.val); } else if from_is_bool { put(self, "(v"); put_u(self, c.val); put(self, " ? 1 : 0)"); } else { put(self, "v"); put_u(self, c.val); } put(self, ";\n"); }, _ => {}, } } fn emit_const(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .Const(c) => { if tid_is_unit(self, c.tid) { ret; } put(self, "v"); put_u(self, ref); put(self, " = "); match c.lit { .Bool(b) => { if b { put(self, "1"); } else { put(self, "0"); } }, .Char(v) => { put_u(self, v as usize); }, .Int(v) => { if tid_is_signed(self, c.tid) { var iv = v as i64; if iv == (-9223372036854775807 - 1) { put(self, "(-9223372036854775807 - 1)"); } else { put_i(self, iv); } } else { put_u(self, v); if tid_int_bits(self, c.tid) >= 64 { put(self, "ull"); } } }, .Ptr(v) => { put(self, "(void*)"); put_u(self, v); }, .Float(v) => { put(self, "0.0"); }, .Fn(fid) => { put(self, "(void*)&"); c_fn_name(self, fid); }, } put(self, ";\n"); }, _ => {}, } } fn emit_mem(self: *Ir2C, f: *IrFunc, ref: usize, n: *IrEntry) { match n.body { .MemAlloc(m) => { put(self, "v"); put_u(self, ref); put(self, " = (void*)s"); put_u(self, ref); put(self, ";\n"); }, .MemLoad(m) => { if is_aggregate(self, m.tid) { var sz = type_size(self, m.tid); bind_agg(self, ref); put(self, "memcpy(v"); put_u(self, ref); put(self, ", v"); put_u(self, m.ptr); put(self, ", "); put_u(self, sz); put(self, ");\n"); } else { put(self, "v"); put_u(self, ref); put(self, " = *("); put_type(self, m.tid); put(self, "*)v"); put_u(self, m.ptr); put(self, ";\n"); } }, .MemStore(m) => { if is_aggregate(self, m.tid) { var sz = type_size(self, m.tid); put(self, "memcpy(v"); put_u(self, m.ptr); put(self, ", v"); put_u(self, m.val); put(self, ", "); put_u(self, sz); put(self, ");\n"); } else { put(self, "*("); put_type(self, m.tid); put(self, "*)v"); put_u(self, m.ptr); put(self, " = v"); put_u(self, m.val); put(self, ";\n"); } }, .MemOffset(m) => { var size = type_size(self, m.tid); if size == 0 { size = 1; } put(self, "v"); put_u(self, ref); put(self, " = (void*)((u8*)v"); put_u(self, m.ptr); put(self, " + (u64)v"); put_u(self, m.offset); put(self, " * "); put_u(self, size); put(self, ");\n"); }, .MemFieldPtr(m) => { var foff = field_off(self, m.tid, m.field_idx); put(self, "v"); put_u(self, ref); put(self, " = (void*)((u8*)v"); put_u(self, m.agg); put(self, " + "); put_u(self, foff); put(self, ");\n"); }, .MemGlobalAlloc(m) => { var ctid: usize = 0; var pv: usize = 0; var found = false; if m.const_node > 0 && m.const_node < f.nodes.len { var cn = (f.nodes.data as *IrEntry) + m.const_node; match cn.body { .Const(c) => { ctid = c.tid; match c.lit { .Ptr(v) => { pv = v; found = true; }, _ => {} } }, _ => {}, } } if !found { put(self, "v"); put_u(self, ref); put(self, " = (void*)0;\n"); ret; } var size = type_size(self, ctid); if size == 0 { size = 8; } var gid = self.gdata_n; self.gdata_n = self.gdata_n + 1; var words = (size + 7) / 8; if words == 0 { words = 1; } put(self, "static const u64 g"); put_u(self, gid); put(self, "["); put_u(self, words); put(self, "] = {"); var j: usize = 0; while j < words { if j > 0 { put(self, ", "); } var w: u64 = 0; var k: usize = 0; while k < 8 { var idx = j * 8 + k; var b: u64 = 0; if idx < size { b = ((pv + idx) as *u8).* as u64; } w = w | (b << (k as u64 * 8)); k = k + 1; } put_u64(self, w); put(self, "ull"); j = j + 1; } put(self, "};\nv"); put_u(self, ref); put(self, " = (void*)g"); put_u(self, gid); put(self, ";\n"); }, _ => {}, } } fn emit_typeop(self: *Ir2C, ref: usize, n: *IrEntry) { match n.body { .TypeOp(t) => { var v: usize = 0; match n.kind { .TypeSizeof => { v = type_size(self, t.tid); }, .TypeBitsizeof => { var info = info_of(self, t.tid); if info != null { v = info.size_bits; } }, .TypeAlignof => { v = type_align(self, t.tid); }, .TypeFieldCount => { var te = TypeTable.node(self.ty, t.tid); if te != null { match te.node { .Struct(a) => { v = a.variants.len; }, .Union(a) => { v = a.variants.len; }, .Array(a) => { v = a.len; }, _ => {}, } } }, _ => {}, } put(self, "v"); put_u(self, ref); put(self, " = "); put_u(self, v); put(self, ";\n"); }, _ => {}, } } // 节点的「值类型」;0 表示无结果。 fn result_tid(self: *Ir2C, n: *IrEntry): usize { match n.body { .Arith(a) => { ret a.tid; }, .Cmp(c) => { ret TypeTable.make_bool(self.ty); }, .Cast(c) => { ret c.to_tid; }, .MemAlloc(m) => { ret TypeTable.make_ptr(self.ty, m.tid); }, .MemGlobalAlloc(m) => { ret TypeTable.make_ptr(self.ty, m.tid); }, .MemLoad(m) => { ret m.tid; }, .MemOffset(m) => { ret TypeTable.make_ptr(self.ty, m.tid); }, .MemFieldPtr(m) => { var ft = field_tid(self, m.tid, m.field_idx); ret TypeTable.make_ptr(self.ty, ft); }, .Const(c) => { ret c.tid; }, .TypeOp(t) => { ret TypeTable.make_int(self.ty, 64, false); }, .AggConstruct(a) => { ret a.tid; }, .AggExtract(a) => { ret a.field_tid; }, .AggInsert(a) => { ret a.tid; }, .Select(s) => { ret s.tid; }, .Call(c) => { ret c.tid; }, .Param(p) => { ret p.tid; }, _ => {}, } ret 0; } fn res_tid_ref(self: *Ir2C, f: *IrFunc, ref: usize): usize { if ref == 0 || ref >= f.nodes.len { ret 0; } ret result_tid(self, (f.nodes.data as *IrEntry) + ref); } fn emit_call(self: *Ir2C, f: *IrFunc, ref: usize, n: *IrEntry) { match n.body { .Call(c) => { var callee: usize = 0; if c.func > 0 && c.func < f.nodes.len { var fnode = (f.nodes.data as *IrEntry) + c.func; match fnode.body { .Const(cc) => { match cc.lit { .Fn(nf) => { callee = nf; }, _ => {} } }, _ => {}, } } var ret_agg = is_aggregate(self, c.tid); if callee != 0 { if ret_agg { bind_agg(self, ref); } else if !tid_is_unit(self, c.tid) { put(self, "v"); put_u(self, ref); put(self, " = "); } c_fn_name(self, callee); put(self, "("); if ret_agg { put(self, "v"); put_u(self, ref); } var k: usize = 0; while k < c.params.len { if k > 0 || ret_agg { put(self, ", "); } put(self, "v"); put_u(self, usize_at(&c.params, k)); k = k + 1; } put(self, ");\n"); ret; } // 间接调用:从 func 值的类型构造函数指针类型 var func_tid = res_tid_ref(self, f, c.func); var ftnode = TypeTable.node(self.ty, func_tid); if ftnode == null { put_unsupported(self, "indirect call type"); ret; } var params_tid: usize = 0; match ftnode.node { .Fn(fd) => { params_tid = func_tid; }, _ => {} } if ret_agg { bind_agg(self, ref); } else if !tid_is_unit(self, c.tid) { put(self, "v"); put_u(self, ref); put(self, " = "); } put(self, "(("); if ret_agg || tid_is_unit(self, c.tid) { put(self, "void"); } else { if !put_type(self, c.tid) { put(self, "void"); } } put(self, " (*)("); var need_comma = false; if ret_agg { put(self, "void*"); need_comma = true; } var np: usize = 0; var te = TypeTable.node(self.ty, params_tid); if te != null { match te.node { .Fn(fd) => { np = fd.params.len; var kp: usize = 0; while kp < np { if need_comma { put(self, ", "); } var pt = usize_at(&fd.params, kp); if is_aggregate(self, pt) { put(self, "void*"); } else { if !put_type(self, pt) { put(self, "void*"); } } need_comma = true; kp = kp + 1; } }, _ => {}, } } if !need_comma { put(self, "void"); } put(self, "))v"); put_u(self, c.func); put(self, ")("); if ret_agg { put(self, "v"); put_u(self, ref); } var k2: usize = 0; while k2 < c.params.len { if k2 > 0 || ret_agg { put(self, ", "); } put(self, "v"); put_u(self, usize_at(&c.params, k2)); k2 = k2 + 1; } put(self, ");\n"); }, _ => {}, } } fn emit_control(self: *Ir2C, f: *IrFunc, ref: usize, n: *IrEntry, ret_tid: usize) { match n.body { .Param(p) => { var idx = const_node(self, f, p.idx); if is_aggregate(self, p.tid) { put(self, "v"); put_u(self, ref); put(self, " = a"); put_u(self, idx); put(self, ";\n"); } else { put(self, "v"); put_u(self, ref); put(self, " = ("); put_type(self, p.tid); put(self, ")a"); put_u(self, idx); put(self, ";\n"); } }, .Ret(r) => { if is_aggregate(self, ret_tid) { if r.val != 0 { var sz = type_size(self, ret_tid); put(self, "memcpy(ret__, v"); put_u(self, r.val); put(self, ", "); put_u(self, sz); put(self, ");\n"); } put(self, "return;\n"); } else if tid_is_unit(self, ret_tid) { put(self, "return;\n"); } else { put(self, "return v"); put_u(self, r.val); put(self, ";\n"); } }, .Br(b) => { put(self, "if (v"); put_u(self, b.cond); put(self, ") goto L"); put_u(self, b.true_label); put(self, ";\ngoto L"); put_u(self, b.false_label); put(self, ";\n"); }, .Jmp(j) => { put(self, "goto L"); put_u(self, j.label); put(self, ";\n"); }, .Call(c) => { emit_call(self, f, ref, n); }, _ => {}, } } fn hex_digit(v: u8): []u8 { if v == 0 { ret "0"; } if v == 1 { ret "1"; } if v == 2 { ret "2"; } if v == 3 { ret "3"; } if v == 4 { ret "4"; } if v == 5 { ret "5"; } if v == 6 { ret "6"; } if v == 7 { ret "7"; } if v == 8 { ret "8"; } if v == 9 { ret "9"; } if v == 10 { ret "a"; } if v == 11 { ret "b"; } if v == 12 { ret "c"; } if v == 13 { ret "d"; } if v == 14 { ret "e"; } ret "f"; } fn emit_c_string(self: *Ir2C, msg: ByteView) { put(self, "\""); var i: usize = 0; while i < msg.len { var b = msg.ptr[i]; if b == 34 { put(self, "\\\""); } else if b == 92 { put(self, "\\\\"); } else if b == 10 { put(self, "\\n"); } else if b == 13 { put(self, "\\r"); } else if b == 9 { put(self, "\\t"); } else if b >= 32 && b < 127 { put_byte(self, b); } else { put(self, "\\x"); put(self, hex_digit((b >> 4) & 15)); put(self, hex_digit(b & 15)); } i = i + 1; } put(self, "\""); } fn emit_node(self: *Ir2C, fid: usize, f: *IrFunc, ref: usize, n: *IrEntry, ret_tid: usize) { match n.kind { .TypeConst => { emit_const(self, ref, n); }, .ArithAdd => { emit_arith(self, ref, n); }, .ArithSub => { emit_arith(self, ref, n); }, .ArithMul => { emit_arith(self, ref, n); }, .ArithDiv => { emit_arith(self, ref, n); }, .ArithRem => { emit_arith(self, ref, n); }, .ArithAnd => { emit_arith(self, ref, n); }, .ArithOr => { emit_arith(self, ref, n); }, .ArithXor => { emit_arith(self, ref, n); }, .ArithShl => { emit_arith(self, ref, n); }, .ArithShr => { emit_arith(self, ref, n); }, .ArithNeg => { emit_arith(self, ref, n); }, .ArithNot => { emit_arith(self, ref, n); }, .ArithAbs => { emit_arith(self, ref, n); }, .CmpEq => { emit_cmp(self, ref, n); }, .CmpNe => { emit_cmp(self, ref, n); }, .CmpLt => { emit_cmp(self, ref, n); }, .CmpLe => { emit_cmp(self, ref, n); }, .CmpGt => { emit_cmp(self, ref, n); }, .CmpGe => { emit_cmp(self, ref, n); }, .CastTrunc => { emit_cast(self, ref, n); }, .CastZext => { emit_cast(self, ref, n); }, .CastSext => { emit_cast(self, ref, n); }, .CastBitcast => { emit_cast(self, ref, n); }, .CastPtr2int => { emit_cast(self, ref, n); }, .CastInt2ptr => { emit_cast(self, ref, n); }, .CastBool2int => { emit_cast(self, ref, n); }, .MemAlloca => { emit_mem(self, f, ref, n); }, .MemLoad => { emit_mem(self, f, ref, n); }, .MemStore => { emit_mem(self, f, ref, n); }, .MemOffset => { emit_mem(self, f, ref, n); }, .MemFieldPtr => { emit_mem(self, f, ref, n); }, .MemGlobalAlloc => { emit_mem(self, f, ref, n); }, .AggConstruct => { emit_agg_construct(self, ref, n); }, .AggExtract => { emit_agg_extract(self, ref, n); }, .AggInsert => { emit_agg_insert(self, ref, n); }, .TypeSizeof => { emit_typeop(self, ref, n); }, .TypeBitsizeof => { emit_typeop(self, ref, n); }, .TypeAlignof => { emit_typeop(self, ref, n); }, .TypeFieldCount => { emit_typeop(self, ref, n); }, .ControlParam => { emit_control(self, f, ref, n, ret_tid); }, .ControlRet => { emit_control(self, f, ref, n, ret_tid); }, .ControlBr => { emit_control(self, f, ref, n, ret_tid); }, .ControlJmp => { emit_control(self, f, ref, n, ret_tid); }, .ControlCall => { emit_control(self, f, ref, n, ret_tid); }, .ControlSelect => { match n.body { .Select(s) => { if is_aggregate(self, s.tid) { put(self, "v"); put_u(self, ref); put(self, " = v"); put_u(self, s.cond); put(self, " ? v"); put_u(self, s.true_val); put(self, " : v"); put_u(self, s.false_val); put(self, ";\n"); } else { put(self, "v"); put_u(self, ref); put(self, " = v"); put_u(self, s.cond); put(self, " ? v"); put_u(self, s.true_val); put(self, " : v"); put_u(self, s.false_val); put(self, ";\n"); } }, _ => {}, } }, .ControlTrap => { put(self, "spl_trap();\n"); }, .ControlUnreachable => { put(self, "spl_trap();\n"); }, .DbgBreakpoint => {}, .DbgPanic => { match n.body { .Panic(p) => { put(self, "spl_panic("); emit_c_string(self, p.msg); put(self, ");\n"); }, _ => {}, } }, _ => { put_unsupported(self, "node kind"); }, } } fn emit_fn_sig(self: *Ir2C, fid: usize, with_names: bool) { var f = IrM.func(self.ir, fid); var ret_tid = fn_ret_type(self, f.fn_tid); var ret_agg = is_aggregate(self, ret_tid); if ret_agg { put(self, "void"); } else if !put_type(self, ret_tid) { put(self, "void"); } put(self, " "); c_fn_name(self, fid); put(self, "("); var need = false; if ret_agg { put(self, "void* ret__"); need = true; } var nargs: usize = 0; var te = TypeTable.node(self.ty, f.fn_tid); if te != null { match te.node { .Fn(fd) => { nargs = fd.params.len; var k: usize = 0; while k < nargs { if need { put(self, ", "); } var pt = usize_at(&fd.params, k); if is_aggregate(self, pt) { put(self, "void*"); } else { if !put_type(self, pt) { put(self, "void*"); } } if with_names { put(self, " a"); put_u(self, k); } need = true; k = k + 1; } }, _ => {}, } } if !need { put(self, "void"); } put(self, ")"); } fn emit_proto(self: *Ir2C, fid: usize) { emit_fn_sig(self, fid, false); put(self, ";\n"); } // 预声明一个 ref 的存储与值变量。 fn declare_ref(self: *Ir2C, ref: usize, tid: usize) { if is_aggregate(self, tid) { var size = type_size(self, tid); var words = (size + 7) / 8; if words == 0 { words = 1; } put(self, "u64 s"); put_u(self, ref); put(self, "["); put_u(self, words); put(self, "]; void* v"); put_u(self, ref); put(self, ";\n"); ret; } if !put_type(self, tid) { put(self, "void*"); } put(self, " v"); put_u(self, ref); put(self, ";\n"); } fn declare_all(self: *Ir2C, f: *IrFunc) { var i: usize = 1; while i < f.nodes.len { var n = (f.nodes.data as *IrEntry) + i; var is_alloc = false; var count: usize = 1; var pointee: usize = 0; match n.body { .MemAlloc(m) => { is_alloc = true; count = const_node(self, f, m.count); if count == 0 { count = 1; } pointee = m.tid; }, _ => {}, } if is_alloc { if is_aggregate(self, pointee) { var esz = type_size(self, pointee); var words = (esz * count + 7) / 8; if words == 0 { words = 1; } put(self, "u64 s"); put_u(self, i); put(self, "["); put_u(self, words); put(self, "]; void* v"); put_u(self, i); put(self, ";\n"); } else { if !put_type(self, pointee) { put(self, "void*"); } put(self, " s"); put_u(self, i); put(self, "["); put_u(self, count); put(self, "]; void* v"); put_u(self, i); put(self, ";\n"); } } else { var tid = result_tid(self, n); if tid != 0 && !tid_is_unit(self, tid) { declare_ref(self, i, tid); } } i = i + 1; } } fn bind_agg(self: *Ir2C, ref: usize) { put(self, "v"); put_u(self, ref); put(self, " = (void*)s"); put_u(self, ref); put(self, ";\n"); } fn emit_def(self: *Ir2C, fid: usize) { var f = IrM.func(self.ir, fid); var ret_tid = fn_ret_type(self, f.fn_tid); emit_fn_sig(self, fid, true); put(self, " {\n"); declare_all(self, f); var i: usize = 1; while i < f.nodes.len { put(self, "L"); put_u(self, i); put(self, ": ;\n"); var n = (f.nodes.data as *IrEntry) + i; emit_node(self, fid, f, i, n, ret_tid); i = i + 1; } put(self, "spl_trap();\n}\n"); } // ---- driver ---- fn find_main(self: *Ir2C): usize { var i: usize = 1; while i < self.ir.funcs.len { var f = IrM.func(self.ir, i); if f != null && !fn_is_extern(self, f) { if ByteView.eq(f.name, ByteView.from_slice("main")) { ret i; } } i = i + 1; } ret 0; } fn run(self: *Ir2C) { put(self, "#include \"spl_rt.h\"\n"); var i: usize = 1; while i < self.ir.funcs.len { var f = IrM.func(self.ir, i); if f != null && !fn_is_extern(self, f) { emit_proto(self, i); } i = i + 1; } i = 1; while i < self.ir.funcs.len { var f = IrM.func(self.ir, i); if f != null && !fn_is_extern(self, f) { emit_def(self, i); } i = i + 1; } var m = find_main(self); if m != 0 { var f = IrM.func(self.ir, m); var nargs: usize = 0; var te = TypeTable.node(self.ty, f.fn_tid); if te != null { match te.node { .Fn(fd) => { nargs = fd.params.len; }, _ => {} } } if nargs == 0 { put(self, "int main(void) { f"); put_u(self, m); put(self, "(); return 0; }\n"); } else { put(self, "int main(int argc, char** argv) { "); if !tid_is_unit(self, fn_ret_type(self, f.fn_tid)) { put(self, "return (int)f"); put_u(self, m); put(self, "(argc, (void*)argv); }\n"); } else { put(self, "f"); put_u(self, m); put(self, "(argc, (void*)argv); return 0; }\n"); } } } } fn new(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): Ir2C { ret Ir2C { .ir = ir, .ty = ty, .layout = layout, .attr = attr, .out = out, .gdata_n = 1, .failed = false, }; } fn compile(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): bool { var c = new(ir, ty, layout, attr, out); run(&c); ret !c.failed; } fn main() {}