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:
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(¶ms[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, ¶ms[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);
}