w6c+w6c_ww: tuple-let receive keyed on type classify, not producer shape (C-t1, #33)
wwstage cglet's tuple receive was producer-SHAPE-keyed: the mixed str/scalar arm required s0_is_str != s1_is_str (syntactic) and the rt16 arm required an N_CALL rhs (rettupleof), so a scalar-scalar tuple LITERAL `let t: (u32,u32) = (3,4)` matched neither and fell to the generic single-word store — word 1 silently dropped (#209/#211-class syntactic-vs-type keying). cstage's twin arm was sz==16/32 magic-size keyed, so 24B 3-scalar tuples dropped words 2+ on BOTH sources. Both stages now key the same way: declared-type TY_TUPLE + in-cap register classify (cg_sret_retsize / sretretsize == 0, the shared SSoT), alias-peeled; the two wwstage shape arms collapse into one type-keyed arm walking the declared element list (the #240 lesson — never the producer's). Over-cap falls through to the sret receive exactly as before; unannotated `let t = f()` rides inferletcalltype. 941 grows the t1 rows: lit packed/16B/3-scalar + call 3-scalar fail at the C-t0 parent (10/39 checks — wwstage lit halves AND both-stage 24B halves), mixed-lit + unannotated-call anchor the untouched paths. Filed while probing: cstage silently accepts an over-cap tuple-LITERAL let where wwstage loud-stops (pre-existing at master, task #64).
This commit is contained in:
@@ -10499,21 +10499,28 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_BP, off + 16));
|
||||
break;
|
||||
}
|
||||
/* Tuple initialiser from a function call (#105 / #164/#107),
|
||||
* 16B (two eightbytes) or 32B (scalar/float + slice/str header).
|
||||
* Each element rides its SysV class: a float its SSE cursor reg
|
||||
* (X0,X1 = tuple_sse_seq), an integer/ptr word its INTEGER cursor
|
||||
* reg (tuple_rseq), a slice/str its 3-word {ptr,len,cap} header
|
||||
* over consecutive INTEGER cursor regs — INDEPENDENT counters,
|
||||
* so the RETURN leaves floats in X0/X1 and integer words in
|
||||
* AX/DX/CX/R8. A blanket MOVQ spill would store garbage where a
|
||||
* float rode and the #103-FACE-Z field read (MOVSD-from-slot)
|
||||
* would see it. tuple_store routes each element from its real
|
||||
* class into its positional slot (eoff steps by the element's
|
||||
* slot size: a slice/str takes its 24B header); the same split
|
||||
* drives the destructure / reassign sites. */
|
||||
/* Tuple initialiser (#105 / #164/#107): every IN-CAP tuple
|
||||
* receive routes here. Each element rides its SysV class: a
|
||||
* float its SSE cursor reg (X0,X1 = tuple_sse_seq), an
|
||||
* integer/ptr word its INTEGER cursor reg (tuple_rseq), a
|
||||
* slice/str its 3-word {ptr,len,cap} header over consecutive
|
||||
* INTEGER cursor regs — INDEPENDENT counters, so the RETURN
|
||||
* leaves floats in X0/X1 and integer words in AX/DX/CX/R8. A
|
||||
* blanket MOVQ spill would store garbage where a float rode
|
||||
* and the #103-FACE-Z field read (MOVSD-from-slot) would see
|
||||
* it. tuple_store routes each element from its real class
|
||||
* into its positional slot (eoff steps by the element's slot
|
||||
* size: a slice/str takes its 24B header); the same split
|
||||
* drives the destructure / reassign sites.
|
||||
*
|
||||
* C-t1 (#33 family): keyed on the TYPE's register classify
|
||||
* (cg_sret_retsize == 0, the shared SSoT), not the sz==16/32
|
||||
* magic — that key missed sz==24/40/48 in-cap shapes (3-scalar
|
||||
* tuples dropped words 2+ silently) and pre-C-t0 missed the
|
||||
* packed sz==8 entirely. Over-cap falls through to the sret
|
||||
* receive below, exactly as before. */
|
||||
if (n->rhs && lu && lu->kind == TY_TUPLE
|
||||
&& (sz == 16 || sz == 32)) {
|
||||
&& cg_sret_retsize(lt) == 0) {
|
||||
cgexpr(c, n->rhs, *locals);
|
||||
int gpcur = 0, ssecur = 0, eoff = 0, ef32;
|
||||
for (Tparam *p = lu->params; p; p = p->next) {
|
||||
|
||||
Reference in New Issue
Block a user