;; Hint-directed fast arithmetic (jolt.passes.numeric). A ^double/^long param hint ;; (or a float literal) drives Chez fl*/fx* emission instead of generic arithmetic; ;; un-hinted integer code stays generic (arbitrary-precision preserved). The pass ;; runs in run-passes with optimization OFF, so this is the open-build path. Run: ;; chez --script test/chez/numeric-test.ss (import (chezscheme)) (load "host/chez/rt.ss") (set-chez-ns! "clojure.core") (load "host/chez/seed/prelude.ss") (load "host/chez/post-prelude.ss") (set-chez-ns! "user") (load "host/chez/host-contract.ss") (load "host/chez/seed/image.ss") (load "host/chez/compile-eval.ss") (define total 0) (define fails 0) (define (ok name pred) (set! total (+ total 1)) (unless pred (set! fails (+ fails 1)) (printf "FAIL: ~a\n" name))) (define (has? s sub) (let ((ns (string-length s)) (nsub (string-length sub))) (let loop ((i 0)) (cond ((> (+ i nsub) ns) #f) ((string=? (substring s i (+ i nsub)) sub) #t) (else (loop (+ i 1))))))) ;; analyze + run-passes (optimization OFF — the always-on numeric pass still runs) ;; + emit one form to a Scheme string. (define (emitf ns str) (let-values (((f j) (rdr-read-form str 0 (string-length str)))) (let ((ctx (make-analyze-ctx ns))) (jolt-ce-emit (jolt-ce-run-passes (jolt-ce-analyze ctx f) ctx))))) ;; --- emission: ^double -> fl-ops, ^long -> fx-ops --- (let ((e (emitf "u" "(fn* ([^double a ^double b] (+ (* a a) (* b b))))"))) (ok "double + lowers to fl+" (has? e "(fl+")) (ok "double * lowers to fl*" (has? e "(fl*")) (ok "double arith is NOT generic +" (not (has? e "(jolt-invoke")))) (ok "long + lowers to fx+" (has? (emitf "u" "(fn* ([^long a ^long b] (+ a b)))") "(fx+")) (ok "long * lowers to fx*" (has? (emitf "u" "(fn* ([^long a ^long b] (* a b)))") "(fx*")) (ok "double < lowers to fl must NOT lower to a fixnum op (let ((e (emitf "u" "(fn* ([^long a ^long b] (/ a b)))"))) (ok "long division is NOT specialized (stays generic /)" (not (has? e "(fx")))) ;; --- runtime values match the generic result --- (define (ev s) (jolt-compile-eval s "u")) (ok "double dot: 3^2+4^2 = 25" (= 25 (jnum->exact (ev "((fn* ([^double a ^double b] (+ (* a a) (* b b)))) 3.0 4.0)")))) (ok "long sum: 2+3 = 5" (= 5 (jnum->exact (ev "((fn* ([^long a ^long b] (+ a b))) 2 3)")))) (ok "double compare true" (jolt-truthy? (ev "((fn* ([^double x] (< x 5.0))) 3.0)"))) (ok "double unary negate" (= -5 (jnum->exact (ev "((fn* ([^double x] (- x))) 5.0)")))) (ok "long unary negate" (= -5 (jnum->exact (ev "((fn* ([^long a] (- a))) 5)")))) (ok "long quot 7/2 = 3" (= 3 (jnum->exact (ev "((fn* ([^long a ^long b] (quot a b))) 7 2)")))) (ok "double + int literal = 4.5" (= 9 (jnum->exact (ev "((fn* ([^double x] (* (+ x 1) 2))) 3.5)")))) (ok "loop double accumulator: 10*1.5 = 15" (= 15 (jnum->exact (ev "((fn* ([] (loop [acc 0.0 i 0] (if (< i 10) (recur (+ acc 1.5) (inc i)) acc)))))")))) (ok "loop integer factorial stays exact (bignum preserved)" (jolt-truthy? (ev "(< 1000000000000000000000 ((fn* ([] (loop [acc 1 i 1] (if (< i 25) (recur (* acc i) (inc i)) acc)))) ))"))) (printf "~a/~a passed~n" (- total fails) total) (exit (if (zero? fails) 0 1))