kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit eb26144df528f7a5dd14f56ceb608b1e14c3f066
parent bf99dd7c5a89cf727659b2500b110dec54164794
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 26 May 2026 17:53:52 -0700

wasm: route both emit backends through semantic IR recorder and shared opt pipeline

Wasm now records via CgIrFunc then goes through cg_ir_lower → native_emit,
the same path as native targets. supports_label_table() returns false, so
switch lowering falls back to if-chains rather than jump tables. This unifies
Wasm's code-generation model with the rest of the pipeline.

Diffstat:
Msrc/arch/wasm/emit.c | 22++++++++++++++++++++--
Msrc/arch/wasm/ir_emit.c | 385+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
2 files changed, 298 insertions(+), 109 deletions(-)

diff --git a/src/arch/wasm/emit.c b/src/arch/wasm/emit.c @@ -188,7 +188,7 @@ static u32 reg_local(WTarget* t, Reg r, CfreeCgTypeId ty, RegClass cls) { * for an SV_CMP reuses one of the cmp operands' Regs (originally e.g. i64) * to hold the i32 cmp result. Detect a type change and rebind to a fresh * wasm local; the previous binding is dead from CG's point of view. */ - if (t->reg_to_local[r] != 0xffffffffu) { + if (t->reg_to_local[r] != 0xffffffffu && t->reg_type[r]) { WasmValType cached_vt = valtype_for_type(t, t->reg_type[r]); WasmValType want_vt = valtype_for_type(t, ty); if (cached_vt == want_vt) return t->reg_to_local[r]; @@ -540,11 +540,25 @@ static WSlot* slot_push(WTarget* t) { return s; } +/* True iff `ty` maps to a single wasm value type (i32/i64/f32/f64) and so can + * live directly in a wasm local. Aggregates (records/arrays) and anything + * wider than 8 bytes must be homed in linear memory. */ +static int type_is_wasm_scalar(WTarget* t, CfreeCgTypeId ty) { + ABITypeInfo ti; + if (!ty) return 0; + ti = abi_cg_type_info(t->c->abi, ty); + if (ti.scalar_kind == ABI_SC_VOID) return 0; + if (ti.scalar_kind == ABI_SC_PTR) return 1; + return ti.size <= 8u; +} + static FrameSlot alloc_frame_slot_kind(WTarget* t, CfreeCgTypeId ty, u32 size, u32 align, int stack_backed) { WSlot* s; u32 slot_id; type_size_align(t, ty, size, align, &size, &align); + /* A non-scalar type has no wasm value type; force it into linear memory. */ + if (!stack_backed && !type_is_wasm_scalar(t, ty)) stack_backed = 1; s = slot_push(t); s->type = ty; s->size = size; @@ -1324,7 +1338,11 @@ void wasm_store(CGTarget* tg, Operand addr, Operand src, MemAccess mem) { } wir_capture_operand(w, 0, src); w->mem = mem; - w->type = addr.type ? addr.type : src.type; + /* The store's value type is the accessed type. When storing through a + * pointer register, addr.type is the (possibly void) pointer rvalue type, + * not the pointee — so prefer the MemAccess type, which always describes + * the element being written, before falling back to the operands. */ + w->type = mem.type ? mem.type : (addr.type ? addr.type : src.type); } /* Variadic CG hooks. va_list on wasm32 is a single i32 pointer into a diff --git a/src/arch/wasm/ir_emit.c b/src/arch/wasm/ir_emit.c @@ -1,7 +1,7 @@ -#include "cg/ir.h" - #include <string.h> +#include "cg/ir.h" + typedef Operand CgSemOperand; typedef CGCallDesc CgSemCallDesc; typedef CGFuncDesc CgSemFuncDesc; @@ -61,6 +61,7 @@ void wasm_asm_block(CGTarget*, const char*, const AsmConstraint*, u32, Operand*, typedef struct WasmIrEmitter { WTarget* target; FrameSlot* local_slots; + CfreeCgTypeId* local_types; /* CG type of each local id, parallel to slots */ u32 local_slots_n; Reg next_temp_reg; CGScope* scope_map; @@ -78,6 +79,17 @@ static RegClass wasm_ir_class_for_type(WTarget* t, CfreeCgTypeId type) { return info.scalar_kind == ABI_SC_FLOAT ? RC_FP : RC_INT; } +/* An aggregate (record/array) value lives in linear memory on wasm: a scalar + * COPY of it must be lowered to a byte-wise memcpy between the two homes. */ +static int wasm_ir_is_aggregate(WTarget* t, CfreeCgTypeId ty) { + ABITypeInfo info; + if (!ty) return 0; + info = abi_cg_type_info(t->c->abi, ty); + if (info.scalar_kind == ABI_SC_PTR) return 0; + if (info.size == 0) return 0; /* genuine void */ + return info.scalar_kind == ABI_SC_VOID || info.size > 8u; +} + static void wasm_ir_bind_reg(WasmIrEmitter* e, Reg reg, u32 wasm_local, CfreeCgTypeId type) { WTarget* t = e->target; @@ -86,8 +98,7 @@ static void wasm_ir_bind_reg(WasmIrEmitter* e, Reg reg, u32 wasm_local, if (reg >= t->reg_cap) { u32 nc = t->reg_cap ? t->reg_cap : 64u; while (nc <= reg) nc *= 2u; - u32* regs = (u32*)h->realloc(h, t->reg_to_local, - sizeof(u32) * t->reg_cap, + u32* regs = (u32*)h->realloc(h, t->reg_to_local, sizeof(u32) * t->reg_cap, sizeof(u32) * nc, _Alignof(u32)); CfreeCgTypeId* types = (CfreeCgTypeId*)h->realloc( h, t->reg_type, sizeof(CfreeCgTypeId) * t->reg_cap, @@ -105,6 +116,10 @@ static void wasm_ir_bind_reg(WasmIrEmitter* e, Reg reg, u32 wasm_local, t->reg_cls = cls; t->reg_cap = nc; } + /* A NONE type carries no wasm value type. This shows up for variadic call + * arguments, whose operands are untyped at the call site. Don't let it + * clobber a binding the locals/params pass already gave a real type. */ + if (!type && t->reg_to_local[reg] != 0xffffffffu && t->reg_type[reg]) return; t->reg_to_local[reg] = wasm_local; t->reg_type[reg] = type; t->reg_cls[reg] = (u8)wasm_ir_class_for_type(t, type); @@ -181,6 +196,50 @@ static Operand wasm_ir_source_op(WasmIrEmitter* e, CgSemOperand in, return wasm_ir_value_op(e, in); } +/* A value-producing instruction whose CG destination is an address-taken + * (stack-homed) local cannot write a wasm local directly: the variable lives + * in linear memory so its address is meaningful. Route the def through a temp + * reg and store it back to the slot once the underlying op has run. */ +typedef struct WasmIrDest { + int spill; + Operand tmp; /* OPK_REG temp the op writes into */ + Operand store_addr; /* OPK_LOCAL frame slot to store back to */ + MemAccess mem; +} WasmIrDest; + +static Operand wasm_ir_dest_op(WasmIrEmitter* e, CgSemOperand in, + WasmIrDest* d) { + memset(d, 0, sizeof *d); + if (in.kind == OPK_LOCAL && in.v.local < e->local_slots_n) { + FrameSlot slot = e->local_slots[in.v.local]; + if (slot != FRAME_SLOT_NONE) { + WSlot* s = &e->target->slots[slot - 1u]; + if (s->kind != W_SLOT_LOCAL) { + Operand tmp = wasm_ir_value_op(e, in); + tmp.kind = OPK_REG; + tmp.v.reg = wasm_ir_temp_reg(e); + d->spill = 1; + d->tmp = tmp; + memset(&d->store_addr, 0, sizeof d->store_addr); + d->store_addr.kind = OPK_LOCAL; + d->store_addr.type = in.type; + d->store_addr.v.frame_slot = slot; + memset(&d->mem, 0, sizeof d->mem); + d->mem.type = in.type; + d->mem.size = s->size; + d->mem.align = s->align; + return tmp; + } + } + } + return wasm_ir_value_op(e, in); +} + +static void wasm_ir_dest_finish(WasmIrEmitter* e, const WasmIrDest* d) { + if (d->spill) + wasm_store((CGTarget*)&e->target->base, d->store_addr, d->tmp, d->mem); +} + static Operand wasm_ir_addr_op(WasmIrEmitter* e, CgSemOperand in, SrcLoc loc) { Operand out; if (in.kind != OPK_LOCAL) return wasm_ir_value_op(e, in); @@ -214,9 +273,8 @@ static const ABIArgInfo* wasm_ir_param_abi(const ABIFuncInfo* abi, u32 index) { } static CGABIValue wasm_ir_abi_value(WasmIrEmitter* e, CGLocal local, - CfreeCgTypeId type, - const ABIArgInfo* abi, int address, - int source, SrcLoc loc) { + CfreeCgTypeId type, const ABIArgInfo* abi, + int address, int source, SrcLoc loc) { CGABIValue out; CgSemOperand sem; memset(&out, 0, sizeof out); @@ -226,9 +284,9 @@ static CGABIValue wasm_ir_abi_value(WasmIrEmitter* e, CGLocal local, sem.v.local = local; out.type = type; out.abi = abi; - out.storage = address ? wasm_ir_addr_op(e, sem, loc) - : source ? wasm_ir_source_op(e, sem, loc) - : wasm_ir_value_op(e, sem); + out.storage = address ? wasm_ir_addr_op(e, sem, loc) + : source ? wasm_ir_source_op(e, sem, loc) + : wasm_ir_value_op(e, sem); return out; } @@ -258,6 +316,11 @@ static void wasm_ir_emit_call(WasmIrEmitter* e, const CgIrInst* in) { const CgType* fty = cg_type_get(e->target->c, src->fn_type); if (fty && fty->kind == CFREE_CG_TYPE_FUNC && i < fty->func.nparams) ty = fty->func.params[i].type; + /* Variadic arguments have no signature slot; recover the type from the + * passed local so the call's vararg packing knows its wasm value type. */ + if (ty == CFREE_CG_TYPE_NONE && src->args[i] != CG_LOCAL_NONE && + (u32)src->args[i] < e->local_slots_n) + ty = e->local_types[src->args[i]]; args[i] = wasm_ir_abi_value(e, src->args[i], ty, ai, ai && ai->kind == ABI_ARG_INDIRECT, 1, in->loc); @@ -267,9 +330,9 @@ static void wasm_ir_emit_call(WasmIrEmitter* e, const CgIrInst* in) { if (src->nresults > 1) wasm_ir_fail(e, in->loc, "wasm: multiple call results not yet supported"); if (src->nresults == 1) { - d.ret = wasm_ir_abi_value(e, src->results[0], ret_type, - abi ? &abi->ret : NULL, abi && abi->has_sret, 0, - in->loc); + d.ret = + wasm_ir_abi_value(e, src->results[0], ret_type, abi ? &abi->ret : NULL, + abi && abi->has_sret, 0, in->loc); } wasm_call((CGTarget*)&e->target->base, &d); if (args) h->free(h, args, sizeof(*args) * src->nargs); @@ -316,69 +379,135 @@ static void wasm_ir_emit_inst(WasmIrEmitter* e, const CgIrFunc* f, case CG_IR_LABEL: wasm_label_place(t, (Label)in->extra.imm); return; - case CG_IR_LOAD_IMM: - wasm_load_imm(t, wasm_ir_value_op(e, in->opnds[0]), in->extra.imm); + case CG_IR_LOAD_IMM: { + WasmIrDest d; + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_load_imm(t, dst, in->extra.imm); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_LOAD_CONST: - wasm_load_const(t, wasm_ir_value_op(e, in->opnds[0]), in->extra.cbytes); + } + case CG_IR_LOAD_CONST: { + WasmIrDest d; + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_load_const(t, dst, in->extra.cbytes); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_COPY: - wasm_copy(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1])); + } + case CG_IR_COPY: { + WasmIrDest d; + Operand src, dst; + if (wasm_ir_is_aggregate(e->target, in->opnds[0].type)) { + /* Aggregate value copy: lower to memory.copy between the two homes. + * copy_bytes wants both endpoints as pointer-valued registers, so + * materialize each slot address with addr_of first. */ + AggregateAccess agg; + CfreeCgTypeId pty = cg_type_ptr_to(e->target->c, in->opnds[0].type); + Operand adst = wasm_ir_addr_op(e, in->opnds[0], in->loc); + Operand asrc = wasm_ir_addr_op(e, in->opnds[1], in->loc); + Operand dreg, sreg; + memset(&dreg, 0, sizeof dreg); + memset(&sreg, 0, sizeof sreg); + dreg.kind = sreg.kind = OPK_REG; + dreg.type = sreg.type = pty; + dreg.cls = sreg.cls = (u8)RC_INT; + dreg.v.reg = wasm_ir_temp_reg(e); + sreg.v.reg = wasm_ir_temp_reg(e); + wasm_addr_of(t, dreg, adst); + wasm_addr_of(t, sreg, asrc); + memset(&agg, 0, sizeof agg); + agg.type = in->opnds[0].type; + agg.size = (u32)abi_cg_sizeof(e->target->c->abi, in->opnds[0].type); + agg.align = (u32)abi_cg_alignof(e->target->c->abi, in->opnds[0].type); + wasm_copy_bytes(t, dreg, sreg, agg); + return; + } + src = wasm_ir_source_op(e, in->opnds[1], in->loc); + dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_copy(t, dst, src); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_LOAD: - wasm_load(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), in->extra.mem); + } + case CG_IR_LOAD: { + WasmIrDest d; + Operand addr = wasm_ir_addr_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_load(t, dst, addr, in->extra.mem); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_STORE: - wasm_store(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), in->extra.mem); + } + case CG_IR_STORE: { + Operand addr = wasm_ir_addr_op(e, in->opnds[0], in->loc); + Operand src = wasm_ir_source_op(e, in->opnds[1], in->loc); + wasm_store(t, addr, src, in->extra.mem); return; - case CG_IR_ADDR_OF: - wasm_addr_of(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_addr_op(e, in->opnds[1], in->loc)); + } + case CG_IR_ADDR_OF: { + WasmIrDest d; + Operand addr = wasm_ir_addr_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_addr_of(t, dst, addr); + wasm_ir_dest_finish(e, &d); return; + } case CG_IR_TLS_ADDR_OF: wasm_ir_fail(e, in->loc, "wasm target: tls_addr_of not yet implemented"); return; case CG_IR_AGG_COPY: { const CgIrAggAux* aux = (const CgIrAggAux*)in->extra.aux; - wasm_copy_bytes(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), aux->access); + Operand dst = wasm_ir_source_op(e, in->opnds[0], in->loc); + Operand src = wasm_ir_source_op(e, in->opnds[1], in->loc); + wasm_copy_bytes(t, dst, src, aux->access); return; } case CG_IR_AGG_SET: { const CgIrAggAux* aux = (const CgIrAggAux*)in->extra.aux; - wasm_set_bytes(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), aux->access); + Operand dst = wasm_ir_source_op(e, in->opnds[0], in->loc); + Operand byte = wasm_ir_source_op(e, in->opnds[1], in->loc); + wasm_set_bytes(t, dst, byte, aux->access); return; } case CG_IR_BITFIELD_LOAD: - wasm_ir_fail(e, in->loc, "wasm target: bitfield_load not yet implemented"); + wasm_ir_fail(e, in->loc, + "wasm target: bitfield_load not yet implemented"); return; case CG_IR_BITFIELD_STORE: wasm_ir_fail(e, in->loc, "wasm target: bitfield_store not yet implemented"); return; - case CG_IR_BINOP: - wasm_binop(t, (BinOp)in->extra.imm, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), - wasm_ir_value_op(e, in->opnds[2])); + case CG_IR_BINOP: { + WasmIrDest d; + Operand a = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand b = wasm_ir_source_op(e, in->opnds[2], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_binop(t, (BinOp)in->extra.imm, dst, a, b); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_UNOP: - wasm_unop(t, (UnOp)in->extra.imm, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1])); + } + case CG_IR_UNOP: { + WasmIrDest d; + Operand a = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_unop(t, (UnOp)in->extra.imm, dst, a); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_CMP: - wasm_cmp(t, (CmpOp)in->extra.imm, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), - wasm_ir_value_op(e, in->opnds[2])); + } + case CG_IR_CMP: { + WasmIrDest d; + Operand a = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand b = wasm_ir_source_op(e, in->opnds[2], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_cmp(t, (CmpOp)in->extra.imm, dst, a, b); + wasm_ir_dest_finish(e, &d); return; - case CG_IR_CONVERT: - wasm_convert(t, (ConvKind)in->extra.imm, - wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1])); + } + case CG_IR_CONVERT: { + WasmIrDest d; + Operand a = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_convert(t, (ConvKind)in->extra.imm, dst, a); + wasm_ir_dest_finish(e, &d); return; + } case CG_IR_CALL: wasm_ir_emit_call(e, in); return; @@ -428,70 +557,87 @@ static void wasm_ir_emit_inst(WasmIrEmitter* e, const CgIrFunc* f, return; } case CG_IR_SCOPE_ELSE: - wasm_scope_else(t, wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, - in->loc)); + wasm_scope_else(t, + wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, in->loc)); return; case CG_IR_SCOPE_END: - wasm_scope_end(t, wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, - in->loc)); + wasm_scope_end(t, + wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, in->loc)); return; case CG_IR_BREAK_TO: - wasm_break_to(t, wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, - in->loc)); + wasm_break_to(t, + wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, in->loc)); return; case CG_IR_CONTINUE_TO: - wasm_continue_to(t, wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, - in->loc)); + wasm_continue_to( + t, wasm_ir_scope_lookup(e, (CGScope)in->extra.imm, in->loc)); return; - case CG_IR_ALLOCA: - wasm_alloca(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), (u32)in->extra.imm); + case CG_IR_ALLOCA: { + WasmIrDest d; + Operand size = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_alloca(t, dst, size, (u32)in->extra.imm); + wasm_ir_dest_finish(e, &d); return; + } case CG_IR_VA_START: - wasm_va_start(t, wasm_ir_value_op(e, in->opnds[0])); + wasm_va_start(t, wasm_ir_source_op(e, in->opnds[0], in->loc)); return; - case CG_IR_VA_ARG: - wasm_va_arg(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), - (CfreeCgTypeId)in->extra.imm); + case CG_IR_VA_ARG: { + WasmIrDest d; + Operand ap = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_va_arg(t, dst, ap, (CfreeCgTypeId)in->extra.imm); + wasm_ir_dest_finish(e, &d); return; + } case CG_IR_VA_END: - wasm_va_end(t, wasm_ir_value_op(e, in->opnds[0])); + wasm_va_end(t, wasm_ir_source_op(e, in->opnds[0], in->loc)); return; - case CG_IR_VA_COPY: - wasm_va_copy(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1])); + case CG_IR_VA_COPY: { + Operand src = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_source_op(e, in->opnds[0], in->loc); + wasm_va_copy(t, dst, src); return; + } case CG_IR_ATOMIC_LOAD: { const CgIrAtomicAux* aux = (const CgIrAtomicAux*)in->extra.aux; - wasm_atomic_load(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), aux->mem, - aux->order); + WasmIrDest d; + Operand addr = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_atomic_load(t, dst, addr, aux->mem, aux->order); + wasm_ir_dest_finish(e, &d); return; } case CG_IR_ATOMIC_STORE: { const CgIrAtomicAux* aux = (const CgIrAtomicAux*)in->extra.aux; - wasm_atomic_store(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), aux->mem, - aux->order); + Operand addr = wasm_ir_source_op(e, in->opnds[0], in->loc); + Operand val = wasm_ir_source_op(e, in->opnds[1], in->loc); + wasm_atomic_store(t, addr, val, aux->mem, aux->order); return; } case CG_IR_ATOMIC_RMW: { const CgIrAtomicAux* aux = (const CgIrAtomicAux*)in->extra.aux; - wasm_atomic_rmw(t, aux->op, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), - wasm_ir_value_op(e, in->opnds[2]), aux->mem, - aux->order); + WasmIrDest d; + Operand addr = wasm_ir_source_op(e, in->opnds[1], in->loc); + Operand val = wasm_ir_source_op(e, in->opnds[2], in->loc); + Operand dst = wasm_ir_dest_op(e, in->opnds[0], &d); + wasm_atomic_rmw(t, aux->op, dst, addr, val, aux->mem, aux->order); + wasm_ir_dest_finish(e, &d); return; } case CG_IR_ATOMIC_CAS: { const CgIrAtomicAux* aux = (const CgIrAtomicAux*)in->extra.aux; - wasm_atomic_cas(t, wasm_ir_value_op(e, in->opnds[0]), - wasm_ir_value_op(e, in->opnds[1]), - wasm_ir_value_op(e, in->opnds[2]), - wasm_ir_value_op(e, in->opnds[3]), - wasm_ir_value_op(e, in->opnds[4]), aux->mem, + WasmIrDest dprior, dok; + Operand addr = wasm_ir_source_op(e, in->opnds[2], in->loc); + Operand expected = wasm_ir_source_op(e, in->opnds[3], in->loc); + Operand desired = wasm_ir_source_op(e, in->opnds[4], in->loc); + Operand prior = wasm_ir_dest_op(e, in->opnds[0], &dprior); + Operand ok = wasm_ir_dest_op(e, in->opnds[1], &dok); + wasm_atomic_cas(t, prior, ok, addr, expected, desired, aux->mem, aux->order, aux->failure); + wasm_ir_dest_finish(e, &dprior); + wasm_ir_dest_finish(e, &dok); return; } case CG_IR_FENCE: @@ -502,22 +648,28 @@ static void wasm_ir_emit_inst(WasmIrEmitter* e, const CgIrFunc* f, Heap* h = e->target->c->ctx->heap; Operand* dsts = NULL; Operand* args = NULL; + WasmIrDest* dd = NULL; if (aux->ndst) { - dsts = (Operand*)h->alloc(h, sizeof(*dsts) * aux->ndst, - _Alignof(Operand)); - if (!dsts) wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); - for (u32 i = 0; i < aux->ndst; ++i) - dsts[i] = wasm_ir_value_op(e, aux->dsts[i]); + dsts = + (Operand*)h->alloc(h, sizeof(*dsts) * aux->ndst, _Alignof(Operand)); + dd = (WasmIrDest*)h->alloc(h, sizeof(*dd) * aux->ndst, + _Alignof(WasmIrDest)); + if (!dsts || !dd) + wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); } if (aux->narg) { - args = (Operand*)h->alloc(h, sizeof(*args) * aux->narg, - _Alignof(Operand)); + args = + (Operand*)h->alloc(h, sizeof(*args) * aux->narg, _Alignof(Operand)); if (!args) wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); for (u32 i = 0; i < aux->narg; ++i) - args[i] = wasm_ir_value_op(e, aux->args[i]); + args[i] = wasm_ir_source_op(e, aux->args[i], in->loc); } + for (u32 i = 0; i < aux->ndst; ++i) + dsts[i] = wasm_ir_dest_op(e, aux->dsts[i], &dd[i]); wasm_intrinsic(t, aux->kind, dsts, aux->ndst, args, aux->narg); + for (u32 i = 0; i < aux->ndst; ++i) wasm_ir_dest_finish(e, &dd[i]); if (dsts) h->free(h, dsts, sizeof(*dsts) * aux->ndst); + if (dd) h->free(h, dd, sizeof(*dd) * aux->ndst); if (args) h->free(h, args, sizeof(*args) * aux->narg); return; } @@ -526,24 +678,28 @@ static void wasm_ir_emit_inst(WasmIrEmitter* e, const CgIrFunc* f, Heap* h = e->target->c->ctx->heap; Operand* outs = NULL; Operand* ins = NULL; + WasmIrDest* od = NULL; if (aux->nout) { - outs = (Operand*)h->alloc(h, sizeof(*outs) * aux->nout, - _Alignof(Operand)); - if (!outs) wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); - for (u32 i = 0; i < aux->nout; ++i) - outs[i] = wasm_ir_value_op(e, aux->out_ops[i]); + outs = + (Operand*)h->alloc(h, sizeof(*outs) * aux->nout, _Alignof(Operand)); + od = (WasmIrDest*)h->alloc(h, sizeof(*od) * aux->nout, + _Alignof(WasmIrDest)); + if (!outs || !od) + wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); } if (aux->nin) { - ins = (Operand*)h->alloc(h, sizeof(*ins) * aux->nin, - _Alignof(Operand)); + ins = (Operand*)h->alloc(h, sizeof(*ins) * aux->nin, _Alignof(Operand)); if (!ins) wasm_ir_fail(e, in->loc, "wasm IR emit: out of memory"); - for (u32 i = 0; i < aux->nin; ++i) { - ins[i] = wasm_ir_value_op(e, aux->in_ops[i]); - } + for (u32 i = 0; i < aux->nin; ++i) + ins[i] = wasm_ir_source_op(e, aux->in_ops[i], in->loc); } + for (u32 i = 0; i < aux->nout; ++i) + outs[i] = wasm_ir_dest_op(e, aux->out_ops[i], &od[i]); wasm_asm_block(t, aux->tmpl, aux->outs, aux->nout, outs, aux->ins, aux->nin, ins, aux->clobbers, aux->nclob); + for (u32 i = 0; i < aux->nout; ++i) wasm_ir_dest_finish(e, &od[i]); if (outs) h->free(h, outs, sizeof(*outs) * aux->nout); + if (od) h->free(h, od, sizeof(*od) * aux->nout); if (ins) h->free(h, ins, sizeof(*ins) * aux->nin); return; } @@ -561,10 +717,16 @@ static void wasm_ir_emit_func(WTarget* t, const CgIrFunc* f) { e.next_temp_reg = (Reg)(f->nlocals + 1u); e.local_slots_n = f->nlocals + 1u; e.local_slots = (FrameSlot*)h->alloc(h, sizeof(FrameSlot) * e.local_slots_n, - _Alignof(FrameSlot)); + _Alignof(FrameSlot)); if (!e.local_slots) compiler_panic(t->c, f->desc.loc, "wasm IR emit: out of memory"); for (u32 i = 0; i < e.local_slots_n; ++i) e.local_slots[i] = FRAME_SLOT_NONE; + e.local_types = (CfreeCgTypeId*)h->alloc( + h, sizeof(CfreeCgTypeId) * e.local_slots_n, _Alignof(CfreeCgTypeId)); + if (!e.local_types) + compiler_panic(t->c, f->desc.loc, "wasm IR emit: out of memory"); + for (u32 i = 0; i < e.local_slots_n; ++i) + e.local_types[i] = CFREE_CG_TYPE_NONE; e.scope_map_n = f->nscopes + 1u; if (e.scope_map_n) { e.scope_map = (CGScope*)h->alloc(h, sizeof(CGScope) * e.scope_map_n, @@ -590,7 +752,8 @@ static void wasm_ir_emit_func(WTarget* t, const CgIrFunc* f) { if (f->nparams) { params = (CGParamDesc*)h->alloc(h, sizeof(*params) * f->nparams, _Alignof(CGParamDesc)); - if (!params) compiler_panic(t->c, f->desc.loc, "wasm IR emit: out of memory"); + if (!params) + compiler_panic(t->c, f->desc.loc, "wasm IR emit: out of memory"); for (u32 i = 0; i < f->nparams; ++i) { const CgIrParam* src = &f->params[i]; memset(&params[i], 0, sizeof params[i]); @@ -607,18 +770,25 @@ static void wasm_ir_emit_func(WTarget* t, const CgIrFunc* f) { } wasm_func_begin((CGTarget*)&t->base, &fd); - for (u32 i = 0; i < f->nlabels; ++i) (void)wasm_label_new((CGTarget*)&t->base); + for (u32 i = 0; i < f->nlabels; ++i) + (void)wasm_label_new((CGTarget*)&t->base); for (u32 i = 0; i < f->nparams; ++i) { const CgIrParam* p = &f->params[i]; CGLocalStorage st = wasm_param((CGTarget*)&t->base, &params[i]); - if (p->local < e.local_slots_n) e.local_slots[p->local] = st.v.frame_slot; + if (p->local < e.local_slots_n) { + e.local_slots[p->local] = st.v.frame_slot; + e.local_types[p->local] = p->desc.type; + } wasm_ir_bind_value_local(&e, p->local, p->desc.type, st.v.frame_slot); } for (u32 i = 0; i < f->nlocals; ++i) { const CgIrLocal* l = &f->locals[i]; if (l->is_param) continue; CGLocalStorage st = wasm_local((CGTarget*)&t->base, &l->desc); - if (l->id < e.local_slots_n) e.local_slots[l->id] = st.v.frame_slot; + if (l->id < e.local_slots_n) { + e.local_slots[l->id] = st.v.frame_slot; + e.local_types[l->id] = l->desc.type; + } wasm_ir_bind_value_local(&e, l->id, l->desc.type, st.v.frame_slot); } for (u32 i = 0; i < f->ninsts; ++i) wasm_ir_emit_inst(&e, f, &f->insts[i]); @@ -626,6 +796,7 @@ static void wasm_ir_emit_func(WTarget* t, const CgIrFunc* f) { if (params) h->free(h, params, sizeof(*params) * f->nparams); if (e.scope_map) h->free(h, e.scope_map, sizeof(CGScope) * e.scope_map_n); + h->free(h, e.local_types, sizeof(CfreeCgTypeId) * e.local_slots_n); h->free(h, e.local_slots, sizeof(FrameSlot) * e.local_slots_n); }