backend: emit bitwise ops as native ops (test.check PRNG ~2.4x)
Profiling the test.check distribution/large-sample slowness (jolt-i5if): the hot path is the SplitMix PRNG, dominated by 64-bit mix arithmetic, and the bitwise ops (bit-and/or/xor/not, shifts) were NOT in the backend native-ops table — so (bit-xor a b) compiled to a var-deref through the variadic overlay (__bit-xor) instead of a direct call, the way +/-/* already emit. Map bit-and/or/xor/not to the Chez bitwise-and/ior/xor/not primitives (inlined to native code; a non-integer operand now errors like the JVM instead of being silently truncated) and the shifts to a direct helper call. bit-and-not stays on its overlay — its only Scheme impl is 2-arg, so a value-position arity-3 use would mis-emit. mix-64 arithmetic 2.7x faster, raw split+rand-long 2.4x, gen/vector ~1.4x. The remaining gap is the bignum-vs-native-long floor (~20x, substrate) plus the generator machinery (deftype/fn dispatch, separate). Corpus rows added for value position, bit-not, apply, and a full-64-bit unsigned shift.
This commit is contained in:
parent
b5ea06c5c2
commit
f17b68ccfe
4 changed files with 153 additions and 135 deletions
File diff suppressed because one or more lines are too long
|
|
@ -539,11 +539,11 @@
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
(def-var! "clojure.core" "to-array-2d" (letrec ((to-array-2d (lambda (coll) (let fnrec4639 ((coll coll)) (jolt-invoke (var-deref "clojure.core" "to-array") (jolt-map (var-deref "clojure.core" "to-array") coll)))))) to-array-2d)))
|
(def-var! "clojure.core" "to-array-2d" (letrec ((to-array-2d (lambda (coll) (let fnrec4639 ((coll coll)) (jolt-invoke (var-deref "clojure.core" "to-array") (jolt-map (var-deref "clojure.core" "to-array") coll)))))) to-array-2d)))
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
(def-var! "clojure.core" "unchecked-byte" (letrec ((unchecked-byte (lambda (x) (let fnrec4640 ((x x)) (jolt-invoke (var-deref "clojure.core" "bit-and") (jolt-invoke (var-deref "clojure.core" "int") x) 255))))) unchecked-byte)))
|
(def-var! "clojure.core" "unchecked-byte" (letrec ((unchecked-byte (lambda (x) (let fnrec4640 ((x x)) (bitwise-and (jolt-invoke (var-deref "clojure.core" "int") x) 255))))) unchecked-byte)))
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
(def-var! "clojure.core" "unchecked-short" (letrec ((unchecked-short (lambda (x) (let fnrec4641 ((x x)) (jolt-invoke (var-deref "clojure.core" "bit-and") (jolt-invoke (var-deref "clojure.core" "int") x) 65535))))) unchecked-short)))
|
(def-var! "clojure.core" "unchecked-short" (letrec ((unchecked-short (lambda (x) (let fnrec4641 ((x x)) (bitwise-and (jolt-invoke (var-deref "clojure.core" "int") x) 65535))))) unchecked-short)))
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
(def-var! "clojure.core" "unchecked-char" (letrec ((unchecked-char (lambda (x) (let fnrec4642 ((x x)) (jolt-invoke (var-deref "clojure.core" "char") (jolt-invoke (var-deref "clojure.core" "bit-and") (jolt-invoke (var-deref "clojure.core" "int") x) 65535)))))) unchecked-char)))
|
(def-var! "clojure.core" "unchecked-char" (letrec ((unchecked-char (lambda (x) (let fnrec4642 ((x x)) (jolt-invoke (var-deref "clojure.core" "char") (bitwise-and (jolt-invoke (var-deref "clojure.core" "int") x) 65535)))))) unchecked-char)))
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
(def-var! "clojure.core" "unchecked-float" (letrec ((unchecked-float (lambda (x) (let fnrec4643 ((x x)) (jolt-invoke (var-deref "clojure.core" "double") x))))) unchecked-float)))
|
(def-var! "clojure.core" "unchecked-float" (letrec ((unchecked-float (lambda (x) (let fnrec4643 ((x x)) (jolt-invoke (var-deref "clojure.core" "double") x))))) unchecked-float)))
|
||||||
(guard (e (#t #f))
|
(guard (e (#t #f))
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,16 @@
|
||||||
"even?" "jolt-even?" "odd?" "jolt-odd?" "pos?" "jolt-pos?" "neg?" "jolt-neg?"
|
"even?" "jolt-even?" "odd?" "jolt-odd?" "pos?" "jolt-pos?" "neg?" "jolt-neg?"
|
||||||
"zero?" "jolt-zero?" "identity" "jolt-identity" "nil?" "jolt-nil?" "some?" "jolt-some?"
|
"zero?" "jolt-zero?" "identity" "jolt-identity" "nil?" "jolt-nil?" "some?" "jolt-some?"
|
||||||
"ex-info" "jolt-ex-info"
|
"ex-info" "jolt-ex-info"
|
||||||
|
;; bit ops: and/or/xor/not are Chez bitwise primitives (inlined to native code,
|
||||||
|
;; no helper call); operands must be integers (a non-integer errors, like the
|
||||||
|
;; JVM). The shifts keep their helpers (Java >>> masking / arithmetic shift) but
|
||||||
|
;; emit a direct call instead of var-deref + the variadic overlay.
|
||||||
|
;; and/or/xor/not map to variadic Chez bitwise prims (safe as a value at any
|
||||||
|
;; arity). bit-and-not is left to its overlay: its only Scheme impl is 2-arg, so
|
||||||
|
;; a value-position arity-3 use (via the variadic overlay) would mis-emit.
|
||||||
|
"bit-and" "bitwise-and" "bit-or" "bitwise-ior" "bit-xor" "bitwise-xor" "bit-not" "bitwise-not"
|
||||||
|
"bit-shift-left" "jolt-bit-shift-left" "bit-shift-right" "jolt-bit-shift-right"
|
||||||
|
"unsigned-bit-shift-right" "jolt-unsigned-bit-shift-right"
|
||||||
;; positional protocol-method dispatch (defprotocol-emitted shims) — bind
|
;; positional protocol-method dispatch (defprotocol-emitted shims) — bind
|
||||||
;; directly to the records.ss entry points so a protocol call doesn't var-deref.
|
;; directly to the records.ss entry points so a protocol call doesn't var-deref.
|
||||||
"protocol-dispatch1" "protocol-dispatch1" "protocol-dispatch2" "protocol-dispatch2"
|
"protocol-dispatch1" "protocol-dispatch1" "protocol-dispatch2" "protocol-dispatch2"
|
||||||
|
|
@ -66,7 +76,10 @@
|
||||||
"cons" #(= % 2) "filter" #(= % 2) "remove" #(= % 2) "into" #(= % 2)
|
"cons" #(= % 2) "filter" #(= % 2) "remove" #(= % 2) "into" #(= % 2)
|
||||||
"take" #(= % 2) "drop" #(= % 2) "map" #(>= % 2) "apply" #(>= % 2)
|
"take" #(= % 2) "drop" #(= % 2) "map" #(>= % 2) "apply" #(>= % 2)
|
||||||
"reduce" #(or (= % 2) (= % 3)) "range" #(and (>= % 0) (<= % 3))
|
"reduce" #(or (= % 2) (= % 3)) "range" #(and (>= % 0) (<= % 3))
|
||||||
"ex-info" #(or (= % 2) (= % 3))})
|
"ex-info" #(or (= % 2) (= % 3))
|
||||||
|
"bit-and" #(= % 2) "bit-or" #(= % 2) "bit-xor" #(= % 2) "bit-not" #(= % 1)
|
||||||
|
"bit-shift-left" #(= % 2) "bit-shift-right" #(= % 2)
|
||||||
|
"unsigned-bit-shift-right" #(= % 2)})
|
||||||
|
|
||||||
;; jolt's comparison ops are vacuously true at arity 1 and DON'T inspect the arg,
|
;; jolt's comparison ops are vacuously true at arity 1 and DON'T inspect the arg,
|
||||||
;; but Scheme's < demands a number even there — special-case.
|
;; but Scheme's < demands a number even there — special-case.
|
||||||
|
|
|
||||||
|
|
@ -1545,6 +1545,11 @@
|
||||||
{:suite "numbers / variadic bit ops" :label "bit-and-not 3" :expected "8" :actual "(bit-and-not 12 6 3)"}
|
{:suite "numbers / variadic bit ops" :label "bit-and-not 3" :expected "8" :actual "(bit-and-not 12 6 3)"}
|
||||||
{:suite "numbers / variadic bit ops" :label "bit-and single arg throws" :expected :throws :actual "(bit-and 5)"}
|
{:suite "numbers / variadic bit ops" :label "bit-and single arg throws" :expected :throws :actual "(bit-and 5)"}
|
||||||
{:suite "numbers / variadic bit ops" :label "bit-or keeps binary fast path" :expected "3" :actual "(bit-or 1 2)"}
|
{:suite "numbers / variadic bit ops" :label "bit-or keeps binary fast path" :expected "3" :actual "(bit-or 1 2)"}
|
||||||
|
{:suite "numbers / variadic bit ops" :label "bit-not" :expected "-6" :actual "(bit-not 5)"}
|
||||||
|
{:suite "numbers / variadic bit ops" :label "bit-and in value position" :expected "8" :actual "(reduce bit-and [15 9 12])"}
|
||||||
|
{:suite "numbers / variadic bit ops" :label "bit-xor in value position" :expected "0" :actual "(reduce bit-xor 0 [1 2 3])"}
|
||||||
|
{:suite "numbers / variadic bit ops" :label "bit-or via apply" :expected "7" :actual "(apply bit-or [1 2 4])"}
|
||||||
|
{:suite "numbers / variadic bit ops" :label "unsigned-shift over a full 64-bit value" :expected "17179869183" :actual "(unsigned-bit-shift-right -1 30)"}
|
||||||
{:suite "predicates / nil & boolean" :label "nil? true" :expected "true" :actual "(nil? nil)"}
|
{:suite "predicates / nil & boolean" :label "nil? true" :expected "true" :actual "(nil? nil)"}
|
||||||
{:suite "predicates / nil & boolean" :label "nil? false" :expected "false" :actual "(nil? 0)"}
|
{:suite "predicates / nil & boolean" :label "nil? false" :expected "false" :actual "(nil? 0)"}
|
||||||
{:suite "predicates / nil & boolean" :label "some? true" :expected "true" :actual "(some? 0)"}
|
{:suite "predicates / nil & boolean" :label "some? true" :expected "true" :actual "(some? 0)"}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue