Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Add float64 support for wasm32 selfhost#66

Merged
Vbitz merged 6 commits into
mainfrom
codex/wasm-float64-wasm32
Mar 7, 2026
Merged

Add float64 support for wasm32 selfhost#66
Vbitz merged 6 commits into
mainfrom
codex/wasm-float64-wasm32

Conversation

@Vbitz

@Vbitz Vbitz commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add the first usable float64 path through the frontend, IR, and wasi/wasm32 backend
  • fix wasm32 float64 handling for interface boxing/dispatch, type assertions, and composite literal layout
  • restore selfhost-wasm fixed-point convergence and drop the stale wasm fullcompiler skip
  • ignore tmp/ and web/*-library.js scratch outputs in the repo root .gitignore

Validation

  • ./build/build build
  • ./build/build selfhost-wasm
  • targeted ./build/rtg -strict -T wasi/wasm32 ... && wasmtime ... repros for:
    • float64 interface dispatch from a struct field
    • interface boxing plus float64 type assertion
    • composite literals with explicit and omitted float64 fields

Notes

  • test-fullcompiler-wasm gets past the earlier iface_typeassert blocker, but there is still unrelated existing coverage failing later in 55_stdlib_additions_extended (strconv.ParseInt signed behavior)

@Vbitz Vbitz force-pushed the codex/wasm-float64-wasm32 branch from a6e2bb6 to fa3da95 Compare March 6, 2026 18:00
@Vbitz Vbitz marked this pull request as ready for review March 7, 2026 07:32
@greptile-apps

greptile-apps Bot commented Mar 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds the first end-to-end float64 path through the RTG compiler pipeline — parser, IR, frontend, and wasi/wasm32 backend — and fixes the iface_typeassert wasm32 validation failure that was previously blocking the fullcompiler test suite. The change also includes a broad mechanical refactoring across all backends (aarch64, i386, x64, riscv, armv8m) that replaces keyed struct-literal construction with field-by-field assignment and switches interface-dispatch map lookups to LookupStringMapLinear, both of which are required to keep the selfhost (wasm32-compiled) build deterministic.

Key changes:

  • New IR: OP_CONST_F64, TY_FLOAT64, IRLocal.IsFloat64, IRFunc.ResultKinds/ResultIs64 — required to carry float type information through the stack-machine IR.
  • Frontend: NFloatLit AST node, isFloatExpr/isConstFloatExpr helpers, setLocalTypeFlags for unified local/param/result type annotation, per-field struct sizing (resolveStructSize), and ifaceMethodRetTypes for interface return-type dispatch.
  • wasm32 backend: per-global/per-local 8-byte float slots, tempLocalF64 temp register, f64 arithmetic/compare/convert op emission, compileCompositeLitCall with field-size-aware layout, compileIfaceBox with 12-byte box for f64/i64, and parseFloatLiteralBits — a self-contained decimal-to-IEEE-754 converter implemented without strconv so it works under selfhost.
  • parseFloatLiteralBits overflow: the converter accumulates the integer mantissa × 10^exp in a uint64; any literal whose intermediate result exceeds ~1.8×10¹⁹ (e.g. 1e20) causes mul10Checked to fail, and the caller silently substitutes 0.0. This is the most significant functional gap in the PR and should be tracked or documented.
  • String dedup removed: stringMap and the deduplication guard in internString were removed (likely to avoid map[string]int direct-index issues under selfhost), so repeated string literals now produce duplicate data-segment entries.
  • Indentation inconsistency in compileLocalAddImm — the else if/else branches carry an extra level of indentation that would be rejected by gofmt.

Confidence Score: 3/5

  • Safe for selfhost convergence but has a silent data-loss bug in the float literal parser for values outside the ~[-1.8e19, 1.8e19] range.
  • The core float64 path (arithmetic, load/store, interface boxing/dispatch, type assertions, composite literals) is well-structured and validated by the selfhost round-trip. The mechanical selfhost-compatibility changes (positional struct literals, LookupStringMapLinear, makeInst) are consistent across all backends. The main risk is parseFloatLiteralBits silently returning 0.0 for out-of-uint64-range float literals, plus the missing i64 branch in multi-return ifaceCall reload (though that is a pre-existing gap). The string dedup removal and compileLocalAddImm indentation are minor concerns.
  • std/compiler/backend/wasm32/backend_wasm32.go — particularly parseFloatLiteralBits and compileIfaceCall multi-return reload path.

Important Files Changed

Filename Overview
std/compiler/backend/wasm32/backend_wasm32.go Core of the PR: adds f64 type tracking, f64 local/global/param/return handling, float arithmetic ops, interface boxing/dispatch, composite literal layout, and type conversions for wasm32. Three issues: parseFloatLiteralBits silently returns 0.0 for floats outside ~1.8e19, a compileLocalAddImm indentation error, and a missing i64 branch in multi-return ifaceCall reload.
std/compiler/backend/wasm32/wasm32.go Adds f64 opcode constants (OP_WASM_F64_*), f64 load/store helpers, f64ConstBits emitter, and unsigned integer operation opcodes. Straightforward constant/helper additions; no logic concerns.
std/compiler/ir/irtypes.go Adds TY_FLOAT64 type kind, OP_CONST_F64 opcode, IsFloat64 field on IRLocal, and ResultKinds/ResultIs64 slices on IRFunc. Companion makeInst helper avoids keyed composite literal issues in selfhost. Clean additions with no apparent issues.
std/compiler/frontend/go/compiler.go Extensive additions for float64 front-end support: isFloatTypeName, isFloatExpr, isConstFloatExpr helpers; setLocalTypeFlags for unified local type annotation; resolveStorageTypeName for type alias resolution; struct field layout with per-field sizing; emitZeroValueForTypeName; ifaceMethodRetTypes tracking for return type dispatch. Also adds emitKnownCall, makeInst, resolvedCallRetCount helpers. Large but well-structured; no functional issues found.
std/compiler/frontend/go/parser.go Removes the float literal error rejection (TOKEN_FLOAT now produces NFloatLit node instead of erroring), removes float64 from the unsupported type list. Minor: adds NFloatLit AST node kind and isValidFloatLiteral validator. Safe change.
std/compiler/backend/becommon/common.go Adds SortDispatchEntries (insertion sort by TypeID/FuncName) and LookupStringMapLinear (linear string map scan to avoid direct indexing in selfhost). Clean additions; SortDispatchEntries is used by i386 but not yet by wasm32.
std/compiler/ir/opt_ir.go Removes the foldLocalAddImm optimization pass from the IR optimizer to prevent incorrect float64 handling (integer immediate folded into a float64 local ADD would use wrong semantics). buildCompositeHelperFunc still uses fieldCount*wordSize for structBytes, which remains potentially misaligned for mixed int/float64 composite types, but this is an existing limitation not introduced by this PR.
tools/build.go Removes the wasm fullcompiler skip for iface_typeassert now that the underlying bug is fixed. Straightforward cleanup.
std/compiler/backend/i386/backend_i386.go Switches to LookupStringMapLinear for method dispatch and adds SortDispatchEntries to ensure deterministic dispatch order. Also converts struct literal initializations to positional form for selfhost. Safe.
std/compiler/backend/irprint/backend_ir.go Adds OP_CONST_F64 and TY_FLOAT64 to the IR printer; OP_CONST_F64 prints its name field (the float literal string) as a quoted atom. Correct and minimal.

Sequence Diagram

sequenceDiagram
    participant FE as Frontend
    participant IR as IR Layer
    participant BE as Wasm32 Backend
    participant W as Wasm Emitter

    FE->>IR: NFloatLit to OP_CONST_F64 with literal string
    FE->>IR: IRLocal.IsFloat64 = true for float64 vars
    FE->>IR: IRFunc.ResultKinds with TY_FLOAT64 for float64 returns
    IR-->>BE: IRFunc with f64-typed locals and results
    BE->>BE: compileFunc assigns tempLocalF64 and localF64 map
    BE->>W: f64ConstBits using parseFloatLiteralBits
    BE->>W: f64Load or f64Store for local and global get/set
    BE->>BE: compileIfaceBox uses 12-byte box for f64 values
    W-->>BE: f64.store at offset 4 in box
    BE->>BE: compileIfaceCall loads recv via f64Load when recvType is F64
    BE->>BE: compileReturn saves and reloads via scratch with i times 8 stride
    BE->>W: emit f64.add, f64.eq, f64.convert and related ops
Loading

Comments Outside Diff (2)

  1. std/compiler/backend/wasm32/backend_wasm32.go, line 2716-2733 (link)

    parseFloatLiteralBits silently produces 0.0 for large float literals

    The integer division algorithm accumulates num by multiplying by 10 for each positive decimal exponent. mul10Checked guards against overflow, but once num exceeds uint64_max / 10 (~1.844e18), it returns (0, false) and the whole parser returns (0, false). The caller then silently uses bits = 0 (IEEE 754 +0.0):

    bits, ok := parseFloatLiteralBits(inst.Name)
    if !ok {
        bits = 0
    }
    g.w.f64ConstBits(bits)

    This means any float literal whose intermediate representation overflows uint64 — practically anything at or above 1e20 — silently compiles as 0.0 with no diagnostic.

    A similar bound applies on the denominator side (for very small exponents like 1e-20), though that threshold is somewhat higher due to the separate den path.

    For the current selfhost use-case, literals like math.Pi or 1.5 are well within range. However, literals such as 1e20, math.MaxFloat64 (~1.8e308), or 1e-20 would be silently wrong. Consider either:

    • Emitting a compile-time warning/error when !ok, or
    • Recognising the overflow condition and returning ±Inf / subnormal as appropriate (matching Go semantics), rather than 0.
  2. std/compiler/backend/wasm32/backend_wasm32.go, line 1521-1533 (link)

    Inconsistent indentation in compileLocalAddImm

    The else if and else branches are indented with an extra level of tabs compared to the opening if, making the block structure visually misleading. While Go syntax is indentation-insensitive (braces define structure), this doesn't match the project's surrounding style and would be flagged by gofmt. Consider aligning the indentation:

Last reviewed commit: ea568bd

Comment thread std/compiler/backend/wasm32/backend_wasm32.go
Comment thread std/compiler/backend/wasm32/backend_wasm32.go
@Vbitz Vbitz added this pull request to the merge queue Mar 7, 2026
Merged via the queue into main with commit 216127b Mar 7, 2026
14 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant