cstage+test: variant-widen f64 arm accepts TY_UNTYPED_FLOAT (#40)
#30 (82be8b9) shipped the f64 variant-widen MOVSD path, but cg_widen_tagged_store's float-arm gate `fld_isfloat` only accepted declared f64/f32 — not TY_UNTYPED_FLOAT. cunop on TK_MINUS over an N_FLOATLIT returns the operand's type (ty_untyped_float), and cbinop on two untyped-floats returns ty_untyped_float too. So `let a: (i64 | f64) = -2.5;` and `(2.5 + 1.0)` fell through to the scalar fallback and stored AX residue at payload+8 (tag still set correctly, payload = 0). Wwstage post-#30 was already correct via exprfloatkind's AST walk. Extend fld_isfloat to accept TY_UNTYPED_FLOAT (defaults to f64, no TY_UNTYPED_F32 exists). Acceptance set now matches cg_isfloat exactly. All 15 other fld_isfloat call sites pass declared field / element / pointee types that never carry TY_UNTYPED_* post-check — no over-trigger. Test 715 grows from 7 → 10 rows: unary_neg_floatlit_direct (`-2.5`), unary_neg_floatlit_paren (`-(2.5)`), binop_floatlit_sum (`2.5+1.0`). All pin payload bits via hex-u64 punning through *u8 — direct/paren land 0xC004000000000000 (sign=1, exp=0x400, mant=0x4000000000000); sum lands 0x400C000000000000 (3.5). Hex literal use is documented inline pointing at #41 (orthogonal comparison-ladder bug surfaced during test development; decimal-u64 RHS of != miscompiles). After this lands, lib/fmt/fmttest.ww's 3 routed-around rows (cited at7f320d3) can drop the `let nv: f64 = -2.5;` indirection and use the direct literal — sibling cleanup.
This commit is contained in:
@@ -117,6 +117,44 @@ static const struct row rows[] = {
|
||||
/* -1.0 == 0xBFF0000000000000 == 13830554455654793216 */
|
||||
"13830554455654793216", "1"),
|
||||
0 },
|
||||
/* #40: N_UN(MINUS, N_FLOATLIT) where the inner literal is untyped.
|
||||
* cunop returns the operand type for TK_MINUS, so the expression's
|
||||
* type is ty_untyped_float; the pre-fix fld_isfloat predicate
|
||||
* accepted only TY_F32/TY_F64 and the variant-widen float arm
|
||||
* silently fell through to MOVQ AX, dropping the X0 result onto
|
||||
* a trashed AX. -2.5 == 0xC004000000000000.
|
||||
*
|
||||
* Hex u64 literal pins the bit pattern directly. Decimal literals
|
||||
* above 2^63 round-trip cleanly through the lexer (cgexpr_int sees
|
||||
* the right bits) but the surrounding comparison ladder has an
|
||||
* unrelated latent miscompile on huge-decimal-u64 RHS — orthogonal
|
||||
* to this fix; do not entangle. */
|
||||
{ "unary_neg_floatlit_direct",
|
||||
BITCHECK_F64(
|
||||
"",
|
||||
"let a: (i64 | f64) = -2.5;\n",
|
||||
"0xC004000000000000", "1"),
|
||||
0 },
|
||||
/* Same expression shape with explicit parens around the literal.
|
||||
* Parser builds N_UN(MINUS, N_FLOATLIT) for both forms; pinning
|
||||
* both rows guards against a future parse change altering that. */
|
||||
{ "unary_neg_floatlit_paren",
|
||||
BITCHECK_F64(
|
||||
"",
|
||||
"let a: (i64 | f64) = -(2.5);\n",
|
||||
"0xC004000000000000", "1"),
|
||||
0 },
|
||||
/* Binop of two untyped-float literals — N_BIN type is
|
||||
* ty_untyped_float (untyped+untyped → untyped, see check.c cbinop).
|
||||
* Same predicate gate as the unary case; pins that the extended
|
||||
* fld_isfloat covers the binop arm too. 2.5 + 1.0 == 3.5 ==
|
||||
* 0x400C000000000000. */
|
||||
{ "binop_floatlit_sum",
|
||||
BITCHECK_F64(
|
||||
"",
|
||||
"let a: (i64 | f64) = (2.5 + 1.0);\n",
|
||||
"0x400C000000000000", "1"),
|
||||
0 },
|
||||
/* Concrete f64 ident — cgexpr emits MOVSD load to X0; AX is
|
||||
* never touched. */
|
||||
{ "ident_f64",
|
||||
|
||||
Reference in New Issue
Block a user