Numeric return-type hints: ^double/^long on a defn (round 3)
A ^double/^long return hint on a fn's name now (a) coerces the fn's value on the way out — exact->inexact / jolt->fx, like a JVM primitive return — and (b) types a call to it, so an accumulator over the result specializes: (defn ^double work [^double x ^double y] (+ (* x x) (* y y))) (loop [acc 0.0] (recur (+ acc (work a b)))) ; (+ acc (work ..)) -> fl+ The analyzer pushes the name's numeric tag onto each arity (:ret-nhint) for the back-end coercion, and resolve-global surfaces the callee's declared return (:num-ret, read from var meta) onto the :var node so jolt.passes.numeric types the call. defn carries the name hint through. This unblocks the accumulator-over-fn-result pattern that round 2 had to demote. The win is bounded by call overhead in an open/dispatched build (~1.15x on a hot loop whose body is a helper call); it compounds with direct-linking and, later, inlining. A numeric return hint is a contract, like ^long — redefining the var to return another type in an open build breaks it. Not yet: per-arity arglist return hints, (defn f (^double [x] ..)). Gate: test/chez/numeric-test.ss 39/39; full make test green, 0 new corpus divergences.
This commit is contained in:
parent
0db417a491
commit
5a9acd3cf4
6 changed files with 227 additions and 164 deletions
|
|
@ -100,5 +100,24 @@
|
|||
(ok "long-seeded loop accumulator counts to 100"
|
||||
(= 100 (jnum->exact (ev "((fn* ([^long start] (loop [acc start] (if (< acc 100) (recur (inc acc)) acc)))) 0)"))))
|
||||
|
||||
;; --- numeric return hints (round 3) ---
|
||||
;; a ^double / ^long return hint coerces the fn's value on the way out (the contract).
|
||||
(jolt-compile-eval "(def ^double dsq (fn* ([x] (* x x))))" "u")
|
||||
(ok "^double return coerces value to a flonum" (flonum? (ev "(dsq 3)")))
|
||||
(jolt-compile-eval "(def ^long ldbl (fn* ([x] (+ x x))))" "u")
|
||||
(ok "^long return coerces value to a fixnum" (let ((r (ev "(ldbl 5)"))) (and (fixnum? r) (= r 10))))
|
||||
;; the defn macro must carry the name's return hint through to the def.
|
||||
(jolt-compile-eval "(defn ^double dnsq [x] (* x x))" "u")
|
||||
(ok "defn ^double return coerces to flonum" (flonum? (ev "(dnsq 4)")))
|
||||
|
||||
;; caller propagation: a call to a ^double-returning fn types an accumulator over it.
|
||||
(let ((e (emitf "u" "(fn* ([] (loop [acc 0.0 i 0] (if (< i 3) (recur (+ acc (dsq 2.0)) (inc i)) acc))))")))
|
||||
(ok "accumulator over a ^double-returning call lowers to fl+" (has? e "(fl+")))
|
||||
(ok "accumulator over ^double call runtime: 3 * (2*2) = 12.0"
|
||||
(= 12 (jnum->exact (ev "((fn* ([] (loop [acc 0.0 i 0] (if (< i 3) (recur (+ acc (dsq 2.0)) (inc i)) acc)))))"))))
|
||||
;; a ^double call result also specializes a straight-line op
|
||||
(let ((e (emitf "u" "(fn* ([^double y] (+ y (dsq 2.0))))")))
|
||||
(ok "straight-line op over ^double call lowers to fl+" (has? e "(fl+")))
|
||||
|
||||
(printf "~a/~a passed~n" (- total fails) total)
|
||||
(exit (if (zero? fails) 0 1))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue