@@ -44,9 +44,10 @@ the front-end to clang, so its scope is the IR→UVM lowering plus the thin driv
4444- ** Back-end codegen: Phases 0–8 done** (arithmetic, control flow, memory,
4545 globals, calls, intrinsics, corner cases) and ** Phase 9 done** (the
4646 clang-driver front-end — ` uvclang foo.c ` drives clang + back-end in one
47- command). Scalar ** ` float ` (f32) is supported** (arithmetic, compare, int↔float
48- conversions, libm f32 calls; see * Floating point* below), and the ** printf
49- family** (` printf ` /` sprintf ` /` snprintf ` /…) is implemented on the callee-side
47+ command). Scalar ** ` float ` (f32) and ` double ` (f64) are supported**
48+ (arithmetic, compare, int↔float conversions, float↔double conversions, libm
49+ f32/f64 calls; see * Floating point* below), and the ** printf family**
50+ (` printf ` /` sprintf ` /` snprintf ` /…) is implemented on the callee-side
5051 ` va_arg ` support (see * C standard library* → ` <stdio.h> ` ). The back-end
5152 differential suite (` .ll ` path) is ** 108 pass / 0 fail / 0 skip** ; the
5253 end-to-end front-end suite (` tests/run_frontend_tests.sh ` , single-command
@@ -152,34 +153,39 @@ support ordinary variadic C (the `printf` family).
152153- ** ` zext ` ** = already satisfied by the invariant (or mask/` trunc ` to source
153154 width). ** ` sext ` ** = ` sx_iW_iW2 ` . ** ` trunc ` ** = ` trunc_uW ` .
154155
155- ### Floating point (f32) — DONE
156- UVM has ** single-precision only ** — a fixed set of ` *_f32 ` ops and no f64
157- instructions at all — so uvclang supports ` float ` and rejects ` double `
158- * arithmetic * (a ` double ` value can still be stored/moved, just not computed on;
159- ` fpext ` / ` fptrunc ` error). This mirrors ncc, which is also f32-only .
160- - ** Slot representation is identical to ` i32 ` :** a float lives in the low 32
161- bits of its slot as the IEEE-754 pattern, upper bits zero ( ` Value::as_f32 `
162- reads ` f32::from_bits(low32) ` ). So ` load float ` / ` store float ` are just
163- ` load_u32 ` /` store_u32 ` , and float phi/select/call-args/returns reuse the exact
156+ ### Floating point (f32 + f64 ) — DONE
157+ UVM has parallel single- and double-precision op sets ( ` *_f32 ` and ` *_f64 ` ), so
158+ uvclang supports both ` float ` and ` double ` as first-class scalars. Each float
159+ codegen path picks its ops/width through one helper, ` float_kind(ty) ` , which
160+ maps ` float ` → ` ("f32", 32) ` and ` double ` → ` ("f64", 64) ` .
161+ - ** Slot representation mirrors the same-width integer :** a ` float ` lives in the
162+ low 32 bits of its slot as the IEEE-754 pattern (like ` i32 ` ); a ` double ` fills
163+ the whole 64-bit slot (like ` i64 ` ). So ` load/ store ` of a float/double are just
164+ ` load_u32 ` /` load_u64 ` etc. , and float phi/select/call-args/returns reuse the
164165 integer value-moving paths (see ` scalar_width ` ).
165- - ** Arithmetic/compare:** ` fadd/fsub/fmul/fdiv ` → ` add/sub/mul/div_f32 ` ;
166- ` fneg ` → xor the sign bit (` ^ 0x80000000 ` ); ` fcmp ` → the six ordered VM ops
167- (` eq/lt/le/gt/ge_f32 ` , all NaN-false) with ` ne_f32 ` for ` une ` , and the
168- remaining unordered/` one ` /` ord ` /` uno ` predicates composed by boolean
169- complement/disjunction.
170- - ** Conversions:** ` sitofp ` sign-extends to i64 then ` i64_to_f32 ` ; ` uitofp ` uses
171- ` i64_to_f32 ` on the already-zero-extended slot; ` fptosi ` /` fptoui ` →
172- ` f32_to_i32 ` then re-truncate to restore the width invariant (target width
173- ≤ 32; float→i64 is unsupported). Float constants lower to ` push_f32 ` (finite)
174- or the raw bit pattern (inf/NaN); ` float ` globals emit ` .f32 ` .
175- - ** libm / intrinsics:** ` sinf/cosf/tanf/asinf/acosf/atanf/sqrtf/powf ` (libcalls)
176- and ` llvm.sqrt/sin/cos/fabs/pow.f32 ` map to the matching ` *_f32 ` op; ` fabsf ` /
177- ` llvm.fabs ` clear the sign bit; ` llvm.fmuladd.f32 ` → ` mul_f32; add_f32 ` (two
178- roundings — matches a baseline no-FMA native target; a float test compares
166+ - ** Arithmetic/compare:** ` fadd/fsub/fmul/fdiv ` → ` add/sub/mul/div_{f32,f64} ` ;
167+ ` fneg ` → xor the sign bit (` ^ 0x8000_0000 ` for f32, ` ^ 0x8000_0000_0000_0000 `
168+ for f64); ` fcmp ` → the six ordered VM ops (` eq/lt/le/gt/ge_{f32,f64} ` , all
169+ NaN-false) with ` ne_* ` for ` une ` , and the remaining unordered/` one ` /` ord ` /` uno `
170+ predicates composed by boolean complement/disjunction (which act on the 0/1
171+ results, so they're width-agnostic).
172+ - ** Conversions:** ` sitofp ` sign-extends to i64 then ` i64_to_{f32,f64} ` ; ` uitofp `
173+ uses ` i64_to_{f32,f64} ` on the already-zero-extended slot. ` fptosi ` /` fptoui `
174+ from f32 to a ≤32-bit int use ` f32_to_i32 ` then re-truncate; every other case
175+ (any float → i64, or f64 → any int) goes through ` f64_to_i64 ` (widening an f32
176+ with ` f32_to_f64 ` first) then truncates to the target width. ` fpext `
177+ (float→double) → ` f32_to_f64 ` ; ` fptrunc ` (double→float) → ` f64_to_f32 ` . Float
178+ constants lower to ` push_f32 ` /` push_f64 ` (finite) or the raw bit pattern
179+ (inf/NaN); ` float ` /` double ` globals emit ` .f32 ` /` .f64 ` .
180+ - ** libm / intrinsics:** ` sinf/…/powf ` and ` sin/…/pow ` (libcalls) plus
181+ ` llvm.sqrt/sin/cos/fabs/pow.{f32,f64} ` map to the matching ` *_f32 ` /` *_f64 ` op
182+ (dispatched on the call name / intrinsic result type); ` fabsf ` /` fabs ` /
183+ ` llvm.fabs ` clear the sign bit; ` llvm.fmuladd ` → ` mul; add ` (two roundings —
184+ matches a baseline no-FMA native target; the float tests compare
179185 transcendentals with tolerance to absorb any last-bit host/libm difference).
180186- ** Header:** a minimal ISO ` <math.h> ` in ` uvclang/include/ ` declares the f32
181- functions (+ ` M_PI ` /` M_PI_F ` constants). Covered by ` tests/floats.c `
182- (differential vs native + self-checking, -O0/-O1/-O2).
187+ and f64 functions (+ ` M_PI ` /` M_PI_F ` constants). Covered by ` tests/floats.c `
188+ and ` tests/doubles.c ` (differential vs native + self-checking, -O0/-O1/-O2).
183189
184190### Memory & pointers
185191- ** ` alloca ` :** assign each alloca a fixed offset within the function's
@@ -446,15 +452,17 @@ verbatim without consuming an argument.
446452| ---| ---| ---|
447453| ` assert ` | ✅ | ✅ passing path (` uvm_* ` self-checks) + failure path (` xfail_assert.c ` ) |
448454
449- ### ` <math.h> ` — partial (f32)
455+ ### ` <math.h> ` — partial (f32 + f64 )
450456A minimal ISO ` <math.h> ` ships in ` uvclang/include/ ` , declaring the
451457single-precision functions uvclang lowers to UVM ` *_f32 ` ops
452- (` sinf ` /` cosf ` /` tanf ` /` asinf ` /` acosf ` /` atanf ` /` sqrtf ` /` fabsf ` /` powf ` ) plus the
453- ` M_* ` /` M_*_F ` constants. Exercised by ` tests/floats.c ` . ** Not** provided: the
454- ` double ` variants (UVM has no f64), and f32 ops with no UVM instruction
455- (` floorf ` /` ceilf ` /` fmodf ` /` expf ` /` logf ` /` atan2f ` /…) — add when a test needs
456- them. Note ` uvm/math.h ` is a separate UVM-specific header (min/max/lerp macros),
457- not ISO ` <math.h> ` .
458+ (` sinf ` /` cosf ` /` tanf ` /` asinf ` /` acosf ` /` atanf ` /` sqrtf ` /` fabsf ` /` powf ` ) and their
459+ double-precision counterparts lowered to ` *_f64 ` ops
460+ (` sin ` /` cos ` /` tan ` /` asin ` /` acos ` /` atan ` /` sqrt ` /` fabs ` /` pow ` ) plus the
461+ ` M_* ` /` M_*_F ` constants. Exercised by ` tests/floats.c ` and ` tests/doubles.c ` .
462+ ** Not** provided: functions with no UVM instruction
463+ (` floorf ` /` ceilf ` /` fmodf ` /` expf ` /` logf ` /` atan2f ` /… and their ` double ` forms) —
464+ add when a test needs them. Note ` uvm/math.h ` is a separate UVM-specific header
465+ (min/max/lerp macros), not ISO ` <math.h> ` .
458466
459467### Out of scope for now
460468` <time.h> ` , ` <locale.h> ` , ` <signal.h> ` , ` <setjmp.h> ` , ` <errno.h> ` , ` <wchar.h> ` —
@@ -709,5 +717,5 @@ the doom path (doom's only libc external is `@strlen`, already covered).
709717 ` print ` , window/framebuffer, keyboard/mouse input) is in scope (Phase 10);
710718 only ** audio** (sound/MIDI) is deferred.
711719- No support for IR features clang ` -O2 ` C output never emits (vectors,
712- ` double ` /f64 arithmetic — UVM is f32-only, exception handling, etc.) until a
713- test needs them. (Scalar ` float ` /f32 * is * supported — see * Floating point* .)
720+ exception handling, etc.) until a test needs them. (Scalar ` float ` /f32 and
721+ ` double ` /f64 * are * supported — see * Floating point* .)
0 commit comments