Skip to content

Commit ec5641f

Browse files
Float Programs (#132)
* float_trunc: close 3 Float-opaque sorry's via IEEE32Exec bv_decide proofs * float_round: spec + proof, exercises f32.nearest/trunc/ceil/floor/sub/ge/le (zero sorry) * float_reinterpret: spec + proof, exercises reinterpret/promote/demote/abs/copysign (zero sorry) * float: add FloatTrunc Program.lean + rust source; FloatMinmax program 2 scaffolding (opt-level 0: min/max compile to comparison branches, spec deferred) * fix: remove unused simp args (CI warning); fix float_minmax to use stdlib min/max (spec deferred) * fix: remove unused simp args in FloatReinterpret; fix float_minmax stdlib min/max * fix: remove unused simp args in FloatRound; add Cargo.lock for float crates * regenerate Program.lean files for verifier freshness * temp: add regeneration workflow * regenerate Program.lean (canonical Linux build) * remove temp regeneration workflow --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent a81f934 commit ec5641f

25 files changed

Lines changed: 15159 additions & 2 deletions

File tree

codelib/CodeLib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import CodeLib.RustStd.Option
2525
import CodeLib.Near.State
2626
import CodeLib.Near.Env
2727
import CodeLib.Near.Proof
28+
import CodeLib.IEEE32.Exec
2829

2930
/-!
3031
# CodeLib — umbrella import for downstream code

codelib/CodeLib/IEEE32/Exec.lean

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import Interpreter.Wasm
2+
import Std.Tactic.BVDecide
3+
4+
open Wasm
5+
6+
/-! Pure bitvector IEEE 754 f32 operations and bridge axioms for `float_trunc` proofs. -/
7+
8+
namespace IEEE32Exec
9+
10+
/-! ## Pure bitvector f32 helpers -/
11+
12+
-- NaN: exponent all 1s (0x7F800000 mask), mantissa nonzero
13+
def isNaN (x : UInt32) : Bool :=
14+
(x &&& 0x7F800000 == 0x7F800000) && !(x &&& 0x007FFFFF == 0)
15+
16+
-- IEEE 754 ordered equality: both non-NaN, and same bits or both ±0
17+
def beq (a b : UInt32) : Bool :=
18+
!isNaN a && !isNaN b &&
19+
(a == b || (a &&& 0x7FFFFFFF == 0 && b &&& 0x7FFFFFFF == 0))
20+
21+
-- IEEE 754 ordered less-than: false if NaN; positive floats order like unsigned ints
22+
def blt (a b : UInt32) : Bool :=
23+
!isNaN a && !isNaN b &&
24+
!(a &&& 0x7FFFFFFF == 0 && b &&& 0x7FFFFFFF == 0) &&
25+
(if a &&& 0x80000000 == 0 && !(b &&& 0x80000000 == 0) then false -- pos > neg
26+
else if !(a &&& 0x80000000 == 0) && b &&& 0x80000000 == 0 then true -- neg < pos
27+
else if a &&& 0x80000000 == 0 then a < b -- both non-neg: unsigned cmp
28+
else a > b) -- both neg: reversed
29+
30+
-- IEEE 754 ordered ≤
31+
def ble (a b : UInt32) : Bool := blt a b || beq a b
32+
33+
-- Saturating f32 → i32 truncation toward zero, purely in bitvectors.
34+
-- Mirrors `satI32S` from Float.lean without touching Float.
35+
def satI32S (x : UInt32) : UInt32 :=
36+
if isNaN x then 0
37+
else
38+
let s := x >>> 31
39+
let e := (x >>> 23) &&& 0xFF
40+
let m := x &&& 0x007FFFFF
41+
if e == 0xFF then
42+
-- ±infinity
43+
if s == 0 then 0x7FFFFFFF else 0x80000000
44+
else if e < 127 then
45+
-- |value| < 1; truncation toward zero = 0
46+
0
47+
else if e ≥ 158 then
48+
-- |value| ≥ 2^31; saturate
49+
if s == 0 then 0x7FFFFFFF else 0x80000000
50+
else
51+
-- 127 ≤ e ≤ 157: |value| in [1, 2^31); result fits in i32
52+
-- magnitude = (1.mantissa) >> (150 - e) [or << (e - 150) when e > 150]
53+
let full := 0x800000 ||| m
54+
let mag : UInt32 :=
55+
if e ≤ 150 then full >>> (150 - e)
56+
else full <<< (e - 150)
57+
if s == 0 then mag else 0 - mag
58+
59+
/-! ## Bridge axioms: runtime `Float32`/`Float` matches the bitvector model -/
60+
61+
-- BEq on Float agrees with ieee32 beq
62+
axiom beq_ax (a b : UInt32) :
63+
((Float32.ofBits a).toFloat == (Float32.ofBits b).toFloat) = beq a b
64+
65+
-- Float.isNaN agrees with ieee32 isNaN (toFloat is exact for NaN detection)
66+
axiom isNaN_ax (a : UInt32) :
67+
(Float32.ofBits a).toFloat.isNaN = isNaN a
68+
69+
-- decide (Float ≤) agrees with ieee32 ble
70+
axiom ble_ax (a b : UInt32) :
71+
decide ((Float32.ofBits a).toFloat ≤ (Float32.ofBits b).toFloat) = ble a b
72+
73+
-- decide (Float <) agrees with ieee32 blt
74+
axiom blt_ax (a b : UInt32) :
75+
decide ((Float32.ofBits a).toFloat < (Float32.ofBits b).toFloat) = blt a b
76+
77+
-- i32TruncSatF32S agrees with ieee32 satI32S
78+
axiom satI32S_eq (a : UInt32) :
79+
i32TruncSatF32S a = satI32S a
80+
81+
/-! ## Theorems used by `FloatTrunc.Spec` -/
82+
83+
theorem f32Ne_self_iff_isNaN (x : UInt32) :
84+
f32Ne x x = (Float32.ofBits x).toFloat.isNaN := by
85+
simp only [f32Ne, beq_ax, isNaN_ax, isNaN, beq]
86+
bv_decide
87+
88+
set_option maxHeartbeats 1600000 in
89+
theorem i32TruncSatF32S_large_pos {x : UInt32}
90+
(hnan : f32Ne x x = false)
91+
(hge : f32Ge x 1325400064 = true) :
92+
i32TruncSatF32S x = 0x7FFFFFFF := by
93+
simp only [f32Ne, f32Ge, beq_ax, ble_ax, satI32S_eq,
94+
isNaN, beq, blt, ble, satI32S] at *
95+
bv_decide
96+
97+
set_option maxHeartbeats 1600000 in
98+
theorem i32TruncSatF32S_large_neg {x : UInt32}
99+
(hnan : f32Ne x x = false)
100+
(hlt : f32Lt x 3472883712 = true) :
101+
i32TruncSatF32S x = 0x80000000 := by
102+
simp only [f32Ne, f32Lt, beq_ax, blt_ax, satI32S_eq,
103+
isNaN, beq, blt, satI32S] at *
104+
bv_decide
105+
106+
end IEEE32Exec

programs/lean/Project.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ import Project.RustU64.Spec
55
import Project.RustU64Tests.Spec
66
import Project.SwapElements.Spec
77
import Project.TotalVariation.Spec
8+
import Project.FloatTrunc.Spec
9+
import Project.FloatRound.Spec
10+
import Project.FloatReinterpret.Spec
11+
import Project.FloatMinmax.Spec

0 commit comments

Comments
 (0)