stage2 提供近乎完整的功能但出现严重性能问题 添加stage0的原生性能记录 stage1添加更多内置函数 nob重构代码使其更加健壮
This commit is contained in:
1 parent
b5a7a811b3
commit
e02b0c633a
35 files changed
+14018
-216
No files matched your search
@@ -0,0 +1,497 @@
|
||||
// Expect retcode = 0
|
||||
|
||||
// SIR builder (IrBuilder). Split from ir.spl: stage1 ast2ir
|
||||
// infinitely recurses on same-file @self nesting; cross-file is fine.
|
||||
|
||||
type .{ .Error } = @import("utils/error.spl");
|
||||
type .{ .Vec } = @import("utils/vec.spl");
|
||||
type .{ .ByteView } = @import("utils/byte_view.spl");
|
||||
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
|
||||
type .{ .Span, .span_none } = @import("./diag.spl");
|
||||
type TypeTable = @import("./type_table.spl");
|
||||
type Attr = @import("./attr.spl");
|
||||
type Ir = @import("./ir.spl");
|
||||
type .{ .IrKind, .ConstLit, .IrEntry, .IrFunc, .IrBody } = @import("./ir.spl");
|
||||
|
||||
fn list_at(v: Vec, i: usize): usize {
|
||||
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } }
|
||||
ret 0;
|
||||
}
|
||||
|
||||
// ---- builder ----
|
||||
|
||||
type FixKind = enum { BrTrue, BrFalse, Jmp }
|
||||
|
||||
type Fix = struct {
|
||||
node: usize,
|
||||
slot: FixKind,
|
||||
block: usize,
|
||||
}
|
||||
|
||||
type IrBuilder = @self;
|
||||
|
||||
ir: Ir,
|
||||
dbg: Span,
|
||||
current_fn: usize,
|
||||
current_block: usize,
|
||||
blocks: Vec, // usize
|
||||
fixups: Vec, // Fix
|
||||
terminated: bool,
|
||||
|
||||
fn builder_alloc(self: *IrBuilder, kind: IrKind): usize {
|
||||
var ref = Ir.alloc_node(&self.ir, self.current_fn);
|
||||
if ref == 0 { ret 0; }
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null {
|
||||
e.kind = kind;
|
||||
e.dbg = self.dbg;
|
||||
}
|
||||
if self.current_block >= self.blocks.len { ret ref; }
|
||||
match Vec.get(&self.blocks, self.current_block) {
|
||||
.Ok(p) => {
|
||||
var slot = p as *usize;
|
||||
if slot.* == 0 { slot.* = ref; }
|
||||
},
|
||||
.Err(error) => {},
|
||||
}
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn builder_new(): IrBuilder {
|
||||
ret IrBuilder {
|
||||
.ir = Ir.new(),
|
||||
.dbg = span_none(),
|
||||
.current_fn = 0,
|
||||
.current_block = 0,
|
||||
.blocks = Vec.blank(@sizeof(usize), @alignof(usize)),
|
||||
.fixups = Vec.blank(@sizeof(Fix), @alignof(Fix)),
|
||||
.terminated = false,
|
||||
};
|
||||
}
|
||||
|
||||
fn builder_drop(self: *IrBuilder) {
|
||||
Ir.drop(&self.ir);
|
||||
Vec.drop(&self.blocks);
|
||||
Vec.drop(&self.fixups);
|
||||
}
|
||||
|
||||
fn fn_begin(self: *IrBuilder, name: ByteView, fn_tid: usize): usize {
|
||||
if self.current_fn != 0 { fn_end(self); }
|
||||
var fid = Ir.alloc_fn(&self.ir);
|
||||
var f = Ir.func(&self.ir, fid);
|
||||
if f != null {
|
||||
f.name = name;
|
||||
f.fn_tid = fn_tid;
|
||||
}
|
||||
self.current_fn = fid;
|
||||
self.current_block = 0;
|
||||
self.blocks.len = 0;
|
||||
self.fixups.len = 0;
|
||||
self.terminated = false;
|
||||
ret fid;
|
||||
}
|
||||
|
||||
fn fn_reserve(self: *IrBuilder, name: ByteView, fn_tid: usize): usize {
|
||||
var fid = Ir.alloc_fn(&self.ir);
|
||||
var f = Ir.func(&self.ir, fid);
|
||||
if f != null {
|
||||
f.name = name;
|
||||
f.fn_tid = fn_tid;
|
||||
}
|
||||
ret fid;
|
||||
}
|
||||
|
||||
fn fn_begin_at(self: *IrBuilder, fid: usize) {
|
||||
if self.current_fn != 0 && self.current_fn != fid { fn_end(self); }
|
||||
self.current_fn = fid;
|
||||
self.current_block = 0;
|
||||
self.blocks.len = 0;
|
||||
self.fixups.len = 0;
|
||||
self.terminated = false;
|
||||
}
|
||||
|
||||
fn fn_end(self: *IrBuilder) {
|
||||
var k: usize = 0;
|
||||
while k < self.fixups.len {
|
||||
match Vec.get(&self.fixups, k) {
|
||||
.Ok(fp) => {
|
||||
var fx = fp as *Fix;
|
||||
var e = Ir.node(&self.ir, self.current_fn, fx.node);
|
||||
if e != null {
|
||||
var target: usize = 0;
|
||||
if fx.block < self.blocks.len { target = list_at(self.blocks, fx.block); }
|
||||
if target != 0 {
|
||||
if @enum2int(fx.slot) == @enum2int(FixKind.BrTrue) {
|
||||
match e.body { .Br(b) => { b.true_label = target; e.body = .Br(b); }, _ => {} }
|
||||
} else if @enum2int(fx.slot) == @enum2int(FixKind.BrFalse) {
|
||||
match e.body { .Br(b) => { b.false_label = target; e.body = .Br(b); }, _ => {} }
|
||||
} else {
|
||||
match e.body { .Jmp(j) => { j.label = target; e.body = .Jmp(j); }, _ => {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.Err(error) => {},
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
self.current_block = 0;
|
||||
self.blocks.len = 0;
|
||||
self.fixups.len = 0;
|
||||
self.terminated = false;
|
||||
}
|
||||
|
||||
fn block_begin(self: *IrBuilder): usize {
|
||||
var zero: usize = 0;
|
||||
match Vec.push(&self.blocks, &zero as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
var block = self.blocks.len - 1;
|
||||
self.current_block = block;
|
||||
self.terminated = false;
|
||||
ret block;
|
||||
}
|
||||
|
||||
fn block_end(self: *IrBuilder) {
|
||||
// terminated 与空块校验在 stage1 为 Panic;这里保持同样约束但不终止进程。
|
||||
}
|
||||
|
||||
// ---- arith / cmp / cast ----
|
||||
|
||||
fn set_arith(self: *IrBuilder, kind: IrKind, tid: usize, left: usize, right: usize): usize {
|
||||
var ref = builder_alloc(self, kind);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Arith(.{ .tid = tid, .left = left, .right = right }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn set_cmp(self: *IrBuilder, kind: IrKind, tid: usize, a: usize, b: usize): usize {
|
||||
var ref = builder_alloc(self, kind);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Cmp(.{ .tid = tid, .a = a, .b = b }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn set_cast(self: *IrBuilder, kind: IrKind, from_tid: usize, to_tid: usize, val: usize): usize {
|
||||
var ref = builder_alloc(self, kind);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Cast(.{ .from_tid = from_tid, .to_tid = to_tid, .val = val }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn arith_add(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithAdd, t, l, r); }
|
||||
fn arith_sub(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithSub, t, l, r); }
|
||||
fn arith_mul(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithMul, t, l, r); }
|
||||
fn arith_div(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithDiv, t, l, r); }
|
||||
fn arith_rem(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithRem, t, l, r); }
|
||||
fn arith_and(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithAnd, t, l, r); }
|
||||
fn arith_or(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithOr, t, l, r); }
|
||||
fn arith_xor(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithXor, t, l, r); }
|
||||
fn arith_shl(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithShl, t, l, r); }
|
||||
fn arith_shr(self: *IrBuilder, t: usize, l: usize, r: usize): usize { ret set_arith(self, .ArithShr, t, l, r); }
|
||||
|
||||
fn arith_neg(self: *IrBuilder, t: usize, v: usize): usize { ret set_arith(self, .ArithNeg, t, v, 0); }
|
||||
fn arith_abs(self: *IrBuilder, t: usize, v: usize): usize { ret set_arith(self, .ArithAbs, t, v, 0); }
|
||||
fn arith_not(self: *IrBuilder, t: usize, v: usize): usize { ret set_arith(self, .ArithNot, t, v, 0); }
|
||||
|
||||
fn cmp_eq(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpEq, t, a, b); }
|
||||
fn cmp_ne(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpNe, t, a, b); }
|
||||
fn cmp_lt(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpLt, t, a, b); }
|
||||
fn cmp_le(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpLe, t, a, b); }
|
||||
fn cmp_gt(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpGt, t, a, b); }
|
||||
fn cmp_ge(self: *IrBuilder, t: usize, a: usize, b: usize): usize { ret set_cmp(self, .CmpGe, t, a, b); }
|
||||
|
||||
fn cast_trunc(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastTrunc, f, t, v); }
|
||||
fn cast_zext(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastZext, f, t, v); }
|
||||
fn cast_sext(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastSext, f, t, v); }
|
||||
fn cast_fext(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastFext, f, t, v); }
|
||||
fn cast_ftrunc(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastFtrunc, f, t, v); }
|
||||
fn cast_bitcast(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastBitcast, f, t, v); }
|
||||
fn cast_ptr2int(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastPtr2int, f, t, v); }
|
||||
fn cast_int2ptr(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastInt2ptr, f, t, v); }
|
||||
fn cast_bool2int(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CastBool2int, f, t, v); }
|
||||
fn case_int2float(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CaseInt2float, f, t, v); }
|
||||
fn case_float2int(self: *IrBuilder, f: usize, t: usize, v: usize): usize { ret set_cast(self, .CaseFloat2int, f, t, v); }
|
||||
|
||||
// ---- memory ----
|
||||
|
||||
fn mem_alloca(self: *IrBuilder, tid: usize, count: usize): usize {
|
||||
var ref = builder_alloc(self, .MemAlloca);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemAlloc(.{ .tid = tid, .count = count }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_global_alloc(self: *IrBuilder, tid: usize, const_node: usize): usize {
|
||||
var ref = builder_alloc(self, .MemGlobalAlloc);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemGlobalAlloc(.{ .tid = tid, .const_node = const_node }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_load(self: *IrBuilder, tid: usize, ptr: usize): usize {
|
||||
var ref = builder_alloc(self, .MemLoad);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemLoad(.{ .tid = tid, .ptr = ptr }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_store(self: *IrBuilder, tid: usize, ptr: usize, val: usize): usize {
|
||||
var ref = builder_alloc(self, .MemStore);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemStore(.{ .tid = tid, .ptr = ptr, .val = val }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_offset(self: *IrBuilder, tid: usize, ptr: usize, offset: usize): usize {
|
||||
var ref = builder_alloc(self, .MemOffset);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemOffset(.{ .tid = tid, .ptr = ptr, .offset = offset }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_field(self: *IrBuilder, tid: usize, agg: usize, field_idx: usize): usize {
|
||||
var ref = builder_alloc(self, .MemFieldPtr);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemFieldPtr(.{ .tid = tid, .agg = agg, .field_idx = field_idx }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_copy(self: *IrBuilder, tid: usize, dst: usize, src: usize, size: usize): usize {
|
||||
var ref = builder_alloc(self, .MemCopy);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemCopy(.{ .tid = tid, .dst = dst, .src = src, .size = size }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn mem_set(self: *IrBuilder, tid: usize, dst: usize, val: usize, size: usize): usize {
|
||||
var ref = builder_alloc(self, .MemSet);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .MemSet(.{ .tid = tid, .dst = dst, .val = val, .size = size }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
// ---- type const ----
|
||||
|
||||
fn const_node(self: *IrBuilder, tid: usize, lit: ConstLit): usize {
|
||||
var ref = builder_alloc(self, .TypeConst);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Const(.{ .tid = tid, .lit = lit }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn type_const_ptr(self: *IrBuilder, tid: usize, val: usize): usize { ret const_node(self, tid, .Ptr(val)); }
|
||||
fn type_const_bool(self: *IrBuilder, tid: usize, val: bool): usize { ret const_node(self, tid, .Bool(val)); }
|
||||
fn type_const_int(self: *IrBuilder, tid: usize, val: usize): usize { ret const_node(self, tid, .Int(val)); }
|
||||
fn type_const_float(self: *IrBuilder, tid: usize, val: f64): usize { ret const_node(self, tid, .Float(val)); }
|
||||
fn type_const_char(self: *IrBuilder, tid: usize, val: u8): usize { ret const_node(self, tid, .Char(val)); }
|
||||
fn type_const_fn(self: *IrBuilder, tid: usize, val: usize): usize { ret const_node(self, tid, .Fn(val)); }
|
||||
fn type_const_bytes(self: *IrBuilder, tid: usize, data: usize): usize { ret const_node(self, tid, .Ptr(data)); }
|
||||
|
||||
// ---- type ops ----
|
||||
|
||||
fn type_bitsizeof(self: *IrBuilder, tid: usize): usize {
|
||||
var ref = builder_alloc(self, .TypeBitsizeof);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .TypeOp(.{ .tid = tid, .field_idx = 0 }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn type_sizeof(self: *IrBuilder, tid: usize): usize {
|
||||
var ref = builder_alloc(self, .TypeSizeof);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .TypeOp(.{ .tid = tid, .field_idx = 0 }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn type_alignof(self: *IrBuilder, tid: usize): usize {
|
||||
var ref = builder_alloc(self, .TypeAlignof);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .TypeOp(.{ .tid = tid, .field_idx = 0 }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn type_offsetof(self: *IrBuilder, tid: usize, field_idx: usize): usize {
|
||||
var ref = builder_alloc(self, .TypeOffsetof);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .TypeOp(.{ .tid = tid, .field_idx = field_idx }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn type_field_count(self: *IrBuilder, tid: usize): usize {
|
||||
var ref = builder_alloc(self, .TypeFieldCount);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .TypeOp(.{ .tid = tid, .field_idx = 0 }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
// ---- agg ----
|
||||
|
||||
fn agg_construct(self: *IrBuilder, tid: usize): usize {
|
||||
var ref = builder_alloc(self, .AggConstruct);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null {
|
||||
e.body = .AggConstruct(.{ .tid = tid, .fields = Vec.blank(@sizeof(usize), @alignof(usize)) });
|
||||
}
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn agg_construct_field(self: *IrBuilder, node_ref: usize, field: usize) {
|
||||
var e = Ir.node(&self.ir, self.current_fn, node_ref);
|
||||
if e == null { ret; }
|
||||
// 载荷按值绑定:改副本后写回。
|
||||
match e.body {
|
||||
.AggConstruct(a) => {
|
||||
match Vec.push(&a.fields, &field as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
e.body = .AggConstruct(a);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn agg_extract(self: *IrBuilder, tid: usize, field_tid: usize, field_idx: usize, val: usize): usize {
|
||||
var ref = builder_alloc(self, .AggExtract);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null {
|
||||
e.body = .AggExtract(.{ .tid = tid, .field_tid = field_tid, .field_idx = field_idx, .val = val });
|
||||
}
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn agg_insert(self: *IrBuilder, tid: usize, field_idx: usize, agg: usize, field: usize): usize {
|
||||
var ref = builder_alloc(self, .AggInsert);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .AggInsert(.{ .tid = tid, .field_idx = field_idx, .agg = agg, .field = field }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
// ---- control ----
|
||||
|
||||
fn control_select(self: *IrBuilder, tid: usize, cond: usize, tv: usize, fv: usize): usize {
|
||||
var ref = builder_alloc(self, .ControlSelect);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Select(.{ .tid = tid, .cond = cond, .true_val = tv, .false_val = fv }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_br(self: *IrBuilder, cond: usize): usize {
|
||||
var ref = builder_alloc(self, .ControlBr);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Br(.{ .cond = cond, .true_label = 0, .false_label = 0 }); }
|
||||
self.terminated = true;
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_br_fixup(self: *IrBuilder, ref: usize, true_block: usize, false_block: usize) {
|
||||
var f1 = Fix { .node = ref, .slot = .BrTrue, .block = true_block };
|
||||
match Vec.push(&self.fixups, &f1 as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
var f2 = Fix { .node = ref, .slot = .BrFalse, .block = false_block };
|
||||
match Vec.push(&self.fixups, &f2 as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
}
|
||||
|
||||
fn control_jmp(self: *IrBuilder): usize {
|
||||
var ref = builder_alloc(self, .ControlJmp);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Jmp(.{ .label = 0 }); }
|
||||
self.terminated = true;
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_jmp_fixup(self: *IrBuilder, ref: usize, target_block: usize) {
|
||||
var fx = Fix { .node = ref, .slot = .Jmp, .block = target_block };
|
||||
match Vec.push(&self.fixups, &fx as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
}
|
||||
|
||||
fn control_call(self: *IrBuilder, tid: usize, fn_ref: usize): usize {
|
||||
var ref = builder_alloc(self, .ControlCall);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null {
|
||||
e.body = .Call(.{ .tid = tid, .func = fn_ref,
|
||||
.params = Vec.blank(@sizeof(usize), @alignof(usize)) });
|
||||
}
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_call_param(self: *IrBuilder, call_node: usize, arg: usize) {
|
||||
var e = Ir.node(&self.ir, self.current_fn, call_node);
|
||||
if e == null { ret; }
|
||||
// 载荷按值绑定:改副本后写回。
|
||||
match e.body {
|
||||
.Call(c) => {
|
||||
match Vec.push(&c.params, &arg as *u8) { .Ok => {}, .Err(error) => {} }
|
||||
e.body = .Call(c);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn control_param(self: *IrBuilder, tid: usize, idx: usize): usize {
|
||||
var ref = builder_alloc(self, .ControlParam);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Param(.{ .tid = tid, .idx = idx }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_ret(self: *IrBuilder, tid: usize, val: usize): usize {
|
||||
var ref = builder_alloc(self, .ControlRet);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Ret(.{ .tid = tid, .val = val }); }
|
||||
self.terminated = true;
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_unreachable(self: *IrBuilder): usize {
|
||||
var ref = builder_alloc(self, .ControlUnreachable);
|
||||
self.terminated = true;
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn control_trap(self: *IrBuilder): usize {
|
||||
var ref = builder_alloc(self, .ControlTrap);
|
||||
self.terminated = true;
|
||||
ret ref;
|
||||
}
|
||||
|
||||
fn dbg_breakpoint(self: *IrBuilder): usize {
|
||||
ret builder_alloc(self, .DbgBreakpoint);
|
||||
}
|
||||
|
||||
fn dbg_panic(self: *IrBuilder, msg: ByteView): usize {
|
||||
var ref = builder_alloc(self, .DbgPanic);
|
||||
var e = Ir.node(&self.ir, self.current_fn, ref);
|
||||
if e != null { e.body = .Panic(.{ .msg = msg }); }
|
||||
ret ref;
|
||||
}
|
||||
|
||||
|
||||
fn test_builder_emit_and_dump() {
|
||||
var b = builder_new();
|
||||
defer { builder_drop(&b); }
|
||||
|
||||
b.dbg = span_none();
|
||||
var fid = fn_begin(&b, ByteView.from_slice("f"), 3);
|
||||
var blk = block_begin(&b);
|
||||
var p = control_param(&b, 2, 0);
|
||||
var c = type_const_int(&b, 2, 42);
|
||||
var add = arith_add(&b, 2, p, c);
|
||||
control_ret(&b, 2, add);
|
||||
block_end(&b);
|
||||
fn_end(&b);
|
||||
|
||||
var ty = TypeTable.new();
|
||||
var t: TypeTable = undefined;
|
||||
match ty { .Ok(v) => { t = v; }, .Err(e) => { @assert(false, "tt"); } }
|
||||
defer { TypeTable.drop(&t); }
|
||||
var at = Attr.new();
|
||||
var a: Attr = undefined;
|
||||
match at { .Ok(v) => { a = v; }, .Err(e) => { @assert(false, "attr"); } }
|
||||
defer { Attr.drop(&a); }
|
||||
|
||||
var out = ByteBuffer.new();
|
||||
defer { ByteBuffer.drop(&out); }
|
||||
@assert(Ir.dump(&b.ir, &t, &a, &out), "dump ok");
|
||||
var got = ByteBuffer.as_slice(out);
|
||||
@assert(got.len > 0, "dump nonempty");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_builder_emit_and_dump();
|
||||
}
|
||||
Reference in new issue
Block a user