kit

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

commit dce052f5cd1a9b361a65cb2e7573b35c0f6fd85f
parent 54fdf61dc669598af59c54ec278002f1686ea817
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue,  2 Jun 2026 02:49:38 -0700

cg: strict PLACE/VALUE addressing, remove the load/store EA rider (Track 7)

Cut the public CfreeCg addressing surface over to a clean, strict PLACE/VALUE
discipline. Every stack entry is exactly one kind and each op declares the kinds
it consumes/produces, panicking on a mismatch — CG never infers a value's kind
or inserts an implicit dereference.

  - load/store consume a PLACE; the CfreeCgEffAddr rider is gone.
  - deref(offset): VALUE(ptr) -> PLACE *(ptr+offset)            [folds offset]
  - field(i):      PLACE(record) -> PLACE(field) by layout, preserving any
                   index/scale a preceding elem left            [folds offset]
  - elem(offset):  VALUE(ptr)+index -> PLACE, scale=sizeof(T)   [folds scale+offset]
  - addr:          PLACE -> VALUE(ptr)

The place ops fold the constant offset and scale into one
OPK_INDIRECT[base + index*scale + offset] (base/index dynamic, scale/offset
folded), so the backend still emits a single addressing-mode memop. cg.h
documents the kinds and per-op contracts.

All frontends (C/toy/wasm), the emulator, and the cg-api tests are conformed to
build explicit places (addr/deref/elem/field) at every memory site. The C
frontend keeps scalar-local reads as direct push_local PLACEs so small accessors
stay inlinable.

Green: toy 1344/0/26, cg-api 173+168, opt (incl tiny-inline), smoke x64/rv64,
libc musl 18 + glibc 9, isa/link/elf/debug/dwarf/ar/lib-deps; `make bootstrap`
reproduces byte-identical at -O0 AND -O1. Remaining Track 7 refinements
(explicit ApiSValue kind tag, aggregate-VALUE panics, wide16-as-value,
bitfields-as-PLACE-subkind, -O0 clean-memop pass for the C frontend) are tracked
in doc/plan/CODEGEN.md.

Diffstat:
Mdoc/CODEGEN.md | 26++++++++++++++++++--------
Mdoc/plan/CODEGEN.md | 27++++++++++++++++++++++++++-
Minclude/cfree/cg.h | 149++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mlang/c/parse/cg_adapter.c | 240++++++++++++++++++++++++++++++++++++-------------------------------------------
Mlang/toy/asm.c | 11++++++++---
Mlang/toy/builtins.c | 54++++++++++++++++++++++++++++++++----------------------
Mlang/toy/expr.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mlang/toy/parser.c | 112+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlang/toy/symbols.c | 12++++++++----
Mlang/wasm/cg.c | 869++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/arch/rv64/emu.c | 10+++++-----
Msrc/cg/control.c | 201+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/cg/internal.h | 5+++--
Msrc/cg/memory.c | 607+++++++++++++++++--------------------------------------------------------------
Mtest/api/cg_switch_test.c | 3+--
Mtest/api/cg_type_test.c | 60++++++++++++++++++++++++++++++------------------------------
16 files changed, 1104 insertions(+), 1415 deletions(-)

diff --git a/doc/CODEGEN.md b/doc/CODEGEN.md @@ -55,14 +55,24 @@ once and shared. ## The public CfreeCg API and value stack -`include/cfree/cg.h` is a 132-call stack machine. A frontend pushes typed -values (locals, lvalues, immediates, constants), names types, and issues -operations that pop operands and push results — `cfree_cg_func_begin`, -`cfree_cg_load`/`cfree_cg_store`, `cfree_cg_fp_binop`, `cfree_cg_call`, -`cfree_cg_branch_true`, `cfree_cg_block_begin`, and so on. This API is the -insulation layer: it is source-stable across all the internal changes below it, -so the C parser's `cg_adapter`, the toy frontend, and the wasm-language frontend -do not change when a backend does. See [FRONTENDS.md](FRONTENDS.md). +`include/cfree/cg.h` is a stack machine. A frontend pushes typed values, names +types, and issues operations that pop operands and push results — +`cfree_cg_func_begin`, `cfree_cg_load`/`cfree_cg_store`, `cfree_cg_fp_binop`, +`cfree_cg_call`, `cfree_cg_branch_true`, `cfree_cg_block_begin`, and so on. This +API is the insulation layer: it is source-stable across all the internal changes +below it. See [FRONTENDS.md](FRONTENDS.md). + +Every stack entry is exactly one of two **kinds**, and each op declares the +kinds it consumes and produces: a **PLACE** (an addressable, typed location — a +local's storage, a global, or a computed `[base + index*scale + offset]`) or a +**VALUE** (a scalar rvalue: integer, float, pointer, or 128-bit scalar). +Addressing is built explicitly — `push_local`→PLACE, `addr` PLACE→VALUE(ptr), +`deref` VALUE(ptr)→PLACE, `field i` PLACE(record)→PLACE, `elem` VALUE(ptr)+index +→PLACE — and the op *panics* on a kind mismatch; CG never infers the kind or +inserts an implicit dereference. `load`/`store` take a PLACE and no +effective-address rider; the place ops fold the constant offset (deref/field) +and scale (elem) into one `OPK_INDIRECT`, so the backend still gets a single +addressing-mode memop. Aggregates are always a PLACE. The implementation lives in `src/cg/`, split by op family rather than one monolith: `value.c` (stack discipline, lvalue/rvalue conversion, operand diff --git a/doc/plan/CODEGEN.md b/doc/plan/CODEGEN.md @@ -54,6 +54,7 @@ Between them sits the translation layer (`src/cg/value.c`, `arith.c`, `memory.c` | `917ffe9` | **2 (AsmDir)** | Deleted internal `AsmDir` + `api_map_asm_dir`; `AsmConstraint.dir` and backends use public `CfreeCgAsmDir`. | | `a2f6367` | **2 (Atomic/Order)** | Deleted internal `AtomicOp`/`MemOrder` + `api_map_atomic_op`/`api_map_mem_order`; **both** the semantic `CgTarget` and physical `NativeTarget` atomic hooks, the recorder+opt IR aux, and the interpreter now carry public `CfreeCgAtomicOp`/`CfreeCgMemOrder`. | | `d03eb4c` | **6.2** | Isolated the `-O0` semantic peephole into `src/cg/fold.{c,h}`: integer constant folding, the `SV_CMP` delayed-compare lifecycle, the (gated-off) `SV_ARITH` delayed-arith lifecycle, and const-local store-to-load forwarding with its invalidation boundaries. `fold.h` is the documented contract, re-exported via `internal.h`; `value.c` keeps stack discipline, `api_lvalue_addr`, and the enum-mapping helpers. Pure relocation, no behavior change. `doc/CODEGEN.md` updated. | +| `c338c74`+`8e17cb9` | **7 (core)** | Strict PLACE/VALUE addressing. Removed `CfreeCgEffAddr` from `load`/`store` (they consume a PLACE); added `deref(offset)` (VALUE ptr→PLACE), renamed `index`→`elem` (VALUE ptr + index→PLACE, scale=sizeof(T)), kept `field(i)`/`addr`. Each op **panics on kind mismatch** — no place/value inference. The place ops fold the constant offset (deref/field) and scale (elem→`log2_scale`) into one `OPK_INDIRECT[base + index*scale + offset]`, so the backend still gets a single addressing-mode memop (base/index dynamic, scale/offset folded). All three frontends + emu + cg-api tests conformed (explicit `deref`/decay/`field`). `cg.h` documents the kinds + per-op contracts. Green: toy 1344/0, cg-api, opt (incl tiny-inline), smoke, libc, isa/link/elf, and `make bootstrap` reproduces byte-identical at -O0 AND -O1. | So **Tracks 1a/1d, 5, 3a, 6.2 are done; Track 2 is 2/3 done** (the 3 identical enums); **Track 4** has FP_REM removed. @@ -241,7 +242,31 @@ The semantic layer is also a `-O0` peephole optimizer — a **kept feature** (Pr --- -## Track 7 — Strict place/value discipline (the centerpiece, UNTOUCHED) +## Track 7 — Strict place/value discipline (the centerpiece) + +**Status: core LANDED** (`c338c74`+`8e17cb9`). The public addressing surface is the strict +`push_local`/`addr`/`deref`/`field`/`elem`/`load`/`store` set; the `CfreeCgEffAddr` rider is +gone; every op panics on a place/value kind mismatch (no inference at the boundary); and the +place ops fold the constant offset/scale into one `OPK_INDIRECT[base + index*scale + offset]` +for clean memops. All frontends + emu + cg-api tests conform; `make bootstrap` reproduces at +-O0 AND -O1. + +**Remaining refinements (follow-ups):** +- The *internal* `api_is_lvalue_sv` is still the place predicate (a heuristic on `ApiSValue`). + The boundary is strict, but replacing the internal heuristic with an explicit `ApiSValue` + kind tag (Model B's "every stack entry is exactly one kind") is not yet done. +- Aggregate **VALUE**s aren't yet hard-forbidden inside the stack (aggregates are PLACEs in + practice, but there's no panic on an aggregate-typed value). +- **wide16** (i128/f128) is still special-cased as aggregate-like in `memory.c`/`call.c`/ + `wide.c` rather than flowing as a VALUE. +- **Bitfields** still ride on `CfreeCgMemAccess`/`CfreeCgField` (Track 3b: make them a PLACE + subkind on the strict `load`/`store`). +- **-O0 mem-op quality**: the C frontend reaches non-trivial places via + `pcg_materialize_lv_to_ptr` (int arithmetic) + `deref`; it could instead emit + `deref(offset)`/`elem` directly so -O0 also gets the folded addressing mode (-O1's + addr-fold already recovers it; decision #8 makes this non-blocking). + +### Original design notes (for the remaining refinements) **Decided:** Model B (explicit place/value kinds); wide-16 scalars are *values*. (Track 3c — the `scale` vs `log2_scale` rider mismatch — is subsumed here: the `CfreeCgEffAddr` rider is diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -266,19 +266,6 @@ typedef struct CfreeCgMemAccess { int bit_signed; } CfreeCgMemAccess; -/* Effective address rider on the memops: encodes - * base + index * scale + offset directly on the load/store. - * - * scale == 0 indicates "no index"; the memop consumes only [base]. - * scale > 0 indicates an indexed access; the memop consumes [base, index] - * and multiplies index by scale raw bytes (frontends pass element size - * explicitly — not log2). offset is a signed byte displacement folded into - * the addressing mode where the target permits. */ -typedef struct CfreeCgEffAddr { - int64_t offset; - uint32_t scale; -} CfreeCgEffAddr; - /* ============================================================ * Declarations and Symbols * ============================================================ */ @@ -561,8 +548,33 @@ CFREE_API void cfree_cg_computed_goto(CfreeCg*, CFREE_API void cfree_cg_unreachable(CfreeCg*); /* ============================================================ - * Value Stack and Lvalues - * ============================================================ */ + * Value stack: PLACES and VALUES + * ============================================================ + * + * Every stack entry is exactly one of two kinds, and each op below declares the + * kinds it consumes and produces. The op enforces this: handing an op the wrong + * kind is a usage error and panics. CG never *infers* the kind of a stack entry + * or silently inserts a dereference — addressing is always built explicitly. + * + * PLACE — an addressable, typed location of an object (a local's storage, a + * global, or a computed `[base + index*scale + offset]`). Produced by + * push_local / deref / field / elem; consumed by load / store / addr. + * + * VALUE — a scalar rvalue: an integer, float, pointer, or 128-bit scalar. + * Produced by push_int/float/null, push_symbol_addr, push_local_addr, + * addr, and load; consumed by the arithmetic / call / branch ops. + * + * Aggregates (records, arrays) are ALWAYS a PLACE — there is no aggregate VALUE. + * Copying an aggregate is an explicit store/memcpy between places. + * + * The four building blocks of addressing: + * - push_local l : — -> PLACE (the local's storage) + * - addr : PLACE -> VALUE(ptr) (address of the place) + * - deref : VALUE(ptr) -> PLACE (the place the ptr names) + * - field i : PLACE(record)-> PLACE(field) (sub-object, by layout) + * - elem : VALUE(ptr),index VALUE -> PLACE (element of an array/ptr) + * From these, `*p` is `deref`, `p->f` is `deref; field`, `s.f` is `field`, + * `a[i]` is `addr; <decay to *elem>; elem`, and `&x` is `addr`. */ CFREE_API void cfree_cg_dup(CfreeCg*); CFREE_API void cfree_cg_dup2(CfreeCg*); /* duplicates the top two slots */ @@ -571,57 +583,71 @@ CFREE_API void cfree_cg_drop(CfreeCg*); CFREE_API void cfree_cg_rot3(CfreeCg*); /* [..., a, b, c] -> [..., b, c, a] */ /* Returns nonzero when the current top-of-stack value is a compile-time known - * integer-like immediate. The value is not popped. */ + * integer-like immediate VALUE. The value is not popped. */ CFREE_API int cfree_cg_top_const_int(CfreeCg*, int64_t* out_value); +/* Push a scalar VALUE. */ CFREE_API void cfree_cg_push_int(CfreeCg*, uint64_t value, CfreeCgTypeId type); CFREE_API void cfree_cg_push_float(CfreeCg*, double value, CfreeCgTypeId type); CFREE_API void cfree_cg_push_null(CfreeCg*, CfreeCgTypeId ptr_type); +/* Push the PLACE that is the local's storage. Stack: [] -> [place]. */ CFREE_API void cfree_cg_push_local(CfreeCg*, CfreeCgLocal local); +/* Push the local's address as a pointer VALUE (sugar for push_local; addr). + * Stack: [] -> [ptr]. */ CFREE_API void cfree_cg_push_local_addr(CfreeCg*, CfreeCgLocal local); /* Anonymous immutable data. Returns a local readonly object symbol; callers - * can materialize its address with push_symbol_addr. pointee_type describes - * the logical value at that address, enabling const_data + indirect + load to - * materialize arbitrary-width constants. */ + * can materialize its address (a VALUE) with push_symbol_addr. pointee_type + * describes the logical value at that address, enabling const_data + + * push_symbol_addr + deref + load to materialize arbitrary-width constants. */ CFREE_API CfreeCgSym cfree_cg_const_data(CfreeCg*, const uint8_t* data, size_t len, uint32_t align, CfreeCgTypeId pointee_type); -/* Pushes &sym + addend as a pointer rvalue. For TLS objects this means the - * address of the current thread's instance; the target chooses LE/IE/GD/TLVP - * or equivalent lowering from the symbol attrs and output mode. */ +/* Push &sym + addend as a pointer VALUE. For TLS objects this means the address + * of the current thread's instance; the target chooses LE/IE/GD/TLVP or + * equivalent lowering from the symbol attrs and output mode. Stack: [] -> [ptr]. + */ CFREE_API void cfree_cg_push_symbol_addr(CfreeCg*, CfreeCgSym sym, int64_t addend); -/* Projects an lvalue TOS back to a pointer rvalue (e.g. for `&x`, passing to - * a call, escape). */ +/* PLACE -> VALUE(ptr): the address of the place (e.g. `&x`, or to pass/escape). + * Stack: [place] -> [ptr]. Errors if TOS is not a PLACE. */ CFREE_API void cfree_cg_addr(CfreeCg*); -/* Project through array/pointer and record fields. These leave an lvalue on - * the stack, so callers can load from or store to the selected slot. */ -CFREE_API void cfree_cg_index(CfreeCg*, uint64_t offset); +/* VALUE(ptr) -> PLACE: the explicit pointer->place transition. The produced + * place is `*(ptr + offset bytes)`; `offset` is a byte displacement folded into + * the addressing mode (0 for a plain `*p`). Stack: [ptr] -> [place]. Errors if + * TOS is not a pointer VALUE — a PLACE must be turned into a pointer with `addr` + * first; the op never guesses. */ +CFREE_API void cfree_cg_deref(CfreeCg*, int64_t offset); + +/* PLACE(record) -> PLACE(field): project a record place to one of its fields by + * index; the byte offset and field type come from the record's layout (CG owns + * layout). Stack: [place] -> [place]. Errors if TOS is not a record PLACE — for + * `p->f` the frontend does `deref; field`, not `field` on a pointer. */ CFREE_API void cfree_cg_field(CfreeCg*, uint32_t field_index); -/* Single load/store ops with an effective-address rider. - * - * `base` is either an lvalue (push_local) or a pointer-typed value. When - * `ea.scale == 0` the memop consumes only [base]; when `ea.scale > 0` it - * also pops an integer-typed `index` (with signedness inherited from its - * producer). Field offsets ride in `ea.offset`; array scales ride in - * `ea.scale` as raw bytes. +/* (VALUE(ptr to T), index VALUE) -> PLACE(T): the element at `*(base + + * index*sizeof(T) + offset)`. The index is scaled by sizeof(T) (the pointer's + * pointee) and the constant `offset` byte displacement is folded in, so the + * place is a single `[base + index*scale + offset]` addressing mode (base and + * index dynamic; scale and offset constant). The base is a pointer VALUE; an + * array is decayed to a pointer (`addr` + cast to *T) by the frontend first. + * Stack: [base, index] -> [place]. Errors if the base is not a pointer VALUE. */ +CFREE_API void cfree_cg_elem(CfreeCg*, int64_t offset); + +/* Load a VALUE from a PLACE / store a VALUE into a PLACE. The PLACE carries all + * addressing (built via push_local / deref / field / elem); the memop takes no + * effective-address rider. Bit-field metadata rides in `access`. Both error if + * the addressed operand is not a PLACE — a pointer VALUE must be `deref`'d + * first. * * Stack effects: - * scale == 0: - * load: [base] -> [value] - * store: [base, value] -> [] - * scale > 0: - * load: [base, index] -> [value] - * store: [base, index, value] -> [] */ -CFREE_API void cfree_cg_load(CfreeCg*, CfreeCgMemAccess access, - CfreeCgEffAddr ea); -CFREE_API void cfree_cg_store(CfreeCg*, CfreeCgMemAccess access, - CfreeCgEffAddr ea); + * load: [place] -> [value] + * store: [place, value] -> [] */ +CFREE_API void cfree_cg_load(CfreeCg*, CfreeCgMemAccess access); +CFREE_API void cfree_cg_store(CfreeCg*, CfreeCgMemAccess access); /* ============================================================ * ABI variadic argument access @@ -1161,18 +1187,16 @@ static inline void cfree_cg_musttail_call_symbol(CfreeCg* cg, CfreeCgSym sym, /* Read the scalar value of a local. Stack: [] -> [value]. */ static inline void cfree_cg_local_read(CfreeCg* cg, CfreeCgLocal local, CfreeCgMemAccess access) { - CfreeCgEffAddr ea = {0, 0}; cfree_cg_push_local(cg, local); - cfree_cg_load(cg, access, ea); + cfree_cg_load(cg, access); } /* Write the scalar value on TOS into a local. Stack: [value] -> []. */ static inline void cfree_cg_local_write(CfreeCg* cg, CfreeCgLocal local, CfreeCgMemAccess access) { - CfreeCgEffAddr ea = {0, 0}; cfree_cg_push_local(cg, local); /* [value, lv] */ cfree_cg_swap(cg); /* [lv, value] */ - cfree_cg_store(cg, access, ea); + cfree_cg_store(cg, access); } /* Increment/decrement an lvalue in place. Stack: [lv] -> [result]. @@ -1181,23 +1205,22 @@ static inline void cfree_cg_local_write(CfreeCg* cg, CfreeCgLocal local, * of the lvalue. */ static inline void cfree_cg_inc_dec(CfreeCg* cg, CfreeCgIntBinOp op, int post, CfreeCgTypeId ty, CfreeCgMemAccess access) { - CfreeCgEffAddr ea = {0, 0}; - cfree_cg_dup(cg); /* [lv, lv] */ - cfree_cg_load(cg, access, ea); /* [lv, old] */ + cfree_cg_dup(cg); /* [lv, lv] */ + cfree_cg_load(cg, access); /* [lv, old] */ if (post) { - cfree_cg_dup(cg); /* [lv, old, old] */ - cfree_cg_push_int(cg, 1, ty); /* [lv, old, old, 1] */ - cfree_cg_int_binop(cg, op, 0); /* [lv, old, new] */ - cfree_cg_rot3(cg); /* [old, new, lv] */ - cfree_cg_swap(cg); /* [old, lv, new] */ - cfree_cg_store(cg, access, ea); /* [old] */ + cfree_cg_dup(cg); /* [lv, old, old] */ + cfree_cg_push_int(cg, 1, ty); /* [lv, old, old, 1] */ + cfree_cg_int_binop(cg, op, 0); /* [lv, old, new] */ + cfree_cg_rot3(cg); /* [old, new, lv] */ + cfree_cg_swap(cg); /* [old, lv, new] */ + cfree_cg_store(cg, access); /* [old] */ } else { - cfree_cg_push_int(cg, 1, ty); /* [lv, old, 1] */ - cfree_cg_int_binop(cg, op, 0); /* [lv, new] */ - cfree_cg_dup(cg); /* [lv, new, new] */ - cfree_cg_rot3(cg); /* [new, new, lv] */ - cfree_cg_swap(cg); /* [new, lv, new] */ - cfree_cg_store(cg, access, ea); /* [new] */ + cfree_cg_push_int(cg, 1, ty); /* [lv, old, 1] */ + cfree_cg_int_binop(cg, op, 0); /* [lv, new] */ + cfree_cg_dup(cg); /* [lv, new, new] */ + cfree_cg_rot3(cg); /* [new, new, lv] */ + cfree_cg_swap(cg); /* [new, lv, new] */ + cfree_cg_store(cg, access); /* [new] */ } } diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -437,24 +437,35 @@ void pcg_push_float(Parser* p, double v, const Type* ty) { pcg_push_type(p, ty); } -/* Fill `access` (CfreeCgMemAccess) and `ea` (CfreeCgEffAddr) for a memop - * against the TOS lvalue. The lvalue's pending EA on aux is consumed: caller - * is expected to follow with the matching cfree_cg_load / cfree_cg_store. */ -static void pcg_consume_ea_for_top(Parser* p, const Type* access_ty, - CfreeCgMemAccess* access, - CfreeCgEffAddr* ea) { - PcgLvAux* lv = pcg_top_lv_aux(p); - *access = pcg_mem(p, access_ty); +/* Fill `access` (CfreeCgMemAccess) for a memop against an lvalue carrying the + * given aux. Bit-field metadata rides in the access; addressing is no longer a + * rider — it is built explicitly with deref/elem/field before the load/store. */ +static CfreeCgMemAccess pcg_access_for(Parser* p, const Type* access_ty, + const PcgLvAux* lv) { + CfreeCgMemAccess access = pcg_mem(p, access_ty); if (lv && lv->bit_width) { - access->bit_offset = lv->bit_offset; - access->bit_width = lv->bit_width; - access->storage_size = lv->storage_size; - access->bit_signed = lv->bit_signed; + access.bit_offset = lv->bit_offset; + access.bit_width = lv->bit_width; + access.storage_size = lv->storage_size; + access.bit_signed = lv->bit_signed; } - ea->offset = lv ? lv->offset : 0; - ea->scale = lv ? lv->scale : 0u; + return access; } +/* A trivially-addressable lvalue: a bare local slot with no pending field + * offset, array scale, or bit-field. Its PLACE is already on the CG stack + * (push_local), so a load/store can consume it directly without first + * materializing an address. */ +static int pcg_lv_is_trivial_local(const PcgLvAux* lv) { + return lv && lv->base_kind == PCG_LV_BASE_LOCAL && lv->offset == 0 && + lv->scale == 0 && lv->bit_width == 0; +} + +/* Materialize the TOS lvalue (folding its pending field offset / array scale + * into the address) as a single pointer rvalue. Defined below; the memops use + * it to build an explicit place before load/store. */ +static void pcg_materialize_lv_to_ptr(Parser* p, const Type* result_ptr_ty); + void pcg_push_local_typed(Parser* p, FrameSlot s, const Type* ty) { if (pcg_emit_enabled(p)) cfree_cg_push_local(p->cg, s); pcg_push_type(p, ty); @@ -481,12 +492,20 @@ void pcg_load(Parser* p) { const Type* ty = pcg_top_type(p); int was_lvalue = pcg_top_is_lvalue(p); if (pcg_emit_enabled(p)) { - CfreeCgMemAccess access; - CfreeCgEffAddr ea; - pcg_consume_ea_for_top(p, ty, &access, &ea); - cfree_cg_load(p->cg, access, ea); + PcgLvAux* lv = pcg_top_lv_aux(p); + CfreeCgMemAccess access = pcg_access_for(p, ty, lv); + /* Build the PLACE the strict load requires. A trivial local already has its + * PLACE on the CG stack (push_local) and loads directly; anything else is + * reduced to a single pointer (materialize, or a pointer-rvalue base) and + * then deref'd to a place. */ + if (!was_lvalue || !pcg_lv_is_trivial_local(lv)) { + if (was_lvalue) pcg_materialize_lv_to_ptr(p, type_ptr(p->pool, ty)); + cfree_cg_deref(p->cg, 0); + } + cfree_cg_load(p->cg, access); } if (was_lvalue && p->cg_type_sp) { + p->cg_type_stack[p->cg_type_sp - 1u] = ty; p->cg_value_flags[p->cg_type_sp - 1u] = 0; pcg_aux_clear(&p->cg_lv_aux[p->cg_type_sp - 1u]); } @@ -613,84 +632,54 @@ void pcg_store(Parser* p) { const Type* rv_ty = pcg_top_type(p); const Type* mem_ty = lv_ty; int emit = pcg_emit_enabled(p); + /* The aux to consume lives on the lvalue slot at parser depth 1. */ + PcgLvAux* lv = pcg_lv_aux_at(p, 1); CfreeCgMemAccess access; - CfreeCgEffAddr ea; - PcgLvAux* lv; if (rv_ty && type_is_ptr(rv_ty) && (!lv_ty || !type_is_ptr(lv_ty))) { mem_ty = rv_ty; } - /* The aux to consume lives on the lvalue slot at parser depth 1. */ - lv = pcg_lv_aux_at(p, 1); - access = pcg_mem(p, mem_ty ? mem_ty : rv_ty); - if (lv && lv->bit_width) { - access.bit_offset = lv->bit_offset; - access.bit_width = lv->bit_width; - access.storage_size = lv->storage_size; - access.bit_signed = lv->bit_signed; - } - ea.offset = lv ? lv->offset : 0; - ea.scale = lv ? lv->scale : 0u; - if (ea.scale == 0 && - !(rv_ty && (rv_ty->kind == TY_INT128 || rv_ty->kind == TY_UINT128 || - rv_ty->kind == TY_LDOUBLE))) { - if (emit) { + access = pcg_access_for(p, mem_ty ? mem_ty : rv_ty, lv); + if (emit) { + int wide = rv_ty && (rv_ty->kind == TY_INT128 || + rv_ty->kind == TY_UINT128 || rv_ty->kind == TY_LDOUBLE); + if (pcg_lv_is_trivial_local(lv) && !wide) { + /* The destination place is already on the CG stack. Keep a copy of rv as + * the assignment's value. Stack: [place, value]. */ cfree_cg_dup(p->cg); cfree_cg_rot3(p->cg); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, access, ea); - } - } else if (ea.scale == 0) { - /* Simple lvalue: stash rv so the actual destination store does not have - * to keep a duplicate expression result live under register pressure. */ - FrameSlotDesc fsd; - FrameSlot tmp; - memset(&fsd, 0, sizeof fsd); - fsd.type = rv_ty; - fsd.size = c_abi_sizeof(p->abi, rv_ty); - fsd.align = c_abi_alignof(p->abi, rv_ty); - fsd.kind = FS_LOCAL; - tmp = pcg_local(p, &fsd); - if (emit) { - CfreeCgMemAccess rv_access = pcg_mem(p, rv_ty); - CfreeCgEffAddr zero_ea; - zero_ea.offset = 0; - zero_ea.scale = 0; - /* [base, rv] */ - cfree_cg_push_local(p->cg, tmp); /* [base, rv, tmp] */ - cfree_cg_swap(p->cg); /* [base, tmp, rv] */ - cfree_cg_store(p->cg, rv_access, zero_ea); /* [base] */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, rv_access, zero_ea); /* [base, rv] */ - cfree_cg_store(p->cg, access, ea); /* [] */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, rv_access, zero_ea); /* [rv] */ - } - } else { - /* Indexed lvalue: CG stack on entry is [base, idx, rv]. Stash rv into a - * compiler-temp local so we can reorder cleanly, then re-load after the - * store. */ - FrameSlotDesc fsd; - FrameSlot tmp; - memset(&fsd, 0, sizeof fsd); - fsd.type = rv_ty; - fsd.size = c_abi_sizeof(p->abi, rv_ty); - fsd.align = c_abi_alignof(p->abi, rv_ty); - fsd.kind = FS_LOCAL; - tmp = pcg_local(p, &fsd); - if (emit) { + cfree_cg_store(p->cg, access); + } else { + /* Stash rv into a temp so the destination place can be built from the + * base — folding any field offset / array scale into an explicit pointer + * — then reload rv to store it and to leave it as the expression value. */ + FrameSlotDesc fsd; + FrameSlot tmp; CfreeCgMemAccess rv_access = pcg_mem(p, rv_ty); - CfreeCgEffAddr zero_ea; - zero_ea.offset = 0; - zero_ea.scale = 0; - /* [base, idx, rv] */ - cfree_cg_push_local(p->cg, tmp); /* [base, idx, rv, tmp] */ - cfree_cg_swap(p->cg); /* [base, idx, tmp, rv] */ - cfree_cg_store(p->cg, rv_access, zero_ea); /* [base, idx] */ + int trivial = pcg_lv_is_trivial_local(lv); + memset(&fsd, 0, sizeof fsd); + fsd.type = rv_ty; + fsd.size = c_abi_sizeof(p->abi, rv_ty); + fsd.align = c_abi_alignof(p->abi, rv_ty); + fsd.kind = FS_LOCAL; + tmp = pcg_local(p, &fsd); + cfree_cg_push_local(p->cg, tmp); /* [base.., value, &tmp] */ + cfree_cg_swap(p->cg); /* [base.., &tmp, value] */ + cfree_cg_store(p->cg, rv_access); /* [base..] (stash rv) */ + if (!trivial) { + /* Materialize operates on the parser-TOS lvalue; drop the rv type slot + * so the lvalue is on top and matches the CG [base..]. The pointer is + * deref'd to the PLACE the strict store requires. */ + pcg_drop_type(p); + pcg_materialize_lv_to_ptr(p, type_ptr(p->pool, lv_ty)); /* [dst_ptr] */ + cfree_cg_deref(p->cg, 0); /* [dst_place] */ + pcg_push_type(p, rv_ty); + } cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, rv_access, zero_ea); /* [base, idx, rv] */ - cfree_cg_store(p->cg, access, ea); /* [] */ + cfree_cg_load(p->cg, rv_access); /* [dst, value] */ + cfree_cg_store(p->cg, access); /* [] */ cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, rv_access, zero_ea); /* [rv] */ + cfree_cg_load(p->cg, rv_access); /* [value] */ } } pcg_drop_type(p); @@ -938,12 +927,9 @@ void pcg_inc_dec(Parser* p, BinOp op, int post) { { CfreeCgIntBinOp cg_op = pcg_int_binop(op); PcgLvAux* lv = pcg_top_lv_aux(p); - int indexed = lv && lv->scale != 0; - CfreeCgMemAccess access; - CfreeCgEffAddr ea; + CfreeCgMemAccess access = pcg_access_for(p, ty, lv); const Type* step_ty = ty; u32 step = 1; - pcg_consume_ea_for_top(p, ty, &access, &ea); if (ty && ty->kind == TY_PTR) { const Type* pointee = ty->ptr.pointee; if (pointee && pointee->kind == TY_VOID) @@ -951,57 +937,51 @@ void pcg_inc_dec(Parser* p, BinOp op, int post) { step = c_abi_sizeof(p->abi, pointee); step_ty = c_abi_ptrdiff_type(p->abi, p->pool); } - /* Allocate a temp to stash the previous (post=1) or new (post=0) value - * for the expression-value. Both indexed and simple paths use the same - * stash so the resulting sequence is uniform. */ + /* Materialize the lvalue to a single destination pointer so its address can + * be duplicated for the read-modify-write. */ + pcg_materialize_lv_to_ptr(p, type_ptr(p->pool, ty)); { FrameSlotDesc fsd; FrameSlot tmp; const Type* result_ty = ty; + CfreeCgMemAccess r_access = pcg_mem(p, result_ty); memset(&fsd, 0, sizeof fsd); fsd.type = result_ty; fsd.size = c_abi_sizeof(p->abi, result_ty); fsd.align = c_abi_alignof(p->abi, result_ty); fsd.kind = FS_LOCAL; tmp = pcg_local(p, &fsd); - { - CfreeCgMemAccess r_access = pcg_mem(p, result_ty); - CfreeCgEffAddr zero_ea = {0, 0}; - /* Duplicate the lvalue base (+ index if indexed) so we can load the - * old value AND store the new value through the same address. */ - if (indexed) { - cfree_cg_dup2(p->cg); - } else { - cfree_cg_dup(p->cg); - } - cfree_cg_load(p->cg, access, ea); /* ..., lv-base[, idx], old */ - if (post) { - /* Stash old, compute new, store, then re-load old as result. */ - cfree_cg_dup(p->cg); /* ..., lv-base[, idx], old, old */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, r_access, - zero_ea); /* ..., lv-base[, idx], old */ - pcg_emit_inc_step(p, ty, op, cg_op, step_ty, - step); /* ..., lv-base[, idx], new */ - cfree_cg_store(p->cg, access, ea); /* [] */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, r_access, zero_ea); /* [old] */ - } else { - /* Compute new, stash new, store, then re-load new as result. */ - pcg_emit_inc_step(p, ty, op, cg_op, step_ty, - step); /* ..., lv-base[, idx], new */ - cfree_cg_dup(p->cg); /* ..., lv-base[, idx], new, new */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, r_access, - zero_ea); /* ..., lv-base[, idx], new */ - cfree_cg_store(p->cg, access, ea); /* [] */ - cfree_cg_push_local(p->cg, tmp); - cfree_cg_load(p->cg, r_access, zero_ea); /* [new] */ - } - (void)step; + cfree_cg_dup(p->cg); /* [ptr, ptr] */ + cfree_cg_deref(p->cg, 0); /* [ptr, place] */ + cfree_cg_load(p->cg, access); /* [ptr, old] */ + if (post) { + /* Stash old, compute new, store, then re-load old as result. */ + cfree_cg_dup(p->cg); /* [ptr, old, old] */ + cfree_cg_push_local(p->cg, tmp); + cfree_cg_swap(p->cg); + cfree_cg_store(p->cg, r_access); /* [ptr, old] */ + pcg_emit_inc_step(p, ty, op, cg_op, step_ty, step); /* [ptr, new] */ + cfree_cg_swap(p->cg); /* [new, ptr] */ + cfree_cg_deref(p->cg, 0); /* [new, place] */ + cfree_cg_swap(p->cg); /* [place, new] */ + cfree_cg_store(p->cg, access); /* [] */ + cfree_cg_push_local(p->cg, tmp); + cfree_cg_load(p->cg, r_access); /* [old] */ + } else { + /* Compute new, stash new, store, then re-load new as result. */ + pcg_emit_inc_step(p, ty, op, cg_op, step_ty, step); /* [ptr, new] */ + cfree_cg_dup(p->cg); /* [ptr, new, new] */ + cfree_cg_push_local(p->cg, tmp); + cfree_cg_swap(p->cg); + cfree_cg_store(p->cg, r_access); /* [ptr, new] */ + cfree_cg_swap(p->cg); /* [new, ptr] */ + cfree_cg_deref(p->cg, 0); /* [new, place] */ + cfree_cg_swap(p->cg); /* [place, new] */ + cfree_cg_store(p->cg, access); /* [] */ + cfree_cg_push_local(p->cg, tmp); + cfree_cg_load(p->cg, r_access); /* [new] */ } + (void)step; } } /* Parser stack: drop the lvalue slot, push the result rvalue type. */ diff --git a/lang/toy/asm.c b/lang/toy/asm.c @@ -187,6 +187,9 @@ static int toy_parse_asm_input_operand(ToyParser* p, toy_error(p, p->cur.loc, "unknown asm memory operand"); return 0; } + /* The "m" operand wants a memory PLACE; toy_emit_var_lvalue leaves the + * variable's address as a pointer VALUE, so deref it back to a place. */ + cfree_cg_deref(p->cg, 0); } else { operand->type = toy_parse_expr(p); } @@ -480,11 +483,13 @@ int toy_parse_typed_asm_tail(ToyParser* p, CfreeCgTypeId result_ty, &foff) != 0) goto done; cfree_cg_push_local(p->cg, rec_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)foff); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)foff, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); } - cfree_cg_push_local(p->cg, rec_slot); + /* Record result lives as a pointer VALUE (its address) on the stack. */ + cfree_cg_push_local_addr(p->cg, rec_slot); } ok = 1; diff --git a/lang/toy/builtins.c b/lang/toy/builtins.c @@ -27,20 +27,20 @@ static void toy_store_top_to_local(ToyParser* p, CfreeCgLocal local, CfreeCgTypeId ty) { cfree_cg_push_local(p->cg, local); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); } static void toy_store_const_to_local(ToyParser* p, CfreeCgLocal local, CfreeCgTypeId ty, uint64_t value) { cfree_cg_push_local(p->cg, local); cfree_cg_push_int(p->cg, value, ty); - cfree_cg_store(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); } static void toy_push_loaded_local(ToyParser* p, CfreeCgLocal local, CfreeCgTypeId ty) { cfree_cg_push_local(p->cg, local); - cfree_cg_load(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); } static void toy_emit_dynamic_memory_loop(ToyParser* p, CfreeCgLocal dst_local, @@ -64,22 +64,25 @@ static void toy_emit_dynamic_memory_loop(ToyParser* p, CfreeCgLocal dst_local, toy_push_loaded_local(p, dst_local, u8_ptr_ty); toy_push_loaded_local(p, index_local, p->int_type); - /* The destination memop carries scale = sizeof(u8) = 1; it pops - * [dst_ptr, index] and then [value]. */ + /* Build the destination element place from [dst_ptr, index]; the element + * scale = sizeof(u8) = 1 is derived from the base type. The store then + * consumes [dst_place, value]. */ + cfree_cg_elem(p->cg, 0); if (is_memset) { cfree_cg_push_int(p->cg, set_value, u8_ty); } else { toy_push_loaded_local(p, src_local, u8_ptr_ty); toy_push_loaded_local(p, index_local, p->int_type); - cfree_cg_load(p->cg, toy_mem_access(p, u8_ty), (CfreeCgEffAddr){0, 1}); + cfree_cg_elem(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, u8_ty)); } - cfree_cg_store(p->cg, toy_mem_access(p, u8_ty), (CfreeCgEffAddr){0, 1}); + cfree_cg_store(p->cg, toy_mem_access(p, u8_ty)); cfree_cg_push_local(p->cg, index_local); toy_push_loaded_local(p, index_local, p->int_type); cfree_cg_push_int(p->cg, 1, p->int_type); cfree_cg_int_binop(p->cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(p->cg, toy_mem_access(p, p->int_type), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_jump(p->cg, loop_label); cfree_cg_label_place(p->cg, end_label); @@ -565,17 +568,17 @@ CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, dst_slot = cfree_cg_local(p->cg, dst_ty, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, src_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, src_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, src_ty)); cfree_cg_push_local(p->cg, dst_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, dst_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, dst_ty)); cfree_cg_push_local(p->cg, dst_slot); - cfree_cg_load(p->cg, toy_mem_access(p, dst_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, dst_ty)); cfree_cg_push_int(p->cg, clear_mask, dst_ty); cfree_cg_int_binop(p->cg, CFREE_CG_INT_AND, 0); cfree_cg_push_local(p->cg, src_slot); - cfree_cg_load(p->cg, toy_mem_access(p, src_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, src_ty)); cfree_cg_push_int(p->cg, src_mask, src_ty); cfree_cg_int_binop(p->cg, CFREE_CG_INT_AND, 0); if (lo > 0) { @@ -998,15 +1001,19 @@ CfreeCgTypeId toy_parse_generic_builtin(ToyParser* p, CfreeSym name, cfree_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); cfree_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); cfree_cg_push_local(p->cg, rec_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)f1_off); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, fields[1].type), - (CfreeCgEffAddr){(int64_t)f1_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, fields[1].type)); cfree_cg_push_local(p->cg, rec_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)f0_off); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, fields[0].type), - (CfreeCgEffAddr){(int64_t)f0_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, fields[0].type)); } - cfree_cg_push_local(p->cg, rec_slot); + /* Record result lives as a pointer VALUE (its address) on the stack, the + * shape record field-access / record-copy consume downstream. */ + cfree_cg_push_local_addr(p->cg, rec_slot); return rec_ty; } @@ -1327,15 +1334,18 @@ CfreeCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, CfreeSym name, cfree_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); cfree_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); cfree_cg_push_local(p->cg, rec_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)f1_off); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, fields[1].type), - (CfreeCgEffAddr){(int64_t)f1_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, fields[1].type)); cfree_cg_push_local(p->cg, rec_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)f0_off); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, fields[0].type), - (CfreeCgEffAddr){(int64_t)f0_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, fields[0].type)); } - cfree_cg_push_local(p->cg, rec_slot); + /* Record result lives as a pointer VALUE (its address) on the stack. */ + cfree_cg_push_local_addr(p->cg, rec_slot); return rec_ty; } diff --git a/lang/toy/expr.c b/lang/toy/expr.c @@ -39,9 +39,20 @@ static int toy_reject_tail_call_operand(ToyParser* p) { CfreeCgTypeId toy_push_named_rvalue(ToyParser* p, CfreeSym name) { ToyVar* v = toy_find_var(p, name); if (v) { - toy_push_var_lvalue(p, v); - if (cfree_cg_type_kind(p->c, v->type) != CFREE_CG_TYPE_RECORD) - cfree_cg_load(p->cg, toy_mem_access(p, v->type), (CfreeCgEffAddr){0, 0}); + if (cfree_cg_type_kind(p->c, v->type) == CFREE_CG_TYPE_RECORD) { + /* Record: leave the address (pointer VALUE) for the caller's copy. */ + toy_push_var_lvalue(p, v); + } else if (v->is_static) { + /* Static scalar: its address is a pointer; deref to a place, then load. */ + cfree_cg_push_symbol_addr(p->cg, v->static_sym, 0); + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, v->type)); + } else { + /* Local scalar: the local's PLACE loads directly (no address round-trip, + * which keeps small accessors inlinable). */ + cfree_cg_push_local(p->cg, v->local); + cfree_cg_load(p->cg, toy_mem_access(p, v->type)); + } p->last_type = v->toy_type; return v->type; } @@ -49,9 +60,10 @@ CfreeCgTypeId toy_push_named_rvalue(ToyParser* p, CfreeSym name) { ToyGlobal* g = toy_find_global(p, name); if (g) { cfree_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0); - if (cfree_cg_type_kind(p->c, g->type) != CFREE_CG_TYPE_RECORD) - cfree_cg_load(p->cg, toy_mem_access(p, g->type), - (CfreeCgEffAddr){0, 0}); + if (cfree_cg_type_kind(p->c, g->type) != CFREE_CG_TYPE_RECORD) { + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, g->type)); + } p->last_type = g->toy_type; return g->type; } @@ -494,7 +506,7 @@ static void toy_store_tos_to_local(ToyParser* p, CfreeCgLocal local, CfreeCgTypeId ty) { cfree_cg_push_local(p->cg, local); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); } /* Consumes [slice_base, idx] where slice_base is a pointer to the slice @@ -518,10 +530,10 @@ CfreeCgTypeId toy_emit_slice_index_lvalue(ToyParser* p, CfreeCgTypeId slice_ty, * and compute element pointer. */ idx_slot = cfree_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); toy_store_tos_to_local(p, idx_slot, p->int_type); - cfree_cg_load(p->cg, toy_mem_access(p, ptr_field.type), - (CfreeCgEffAddr){(int64_t)ptr_field_off, 0}); + cfree_cg_deref(p->cg, (int64_t)ptr_field_off); + cfree_cg_load(p->cg, toy_mem_access(p, ptr_field.type)); cfree_cg_push_local(p->cg, idx_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); toy_addr_index(p, cfree_cg_type_size(p->c, elem_ty), cfree_cg_type_ptr(p->c, elem_ty, 0)); if (elem_toy_out) *elem_toy_out = elem_toy; @@ -585,8 +597,8 @@ CfreeCgTypeId toy_emit_slice_value(ToyParser* p, CfreeCgTypeId base_ty, /* TOS = [base] (slice lvalue/pointer or array lvalue/pointer). */ if (toy_type_is_slice(p, base_toy_type)) { /* Replace slice base with its data pointer (a pointer-rvalue). */ - cfree_cg_load(p->cg, toy_mem_access(p, ptr_field.type), - (CfreeCgEffAddr){(int64_t)ptr_off, 0}); + cfree_cg_deref(p->cg, (int64_t)ptr_off); + cfree_cg_load(p->cg, toy_mem_access(p, ptr_field.type)); } else { /* Array base: TOS is a pointer-rvalue (callers always project * to a pointer for array/slice bases now). Bitcast to *elem. */ @@ -595,30 +607,32 @@ CfreeCgTypeId toy_emit_slice_value(ToyParser* p, CfreeCgTypeId base_ty, /* Compute (base + start * sizeof(elem)) as a pointer to the slice's * first element. */ cfree_cg_push_local(p->cg, start_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); toy_addr_index(p, cfree_cg_type_size(p->c, elem_ty), cfree_cg_type_ptr(p->c, elem_ty, 0)); /* Store the data pointer into result_slot.ptr. */ cfree_cg_push_local(p->cg, result_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)ptr_off); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, ptr_field.type), - (CfreeCgEffAddr){(int64_t)ptr_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ptr_field.type)); /* len = end - start; store into result_slot.len. */ cfree_cg_push_local(p->cg, result_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)len_off); cfree_cg_push_local(p->cg, end_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_push_local(p->cg, start_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_int_binop(p->cg, CFREE_CG_INT_SUB, 0); - cfree_cg_store(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){(int64_t)len_off, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); } - cfree_cg_push_local(p->cg, result_slot); + /* Hand back the slice record as a pointer VALUE (its address), matching the + * "records/slices are pointer VALUEs" shape the downstream record-copy and + * slice-index paths consume. */ + cfree_cg_push_local_addr(p->cg, result_slot); if (slice_toy_out) *slice_toy_out = slice_toy; p->last_type = slice_toy; return slice_ty; @@ -740,6 +754,10 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { attrs.inline_policy = fn->func_attrs.inline_policy; cfree_cg_call_symbol(p->cg, toy_fn_cur_sym(p, fn), (uint32_t)nargs, attrs); } + /* An aggregate return is a PLACE; project it to a pointer VALUE so it + * matches the records-are-pointers invariant used downstream. */ + if (cfree_cg_type_kind(p->c, fn->ret) == CFREE_CG_TYPE_RECORD) + cfree_cg_addr(p->cg); p->last_type = fn->toy_ret; return fn->ret; } @@ -766,6 +784,9 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { &nargs)) return CFREE_CG_TYPE_NONE; cfree_cg_call_default(p->cg, (uint32_t)nargs, fn_ty); + if (cfree_cg_type_kind(p->c, toy_cg_func_ret(p, fn_ty)) == + CFREE_CG_TYPE_RECORD) + cfree_cg_addr(p->cg); p->last_type = source_fn_type ? source_fn_type->ret @@ -850,8 +871,9 @@ static CfreeCgTypeId toy_parse_expr_postfix(ToyParser* p) { } ty = cfree_cg_type_ptr_pointee(p->c, ty); toy_ty = toy_type_pointee(p, toy_ty); - /* TOS is a pointer-rvalue; memop accepts it as base directly. */ - cfree_cg_load(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + /* TOS is a pointer VALUE; deref it to a PLACE, then load. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty); continue; } @@ -899,12 +921,20 @@ static CfreeCgTypeId toy_parse_expr_postfix(ToyParser* p) { toy_ty = source_pointee; } } else if (cfree_cg_type_kind(p->c, ty) == CFREE_CG_TYPE_ARRAY) { - ty = cfree_cg_type_array_elem(p->c, ty); + /* TOS = [ptr-to-array, idx]. Decay the base to *elem so cfree_cg_elem + * scales by the element size, not the whole array. */ + CfreeCgTypeId elem_ty = cfree_cg_type_array_elem(p->c, ty); + cfree_cg_swap(p->cg); + cfree_cg_bitcast(p->cg, cfree_cg_type_ptr(p->c, elem_ty, 0)); + cfree_cg_swap(p->cg); + ty = elem_ty; toy_ty = toy_type_array_elem(p, toy_ty); } else if (toy_type_is_slice(p, toy_ty)) { ty = toy_emit_slice_index_lvalue(p, ty, toy_ty, &toy_ty); if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; - cfree_cg_load(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + /* toy_emit_slice_index_lvalue returns an element pointer VALUE. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty); continue; @@ -912,10 +942,9 @@ static CfreeCgTypeId toy_parse_expr_postfix(ToyParser* p) { toy_error(p, p->cur.loc, "cannot index non-array/non-pointer"); return CFREE_CG_TYPE_NONE; } - /* TOS = [base, idx]; load with element-size scale. */ - cfree_cg_load( - p->cg, toy_mem_access(p, ty), - (CfreeCgEffAddr){0, (uint32_t)cfree_cg_type_size(p->c, ty)}); + /* TOS = [base, idx]; elem yields the element PLACE, then load. */ + cfree_cg_elem(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty); continue; } @@ -955,8 +984,8 @@ static CfreeCgTypeId toy_parse_expr_postfix(ToyParser* p) { if (named && field_index < named->nfields) field_toy_type = named->fields[field_index].toy_type; ty = found_field.type; - cfree_cg_load(p->cg, toy_mem_access(p, ty), - (CfreeCgEffAddr){(int64_t)found_off, 0}); + cfree_cg_deref(p->cg, (int64_t)found_off); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); if (field_toy_type != TOY_TYPE_NONE) { CfreeCgTypeId resolved = toy_type_resolved_cg(p, field_toy_type); p->last_type = field_toy_type; @@ -1001,8 +1030,8 @@ static CfreeCgTypeId toy_parse_expr_postfix(ToyParser* p) { return CFREE_CG_TYPE_NONE; } ty = found_field.type; - cfree_cg_load(p->cg, toy_mem_access(p, ty), - (CfreeCgEffAddr){(int64_t)found_off, 0}); + cfree_cg_deref(p->cg, (int64_t)found_off); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); if (field_toy_type != TOY_TYPE_NONE) { CfreeCgTypeId resolved = toy_type_resolved_cg(p, field_toy_type); p->last_type = field_toy_type; @@ -1129,13 +1158,13 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { cfree_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, idx_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); - cfree_cg_load(p->cg, toy_mem_access(p, ty), - (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); + /* TOS is the chain pointer VALUE (**T); deref to a PLACE and + * load the inner pointer it addresses. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); cfree_cg_push_local(p->cg, idx_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); } if (cfree_cg_type_kind(p->c, pointee) == CFREE_CG_TYPE_ARRAY) { CfreeCgTypeId elem_ty = cfree_cg_type_array_elem(p->c, pointee); @@ -1171,8 +1200,9 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "cannot dereference non-pointer"); return CFREE_CG_TYPE_NONE; } - /* TOS = **T; load to TOS = *T. */ - cfree_cg_load(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + /* TOS = **T (pointer VALUE); deref to PLACE and load to TOS = *T. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); ty = cfree_cg_type_ptr_pointee(p->c, ty); ty_toy = toy_type_pointee(p, ty_toy); continue; @@ -1185,8 +1215,9 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { if (cfree_cg_type_kind(p->c, ty) == CFREE_CG_TYPE_PTR && cfree_cg_type_kind(p->c, cfree_cg_type_ptr_pointee(p->c, ty)) == CFREE_CG_TYPE_RECORD) { - /* TOS = **Rec; load to *Rec. */ - cfree_cg_load(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + /* TOS = **Rec (pointer VALUE); deref to PLACE and load to *Rec. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, ty)); ty = cfree_cg_type_ptr_pointee(p->c, ty); ty_toy = toy_type_pointee(p, ty_toy); } @@ -1559,15 +1590,15 @@ static CfreeCgTypeId toy_parse_expr_and(ToyParser* p) { cfree_cg_branch_false(p->cg, false_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 1, bool_ty); - cfree_cg_store(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, bool_ty)); cfree_cg_jump(p->cg, end_label); cfree_cg_label_place(p->cg, false_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 0, bool_ty); - cfree_cg_store(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, bool_ty)); cfree_cg_label_place(p->cg, end_label); cfree_cg_push_local(p->cg, result_slot); - cfree_cg_load(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, bool_ty)); ty = bool_ty; toy_note_cg_result_type(p, ty); } @@ -1598,15 +1629,15 @@ static CfreeCgTypeId toy_parse_expr_or(ToyParser* p) { cfree_cg_branch_true(p->cg, true_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 0, bool_ty); - cfree_cg_store(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, bool_ty)); cfree_cg_jump(p->cg, end_label); cfree_cg_label_place(p->cg, true_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 1, bool_ty); - cfree_cg_store(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, bool_ty)); cfree_cg_label_place(p->cg, end_label); cfree_cg_push_local(p->cg, result_slot); - cfree_cg_load(p->cg, toy_mem_access(p, bool_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, bool_ty)); ty = bool_ty; toy_note_cg_result_type(p, ty); } diff --git a/lang/toy/parser.c b/lang/toy/parser.c @@ -32,11 +32,15 @@ int toy_parse_block(ToyParser* p) { return 1; } -/* Pushes [base, index] onto the value stack as the EA-shaped pair consumed - * by an indexed memop. Callers supply the element size in the store's EA. */ +/* Pushes [base_ptr, index] for cfree_cg_elem: the array local is decayed to a + * pointer to its element type (its address, bitcast to *elem), then the index + * value is pushed on top. The following cfree_cg_elem(0) yields the element + * PLACE. */ static void toy_push_local_indexed(ToyParser* p, CfreeCgLocal slot, - uint64_t index) { + CfreeCgTypeId elem_ty, uint64_t index) { cfree_cg_push_local(p->cg, slot); + cfree_cg_addr(p->cg); + cfree_cg_bitcast(p->cg, cfree_cg_type_ptr(p->c, elem_ty, 0)); cfree_cg_push_int(p->cg, index, p->int_type); } @@ -99,12 +103,13 @@ static int toy_copy_record_lvalue_to_local(ToyParser* p, CfreeCgTypeId src_ty, uint64_t offset = 0; if (cfree_cg_type_record_field(p->c, dst_ty, i, &field, &offset)) return 0; cfree_cg_dup(p->cg); - cfree_cg_load(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)offset, 0}); + cfree_cg_deref(p->cg, (int64_t)offset); + cfree_cg_load(p->cg, toy_mem_access(p, field.type)); cfree_cg_push_local(p->cg, dst_slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)offset); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)offset, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); } cfree_cg_drop(p->cg); return 1; @@ -126,16 +131,16 @@ static int toy_copy_record_lvalue_to_var(ToyParser* p, CfreeCgTypeId src_ty, uint64_t offset = 0; if (cfree_cg_type_record_field(p->c, dst_ty, i, &field, &offset)) return 0; cfree_cg_dup(p->cg); - cfree_cg_load(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)offset, 0}); + cfree_cg_deref(p->cg, (int64_t)offset); + cfree_cg_load(p->cg, toy_mem_access(p, field.type)); if (dst_var) { toy_push_var_lvalue(p, dst_var); } else { cfree_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, dst_global), 0); } + cfree_cg_deref(p->cg, (int64_t)offset); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)offset, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); } cfree_cg_drop(p->cg); return 1; @@ -159,7 +164,8 @@ static int toy_parse_array_initializer(ToyParser* p, CfreeCgLocal slot, toy_error(p, p->cur.loc, "too many array elements"); return 0; } - toy_push_local_indexed(p, slot, index); + toy_push_local_indexed(p, slot, elem_ty, index); + cfree_cg_elem(p->cg, 0); expr_ty = toy_parse_expr(p); if (expr_ty == CFREE_CG_TYPE_NONE) return 0; if (!toy_check_source_value(p, elem_ty, elem_toy_type, expr_ty, @@ -167,9 +173,7 @@ static int toy_parse_array_initializer(ToyParser* p, CfreeCgLocal slot, return 0; } if (expr_ty != elem_ty) cfree_cg_bitcast(p->cg, elem_ty); - cfree_cg_store( - p->cg, toy_mem_access(p, elem_ty), - (CfreeCgEffAddr){0, (uint32_t)cfree_cg_type_size(p->c, elem_ty)}); + cfree_cg_store(p->cg, toy_mem_access(p, elem_ty)); index++; if (!toy_parser_match(p, TOK_COMMA)) break; } @@ -178,11 +182,10 @@ static int toy_parse_array_initializer(ToyParser* p, CfreeCgLocal slot, return 0; } while (index < count) { - toy_push_local_indexed(p, slot, index); + toy_push_local_indexed(p, slot, elem_ty, index); + cfree_cg_elem(p->cg, 0); cfree_cg_push_int(p->cg, 0, elem_ty); - cfree_cg_store( - p->cg, toy_mem_access(p, elem_ty), - (CfreeCgEffAddr){0, (uint32_t)cfree_cg_type_size(p->c, elem_ty)}); + cfree_cg_store(p->cg, toy_mem_access(p, elem_ty)); index++; } return 1; @@ -207,9 +210,10 @@ static int toy_parse_record_initializer(ToyParser* p, CfreeCgLocal slot, if (cfree_cg_type_record_field(p->c, record_ty, i, &field, &foff) != 0) return 0; cfree_cg_push_local(p->cg, slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)foff); cfree_cg_push_int(p->cg, 0, field.type); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)foff, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); } if (positional) { @@ -226,6 +230,8 @@ static int toy_parse_record_initializer(ToyParser* p, CfreeCgLocal slot, &foff) != 0) return 0; cfree_cg_push_local(p->cg, slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)foff); expr_ty = toy_parse_expr(p); if (expr_ty == CFREE_CG_TYPE_NONE) return 0; { @@ -239,8 +245,7 @@ static int toy_parse_record_initializer(ToyParser* p, CfreeCgLocal slot, } } if (expr_ty != field.type) cfree_cg_bitcast(p->cg, field.type); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)foff, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); field_index++; if (!toy_parser_match(p, TOK_COMMA)) break; } @@ -276,6 +281,8 @@ static int toy_parse_record_initializer(ToyParser* p, CfreeCgLocal slot, 0) return 0; cfree_cg_push_local(p->cg, slot); + cfree_cg_addr(p->cg); + cfree_cg_deref(p->cg, (int64_t)foff); expr_ty = toy_parse_expr(p); if (expr_ty == CFREE_CG_TYPE_NONE) return 0; { @@ -288,8 +295,7 @@ static int toy_parse_record_initializer(ToyParser* p, CfreeCgLocal slot, } } if (expr_ty != field.type) cfree_cg_bitcast(p->cg, field.type); - cfree_cg_store(p->cg, toy_mem_access(p, field.type), - (CfreeCgEffAddr){(int64_t)foff, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, field.type)); if (!toy_parser_match(p, TOK_COMMA)) break; } if (!toy_parser_expect(p, TOK_RBRACE)) { @@ -370,7 +376,7 @@ static int toy_parse_value_block_body_to_local(ToyParser* p, CfreeCgLocal slot, if (arm_ty != result_ty) cfree_cg_bitcast(p->cg, result_ty); cfree_cg_push_local(p->cg, slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, result_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, result_ty)); if (!toy_parser_expect(p, TOK_RBRACE)) { toy_error(p, p->cur.loc, "expected '}' after value block"); p->nvars = saved_nvars; @@ -456,7 +462,7 @@ static int toy_parse_switch_initializer(ToyParser* p, CfreeCgLocal slot, selector_slot = cfree_cg_local(p->cg, selector_ty, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, selector_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, selector_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, selector_ty)); end_label = cfree_cg_label_new(p->cg); dispatch_label = cfree_cg_label_new(p->cg); /* Skip the arm bodies on entry; come back through the dispatch label. */ @@ -539,7 +545,7 @@ static int toy_parse_switch_initializer(ToyParser* p, CfreeCgLocal slot, } cfree_cg_label_place(p->cg, dispatch_label); cfree_cg_push_local(p->cg, selector_slot); - cfree_cg_load(p->cg, toy_mem_access(p, selector_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, selector_ty)); if (saw_default) { sw.default_label = default_arm_label; } else { @@ -648,7 +654,7 @@ static int toy_parse_while_initializer_named(ToyParser* p, CfreeCgLocal slot, p->nscopes--; cfree_cg_push_local(p->cg, slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, result_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, result_ty)); return 1; } @@ -836,7 +842,7 @@ static int toy_parse_let_stmt(ToyParser* p) { if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0; cfree_cg_push_local(p->cg, slot); cfree_cg_push_int(p->cg, (uint64_t)value, ty); - cfree_cg_store(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after let"); return 0; @@ -954,7 +960,7 @@ static int toy_parse_let_stmt(ToyParser* p) { } else { cfree_cg_push_local(p->cg, slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); } } if (!toy_parser_expect(p, TOK_SEMI)) { @@ -1059,7 +1065,7 @@ static int toy_parse_switch_stmt_named(ToyParser* p, CfreeSym label_name) { selector_slot = cfree_cg_local(p->cg, selector_ty, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, selector_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, selector_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, selector_ty)); end_label = cfree_cg_label_new(p->cg); dispatch_label = cfree_cg_label_new(p->cg); if (!toy_parser_reserve(p, (void**)&p->scopes, &p->cap_scopes, @@ -1124,7 +1130,7 @@ static int toy_parse_switch_stmt_named(ToyParser* p, CfreeSym label_name) { } cfree_cg_label_place(p->cg, dispatch_label); cfree_cg_push_local(p->cg, selector_slot); - cfree_cg_load(p->cg, toy_mem_access(p, selector_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, selector_ty)); sw.selector_type = selector_ty; sw.default_label = default_arm_label != CFREE_CG_LABEL_NONE ? default_arm_label : end_label; @@ -1427,8 +1433,7 @@ static int toy_parse_return_stmt(ToyParser* p) { } } cfree_cg_push_local(p->cg, slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->cur_fn_ret), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->cur_fn_ret)); cfree_cg_ret(p->cg); if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after return"); @@ -1579,13 +1584,13 @@ static int toy_parse_stmt(ToyParser* p) { cfree_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, idx_slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); - cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty), - (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); + /* TOS is the chain pointer VALUE (**T); deref to a PLACE and + * load the inner pointer it addresses. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty)); cfree_cg_push_local(p->cg, idx_slot); - cfree_cg_load(p->cg, toy_mem_access(p, p->int_type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); } if (cfree_cg_type_kind(p->c, pointee) == CFREE_CG_TYPE_ARRAY) { CfreeCgTypeId elem_ty = cfree_cg_type_array_elem(p->c, pointee); @@ -1621,8 +1626,9 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "cannot dereference non-pointer"); return 0; } - /* TOS = `**T`; load to TOS = `*T`. */ - cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty), (CfreeCgEffAddr){0, 0}); + /* TOS = `**T` (pointer VALUE); deref to PLACE and load to `*T`. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty)); lhs_ty = cfree_cg_type_ptr_pointee(p->c, lhs_ty); lhs_toy_type = toy_type_pointee(p, lhs_toy_type); continue; @@ -1635,9 +1641,10 @@ static int toy_parse_stmt(ToyParser* p) { if (cfree_cg_type_kind(p->c, lhs_ty) == CFREE_CG_TYPE_PTR && cfree_cg_type_kind(p->c, cfree_cg_type_ptr_pointee(p->c, lhs_ty)) == CFREE_CG_TYPE_RECORD) { - /* `p.field`: load the pointer value to address the record. */ - cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty), - (CfreeCgEffAddr){0, 0}); + /* `p.field`: deref to PLACE and load the pointer value that + * addresses the record. */ + cfree_cg_deref(p->cg, 0); + cfree_cg_load(p->cg, toy_mem_access(p, lhs_ty)); lhs_ty = cfree_cg_type_ptr_pointee(p->c, lhs_ty); lhs_toy_type = toy_type_pointee(p, lhs_toy_type); } @@ -1700,6 +1707,9 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "cannot assign to slice metadata"); return 0; } + /* The address chain leaves a pointer VALUE (`*lhs_ty`) on the stack; turn + * it into a PLACE before pushing the rhs so store sees [place, value]. */ + cfree_cg_deref(p->cg, 0); { CfreeCgTypeId expr_ty = toy_parse_expr(p); ToyTypeId expr_toy_type = p->last_type; @@ -1714,7 +1724,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "type mismatch in assignment"); return 0; } - cfree_cg_store(p->cg, toy_mem_access(p, lhs_ty), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, lhs_ty)); } if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after assignment"); @@ -1751,10 +1761,10 @@ static int toy_parse_stmt(ToyParser* p) { return 1; } toy_push_var_lvalue(p, v); + cfree_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */ cfree_cg_swap(p->cg); if (expr_ty != v->type) cfree_cg_bitcast(p->cg, v->type); - cfree_cg_store(p->cg, toy_mem_access(p, v->type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, v->type)); } else { ToyGlobal* g = toy_find_global(p, name); if (!g) { @@ -1779,10 +1789,10 @@ static int toy_parse_stmt(ToyParser* p) { return 1; } cfree_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0); + cfree_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */ cfree_cg_swap(p->cg); if (expr_ty != g->type) cfree_cg_bitcast(p->cg, g->type); - cfree_cg_store(p->cg, toy_mem_access(p, g->type), - (CfreeCgEffAddr){0, 0}); + cfree_cg_store(p->cg, toy_mem_access(p, g->type)); } } if (!toy_parser_expect(p, TOK_SEMI)) { diff --git a/lang/toy/symbols.c b/lang/toy/symbols.c @@ -165,14 +165,18 @@ ToyScope* toy_find_innermost_loop_scope(ToyParser* p) { return NULL; } -/* Pushes a base operand suitable for the canonical memops: for a frame-local - * this is the lvalue; for a static-local this is the symbol address (the - * memop accepts both shapes as `base`). */ +/* Pushes the variable's address as a pointer VALUE for the chained-memop + * paths: a frame-local yields `push_local_addr`, a static-local yields its + * symbol address. Callers turn the pointer into a PLACE with `cfree_cg_deref` + * (offset 0 for the whole object) before a load/store, and compose field / + * index selectors on the pointer with the address-chain helpers. This keeps a + * single uniform shape (pointer VALUE) regardless of storage class, matching + * the `push_symbol_addr` shape used for globals. */ void toy_push_var_lvalue(ToyParser* p, const ToyVar* v) { if (v->is_static) cfree_cg_push_symbol_addr(p->cg, v->static_sym, 0); else - cfree_cg_push_local(p->cg, v->local); + cfree_cg_push_local_addr(p->cg, v->local); } void toy_push_var_addr(ToyParser* p, const ToyVar* v) { diff --git a/lang/wasm/cg.c b/lang/wasm/cg.c @@ -35,15 +35,6 @@ static CfreeCgMemAccess wasm_cg_mem_type(CfreeCgTypeId ty) { return mem; } -/* Convenience: zero effective-address (no offset, no index). Used for - * load/store on a base TOS that already represents the exact address. */ -static CfreeCgEffAddr wasm_cg_ea0(void) { - CfreeCgEffAddr ea; - ea.offset = 0; - ea.scale = 0; - return ea; -} - static void wasm_cg_push_zero(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, WasmValType vt) { CfreeCgTypeId ty = wasm_cg_type(c, b, vt); @@ -502,14 +493,16 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, * Stack: [] -> [void*]. Callers fold a struct offset into the memop's EA. */ static void wasm_cg_push_instance_ptr(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { - CfreeCgEffAddr ea = {0, 0}; cfree_cg_push_local(cg, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty), ea); + cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty)); } +/* Push the instance as a record PLACE (the pointee of the instance pointer). + * Stack: [] -> [place]. Callers project struct fields off it with field/elem. */ static void wasm_cg_push_instance_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { wasm_cg_push_instance_ptr(cg, rt, instance_local); + cfree_cg_deref(cg, 0); } /* Add a constant byte offset to the pointer rvalue on TOS, retyping to @@ -532,11 +525,9 @@ static void wasm_cg_ptr_add_offset(CfreeCg* cg, CfreeCgBuiltinTypes b, static void wasm_cg_push_memory_data_ptr(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local, uint32_t memidx) { - CfreeCgEffAddr ea; - ea.offset = (int64_t)(rt->memory_offset[memidx] + rt->memory_data_offset); - ea.scale = 0; wasm_cg_push_instance_ptr(cg, rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->i8_ptr_ty), ea); + cfree_cg_deref(cg, (int64_t)(rt->memory_offset[memidx] + rt->memory_data_offset)); + cfree_cg_load(cg, wasm_cg_mem_type(rt->i8_ptr_ty)); } static void wasm_cg_push_memory_pages_lvalue(CfreeCg* cg, @@ -552,12 +543,11 @@ static void wasm_cg_push_memory_pages_lvalue(CfreeCg* cg, static void wasm_cg_push_import_func_ptr(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local, uint32_t func_index) { - CfreeCgEffAddr ea; - ea.offset = - (int64_t)(rt->func_import_offset[func_index] + rt->func_import_fn_offset); - ea.scale = 0; wasm_cg_push_instance_ptr(cg, rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty), ea); + cfree_cg_deref( + cg, + (int64_t)(rt->func_import_offset[func_index] + rt->func_import_fn_offset)); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); } /* Push a pointer rvalue to instance->globals[global_index]'s value cell, @@ -572,12 +562,10 @@ static void wasm_cg_push_global_value_ptr(CfreeCompiler* c, CfreeCg* cg, CfreeCgTypeId ptr_ty = cfree_cg_type_ptr( c, wasm_cg_type(c, b, m->globals[global_index].type), 0); if (m->globals[global_index].is_import) { - CfreeCgEffAddr ea; - ea.offset = (int64_t)(rt->global_offset[global_index] + - rt->global_import_addr_offset); - ea.scale = 0; wasm_cg_push_instance_ptr(cg, rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty), ea); + cfree_cg_deref(cg, (int64_t)(rt->global_offset[global_index] + + rt->global_import_addr_offset)); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); cfree_cg_dup(cg); cfree_cg_push_null(cg, rt->void_ptr_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); @@ -609,10 +597,10 @@ static void wasm_cg_push_table_entry_lvalue(CfreeCg* cg, CfreeCgMemAccess index_mem) { wasm_cg_push_table_lvalue(cg, rt, instance_local, table_index); cfree_cg_field(cg, rt->table_entries_ptr_field); - cfree_cg_load(cg, wasm_cg_mem_type(rt->table_entry_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt->table_entry_ptr_ty)); cfree_cg_push_local(cg, index_local); - cfree_cg_load(cg, index_mem, wasm_cg_ea0()); - cfree_cg_index(cg, 0); + cfree_cg_load(cg, index_mem); + cfree_cg_elem(cg, 0); } /* Push a pointer rvalue to instance->tables[table_index].entries[index_local]. @@ -624,19 +612,17 @@ static void wasm_cg_push_table_entry_ptr(CfreeCg* cg, CfreeCgBuiltinTypes b, uint32_t table_index, CfreeCgLocal index_local, CfreeCgMemAccess index_mem) { - CfreeCgEffAddr ea; - CfreeCgEffAddr ea_idx = {0, 0}; CfreeCgTypeId i64_ty = b.id[CFREE_CG_BUILTIN_I64]; /* Load entries pointer from instance->tables[i].entries. */ - ea.offset = - (int64_t)(rt->table_offset[table_index] + rt->table_entries_ptr_offset); - ea.scale = 0; wasm_cg_push_instance_ptr(cg, rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->table_entry_ptr_ty), ea); + cfree_cg_deref( + cg, + (int64_t)(rt->table_offset[table_index] + rt->table_entries_ptr_offset)); + cfree_cg_load(cg, wasm_cg_mem_type(rt->table_entry_ptr_ty)); /* Compute entries + index * sizeof(entry) into a pointer rvalue. */ cfree_cg_ptr_to_int(cg, i64_ty); cfree_cg_push_local(cg, index_local); - cfree_cg_load(cg, index_mem, ea_idx); + cfree_cg_load(cg, index_mem); cfree_cg_zext(cg, i64_ty); cfree_cg_push_int(cg, rt->table_entry_size, i64_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); @@ -675,7 +661,6 @@ static void wasm_cg_memory_check(CfreeCompiler* c, CfreeCg* cg, uint32_t width = wasm_mem_width(in->kind); uint64_t end = in->offset64 + width; CfreeCgLabel ok = cfree_cg_label_new(cg); - CfreeCgEffAddr pages_ea; uint32_t max_pages = (uint32_t)(m->memories[in->memidx].has_max ? m->memories[in->memidx].max_pages : m->memories[in->memidx].min_pages); @@ -685,11 +670,10 @@ static void wasm_cg_memory_check(CfreeCompiler* c, CfreeCg* cg, } (void)c; cfree_cg_dup(cg); - pages_ea.offset = - (int64_t)(rt->memory_offset[in->memidx] + rt->memory_pages_offset); - pages_ea.scale = 0; wasm_cg_push_instance_ptr(cg, rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), pages_ea); + cfree_cg_deref( + cg, (int64_t)(rt->memory_offset[in->memidx] + rt->memory_pages_offset)); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); cfree_cg_push_int(cg, end, b.id[CFREE_CG_BUILTIN_I64]); @@ -739,24 +723,24 @@ static void wasm_cg_rotate(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, lhs = cfree_cg_local(cg, ty, attrs); cfree_cg_push_local(cg, rhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, lhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, mask, ty); cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); cfree_cg_int_binop(cg, right ? CFREE_CG_INT_LSHR : CFREE_CG_INT_SHL, 0); cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 0, ty); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_push_int(cg, mask, ty); cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); @@ -779,12 +763,12 @@ static void wasm_cg_checked_divrem(CfreeCompiler* c, CfreeCg* cg, lhs = cfree_cg_local(cg, ty, attrs); cfree_cg_push_local(cg, rhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, lhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 0, ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, ok); @@ -795,12 +779,12 @@ static void wasm_cg_checked_divrem(CfreeCompiler* c, CfreeCg* cg, uint64_t min_val = vt == WASM_VAL_I32 ? UINT64_C(0x80000000) : UINT64_C(0x8000000000000000); cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, min_val, ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, no_overflow); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, UINT64_MAX, ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, no_overflow); @@ -808,9 +792,9 @@ static void wasm_cg_checked_divrem(CfreeCompiler* c, CfreeCg* cg, cfree_cg_label_place(cg, no_overflow); } cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_int_binop(cg, op, 0); } @@ -840,25 +824,25 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, abs_bits = cfree_cg_local(cg, bit_ty, attrs); cfree_cg_push_local(cg, value); cfree_cg_swap(cg); - cfree_cg_store(cg, src_mem, wasm_cg_ea0()); + cfree_cg_store(cg, src_mem); cfree_cg_push_local(cg, bits); cfree_cg_push_local(cg, value); - cfree_cg_load(cg, src_mem, wasm_cg_ea0()); + cfree_cg_load(cg, src_mem); cfree_cg_bitcast(cg, bit_ty); - cfree_cg_store(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_store(cg, bit_mem); cfree_cg_push_local(cg, abs_bits); cfree_cg_push_local(cg, bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, abs_mask, bit_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); - cfree_cg_store(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_store(cg, bit_mem); { CfreeCgLabel finite = cfree_cg_label_new(cg); cfree_cg_push_local(cg, abs_bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, inf_bits, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); cfree_cg_branch_true(cg, finite); @@ -883,12 +867,12 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, if (is_unsigned) { CfreeCgLabel nonnegative = cfree_cg_label_new(cg); cfree_cg_push_local(cg, abs_bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, 0, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, nonnegative); cfree_cg_push_local(cg, bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, sign_mask, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, nonnegative); @@ -898,7 +882,7 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, { CfreeCgLabel in_range = cfree_cg_label_new(cg); cfree_cg_push_local(cg, abs_bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, limit_bits, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, in_range); @@ -909,19 +893,19 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, CfreeCgLabel negative = cfree_cg_label_new(cg); CfreeCgLabel in_range = cfree_cg_label_new(cg); cfree_cg_push_local(cg, bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, sign_mask, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, negative); cfree_cg_push_local(cg, abs_bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, limit_bits, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, in_range); wasm_cg_trap_invalid_conversion(cg, rt); cfree_cg_label_place(cg, negative); cfree_cg_push_local(cg, abs_bits); - cfree_cg_load(cg, bit_mem, wasm_cg_ea0()); + cfree_cg_load(cg, bit_mem); cfree_cg_push_int(cg, limit_bits, bit_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); cfree_cg_branch_true(cg, in_range); @@ -930,7 +914,7 @@ static void wasm_cg_checked_trunc(CfreeCompiler* c, CfreeCg* cg, } cfree_cg_push_local(cg, value); - cfree_cg_load(cg, src_mem, wasm_cg_ea0()); + cfree_cg_load(cg, src_mem); if (is_unsigned) cfree_cg_float_to_uint(cg, dst_ty, CFREE_CG_ROUND_TOWARD_ZERO); else @@ -1010,30 +994,30 @@ static void wasm_cg_call_func(CfreeCompiler* c, CfreeCg* cg, cfree_cg_local(cg, wasm_cg_type(c, b, f->params[param]), attrs); cfree_cg_push_local(cg, args[param]); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, f->params[param]), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, f->params[param])); } if (f->is_import) { CfreeCgLabel ok = cfree_cg_label_new(cg); callee = cfree_cg_local(cg, rt->void_ptr_ty, attrs); cfree_cg_push_local(cg, callee); wasm_cg_push_import_func_ptr(cg, rt, instance_local, func_index); - cfree_cg_store(cg, wasm_cg_mem_type(rt->void_ptr_ty), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(rt->void_ptr_ty)); cfree_cg_push_local(cg, callee); - cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); cfree_cg_push_null(cg, rt->void_ptr_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, ok); wasm_cg_trap_table(cg, rt); cfree_cg_label_place(cg, ok); cfree_cg_push_local(cg, callee); - cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, func_type, 0)); } cfree_cg_push_local(cg, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty)); for (uint32_t p = 0; p < f->nparams; ++p) { cfree_cg_push_local(cg, args[p]); - cfree_cg_load(cg, wasm_cg_mem(c, b, f->params[p]), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, f->params[p])); } if (f->is_import) cfree_cg_call( @@ -1276,20 +1260,20 @@ static void wasm_cg_bulk_bounds_check(CfreeCg* cg, CfreeCgBuiltinTypes b, * overflow. First check size >= addr. */ CfreeCgLabel addr_ok = cfree_cg_label_new(cg); cfree_cg_push_local(cg, size_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, addr_ok); wasm_cg_trap_bounds(cg, rt); cfree_cg_label_place(cg, addr_ok); cfree_cg_push_local(cg, size_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, ok); wasm_cg_trap_bounds(cg, rt); @@ -1324,7 +1308,7 @@ static void wasm_cg_emit_byte_copy_loop(CfreeCg* cg, CfreeCgBuiltinTypes b, (void)ptr_mem; /* If n == 0, nothing to do. */ cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, done); @@ -1335,101 +1319,99 @@ static void wasm_cg_emit_byte_copy_loop(CfreeCg* cg, CfreeCgBuiltinTypes b, * ? backward : forward. */ cfree_cg_push_local(cg, dir); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); - cfree_cg_store(cg, wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I32]), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I32])); cfree_cg_push_local(cg, dir); - cfree_cg_load(cg, wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I32]), - wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I32])); cfree_cg_branch_false(cg, forward); cfree_cg_push_local(cg, dst_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, src_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GT_U); cfree_cg_branch_false(cg, forward); /* Backward loop: idx = n - 1, while idx >= 0 then idx-- (stop at 0). */ cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); + cfree_cg_store(cg, i64_mem); { CfreeCgLabel back_loop = cfree_cg_label_new(cg); cfree_cg_label_place(cg, back_loop); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, done); /* idx-- */ cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); /* dst_base[dst_addr + idx] = src_base[src_addr + idx] */ cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); - cfree_cg_load(cg, i8_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i8_mem, wasm_cg_ea0()); + cfree_cg_elem(cg, 0); + cfree_cg_load(cg, i8_mem); + cfree_cg_store(cg, i8_mem); cfree_cg_jump(cg, back_loop); } cfree_cg_label_place(cg, forward); /* Forward loop: idx = 0; while idx < n then dst[idx]=src[idx]; idx++. */ cfree_cg_push_local(cg, idx); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_jump(cg, after_dir); cfree_cg_label_place(cg, after_dir); cfree_cg_label_place(cg, loop_start); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, done); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); - cfree_cg_load(cg, i8_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i8_mem, wasm_cg_ea0()); + cfree_cg_elem(cg, 0); + cfree_cg_load(cg, i8_mem); + cfree_cg_store(cg, i8_mem); cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_jump(cg, loop_start); cfree_cg_label_place(cg, done); } @@ -1455,32 +1437,32 @@ static void wasm_cg_emit_byte_fill_loop(CfreeCg* cg, CfreeCgBuiltinTypes b, idx = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I64], attrs); cfree_cg_push_local(cg, idx); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_label_place(cg, loop_start); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, done); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_addr_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_push_local(cg, val_local); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I8]); - cfree_cg_store(cg, i8_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i8_mem); cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_jump(cg, loop_start); cfree_cg_label_place(cg, done); } @@ -1506,145 +1488,145 @@ static void wasm_cg_emit_table_copy_loop( idx = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I64], attrs); dir = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, done); /* dir = (dst_base == src_base) ? (dst_idx > src_idx) : 0 */ cfree_cg_push_local(cg, dir); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, dir); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_branch_false(cg, forward); cfree_cg_push_local(cg, dst_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, src_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GT_U); cfree_cg_branch_false(cg, forward); { CfreeCgLabel back_loop = cfree_cg_label_new(cg); cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); + cfree_cg_store(cg, i64_mem); cfree_cg_label_place(cg, back_loop); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, done); cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); /* copy fn and typeidx fields */ cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_fn_field); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_fn_field); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_typeidx_field); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_typeidx_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_jump(cg, back_loop); } cfree_cg_label_place(cg, forward); cfree_cg_push_local(cg, idx); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_label_place(cg, loop_start); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, n_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, done); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_fn_field); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_fn_field); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); cfree_cg_push_local(cg, dst_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, dst_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_typeidx_field); cfree_cg_push_local(cg, src_base_local); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); cfree_cg_push_local(cg, src_idx_local); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_field(cg, rt->table_entry_typeidx_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, idx); cfree_cg_push_local(cg, idx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_jump(cg, loop_start); cfree_cg_label_place(cg, done); } @@ -1786,20 +1768,21 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, const WasmMemory* mem = &m->memories[i]; uint64_t max_pages = mem->has_max ? mem->max_pages : mem->min_pages; uint32_t flags = (mem->shared ? 1u : 0u) | (mem->is64 ? 2u : 0u); - CfreeCgEffAddr ea; - ea.scale = 0; - ea.offset = (int64_t)(rt.memory_offset[i] + rt.memory_pages_offset); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, + (int64_t)(rt.memory_offset[i] + rt.memory_pages_offset)); cfree_cg_push_int(cg, mem->min_pages, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea); - ea.offset = (int64_t)(rt.memory_offset[i] + rt.memory_max_pages_offset); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref( + cg, (int64_t)(rt.memory_offset[i] + rt.memory_max_pages_offset)); cfree_cg_push_int(cg, max_pages, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea); - ea.offset = (int64_t)(rt.memory_offset[i] + rt.memory_flags_offset); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, + (int64_t)(rt.memory_offset[i] + rt.memory_flags_offset)); cfree_cg_push_int(cg, flags, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), ea); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); /* For each active data segment targeting this memory, memcpy its * bytes into the linear memory at the segment's offset. Passive * segments are not initialized here — they're consumed by an @@ -1838,53 +1821,51 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, } else { cfree_cg_push_null(cg, rt.i8_ptr_ty); } - cfree_cg_store(cg, wasm_cg_mem_type(rt.i8_ptr_ty), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(rt.i8_ptr_ty)); wasm_cg_push_passive_data_lvalue(cg, &rt, instance_local, di); cfree_cg_field(cg, rt.passive_data_len_field); cfree_cg_push_int(cg, (d->mode == WASM_SEG_PASSIVE) ? d->nbytes : 0u, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); } for (i = 0; i < m->nfuncs; ++i) { - CfreeCgEffAddr ea; - ea.scale = 0; - ea.offset = - (int64_t)(rt.func_ref_entry_offset[i] + rt.table_entry_fn_offset); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref( + cg, + (int64_t)(rt.func_ref_entry_offset[i] + rt.table_entry_fn_offset)); if (m->funcs[i].is_import) { wasm_cg_push_import_func_ptr(cg, &rt, instance_local, i); } else { cfree_cg_push_symbol_addr(cg, syms[i], 0); cfree_cg_bitcast(cg, rt.void_ptr_ty); } - cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty), ea); - ea.offset = (int64_t)(rt.func_ref_entry_offset[i] + - rt.table_entry_typeidx_offset); + cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, (int64_t)(rt.func_ref_entry_offset[i] + + rt.table_entry_typeidx_offset)); cfree_cg_push_int(cg, m->funcs[i].typeidx, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), ea); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); } for (i = 0; i < m->ntables; ++i) { const WasmTable* t = &m->tables[i]; uint32_t max = t->has_max ? t->max : t->min; - CfreeCgEffAddr ea; - ea.scale = 0; /* tables[i].entries = &instance->table_entries_arr[i][0]. The address * of the entries array is instance + table_entries_offset[i]. */ - ea.offset = (int64_t)(rt.table_offset[i] + rt.table_entries_ptr_offset); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref( + cg, (int64_t)(rt.table_offset[i] + rt.table_entries_ptr_offset)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); wasm_cg_ptr_add_offset(cg, b, rt.table_entries_offset[i], rt.table_entry_ptr_ty); - cfree_cg_store(cg, wasm_cg_mem_type(rt.table_entry_ptr_ty), ea); - ea.offset = (int64_t)(rt.table_offset[i] + rt.table_len_offset); + cfree_cg_store(cg, wasm_cg_mem_type(rt.table_entry_ptr_ty)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, (int64_t)(rt.table_offset[i] + rt.table_len_offset)); cfree_cg_push_int(cg, t->min, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), ea); - ea.offset = (int64_t)(rt.table_offset[i] + rt.table_max_offset); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, (int64_t)(rt.table_offset[i] + rt.table_max_offset)); cfree_cg_push_int(cg, max, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), ea); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); } for (i = 0; i < m->nelems; ++i) { const WasmElemSegment* seg = &m->elems[i]; @@ -1903,7 +1884,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_int(cg, (uint32_t)(seg->offset + j), b.id[CFREE_CG_BUILTIN_I32]); } - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); /* Resolve the target table-entry lvalue: active segments write into * the module's table; passive segments write into the per-segment * inline storage array so the bytes survive instantiation for @@ -1911,9 +1892,11 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, if (is_passive) { wasm_cg_push_passive_elem_storage_array_lvalue(cg, &rt, instance_local, i); + cfree_cg_addr(cg); + cfree_cg_bitcast(cg, rt.table_entry_ptr_ty); cfree_cg_push_local(cg, slot_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); - cfree_cg_index(cg, 0); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_elem(cg, 0); } else { wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, seg->tableidx, slot_local, @@ -1926,13 +1909,15 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_symbol_addr(cg, syms[funcidx], 0); cfree_cg_bitcast(cg, rt.void_ptr_ty); } - cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty)); if (is_passive) { wasm_cg_push_passive_elem_storage_array_lvalue(cg, &rt, instance_local, i); + cfree_cg_addr(cg); + cfree_cg_bitcast(cg, rt.table_entry_ptr_ty); cfree_cg_push_local(cg, slot_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); - cfree_cg_index(cg, 0); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_elem(cg, 0); } else { wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, seg->tableidx, slot_local, @@ -1941,7 +1926,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_field(cg, rt.table_entry_typeidx_field); cfree_cg_push_int(cg, m->funcs[funcidx].typeidx, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); } /* Initialize the passive_elem descriptor (entries pointer + length). * Active segments get a zero-length descriptor so table.init on an @@ -1951,33 +1936,32 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, if (is_passive && seg->nfuncs) { wasm_cg_push_passive_elem_storage_array_lvalue(cg, &rt, instance_local, i); + cfree_cg_addr(cg); + cfree_cg_bitcast(cg, rt.table_entry_ptr_ty); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_index(cg, 0); + cfree_cg_elem(cg, 0); cfree_cg_addr(cg); } else { cfree_cg_push_null(cg, rt.table_entry_ptr_ty); } - cfree_cg_store(cg, wasm_cg_mem_type(rt.table_entry_ptr_ty), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(rt.table_entry_ptr_ty)); wasm_cg_push_passive_elem_lvalue(cg, &rt, instance_local, i); cfree_cg_field(cg, rt.passive_elem_length_field); cfree_cg_push_int(cg, is_passive ? seg->nfuncs : 0u, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); } for (i = 0; i < m->nglobals; ++i) { const WasmGlobal* g = &m->globals[i]; - CfreeCgEffAddr ea; if (g->is_import) continue; - ea.scale = 0; - ea.offset = (int64_t)rt.global_offset[i]; wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref(cg, (int64_t)rt.global_offset[i]); if (g->type == WASM_VAL_F32 || g->type == WASM_VAL_F64) cfree_cg_push_float(cg, g->init.fp, wasm_cg_type(c, b, g->type)); else cfree_cg_push_int(cg, (uint64_t)g->init.imm, wasm_cg_type(c, b, g->type)); - cfree_cg_store(cg, wasm_cg_mem(c, b, g->type), ea); + cfree_cg_store(cg, wasm_cg_mem(c, b, g->type)); } if (m->has_start) wasm_cg_call_func(c, cg, b, &m->funcs[m->start_func], &rt, @@ -2040,7 +2024,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_local(cg, wasm_cg_type(c, b, f->locals[j]), attrs); cfree_cg_push_local(cg, locals[f->nparams + j]); wasm_cg_push_zero(c, cg, b, f->locals[j]); - cfree_cg_store(cg, wasm_cg_mem(c, b, f->locals[j]), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, f->locals[j])); } for (j = 0; j < f->ninsns; ++j) { WasmInsn in = f->insns[j]; @@ -2188,30 +2172,30 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, cond); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); cfree_cg_push_local(cg, rhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, lhs); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, cond); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); cfree_cg_branch_false(cg, else_label); cfree_cg_push_local(cg, result); cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); cfree_cg_jump(cg, end_label); cfree_cg_label_place(cg, else_label); cfree_cg_push_local(cg, result); cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem, wasm_cg_ea0()); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); cfree_cg_label_place(cg, end_label); cfree_cg_push_local(cg, result); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); } break; case WASM_INSN_I32_CONST: cfree_cg_push_int(cg, (uint64_t)(uint32_t)in.imm, @@ -2229,16 +2213,14 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, case WASM_INSN_LOCAL_GET: { uint32_t index = (uint32_t)in.imm; cfree_cg_push_local(cg, locals[index]); - cfree_cg_load(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index)), - wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); break; } case WASM_INSN_LOCAL_SET: { uint32_t index = (uint32_t)in.imm; cfree_cg_push_local(cg, locals[index]); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index)), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); break; } case WASM_INSN_LOCAL_TEE: { @@ -2246,8 +2228,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_dup(cg); cfree_cg_push_local(cg, locals[index]); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index)), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); break; } case WASM_INSN_CALL: @@ -2294,27 +2275,24 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_local(cg, wasm_cg_type(c, b, t->results[0]), attrs); cfree_cg_push_local(cg, selector); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); for (uint32_t p = 0; p < t->nparams; ++p) { uint32_t param = t->nparams - 1u - p; args[param] = cfree_cg_local(cg, wasm_cg_type(c, b, t->params[param]), attrs); cfree_cg_push_local(cg, args[param]); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param]), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param])); } ok = cfree_cg_label_new(cg); cfree_cg_push_local(cg, selector); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); { - CfreeCgEffAddr ea_len; - ea_len.scale = 0; - ea_len.offset = - (int64_t)(rt.table_offset[in.align] + rt.table_len_offset); wasm_cg_push_instance_ptr(cg, &rt, instance_local); - cfree_cg_load(cg, i32_mem, ea_len); + cfree_cg_deref( + cg, (int64_t)(rt.table_offset[in.align] + rt.table_len_offset)); + cfree_cg_load(cg, i32_mem); } cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, ok); @@ -2326,14 +2304,12 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, wasm_cg_push_table_entry_ptr(cg, b, &rt, instance_local, in.align, selector, i32_mem); { - CfreeCgEffAddr ea_fn; - ea_fn.scale = 0; - ea_fn.offset = (int64_t)rt.table_entry_fn_offset; - cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty), ea_fn); + cfree_cg_deref(cg, (int64_t)rt.table_entry_fn_offset); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); } - cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty)); cfree_cg_push_local(cg, callee); - cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); cfree_cg_push_null(cg, rt.void_ptr_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, ok); @@ -2344,10 +2320,8 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, wasm_cg_push_table_entry_ptr(cg, b, &rt, instance_local, in.align, selector, i32_mem); { - CfreeCgEffAddr ea_ti; - ea_ti.scale = 0; - ea_ti.offset = (int64_t)rt.table_entry_typeidx_offset; - cfree_cg_load(cg, i32_mem, ea_ti); + cfree_cg_deref(cg, (int64_t)rt.table_entry_typeidx_offset); + cfree_cg_load(cg, i32_mem); } cfree_cg_push_int(cg, (uint32_t)in.imm, b.id[CFREE_CG_BUILTIN_I32]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); @@ -2356,14 +2330,13 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_label_place(cg, ok); cfree_cg_push_local(cg, callee); - cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, indirect_func_type, 0)); cfree_cg_push_local(cg, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty), - wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty)); for (uint32_t p = 0; p < t->nparams; ++p) { cfree_cg_push_local(cg, args[p]); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p]), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p])); } cfree_cg_call(cg, t->nparams + 1u, indirect_func_type, (CfreeCgCallAttrs){ @@ -2376,9 +2349,9 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, } else if (t->nresults) { cfree_cg_push_local(cg, result); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0]), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0])); cfree_cg_push_local(cg, result); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0]), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0])); } break; } @@ -2415,19 +2388,18 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, callee = cfree_cg_local(cg, rt.void_ptr_ty, attrs); cfree_cg_push_local(cg, callee_ref); cfree_cg_swap(cg); - cfree_cg_store(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ref_mem); for (uint32_t p = 0; p < t->nparams; ++p) { uint32_t param = t->nparams - 1u - p; args[param] = cfree_cg_local(cg, wasm_cg_type(c, b, t->params[param]), attrs); cfree_cg_push_local(cg, args[param]); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param]), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param])); } ok = cfree_cg_label_new(cg); cfree_cg_push_local(cg, callee_ref); - cfree_cg_load(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ref_mem); cfree_cg_push_null(cg, rt.void_ptr_ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, ok); @@ -2436,13 +2408,11 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, ok = cfree_cg_label_new(cg); cfree_cg_push_local(cg, callee_ref); - cfree_cg_load(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ref_mem); cfree_cg_bitcast(cg, rt.table_entry_ptr_ty); { - CfreeCgEffAddr ea_ti; - ea_ti.scale = 0; - ea_ti.offset = (int64_t)rt.table_entry_typeidx_offset; - cfree_cg_load(cg, i32_mem, ea_ti); + cfree_cg_deref(cg, (int64_t)rt.table_entry_typeidx_offset); + cfree_cg_load(cg, i32_mem); } cfree_cg_push_int(cg, (uint32_t)in.imm, b.id[CFREE_CG_BUILTIN_I32]); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); @@ -2452,15 +2422,13 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, callee); cfree_cg_push_local(cg, callee_ref); - cfree_cg_load(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ref_mem); cfree_cg_bitcast(cg, rt.table_entry_ptr_ty); { - CfreeCgEffAddr ea_fn; - ea_fn.scale = 0; - ea_fn.offset = (int64_t)rt.table_entry_fn_offset; - cfree_cg_load(cg, ref_mem, ea_fn); + cfree_cg_deref(cg, (int64_t)rt.table_entry_fn_offset); + cfree_cg_load(cg, ref_mem); } - cfree_cg_store(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ref_mem); ref_params[0].type = rt.instance_ptr_ty; for (uint32_t p = 0; p < t->nparams; ++p) @@ -2481,14 +2449,13 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, result = cfree_cg_local(cg, wasm_cg_type(c, b, t->results[0]), attrs); cfree_cg_push_local(cg, callee); - cfree_cg_load(cg, ref_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ref_mem); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, ref_func_type, 0)); cfree_cg_push_local(cg, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty), - wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty)); for (uint32_t p = 0; p < t->nparams; ++p) { cfree_cg_push_local(cg, args[p]); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p]), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p])); } cfree_cg_call( cg, t->nparams + 1u, ref_func_type, @@ -2501,9 +2468,9 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, } else if (t->nresults) { cfree_cg_push_local(cg, result); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0]), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0])); cfree_cg_push_local(cg, result); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0]), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0])); } break; } @@ -2511,17 +2478,17 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, uint32_t index = (uint32_t)in.imm; wasm_cg_push_global_value_ptr(c, cg, b, &rt, instance_local, m, index); - cfree_cg_load(cg, wasm_cg_mem(c, b, m->globals[index].type), - wasm_cg_ea0()); + cfree_cg_deref(cg, 0); + cfree_cg_load(cg, wasm_cg_mem(c, b, m->globals[index].type)); break; } case WASM_INSN_GLOBAL_SET: { uint32_t index = (uint32_t)in.imm; wasm_cg_push_global_value_ptr(c, cg, b, &rt, instance_local, m, index); + cfree_cg_deref(cg, 0); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, m->globals[index].type), - wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, m->globals[index].type)); break; } case WASM_INSN_RETURN: @@ -2531,12 +2498,11 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_drop(cg); break; case WASM_INSN_MEMORY_SIZE: { - CfreeCgEffAddr ea_pages; - ea_pages.scale = 0; - ea_pages.offset = - (int64_t)(rt.memory_offset[in.memidx] + rt.memory_pages_offset); wasm_cg_push_instance_ptr(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea_pages); + cfree_cg_deref( + cg, + (int64_t)(rt.memory_offset[in.memidx] + rt.memory_pages_offset)); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); if (!m->memories[in.memidx].is64) cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I32]); break; @@ -2549,13 +2515,6 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, WasmValType page_vt = m->memories[in.memidx].is64 ? WASM_VAL_I64 : WASM_VAL_I32; CfreeCgTypeId page_ty = wasm_cg_type(c, b, page_vt); - CfreeCgEffAddr ea_pages, ea_max; - ea_pages.scale = 0; - ea_pages.offset = - (int64_t)(rt.memory_offset[in.memidx] + rt.memory_pages_offset); - ea_max.scale = 0; - ea_max.offset = (int64_t)(rt.memory_offset[in.memidx] + - rt.memory_max_pages_offset); memset(&attrs, 0, sizeof attrs); attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; delta = cfree_cg_local(cg, page_ty, attrs); @@ -2563,47 +2522,55 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, grow_result = cfree_cg_local(cg, page_ty, attrs); cfree_cg_push_local(cg, delta); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt)); cfree_cg_push_local(cg, old_pages); wasm_cg_push_instance_ptr(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea_pages); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_deref( + cg, + (int64_t)(rt.memory_offset[in.memidx] + rt.memory_pages_offset)); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, delta); - cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt)); if (!m->memories[in.memidx].is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); wasm_cg_push_instance_ptr(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea_max); + cfree_cg_deref(cg, (int64_t)(rt.memory_offset[in.memidx] + + rt.memory_max_pages_offset)); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); cfree_cg_branch_false(cg, fail); wasm_cg_push_instance_ptr(cg, &rt, instance_local); + cfree_cg_deref( + cg, + (int64_t)(rt.memory_offset[in.memidx] + rt.memory_pages_offset)); cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, delta); - cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt)); if (!m->memories[in.memidx].is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), ea_pages); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, grow_result); cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); if (!m->memories[in.memidx].is64) cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt)); cfree_cg_jump(cg, done); cfree_cg_label_place(cg, fail); cfree_cg_push_local(cg, grow_result); cfree_cg_push_int(cg, UINT64_MAX, page_ty); - cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, page_vt)); cfree_cg_label_place(cg, done); cfree_cg_push_local(cg, grow_result); - cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, page_vt)); break; } case WASM_INSN_MEMORY_COPY: { @@ -2631,34 +2598,34 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); if (!dst_is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_addr_l); cfree_cg_swap(cg); if (!src_is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_addr_l); cfree_cg_swap(cg); if (!dst_is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); /* Cache base and size for src and dst memories. */ cfree_cg_push_local(cg, src_base_l); wasm_cg_push_memory_data_ptr(cg, &rt, instance_local, src_memidx); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, dst_base_l); wasm_cg_push_memory_data_ptr(cg, &rt, instance_local, dst_memidx); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, src_size_l); wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, src_memidx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_size_l); wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, dst_memidx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); wasm_cg_bulk_bounds_check(cg, b, &rt, src_addr_l, n_l, src_size_l); wasm_cg_bulk_bounds_check(cg, b, &rt, dst_addr_l, n_l, dst_size_l); wasm_cg_emit_byte_copy_loop(cg, b, &rt, dst_base_l, src_base_l, @@ -2686,23 +2653,23 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); if (!is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, val_l); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, dst_addr_l); cfree_cg_swap(cg); if (!is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_base_l); wasm_cg_push_memory_data_ptr(cg, &rt, instance_local, memidx); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, dst_size_l); wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, memidx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); wasm_cg_bulk_bounds_check(cg, b, &rt, dst_addr_l, n_l, dst_size_l); wasm_cg_emit_byte_fill_loop(cg, b, &rt, dst_base_l, dst_addr_l, val_l, n_l); @@ -2732,36 +2699,36 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_addr_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_addr_l); cfree_cg_swap(cg); if (!is64) cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); /* src_base = inst->passive_data[dataidx].base */ cfree_cg_push_local(cg, src_base_l); wasm_cg_push_passive_data_lvalue(cg, &rt, instance_local, dataidx); cfree_cg_field(cg, rt.passive_data_base_field); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); + cfree_cg_store(cg, ptr_mem); /* src_size = inst->passive_data[dataidx].len */ cfree_cg_push_local(cg, src_size_l); wasm_cg_push_passive_data_lvalue(cg, &rt, instance_local, dataidx); cfree_cg_field(cg, rt.passive_data_len_field); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_base_l); wasm_cg_push_memory_data_ptr(cg, &rt, instance_local, memidx); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, dst_size_l); wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local, memidx); - cfree_cg_load(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i64_mem); cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I64]); cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); wasm_cg_bulk_bounds_check(cg, b, &rt, src_addr_l, n_l, src_size_l); wasm_cg_bulk_bounds_check(cg, b, &rt, dst_addr_l, n_l, dst_size_l); wasm_cg_emit_byte_copy_loop(cg, b, &rt, dst_base_l, src_base_l, @@ -2773,7 +2740,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, wasm_cg_push_passive_data_lvalue(cg, &rt, instance_local, dataidx); cfree_cg_field(cg, rt.passive_data_len_field); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); break; } case WASM_INSN_ELEM_DROP: { @@ -2781,14 +2748,14 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, wasm_cg_push_passive_elem_lvalue(cg, &rt, instance_local, elemidx); cfree_cg_field(cg, rt.passive_elem_length_field); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); break; } case WASM_INSN_TABLE_SIZE: { uint32_t tableidx = (uint32_t)in.imm; wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); break; } case WASM_INSN_TABLE_GROW: { @@ -2814,10 +2781,10 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, idx_l = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, delta_l); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, val_l); cfree_cg_swap(cg); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_store(cg, fn_mem); /* Cache *val (a CfreeWasmTableEntry) into fn/typeidx locals so the * fill loop writes the correct pair into each new slot. */ CfreeCgLocal val_fn_l = cfree_cg_local(cg, rt.void_ptr_ty, attrs); @@ -2825,63 +2792,65 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, val_fn_l); cfree_cg_push_local(cg, val_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, rt.table_entry_ty, 0)); + cfree_cg_deref(cg, 0); cfree_cg_field(cg, rt.table_entry_fn_field); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); cfree_cg_push_local(cg, val_typeidx_l); cfree_cg_push_local(cg, val_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, rt.table_entry_ty, 0)); + cfree_cg_deref(cg, 0); cfree_cg_field(cg, rt.table_entry_typeidx_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, old_len_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); /* Check old_len + delta <= max. */ wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_max_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, fail); /* max - old_len >= delta */ wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_max_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_push_local(cg, delta_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); cfree_cg_branch_true(cg, fail); /* Update length first. */ wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_len_field); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, delta_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); /* Initialize new slots [old_len, old_len+delta) to val. */ cfree_cg_push_local(cg, idx_l); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_label_place(cg, fill_loop); cfree_cg_push_local(cg, idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, delta_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); { @@ -2891,36 +2860,36 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, idx_l, i32_mem); cfree_cg_field(cg, rt.table_entry_fn_field); cfree_cg_push_local(cg, val_fn_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, tableidx, idx_l, i32_mem); cfree_cg_field(cg, rt.table_entry_typeidx_field); cfree_cg_push_local(cg, val_typeidx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, idx_l); cfree_cg_push_local(cg, idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I32]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_jump(cg, fill_loop); cfree_cg_label_place(cg, fill_end); } cfree_cg_push_local(cg, result_l); cfree_cg_push_local(cg, old_len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_jump(cg, done); cfree_cg_label_place(cg, fail); cfree_cg_push_local(cg, result_l); cfree_cg_push_int(cg, UINT32_C(0xffffffff), b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_label_place(cg, done); cfree_cg_push_local(cg, result_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); break; } case WASM_INSN_TABLE_FILL: { @@ -2949,40 +2918,42 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, val_typeidx_l = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, val_l); cfree_cg_swap(cg); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_store(cg, fn_mem); cfree_cg_push_local(cg, dst_idx_l); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); /* Cache *val into (val_fn, val_typeidx). val points at a * CfreeWasmTableEntry which has fn (void*) at offset 0 and * typeidx (i32) at offset sizeof(void*). */ cfree_cg_push_local(cg, val_fn_l); cfree_cg_push_local(cg, val_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, rt.table_entry_ty, 0)); + cfree_cg_deref(cg, 0); cfree_cg_field(cg, rt.table_entry_fn_field); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); cfree_cg_push_local(cg, val_typeidx_l); cfree_cg_push_local(cg, val_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, rt.table_entry_ty, 0)); + cfree_cg_deref(cg, 0); cfree_cg_field(cg, rt.table_entry_typeidx_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); /* Bounds check: dst_idx + n <= len. */ cfree_cg_push_local(cg, len_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); cfree_cg_push_local(cg, len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, dst_idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, ok); wasm_cg_trap_bounds(cg, &rt); @@ -2990,12 +2961,12 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, { CfreeCgLabel ok2 = cfree_cg_label_new(cg); cfree_cg_push_local(cg, len_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, dst_idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_push_local(cg, n_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, ok2); wasm_cg_trap_bounds(cg, &rt); @@ -3004,12 +2975,12 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, /* idx = 0; while idx < n: table[dst_idx+idx] = val; idx++ */ cfree_cg_push_local(cg, idx_l); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_label_place(cg, loop); cfree_cg_push_local(cg, idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, n_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_GE_U); cfree_cg_branch_true(cg, done); { @@ -3019,30 +2990,30 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, slot_l); cfree_cg_push_local(cg, dst_idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_local(cg, idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, tableidx, slot_l, i32_mem); cfree_cg_field(cg, rt.table_entry_fn_field); cfree_cg_push_local(cg, val_fn_l); - cfree_cg_load(cg, fn_mem, wasm_cg_ea0()); - cfree_cg_store(cg, fn_mem, wasm_cg_ea0()); + cfree_cg_load(cg, fn_mem); + cfree_cg_store(cg, fn_mem); wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, tableidx, slot_l, i32_mem); cfree_cg_field(cg, rt.table_entry_typeidx_field); cfree_cg_push_local(cg, val_typeidx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); + cfree_cg_store(cg, i32_mem); } cfree_cg_push_local(cg, idx_l); cfree_cg_push_local(cg, idx_l); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I32]); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); cfree_cg_jump(cg, loop); cfree_cg_label_place(cg, done); break; @@ -3071,37 +3042,37 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_idx_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_idx_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_base_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, src_tbl); cfree_cg_field(cg, rt.table_entries_ptr_field); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, dst_base_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, dst_tbl); cfree_cg_field(cg, rt.table_entries_ptr_field); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, src_len_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, src_tbl); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_len_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, dst_tbl); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); wasm_cg_bulk_bounds_check(cg, b, &rt, src_idx_l, n_l, src_len_l); wasm_cg_bulk_bounds_check(cg, b, &rt, dst_idx_l, n_l, dst_len_l); wasm_cg_emit_table_copy_loop(c, cg, b, &rt, dst_base_l, src_base_l, @@ -3132,37 +3103,37 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, cfree_cg_push_local(cg, n_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_idx_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_idx_l); cfree_cg_swap(cg); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, src_base_l); wasm_cg_push_passive_elem_lvalue(cg, &rt, instance_local, elemidx); cfree_cg_field(cg, rt.passive_elem_entries_field); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, dst_base_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_entries_ptr_field); - cfree_cg_load(cg, ptr_mem, wasm_cg_ea0()); - cfree_cg_store(cg, ptr_mem, wasm_cg_ea0()); + cfree_cg_load(cg, ptr_mem); + cfree_cg_store(cg, ptr_mem); cfree_cg_push_local(cg, src_len_l); wasm_cg_push_passive_elem_lvalue(cg, &rt, instance_local, elemidx); cfree_cg_field(cg, rt.passive_elem_length_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); cfree_cg_push_local(cg, dst_len_l); wasm_cg_push_table_lvalue(cg, &rt, instance_local, tableidx); cfree_cg_field(cg, rt.table_len_field); - cfree_cg_load(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_load(cg, i32_mem); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_store(cg, i64_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i64_mem); wasm_cg_bulk_bounds_check(cg, b, &rt, src_idx_l, n_l, src_len_l); wasm_cg_bulk_bounds_check(cg, b, &rt, dst_idx_l, n_l, dst_len_l); wasm_cg_emit_table_copy_loop(c, cg, b, &rt, dst_base_l, src_base_l, @@ -3227,12 +3198,12 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, value_tmp = cfree_cg_local(cg, ty, attrs); cfree_cg_push_local(cg, value_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); cfree_cg_push_local(cg, value_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_atomic_store(cg, mem, CFREE_CG_MO_SEQ_CST); break; } @@ -3259,12 +3230,12 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, value_tmp = cfree_cg_local(cg, ty, attrs); cfree_cg_push_local(cg, value_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); cfree_cg_push_local(cg, value_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_atomic_rmw(cg, mem, wasm_atomic_rmw_op(in.kind), CFREE_CG_MO_SEQ_CST); break; @@ -3283,17 +3254,17 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, expected_tmp = cfree_cg_local(cg, ty, attrs); cfree_cg_push_local(cg, desired_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, expected_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); cfree_cg_push_local(cg, expected_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_push_local(cg, desired_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_atomic_cmpxchg(cg, mem, CFREE_CG_MO_SEQ_CST, CFREE_CG_MO_SEQ_CST, 0); cfree_cg_drop(cg); @@ -3316,30 +3287,30 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, result_tmp = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, timeout_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I64)); cfree_cg_push_local(cg, expected_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); cfree_cg_atomic_load(cg, mem, CFREE_CG_MO_SEQ_CST); cfree_cg_push_local(cg, expected_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_branch_true(cg, equal); cfree_cg_push_local(cg, result_tmp); cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); cfree_cg_jump(cg, done); cfree_cg_label_place(cg, equal); (void)timeout_tmp; cfree_cg_push_local(cg, result_tmp); cfree_cg_push_int(cg, 2, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); cfree_cg_label_place(cg, done); cfree_cg_push_local(cg, result_tmp); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); break; } case WASM_INSN_MEMORY_ATOMIC_NOTIFY: { @@ -3351,7 +3322,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, count_tmp = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); cfree_cg_push_local(cg, count_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem, wasm_cg_ea0()); + cfree_cg_store(cg, i32_mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); cfree_cg_drop(cg); cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); @@ -3381,7 +3352,8 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); - cfree_cg_load(cg, mem, wasm_cg_ea0()); + cfree_cg_deref(cg, 0); + cfree_cg_load(cg, mem); if (storage != result) { if (in.kind == WASM_INSN_I32_LOAD8_S || in.kind == WASM_INSN_I32_LOAD16_S || @@ -3421,18 +3393,19 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, addr_tmp = cfree_cg_local(cg, wasm_cg_type(c, b, addr_vt), attrs); cfree_cg_push_local(cg, value_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_store(cg, mem); wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); cfree_cg_push_local(cg, addr_tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, addr_vt), wasm_cg_ea0()); + cfree_cg_store(cg, wasm_cg_mem(c, b, addr_vt)); cfree_cg_push_local(cg, addr_tmp); - cfree_cg_load(cg, wasm_cg_mem(c, b, addr_vt), wasm_cg_ea0()); + cfree_cg_load(cg, wasm_cg_mem(c, b, addr_vt)); wasm_cg_memory_addr_from_tos(cg, b, &rt, m, instance_local, in.memidx, in.offset64); + cfree_cg_deref(cg, 0); cfree_cg_push_local(cg, value_tmp); - cfree_cg_load(cg, mem, wasm_cg_ea0()); - cfree_cg_store(cg, mem, wasm_cg_ea0()); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); break; } case WASM_INSN_I32_ADD: diff --git a/src/arch/rv64/emu.c b/src/arch/rv64/emu.c @@ -153,7 +153,7 @@ static CfreeCgMemAccess rv64_emu_mem(CfreeCgTypeId type) { static void rv64_emu_push_thread(CfreeCg* cg, CfreeCgLocal thread, CfreeCgTypeId thread_ptr) { cfree_cg_push_local(cg, thread); - cfree_cg_load(cg, rv64_emu_mem(thread_ptr), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, rv64_emu_mem(thread_ptr)); } static void rv64_emu_push_xreg(CfreeCg* cg, const Rv64EmuLiftSyms* s, @@ -174,7 +174,7 @@ static void rv64_emu_store_xreg_from_tmp(CfreeCg* cg, const Rv64EmuLiftSyms* s, rv64_emu_push_thread(cg, thread, s->thread_ptr); cfree_cg_push_int(cg, reg, s->i32); cfree_cg_push_local(cg, tmp); - cfree_cg_load(cg, rv64_emu_mem(s->i64), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, rv64_emu_mem(s->i64)); cfree_cg_call_symbol(cg, s->set_xreg, 3, (CfreeCgCallAttrs){0}); } @@ -184,7 +184,7 @@ static void rv64_emu_store_xreg_from_stack(CfreeCg* cg, CfreeCgLocal tmp) { cfree_cg_push_local(cg, tmp); cfree_cg_swap(cg); - cfree_cg_store(cg, rv64_emu_mem(s->i64), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, rv64_emu_mem(s->i64)); if (reg == 0u) return; rv64_emu_store_xreg_from_tmp(cg, s, thread, tmp, reg); } @@ -194,13 +194,13 @@ static void rv64_emu_store_local_from_stack(CfreeCg* cg, CfreeCgLocal local) { cfree_cg_push_local(cg, local); cfree_cg_swap(cg); - cfree_cg_store(cg, rv64_emu_mem(s->i64), (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, rv64_emu_mem(s->i64)); } static void rv64_emu_push_local_value(CfreeCg* cg, const Rv64EmuLiftSyms* s, CfreeCgLocal local) { cfree_cg_push_local(cg, local); - cfree_cg_load(cg, rv64_emu_mem(s->i64), (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, rv64_emu_mem(s->i64)); } static void rv64_emu_push_addr(CfreeCg* cg, const Rv64EmuLiftSyms* s, diff --git a/src/cg/control.c b/src/cg/control.c @@ -259,19 +259,17 @@ static void cg_emit_switch_table(CfreeCg* g, const CGSwitchDesc* d, decl.as.object.flags = CFREE_CG_OBJ_READONLY; api_remember_sym(g, table_sym, arr_ty, decl); - /* 6. Load table[idx]: push the table's address, swap so the index is on top, - * then load with EA scale = pointer size. */ + /* 6. Load table[idx]: bitcast the table pointer to a pointer-to-element so + * the element place carries the pointer-size scale, put the index on top, + * project the element place, then load it. */ cfree_cg_push_symbol_addr(g, (CfreeCgSym)table_sym, 0); /* [idx, &table] */ + cfree_cg_bitcast(g, cg_type_ptr_to(c, void_ptr_ty)); /* &table : void** */ cfree_cg_swap(g); /* [&table, idx] */ + cfree_cg_elem(g, 0); /* [&table[idx]] */ memset(&acc, 0, sizeof acc); acc.type = void_ptr_ty; acc.align = (uint32_t)c->target.ptr_align; - { - CfreeCgEffAddr ea; - ea.offset = 0; - ea.scale = (uint32_t)c->target.ptr_size; - cfree_cg_load(g, acc, ea); /* [label_addr] */ - } + cfree_cg_load(g, acc); /* [label_addr] */ /* 7. Indirect branch with the full closed target set (every case + * default), so backends doing branch-target hardening (BTI/IBT/CFG) @@ -826,96 +824,97 @@ void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, api_release(g, &dst); } -void cfree_cg_index(CfreeCg* g, uint64_t offset) { +/* log2 of a {1,2,4,8} scale, else -1. */ +static int cg_scale_to_log2(u32 scale) { + switch (scale) { + case 1: + return 0; + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + default: + return -1; + } +} + +void cfree_cg_elem(CfreeCg* g, int64_t offset) { ApiSValue idx, base; CgTarget* T; CfreeCgTypeId base_ty, base_ptr_ty, elem_ty, idx_ty; const CgType* base_info; u32 elemsz; - int free_base_op = 0; - Operand base_op, idx_op, result; - CGLocal rr; + Operand base_op, idx_op; + CGLocal base_local; if (!g) return; - if (offset > INT64_MAX) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: index offset too large"); - return; - } T = g->target; idx = api_pop(g); base = api_pop(g); - api_ensure_local(g, &base); base_ty = api_sv_type(&base); base_info = cg_type_get(g->c, base_ty); - if (base_info && base_info->kind == CFREE_CG_TYPE_PTR) { - elem_ty = base_info->ptr.pointee; - base_ptr_ty = base_ty; - } else if (base_info && base_info->kind == CFREE_CG_TYPE_ARRAY && - api_is_lvalue_sv(&base)) { - elem_ty = base_info->array.elem; - base_ptr_ty = cg_type_ptr_to(g->c, elem_ty); - } else { + if (api_is_lvalue_sv(&base) || !base_info || + base_info->kind != CFREE_CG_TYPE_PTR) { compiler_panic(g->c, g->cur_loc, - "CfreeCg: index base is not a pointer or array lvalue"); + "CfreeCg: elem requires a pointer value base (decay an " + "array to a pointer first)"); return; } + elem_ty = base_info->ptr.pointee; + base_ptr_ty = base_ty; elemsz = (u32)abi_cg_sizeof(g->c->abi, elem_ty); idx_ty = idx.type ? idx.type : idx.op.type; - if (!idx_ty) idx_ty = builtin_id(CFREE_CG_BUILTIN_I32); - if (base_info && base_info->kind == CFREE_CG_TYPE_ARRAY) { - rr = api_alloc_temp_local(g, base_ptr_ty); - base_op = api_op_local(rr, base_ptr_ty); - T->addr_of(T, base_op, base.op); - api_release(g, &base); - free_base_op = 1; - } else { - base_op = api_force_local(g, &base, base_ptr_ty); - } + if (!idx_ty) idx_ty = builtin_id(CFREE_CG_BUILTIN_I64); + base_op = api_force_local(g, &base, base_ptr_ty); + base_local = base_op.v.local; idx_op = api_force_local_unless_imm(g, &idx, idx_ty); - rr = api_alloc_temp_local(g, base_ptr_ty); - result = api_op_local(rr, base_ptr_ty); + + /* Constant index folds entirely into the displacement — no instructions, just + * a larger offset on the OPK_INDIRECT. */ if (idx_op.kind == OPK_IMM) { - i64 total_offset = idx_op.v.imm * (i64)elemsz + (i64)offset; - T->binop(T, BO_IADD, result, base_op, - api_op_imm(total_offset, base_ptr_ty)); - } else { - CGLocal sr = api_alloc_temp_local(g, idx_ty); - Operand scaled = api_op_local(sr, idx_ty); - /* Allocating `scaled` can materialize a delayed index expression into a - * fresh virtual local under opt. Refresh idx_op so the multiply uses - * the materialized value, not the pre-materialization source operand. */ + i64 ofs = idx_op.v.imm * (i64)elemsz + offset; + Operand place; + if (ofs >= INT32_MIN && ofs <= INT32_MAX) { + place = api_op_indirect(base_local, (i32)ofs, elem_ty); + } else { + CGLocal r = api_alloc_temp_local(g, base_ptr_ty); + Operand ro = api_op_local(r, base_ptr_ty); + T->binop(T, BO_IADD, ro, api_op_local(base_local, base_ptr_ty), + api_op_imm(ofs, base_ptr_ty)); + place = api_op_indirect(r, 0, elem_ty); + } + api_release(g, &base); + api_release(g, &idx); + api_push(g, api_make_lv(place, elem_ty)); + return; + } + + /* Dynamic index: build a scaled-index place so the backend emits one + * [base + index*scale] addressing mode. A power-of-two element size rides in + * log2_scale; any other size pre-multiplies the index once (scale 1). The + * index is copied into a fresh local for unambiguous ownership. */ + { + int lg2 = cg_scale_to_log2(elemsz); + CGLocal ir = api_alloc_temp_local(g, idx_ty); + Operand iro = api_op_local(ir, idx_ty); + u8 log2_scale; + /* Refresh idx_op: allocating `ir` may have materialized a delayed index. */ idx_op = api_force_local_unless_imm(g, &idx, idx_ty); if (idx.op.kind == OPK_LOCAL) idx_op = idx.op; - T->binop(T, BO_IMUL, scaled, idx_op, api_op_imm((i64)elemsz, idx_ty)); - if (offset > 0) { - T->binop(T, BO_IADD, scaled, scaled, api_op_imm((i64)offset, idx_ty)); - } - /* The final IADD takes operands with the pointer's integer width. Match - * the scaled index to the base pointer width before adding. */ - u32 idx_sz = (u32)abi_cg_sizeof(g->c->abi, idx_ty); - u32 ptr_sz = (u32)abi_cg_sizeof(g->c->abi, base_ptr_ty); - if (idx_sz && ptr_sz && idx_sz > ptr_sz) { - CGLocal narrow_r = api_alloc_temp_local(g, base_ptr_ty); - Operand narrow = api_op_local(narrow_r, base_ptr_ty); - T->convert(T, CV_TRUNC, narrow, scaled); - T->binop(T, BO_IADD, result, base_op, narrow); - api_release_temp_local(g, narrow_r); - } else if (idx_sz && ptr_sz && idx_sz < ptr_sz) { - CGLocal wide_r = api_alloc_temp_local(g, base_ptr_ty); - Operand wide = api_op_local(wide_r, base_ptr_ty); - T->convert(T, CV_ZEXT, wide, scaled); - T->binop(T, BO_IADD, result, base_op, wide); - api_release_temp_local(g, wide_r); + if (lg2 >= 0) { + T->copy(T, iro, idx_op); + log2_scale = (u8)lg2; } else { - T->binop(T, BO_IADD, result, base_op, scaled); + T->binop(T, BO_IMUL, iro, idx_op, api_op_imm((i64)elemsz, idx_ty)); + log2_scale = 0; } - api_release_temp_local(g, sr); - } - if (free_base_op) api_release_temp_local(g, base_op.v.local); - if (!base_info || base_info->kind != CFREE_CG_TYPE_ARRAY) api_release(g, &base); - api_release(g, &idx); - api_push(g, - api_make_lv(api_op_indirect(result.v.local, 0, elem_ty), elem_ty)); + api_release(g, &idx); + api_push(g, api_make_lv(api_op_indirect_indexed(base_local, ir, log2_scale, + (i32)offset, elem_ty), + elem_ty)); + } } void cfree_cg_field(CfreeCg* g, uint32_t field_index) { @@ -925,11 +924,9 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { CfreeCgTypeId base_ty; CfreeCgTypeId field_ty; CfreeCgTypeId rec_ptr_ty; - const CgType* base_info; const CgType* rec_info; const ABIRecordLayout* layout; u32 field_offset; - int base_is_lvalue; Operand result; CGLocal rr; if (!g) return; @@ -937,20 +934,15 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { base = api_pop(g); api_ensure_local(g, &base); base_ty = api_sv_type(&base); - base_is_lvalue = api_is_lvalue_sv(&base); - if (base_is_lvalue) { - rec_ty = base_ty; - } else { - base_info = cg_type_get(g->c, base_ty); - if (!base_info || base_info->kind != CFREE_CG_TYPE_PTR) { - compiler_panic(g->c, g->cur_loc, - "CfreeCg: field base is not an lvalue or record pointer"); - api_release(g, &base); - return; - } - rec_ty = base_info->ptr.pointee; + if (!api_is_lvalue_sv(&base)) { + compiler_panic(g->c, g->cur_loc, + "CfreeCg: field requires a record place; deref a pointer " + "first"); + api_release(g, &base); + return; } - rec_ptr_ty = base_is_lvalue ? cg_type_ptr_to(g->c, rec_ty) : base_ty; + rec_ty = base_ty; + rec_ptr_ty = cg_type_ptr_to(g->c, rec_ty); layout = abi_cg_record_layout(g->c->abi, rec_ty); if (!layout || field_index >= layout->nfields) { compiler_panic(g->c, g->cur_loc, "CfreeCg: invalid field index"); @@ -975,12 +967,6 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { api_release(g, &base); return; } - if (!base_is_lvalue) { - compiler_panic(g->c, g->cur_loc, - "CfreeCg: pointer field bit-fields are not supported"); - api_release(g, &base); - return; - } base_addr = api_lvalue_addr(g, &base, rec_ptr_ty); memset(&bf, 0, sizeof bf); bf.field_type = field_ty; @@ -997,29 +983,18 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { api_push(g, sv); return; } - if (!base_is_lvalue) { - Operand base_op = api_force_local(g, &base, rec_ptr_ty); - if (field_offset == 0) { - result = base_op; - base.res = RES_INHERENT; - } else { - rr = api_alloc_temp_local(g, rec_ptr_ty); - result = api_op_local(rr, rec_ptr_ty); - T->binop(T, BO_IADD, result, base_op, - api_op_imm((i64)field_offset, rec_ptr_ty)); - api_release(g, &base); - } - api_push( - g, api_make_lv(api_op_indirect(result.v.local, 0, field_ty), field_ty)); - } else if (base.op.kind == OPK_GLOBAL) { + if (base.op.kind == OPK_GLOBAL) { result = api_op_global(base.op.v.global.sym, base.op.v.global.addend + (i64)field_offset, field_ty); api_push(g, api_make_lv(result, field_ty)); } else if (base.op.kind == OPK_INDIRECT && field_offset <= (u32)INT32_MAX && base.op.v.ind.ofs <= INT32_MAX - (i32)field_offset) { - result = api_op_indirect(base.op.v.ind.base, - base.op.v.ind.ofs + (i32)field_offset, field_ty); + /* Fold the field offset into the displacement, preserving any index/scale + * a preceding `elem` left so `p[i].f` stays one [base+index*scale+off]. */ + result = api_op_indirect_indexed( + base.op.v.ind.base, base.op.v.ind.index, base.op.v.ind.log2_scale, + base.op.v.ind.ofs + (i32)field_offset, field_ty); api_push(g, api_make_lv(result, field_ty)); } else { Operand base_addr; diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -333,9 +333,10 @@ void api_push_source_local_lvalue(CfreeCg* g, CfreeCgLocal local, void cfree_cg_push_local(CfreeCg* g, CfreeCgLocal local); void cfree_cg_push_local_addr(CfreeCg* g, CfreeCgLocal local); void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend); -void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea); +void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access); void cfree_cg_addr(CfreeCg* g); -void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea); +void cfree_cg_deref(CfreeCg* g, int64_t offset); +void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access); void cfree_cg_dup(CfreeCg* g); void cfree_cg_dup2(CfreeCg* g); void cfree_cg_swap(CfreeCg* g); diff --git a/src/cg/memory.c b/src/cg/memory.c @@ -141,224 +141,6 @@ void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { } } -/* ============================================================ - * Load / addr / store - * - * The memops dispatch on the TOS shape of `base`: - * 1. lvalue base, no index -> fold ea.offset into the operand encoding - * (OPK_LOCAL / OPK_GLOBAL / OPK_INDIRECT) and emit a single memop. - * 2. lvalue base, scaled index -> take the lvalue's address, then form an - * indexed OPK_INDIRECT and emit a single memop. - * 3. pointer-rvalue base, no index -> for OPK_GLOBAL fold the offset into - * the addend; otherwise use [local + offset]. - * 4. pointer-rvalue base, scaled index -> form OPK_INDIRECT against the - * pointer local with index/scale. - * - * Scale normalization (ea.scale != 0): - * {1,2,4,8} -> log2_scale 0..3 on OPK_INDIRECT. - * otherwise -> compute index*scale into a fresh local, fold into base, - * dispatch with index = CG_LOCAL_NONE. - * ============================================================ */ - -/* log2 of a {1,2,4,8} scale, else -1. */ -static int scale_to_log2(uint32_t scale) { - switch (scale) { - case 1: - return 0; - case 2: - return 1; - case 4: - return 2; - case 8: - return 3; - default: - return -1; - } -} - -/* Materialize the EA into an OPK_INDIRECT operand suitable for the backend - * load/store. `addr` may be OPK_LOCAL, OPK_GLOBAL, or OPK_INDIRECT. The - * `offset` is folded into the operand; the indexed form is encoded directly. - * If the index path requires arithmetic on a global/local, the address is - * first lowered into a local via T->addr_of and then combined. - * - * The caller owns `index_local` (CG_LOCAL_NONE if no index). On return, - * *out_owned_base is set to the local that the caller must free after the - * memop completes (CG_LOCAL_NONE if no new local was allocated). The returned - * operand's index local is freed by the caller separately when applicable; - * this helper does not free it. - */ -static Operand fold_ea_into_operand(CfreeCg* g, Operand addr, i64 offset, - CGLocal index, u8 log2_scale, - CfreeCgTypeId access_ty, - int addr_is_pointer_value, - CGLocal* out_owned_base) { - CgTarget* T = g->target; - CfreeCgTypeId base_ty = cg_type_is_ptr(g->c, addr.type) - ? addr.type - : cg_type_ptr_to(g->c, access_ty); - *out_owned_base = CG_LOCAL_NONE; - - if (index == CG_LOCAL_NONE) { - /* No index: fold offset into the operand directly. */ - if (addr.kind == OPK_LOCAL) { - if (addr_is_pointer_value) { - if (offset >= INT32_MIN && offset <= INT32_MAX) { - return api_op_indirect(addr.v.local, (i32)offset, access_ty); - } - { - CGLocal br = api_alloc_temp_local(g, base_ty); - Operand base_reg = api_op_local(br, base_ty); - T->binop(T, BO_IADD, base_reg, api_op_local(addr.v.local, base_ty), - api_op_imm(offset, base_ty)); - *out_owned_base = br; - return api_op_indirect(br, 0, access_ty); - } - } - if (offset == 0) { - (void)access_ty; - return addr; - } - /* OPK_LOCAL has no displacement field; materialize the base address into - * a local and apply the offset. */ - { - CGLocal br = api_alloc_temp_local(g, base_ty); - Operand base_reg = api_op_local(br, base_ty); - T->addr_of(T, base_reg, addr); - if (offset >= INT32_MIN && offset <= INT32_MAX) { - *out_owned_base = br; - return api_op_indirect(br, (i32)offset, access_ty); - } - T->binop(T, BO_IADD, base_reg, base_reg, api_op_imm(offset, base_ty)); - *out_owned_base = br; - return api_op_indirect(br, 0, access_ty); - } - } - if (addr.kind == OPK_GLOBAL) { - Operand r = api_op_global(addr.v.global.sym, - addr.v.global.addend + offset, access_ty); - return r; - } - if (addr.kind == OPK_INDIRECT) { - i64 sum = (i64)addr.v.ind.ofs + offset; - if (sum >= INT32_MIN && sum <= INT32_MAX) { - return api_op_indirect_indexed(addr.v.ind.base, addr.v.ind.index, - addr.v.ind.log2_scale, (i32)sum, - access_ty); - } - /* Offset too large for i32 displacement; materialize. */ - { - CGLocal br = api_alloc_temp_local(g, base_ty); - Operand base_reg = api_op_local(br, base_ty); - T->copy(T, base_reg, api_op_local(addr.v.ind.base, base_ty)); - T->binop(T, BO_IADD, base_reg, base_reg, api_op_imm(offset, base_ty)); - *out_owned_base = br; - return api_op_indirect_indexed(br, addr.v.ind.index, - addr.v.ind.log2_scale, addr.v.ind.ofs, - access_ty); - } - } - } - - /* Indexed form. addr must be reduced to a base local first when it is - * not already an OPK_INDIRECT with room for an index local. */ - if (addr.kind == OPK_INDIRECT && addr.v.ind.index == CG_LOCAL_NONE && - offset == 0) { - /* Reuse existing INDIRECT base; add index and scale. The displacement - * stays whatever the operand already had. */ - return api_op_indirect_indexed(addr.v.ind.base, index, log2_scale, - addr.v.ind.ofs, access_ty); - } - if (addr.kind == OPK_INDIRECT && addr.v.ind.index == CG_LOCAL_NONE) { - i64 sum = (i64)addr.v.ind.ofs + offset; - if (sum >= INT32_MIN && sum <= INT32_MAX) { - return api_op_indirect_indexed(addr.v.ind.base, index, log2_scale, - (i32)sum, access_ty); - } - } - /* Otherwise, materialize addr into a local and then build the indexed - * operand around it. */ - { - CGLocal br = api_alloc_temp_local(g, base_ty); - Operand base_reg = api_op_local(br, base_ty); - if (addr.kind == OPK_LOCAL) { - if (addr_is_pointer_value) - T->copy(T, base_reg, api_op_local(addr.v.local, base_ty)); - else - T->addr_of(T, base_reg, addr); - } else { - T->addr_of(T, base_reg, addr); - } - if (offset != 0) { - if (offset >= INT32_MIN && offset <= INT32_MAX) { - *out_owned_base = br; - return api_op_indirect_indexed(br, index, log2_scale, (i32)offset, - access_ty); - } - T->binop(T, BO_IADD, base_reg, base_reg, api_op_imm(offset, base_ty)); - } - *out_owned_base = br; - return api_op_indirect_indexed(br, index, log2_scale, 0, access_ty); - } -} - -/* Pop the index operand for a scaled-index memop. Returns the index in a - * freshly allocated local that the caller owns and must free after the - * memop. Handles the scale-not-in-{1,2,4,8} case by computing index*scale. - * - * On return: - * *out_log2 = log2_scale (0..3) if scale was normalized to one of {1,2,4,8} - * or to 0 if we materialized the scaled value (log2=0). - */ -static CGLocal pop_and_normalize_index(CfreeCg* g, uint32_t scale, - u8* out_log2) { - ApiSValue idx; - CfreeCgTypeId idx_ty; - int lg2; - Operand idx_op; - CgTarget* T = g->target; - CGLocal sr; - Operand scaled; - - idx = api_pop(g); - idx_ty = api_sv_type(&idx); - if (!idx_ty) idx_ty = builtin_id(CFREE_CG_BUILTIN_I64); - - lg2 = scale_to_log2(scale); - if (lg2 >= 0) { - *out_log2 = (u8)lg2; - /* Always allocate a fresh local so the caller has unambiguous - * ownership; copy the index value in. */ - idx_op = api_force_local_unless_imm(g, &idx, idx_ty); - sr = api_alloc_temp_local(g, idx_ty); - scaled = api_op_local(sr, idx_ty); - if (idx_op.kind == OPK_IMM) { - T->load_imm(T, scaled, idx_op.v.imm); - } else { - /* Re-fetch in case alloc materialized a delayed expression. */ - idx_op = api_force_local_unless_imm(g, &idx, idx_ty); - if (idx.op.kind == OPK_LOCAL) idx_op = idx.op; - T->copy(T, scaled, idx_op); - } - api_release(g, &idx); - return sr; - } - - /* Non-power-of-two scale: materialize index*scale into a fresh local. */ - idx_op = api_force_local_unless_imm(g, &idx, idx_ty); - sr = api_alloc_temp_local(g, idx_ty); - scaled = api_op_local(sr, idx_ty); - if (idx_op.kind == OPK_IMM) { - T->load_imm(T, scaled, idx_op.v.imm * (i64)scale); - } else { - idx_op = api_force_local_unless_imm(g, &idx, idx_ty); - if (idx.op.kind == OPK_LOCAL) idx_op = idx.op; - T->binop(T, BO_IMUL, scaled, idx_op, api_op_imm((i64)scale, idx_ty)); - } - api_release(g, &idx); - *out_log2 = 0; - return sr; -} /* Build a BitFieldAccess descriptor from the CfreeCgMemAccess metadata. */ static BitFieldAccess bf_from_access(CfreeCg* g, CfreeCgMemAccess access, @@ -387,54 +169,51 @@ static int api_sv_local_storage_is_aggregate(CfreeCg* g, const ApiSValue* sv) { cg_type_is_aggregate(g->c, rec->type); } -/* Pop the base for a memop; populate `*base_addr` with an operand the backend - * can consume (LOCAL/GLOBAL/INDIRECT for lvalue forms, or LOCAL holding a - * pointer for rvalue forms). Returns 1 if `base` is an lvalue, 0 otherwise. - * - * Sets `*source_local_out` to the lvalue's source_local handle when applicable - * (so the caller can update constant tracking). Sets `*lvalue_sv` to a copy of - * the popped lvalue so the caller can call api_release on it after the memop; - * for rvalue-pointer forms, `*lvalue_sv` is the popped value (used for - * release). - */ +/* Retype an already-addressable place operand to the access type — the way the + * old offset-0 EA fold did. GLOBAL/INDIRECT carry the access type into the + * operand; a bare LOCAL keeps its own type (the memop's MemAccess carries the + * access width). */ +static Operand place_operand_for_access(Operand op, CfreeCgTypeId access_ty) { + switch (op.kind) { + case OPK_GLOBAL: + return api_op_global(op.v.global.sym, op.v.global.addend, access_ty); + case OPK_INDIRECT: + return api_op_indirect_indexed(op.v.ind.base, op.v.ind.index, + op.v.ind.log2_scale, op.v.ind.ofs, + access_ty); + default: + return op; + } +} -void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { +/* Load a VALUE from the PLACE on TOS. The place encodes the full address (built + * by push_local / deref / field / elem); there is no EA rider. Strict: the + * operand must be a PLACE — a pointer VALUE must be `deref`'d first. */ +void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue base; CgTarget* T; CfreeCgTypeId ty; CfreeCgTypeId access_ty; CGLocal owned_base = CG_LOCAL_NONE; - CGLocal owned_index = CG_LOCAL_NONE; - u8 log2_scale = 0; Operand mem_op; CGLocal dst_r; Operand dst; - int is_lvalue; int is_bitfield; - int has_index; if (!g) return; T = g->target; if (access.flags & CFREE_CG_MEM_VOLATILE) api_local_const_memory_boundary(g); - has_index = (ea.scale != 0); is_bitfield = (access.bit_width != 0); - if (has_index) { - /* Pop and normalize the index first; it sits between base and any - * follow-up value (none for load). */ - owned_index = pop_and_normalize_index(g, ea.scale, &log2_scale); - } - base = api_pop(g); - is_lvalue = api_is_lvalue_sv(&base); + if (!api_is_lvalue_sv(&base)) { + compiler_panic(g->c, g->cur_loc, + "CfreeCg: load requires a place; deref the pointer first"); + } - /* Aggregate / non-EA fast paths only apply to the no-index, no-bitfield - * case where the result is the lvalue itself (matches old behavior). - * Scalar accesses at an offset into an aggregate lvalue are the canonical - * field-access pattern under the EA model and fall through to the normal - * scalar load path below. */ - if (!has_index && !is_bitfield && is_lvalue && ea.offset == 0 && - cg_type_is_aggregate(g->c, api_sv_type(&base))) { + /* Aggregate place: an aggregate-typed access returns the place itself; a + * scalar access reads a scalar sub-object and falls through. */ + if (!is_bitfield && cg_type_is_aggregate(g->c, api_sv_type(&base))) { ty = api_mem_access_type(g, access, api_sv_type(&base), "load"); if (cg_type_is_aggregate(g->c, ty)) { u32 access_size = api_mem_type_size(g, ty, "load"); @@ -448,48 +227,26 @@ void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { api_push(g, base); return; } - /* Scalar access from aggregate lvalue: fall through. */ - } - - /* From here on, base must reduce to something we can address. */ - if (!is_lvalue && cg_type_is_aggregate(g->c, api_sv_type(&base))) { - /* Pointer rvalue to aggregate without any EA -- return as-is. */ - if (!has_index && !is_bitfield && ea.offset == 0) { - api_push(g, base); - return; - } + /* scalar access from an aggregate place: fall through */ } ty = api_mem_access_type(g, access, api_sv_type(&base), "load"); access_ty = ty; - if (!has_index && !is_bitfield && !is_lvalue && base.kind == SV_OPERAND && - base.op.kind == OPK_GLOBAL && - (cg_type_is_aggregate(g->c, ty) || api_is_wide16_scalar_type(g->c, ty))) { - base.type = ty; - base.op.type = ty; - base.lvalue = 1; - api_push(g, base); - return; - } - if (!is_bitfield) api_require_scalar_mem_type(g, "load", access_ty); - /* Source-local constant load (only the plain, no-EA case is tracked). */ - if (!has_index && !is_bitfield && ea.offset == 0 && is_lvalue && - base.source_local != CFREE_CG_LOCAL_NONE && + /* Source-local constant load. */ + if (!is_bitfield && base.source_local != CFREE_CG_LOCAL_NONE && api_local_const_load(g, base.source_local, access, &dst)) { api_release(g, &base); api_push(g, api_make_sv(dst, dst.type)); return; } - /* Scalar local lvalue: plain no-EA load returns the local value directly. - * Aggregate locals are storage; even offset-zero field accesses must go - * through the memory path so the access type controls the dereference instead - * of treating the whole aggregate as a scalar value. */ - if (!has_index && !is_bitfield && ea.offset == 0 && is_lvalue && - base.source_local != CFREE_CG_LOCAL_NONE && base.op.kind == OPK_LOCAL && + /* Scalar local place: the value already lives in the local; hand it back + * directly without a memory access. */ + if (!is_bitfield && base.source_local != CFREE_CG_LOCAL_NONE && + base.op.kind == OPK_LOCAL && !api_sv_local_storage_is_aggregate(g, &base) && !cg_type_is_aggregate(g->c, api_sv_type(&base)) && !cg_type_is_aggregate(g->c, ty) && @@ -501,76 +258,23 @@ void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { return; } - /* Wide-16 scalar lvalue load: keep the addressable storage as the value. - * For fields at a fixed offset, fold the EA into a new lvalue operand instead - * of asking the backend for a single 16-byte local load. */ - if (!has_index && !is_bitfield && is_lvalue && - api_is_wide16_scalar_type(g->c, ty)) { - if (ea.offset == 0) { - api_push(g, base); - return; - } - if (!api_operand_can_address(&base.op)) { - CfreeCgTypeId pty = cg_type_ptr_to(g->c, api_sv_type(&base)); - Operand addr = api_lvalue_addr(g, &base, pty); - mem_op = fold_ea_into_operand(g, addr, ea.offset, CG_LOCAL_NONE, 0, ty, 1, - &owned_base); - if (owned_base == CG_LOCAL_NONE) - owned_base = addr.v.local; - else if (owned_base != addr.v.local) - api_release_temp_local(g, addr.v.local); - } else { - mem_op = fold_ea_into_operand(g, base.op, ea.offset, CG_LOCAL_NONE, 0, ty, - 0, &owned_base); - } - if (mem_op.kind == OPK_INDIRECT && owned_base == CG_LOCAL_NONE && - base.op.kind == OPK_INDIRECT) { - base.res = RES_INHERENT; - } - api_release(g, &base); - api_push(g, api_make_lv(mem_op, ty)); + /* Wide-16 scalar place: keep the addressable storage as the value. */ + if (!is_bitfield && api_is_wide16_scalar_type(g->c, ty)) { + api_push(g, base); return; } - /* Compute the memop operand. Lvalue bases preserve named-storage operands; - * pointer rvalues use the local holding the address. */ - if (is_lvalue) { - if (!api_operand_can_address(&base.op)) { - /* Source-local needs an EA: take - * the lvalue's address first. */ - CfreeCgTypeId pty = cg_type_ptr_to(g->c, api_sv_type(&base)); - Operand addr = api_lvalue_addr(g, &base, pty); - mem_op = fold_ea_into_operand(g, addr, ea.offset, owned_index, log2_scale, - access_ty, 1, &owned_base); - /* `addr` is an owned local from api_lvalue_addr. */ - if (owned_base == CG_LOCAL_NONE) - owned_base = addr.v.local; - else if (owned_base != addr.v.local) - api_release_temp_local(g, addr.v.local); - } else { - /* The lvalue carries its own operand; fold the EA into it. */ - mem_op = fold_ea_into_operand(g, base.op, ea.offset, owned_index, - log2_scale, access_ty, 0, &owned_base); - } - } else if (base.kind == SV_OPERAND && base.op.kind == OPK_GLOBAL) { - /* Pointer-rvalue OPK_GLOBAL: fold the EA directly against the global - * (matching the lvalue OPK_GLOBAL path) so the backend can emit a single - * PC-relative or absolute access. */ - mem_op = fold_ea_into_operand(g, base.op, ea.offset, owned_index, - log2_scale, access_ty, 0, &owned_base); + /* Resolve the place into a single backend memop operand. */ + if (!api_operand_can_address(&base.op)) { + CfreeCgTypeId pty = cg_type_ptr_to(g->c, api_sv_type(&base)); + Operand addr = api_lvalue_addr(g, &base, pty); + mem_op = api_op_indirect(addr.v.local, 0, access_ty); + owned_base = addr.v.local; } else { - /* Pointer rvalue: ensure the address is in a local and treat that as - * the base. */ - CfreeCgTypeId pty = api_sv_type(&base); - Operand ptr_op = api_force_local(g, &base, pty); - mem_op = fold_ea_into_operand(g, ptr_op, ea.offset, owned_index, log2_scale, - access_ty, 1, &owned_base); + mem_op = place_operand_for_access(base.op, access_ty); } - /* Mutate source-local tracking. Any EA-shaped load through a tracked local - * (offset != 0 or has_index or non-matching access) cannot use the cached - * scalar value: clear it. */ - if (is_lvalue && base.source_local != CFREE_CG_LOCAL_NONE) { + if (base.source_local != CFREE_CG_LOCAL_NONE) { api_local_const_clear(api_local_from_handle(g, base.source_local)); } @@ -585,33 +289,51 @@ void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { T->load(T, dst, mem_op, api_mem_from_access(g, &mem_op, access)); } - /* Release the base lvalue/rvalue and any owned locals. */ - if (is_lvalue) { - /* If the original lvalue's operand was OPK_INDIRECT, its base local - * was owned by the lvalue and is still in mem_op.v.ind.base when we did - * not allocate a new owned_base. Free that base when no new owned_base - * shadows it. */ - if (base.op.kind == OPK_INDIRECT && owned_base == CG_LOCAL_NONE) { - /* mem_op uses the same base local as base.op; free it via the - * lvalue release. */ - } - api_release(g, &base); - } else { - /* For rvalue-pointer bases, the local holding the pointer was the - * owned local of `base`; api_release will free it unless the EA folding - * already absorbed it into mem_op. The fold_ea_into_operand path for - * LOCAL returns either OPK_INDIRECT(addr.v.local, ofs) (no new owned_base) - * or a freshly allocated owned_base. In either case api_release(&base) - * frees the pointer local; that is fine because we already issued - * the memop. */ - api_release(g, &base); - } + api_release(g, &base); if (owned_base != CG_LOCAL_NONE) api_release_temp_local(g, owned_base); - if (owned_index != CG_LOCAL_NONE) api_release_temp_local(g, owned_index); - api_push(g, api_make_sv(dst, access_ty)); } +/* VALUE(ptr) -> PLACE: the explicit pointer->place transition. The produced + * place is *(ptr + offset bytes). Strict on kind: the operand must be a pointer + * VALUE, never a PLACE — the caller turns a place into a pointer with `addr` + * first. */ +void cfree_cg_deref(CfreeCg* g, int64_t offset) { + ApiSValue v; + CfreeCgTypeId pty; + CfreeCgTypeId pointee; + Operand ptr; + if (!g) return; + v = api_pop(g); + pty = api_sv_type(&v); + if (api_is_lvalue_sv(&v) || !cg_type_is_ptr(g->c, pty)) { + compiler_panic(g->c, g->cur_loc, + "CfreeCg: deref requires a pointer value, not a place"); + } + pointee = cg_type_pointee(g->c, pty); + if (!pointee) pointee = builtin_id(CFREE_CG_BUILTIN_VOID); + /* A symbol address derefs to a global place, preserving direct + * (PC-relative/absolute) addressing rather than materializing the address. */ + if (v.kind == SV_OPERAND && v.op.kind == OPK_GLOBAL) { + api_push(g, api_make_lv( + api_op_global(v.op.v.global.sym, + v.op.v.global.addend + offset, pointee), + pointee)); + return; + } + ptr = api_force_local(g, &v, pty); + if (offset >= INT32_MIN && offset <= INT32_MAX) { + api_push(g, api_make_lv(api_op_indirect(ptr.v.local, (i32)offset, pointee), + pointee)); + } else { + CGLocal r = api_alloc_temp_local(g, pty); + Operand p2 = api_op_local(r, pty); + g->target->binop(g->target, BO_IADD, p2, ptr, api_op_imm(offset, pty)); + api_push(g, api_make_lv(api_op_indirect(r, 0, pointee), pointee)); + } +} + + void cfree_cg_addr(CfreeCg* g) { ApiSValue v; CfreeCgTypeId pty; @@ -626,57 +348,42 @@ void cfree_cg_addr(CfreeCg* g) { api_push(g, api_make_sv(dst, pty)); } -void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { +/* Store the VALUE on TOS into the PLACE beneath it. Stack: [place, value] -> []. + * The place encodes the full address; there is no EA rider. Strict: the + * destination must be a PLACE — a pointer VALUE must be `deref`'d first. */ +void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue base, rv; CgTarget* T; CfreeCgTypeId ty; CfreeCgTypeId access_ty; Operand src; CGLocal owned_base = CG_LOCAL_NONE; - CGLocal owned_index = CG_LOCAL_NONE; - u8 log2_scale = 0; Operand mem_op; int is_lvalue; int is_bitfield; - int has_index; if (!g) return; T = g->target; if (access.flags & CFREE_CG_MEM_VOLATILE) api_local_const_memory_boundary(g); - has_index = (ea.scale != 0); is_bitfield = (access.bit_width != 0); - /* Stack: - * no index: [base, value] - pop value, then index (none), then base - * indexed: [base, index, value] - pop value, then index, then base - */ + /* Stack: [base, value] - pop value, then base. */ rv = api_pop(g); - if (has_index) { - owned_index = pop_and_normalize_index(g, ea.scale, &log2_scale); - } base = api_pop(g); is_lvalue = api_is_lvalue_sv(&base); if (!is_lvalue) { - /* The "destination is not an lvalue" diagnostic now only fires when the - * popped base is neither an lvalue nor a pointer-typed rvalue. */ - if (!cg_type_is_ptr(g->c, api_sv_type(&base))) { - compiler_panic(g->c, g->cur_loc, - "CfreeCg: store destination is not an lvalue or pointer"); - return; - } + compiler_panic(g->c, g->cur_loc, + "CfreeCg: store requires a place destination; deref first"); + return; } ty = api_mem_access_type(g, access, api_sv_type(&base), "store"); access_ty = ty; - /* Aggregate store (no EA): memcpy through src lvalue. Only triggers when - * the access type itself is aggregate. Scalar stores at an offset into an - * aggregate lvalue are field-stores under the EA model and fall through to - * the scalar store path. */ - if (!has_index && !is_bitfield && ea.offset == 0 && - (cg_type_is_aggregate(g->c, ty) || - cg_type_is_aggregate(g->c, api_sv_type(&rv)))) { + /* Aggregate store: memcpy through the source place. */ + if (!is_bitfield && (cg_type_is_aggregate(g->c, ty) || + cg_type_is_aggregate(g->c, api_sv_type(&rv)))) { CfreeCgTypeId ptr_ty; Operand dst_addr, src_addr; int dst_addr_owned; @@ -712,13 +419,8 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { api_local_const_memory_boundary(g); } ptr_ty = cg_type_ptr_to(g->c, ty); - if (is_lvalue) { - dst_addr = api_lvalue_addr(g, &base, ptr_ty); - dst_addr_owned = 1; - } else { - dst_addr = api_force_local(g, &base, api_sv_type(&base)); - dst_addr_owned = 0; - } + dst_addr = api_lvalue_addr(g, &base, ptr_ty); + dst_addr_owned = 1; if (src_ptr_rvalue) { src_addr = api_force_local(g, &rv, api_sv_type(&rv)); src_addr_owned = 0; @@ -739,28 +441,8 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { if (!is_bitfield) api_validate_memory_value(g, "store", ty, api_sv_type(&rv)); - /* Wide-16 scalar store: keep the pre-existing wide16 lowering for the plain - * (no-EA) case. */ - if (!has_index && !is_bitfield && api_is_wide16_scalar_type(g->c, ty)) { - /* Normalize the destination up front into a single offset-0 lvalue - * operand so every sub-branch below addresses the right location. Two - * cases otherwise misbehave: a pointer-rvalue base (`*p`) is the address - * itself and must be dereferenced (not treated as storage), and a field - * offset (a struct member) must be folded in. Both collapse to an - * OPK_INDIRECT lvalue here. */ - if (!is_lvalue) { - /* Pointer-rvalue base: the operand value is the destination address. */ - Operand ptr_op = api_force_local(g, &base, api_sv_type(&base)); - base = - api_make_lv(api_op_indirect(ptr_op.v.local, (i32)ea.offset, ty), ty); - ea.offset = 0; - is_lvalue = 1; - } else if (ea.offset != 0 && base.op.kind == OPK_LOCAL) { - CfreeCgTypeId base_ptr_ty = cg_type_ptr_to(g->c, ty); - Operand addr = api_lvalue_addr(g, &base, base_ptr_ty); - base = api_make_lv(api_op_indirect(addr.v.local, (i32)ea.offset, ty), ty); - ea.offset = 0; - } + /* Wide-16 scalar store. */ + if (!is_bitfield && api_is_wide16_scalar_type(g->c, ty)) { if (base.source_local != CFREE_CG_LOCAL_NONE) { api_local_const_clear(api_local_from_handle(g, base.source_local)); } else if (base.op.kind == OPK_INDIRECT || base.op.kind == OPK_GLOBAL || @@ -774,19 +456,11 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { int dst_addr_owned = 0; int src_addr_owned = 0; AggregateAccess agg; - if (is_lvalue && base.op.kind == OPK_LOCAL) { - if (ea.offset == 0) { - dst_addr = base.op; - } else { - dst_addr = fold_ea_into_operand(g, base.op, ea.offset, CG_LOCAL_NONE, - 0, ty, 0, &owned_base); - dst_addr_owned = owned_base != CG_LOCAL_NONE; - } - } else if (is_lvalue) { + if (base.op.kind == OPK_LOCAL) { + dst_addr = base.op; + } else { dst_addr = api_lvalue_addr(g, &base, ptr_ty); dst_addr_owned = 1; - } else { - dst_addr = api_force_local(g, &base, api_sv_type(&base)); } if (rv.op.kind == OPK_LOCAL) { src_addr = rv.op; @@ -823,21 +497,15 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { CfreeCgTypeId ptr_ty = cg_type_ptr_to(g->c, ty); Operand dst_addr; Operand src_addr; - int dst_addr_owned = 0; AggregateAccess agg; api_store_f128_bytes(g, local, ty, bytes); - if (is_lvalue) { - dst_addr = api_lvalue_addr(g, &base, ptr_ty); - dst_addr_owned = 1; - } else { - dst_addr = api_force_local(g, &base, api_sv_type(&base)); - } + dst_addr = api_lvalue_addr(g, &base, ptr_ty); src_addr = api_lvalue_addr(g, &tmp, ptr_ty); memset(&agg, 0, sizeof agg); agg.size = 16; agg.align = access.align ? access.align : 16; T->copy_bytes(T, dst_addr, src_addr, agg); - if (dst_addr_owned) api_release_temp_local(g, dst_addr.v.local); + api_release_temp_local(g, dst_addr.v.local); api_release_temp_local(g, src_addr.v.local); } } else { @@ -849,11 +517,8 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { return; } - /* General EA-shaped scalar / bit-field store. Resolve the EA into a - * single operand the backend can consume. */ - - /* Compute the source operand first so its local lifetime doesn't - * overlap any EA-arith we issue. */ + /* General scalar / bit-field store. Compute the source operand first so its + * local lifetime doesn't overlap any addressing arith. */ api_ensure_local(g, &rv); if (api_sv_op_is_local_or_imm(&rv)) { src = rv.op; @@ -861,11 +526,9 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { src = api_force_local(g, &rv, api_sv_type(&rv)); } - /* Scalar local-resident lvalue, plain no-EA store: just copy into the local. - * Aggregate locals are storage; field stores into them need the normal memory - * path so offset-zero fields still use the scalar access type. */ - if (!has_index && !is_bitfield && ea.offset == 0 && is_lvalue && - base.source_local != CFREE_CG_LOCAL_NONE && base.op.kind == OPK_LOCAL && + /* Scalar local-resident place, plain store: copy into the local. */ + if (!is_bitfield && base.source_local != CFREE_CG_LOCAL_NONE && + base.op.kind == OPK_LOCAL && !api_sv_local_storage_is_aggregate(g, &base) && !cg_type_is_aggregate(g->c, api_sv_type(&base)) && !cg_type_is_aggregate(g->c, ty) && @@ -884,49 +547,29 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { } api_release(g, &base); api_release(g, &rv); - if (owned_index != CG_LOCAL_NONE) api_release_temp_local(g, owned_index); return; } - if (is_lvalue) { - if (!api_operand_can_address(&base.op)) { - CfreeCgTypeId pty = cg_type_ptr_to(g->c, api_sv_type(&base)); - Operand addr = api_lvalue_addr(g, &base, pty); - mem_op = fold_ea_into_operand(g, addr, ea.offset, owned_index, log2_scale, - access_ty, 1, &owned_base); - if (owned_base == CG_LOCAL_NONE) - owned_base = addr.v.local; - else if (owned_base != addr.v.local) - api_release_temp_local(g, addr.v.local); - } else { - mem_op = fold_ea_into_operand(g, base.op, ea.offset, owned_index, - log2_scale, access_ty, 0, &owned_base); - } - } else if (base.kind == SV_OPERAND && base.op.kind == OPK_GLOBAL) { - /* Pointer-rvalue OPK_GLOBAL: fold EA directly. */ - mem_op = fold_ea_into_operand(g, base.op, ea.offset, owned_index, - log2_scale, access_ty, 0, &owned_base); + /* Resolve the place into a single backend memop operand. */ + if (!api_operand_can_address(&base.op)) { + CfreeCgTypeId pty = cg_type_ptr_to(g->c, api_sv_type(&base)); + Operand addr = api_lvalue_addr(g, &base, pty); + mem_op = api_op_indirect(addr.v.local, 0, access_ty); + owned_base = addr.v.local; } else { - CfreeCgTypeId pty = api_sv_type(&base); - Operand ptr_op = api_force_local(g, &base, pty); - mem_op = fold_ea_into_operand(g, ptr_op, ea.offset, owned_index, log2_scale, - access_ty, 1, &owned_base); + mem_op = place_operand_for_access(base.op, access_ty); } - /* Source-local tracking. Only the plain no-EA scalar-to-scalar store can - * fold into a tracked constant; everything else clears tracking. */ - if (is_lvalue && base.source_local != CFREE_CG_LOCAL_NONE) { - if (!has_index && !is_bitfield && ea.offset == 0 && src.kind == OPK_IMM) { + /* Source-local tracking: only a plain scalar-to-scalar store can fold into a + * tracked constant; everything else clears tracking. */ + if (base.source_local != CFREE_CG_LOCAL_NONE) { + if (!is_bitfield && src.kind == OPK_IMM) { api_local_const_store(g, base.source_local, access, src.v.imm); } else { api_local_const_clear(api_local_from_handle(g, base.source_local)); } - } else if (is_lvalue && - (base.op.kind == OPK_INDIRECT || base.op.kind == OPK_GLOBAL || - (access.flags & CFREE_CG_MEM_VOLATILE))) { - api_local_const_memory_boundary(g); - } else if (!is_lvalue) { - /* Store through pointer is a memory write -- be conservative. */ + } else if (base.op.kind == OPK_INDIRECT || base.op.kind == OPK_GLOBAL || + (access.flags & CFREE_CG_MEM_VOLATILE)) { api_local_const_memory_boundary(g); } @@ -940,9 +583,9 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgEffAddr ea) { api_release(g, &base); api_release(g, &rv); if (owned_base != CG_LOCAL_NONE) api_release_temp_local(g, owned_base); - if (owned_index != CG_LOCAL_NONE) api_release_temp_local(g, owned_index); } + /* ============================================================ * Stack manipulation * ============================================================ */ diff --git a/test/api/cg_switch_test.c b/test/api/cg_switch_test.c @@ -144,8 +144,7 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_load( cg, (CfreeCgMemAccess){.type = sh->selector_type, - .align = cfree_cg_type_align(c, sh->selector_type)}, - (CfreeCgEffAddr){0, 0}); + .align = cfree_cg_type_align(c, sh->selector_type)}); memset(&sw, 0, sizeof sw); sw.selector_type = sh->selector_type; sw.default_label = default_lbl; diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -146,13 +146,13 @@ static void exercise_cg_handles(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_push_local(cg, local); cfree_cg_push_local_addr(cg, param); - /* removed: cfree_cg_indirect no longer needed */ - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_deref(cg, 0); /* pointer VALUE -> PLACE for the load */ + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); cfree_cg_push_local_addr(cg, local); - /* removed: cfree_cg_indirect no longer needed */ - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_deref(cg, 0); /* pointer VALUE -> PLACE for the load */ + cfree_cg_load(cg, mem); cfree_cg_ret(cg); cfree_cg_func_end(cg); @@ -218,9 +218,9 @@ static void exercise_cg_scalar_local(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 2, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_ret(cg); @@ -288,10 +288,10 @@ static void exercise_cg_late_local_addr(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 41, i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); cfree_cg_push_local_addr(cg, local); - /* removed: cfree_cg_indirect no longer needed */ - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_deref(cg, 0); /* pointer VALUE -> PLACE for the load */ + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 1, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_ret(cg); @@ -549,7 +549,7 @@ static uint32_t cg_emit_delayed_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, mem.type = i32_ty; mem.align = cfree_cg_type_align(c, i32_ty); cfree_cg_push_local(cg, param); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 40, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_push_int(cg, 2, i32_ty); @@ -622,7 +622,7 @@ static uint32_t cg_emit_unary_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, mem.type = i32_ty; mem.align = cfree_cg_type_align(c, i32_ty); cfree_cg_push_local(cg, param); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); cfree_cg_int_unop(cg, CFREE_CG_INT_BNOT, 0); cfree_cg_ret(cg); @@ -689,9 +689,9 @@ static uint32_t cg_emit_local_shadow(CfreeCompiler* c, CfreeCgTypeId i32_ty, mem.align = cfree_cg_type_align(c, i32_ty); cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 2, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_ret(cg); @@ -762,7 +762,7 @@ static uint32_t cg_emit_delayed_cmp(CfreeCompiler* c, CfreeCgTypeId i32_ty, mem.type = i32_ty; mem.align = cfree_cg_type_align(c, i32_ty); cfree_cg_push_local(cg, param); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 40, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_push_int(cg, 2, i32_ty); @@ -842,14 +842,14 @@ static uint32_t cg_emit_delayed_store(CfreeCompiler* c, CfreeCgTypeId i32_ty, mem.align = cfree_cg_type_align(c, i32_ty); cfree_cg_push_local(cg, local); cfree_cg_push_local(cg, param); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 40, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_push_int(cg, 2, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_ret(cg); cfree_cg_func_end(cg); @@ -925,12 +925,12 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, CfreeCgTypeId i32_ty, for (uint32_t i = 0; i + 1 < NPARAMS; ++i) { cfree_cg_push_local(cg, params[i]); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 1, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); } cfree_cg_push_local(cg, params[NPARAMS - 1]); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_drop(cg); for (uint32_t i = 0; i + 1 < NPARAMS; ++i) cfree_cg_drop(cg); cfree_cg_push_int(cg, 0, i32_ty); @@ -1009,7 +1009,7 @@ static uint32_t cg_emit_local_shadow_boundary(CfreeCompiler* c, cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); switch (boundary) { case CG_SHADOW_LABEL: { @@ -1031,20 +1031,20 @@ static uint32_t cg_emit_local_shadow_boundary(CfreeCompiler* c, case CG_SHADOW_VOLATILE: mem.flags = CFREE_CG_MEM_VOLATILE; cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_drop(cg); mem.flags = 0; break; case CG_SHADOW_INDIRECT_STORE: cfree_cg_push_local_addr(cg, local); - /* removed: cfree_cg_indirect no longer needed */ + cfree_cg_deref(cg, 0); /* pointer VALUE -> PLACE for the store */ cfree_cg_push_int(cg, 41, i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); break; } cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem); cfree_cg_push_int(cg, 2, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_ret(cg); @@ -1118,12 +1118,12 @@ static uint32_t cg_emit_local_shadow_partial_store(CfreeCompiler* c, cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 40, i32_ty); - cfree_cg_store(cg, mem_i32, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem_i32); cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 7, i8_ty); - cfree_cg_store(cg, mem_i8, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem_i8); cfree_cg_push_local(cg, local); - cfree_cg_load(cg, mem_i32, (CfreeCgEffAddr){0, 0}); + cfree_cg_load(cg, mem_i32); cfree_cg_push_int(cg, 2, i32_ty); cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); cfree_cg_ret(cg); @@ -1258,7 +1258,7 @@ static void run_bad_scalar_access_to_aggregate(void* arg) { mem.align = cfree_cg_type_align(ctx->c, ctx->i32_ty); cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 42, ctx->i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); } static void run_bad_store_value_size(void* arg) { @@ -1276,7 +1276,7 @@ static void run_bad_store_value_size(void* arg) { mem.align = cfree_cg_type_align(ctx->c, ctx->i64_ty); cfree_cg_push_local(cg, local); cfree_cg_push_int(cg, 42, ctx->i32_ty); - cfree_cg_store(cg, mem, (CfreeCgEffAddr){0, 0}); + cfree_cg_store(cg, mem); } static void exercise_cg_memory_mismatch_diags(CfreeCompiler* c,