Skip to main content

shape_jit/ffi/
math.rs

1//! Math FFI Functions for JIT
2//!
3//! Trigonometric and mathematical functions for JIT-compiled code.
4//!
5//! ## SIMD Optimization
6//!
7//! Series arithmetic (+, -, *, /) uses SIMD-accelerated operations from
8//! shape-runtime for high performance vectorized computation.
9//!
10//! ## R7.1 cleanup
11//!
12//! The 11 dispatch-fallback trampolines (`jit_generic_add`/`sub`/`mul`/
13//! `div`/`mod`, `jit_generic_eq`/`neq`, `jit_generic_lt`/`le`/`gt`/`ge`)
14//! were removed here after R5 retargeted the dynamic arithmetic /
15//! comparison paths to typed opcodes + `CallMethod`; the only remaining
16//! callers in MIR (`compile_binop`) were deleted in the same commit.
17
18use super::value_ffi::*;
19
20// SIMD threshold - use SIMD for arrays >= this size
21#[allow(dead_code)]
22const SIMD_THRESHOLD: usize = 16;
23
24// ============================================================================
25// Trigonometric Functions
26// ============================================================================
27
28pub extern "C" fn jit_sin(value_bits: u64) -> u64 {
29    let x = if is_number(value_bits) {
30        unbox_number(value_bits)
31    } else {
32        return box_number(f64::NAN);
33    };
34    box_number(x.sin())
35}
36
37pub extern "C" fn jit_cos(value_bits: u64) -> u64 {
38    let x = if is_number(value_bits) {
39        unbox_number(value_bits)
40    } else {
41        return box_number(f64::NAN);
42    };
43    box_number(x.cos())
44}
45
46pub extern "C" fn jit_tan(value_bits: u64) -> u64 {
47    let x = if is_number(value_bits) {
48        unbox_number(value_bits)
49    } else {
50        return box_number(f64::NAN);
51    };
52    box_number(x.tan())
53}
54
55pub extern "C" fn jit_asin(value_bits: u64) -> u64 {
56    let x = if is_number(value_bits) {
57        unbox_number(value_bits)
58    } else {
59        return box_number(f64::NAN);
60    };
61    box_number(x.asin())
62}
63
64pub extern "C" fn jit_acos(value_bits: u64) -> u64 {
65    let x = if is_number(value_bits) {
66        unbox_number(value_bits)
67    } else {
68        return box_number(f64::NAN);
69    };
70    box_number(x.acos())
71}
72
73pub extern "C" fn jit_atan(value_bits: u64) -> u64 {
74    let x = if is_number(value_bits) {
75        unbox_number(value_bits)
76    } else {
77        return box_number(f64::NAN);
78    };
79    box_number(x.atan())
80}
81
82// ============================================================================
83// Exponential and Logarithmic Functions
84// ============================================================================
85
86pub extern "C" fn jit_exp(value_bits: u64) -> u64 {
87    let x = if is_number(value_bits) {
88        unbox_number(value_bits)
89    } else {
90        return box_number(f64::NAN);
91    };
92    box_number(x.exp())
93}
94
95pub extern "C" fn jit_ln(value_bits: u64) -> u64 {
96    let x = if is_number(value_bits) {
97        unbox_number(value_bits)
98    } else {
99        return box_number(f64::NAN);
100    };
101    box_number(x.ln())
102}
103
104pub extern "C" fn jit_log(value_bits: u64, base_bits: u64) -> u64 {
105    let x = if is_number(value_bits) {
106        unbox_number(value_bits)
107    } else {
108        return box_number(f64::NAN);
109    };
110    let base = if is_number(base_bits) {
111        unbox_number(base_bits)
112    } else {
113        return box_number(f64::NAN);
114    };
115    box_number(x.log(base))
116}
117
118// ============================================================================
119// Power Function
120// ============================================================================
121
122pub extern "C" fn jit_pow(base_bits: u64, exp_bits: u64) -> u64 {
123    let base = if is_number(base_bits) {
124        unbox_number(base_bits)
125    } else {
126        return box_number(f64::NAN);
127    };
128    let exp = if is_number(exp_bits) {
129        unbox_number(exp_bits)
130    } else {
131        return box_number(f64::NAN);
132    };
133    box_number(base.powf(exp))
134}
135
136// ============================================================================
137// Generic Binary Operations (REMOVED — R7.1)
138// ============================================================================
139// The `jit_generic_add` / `sub` / `mul` / `div` / `mod` / `eq` / `neq` /
140// `lt` / `le` / `gt` / `ge` trampolines that used to live here were the
141// last thing pinning the matching `FFIFuncRefs` fields alive. After
142// R5.1–R5.6 retargeted every dynamic-arithmetic / comparison path
143// (typed bitwise, user operator traits, DateTime, Matrix/Vec, string +
144// scalar), MIR no longer emits a fully dynamic binop and
145// `compile_binop` surfaces an error if one ever reaches it. The 11
146// Rust FFI bodies, their Cranelift signatures, and the matching
147// symbol registrations were deleted in the same commit.
148
149/// SIMD-accelerated Series addition
150#[allow(dead_code)]
151fn series_add_simd(a_bits: u64, b_bits: u64) -> u64 {
152    series_simd_binary_op(
153        a_bits,
154        b_bits,
155        super::simd::jit_simd_add,
156        super::simd::jit_simd_add_scalar,
157    )
158}
159
160/// SIMD-accelerated Series subtraction
161#[allow(dead_code)]
162fn series_sub_simd(a_bits: u64, b_bits: u64) -> u64 {
163    series_simd_binary_op(
164        a_bits,
165        b_bits,
166        super::simd::jit_simd_sub,
167        super::simd::jit_simd_sub_scalar,
168    )
169}
170
171/// SIMD-accelerated Series multiplication
172#[allow(dead_code)]
173fn series_mul_simd(a_bits: u64, b_bits: u64) -> u64 {
174    series_simd_binary_op(
175        a_bits,
176        b_bits,
177        super::simd::jit_simd_mul,
178        super::simd::jit_simd_mul_scalar,
179    )
180}
181
182/// SIMD-accelerated Series division
183#[allow(dead_code)]
184fn series_div_simd(a_bits: u64, b_bits: u64) -> u64 {
185    series_simd_binary_op(
186        a_bits,
187        b_bits,
188        super::simd::jit_simd_div,
189        super::simd::jit_simd_div_scalar,
190    )
191}
192
193/// Helper for SIMD series binary operations
194/// Uses raw pointer SIMD functions for maximum performance
195fn series_simd_binary_op(
196    _a_bits: u64,
197    _b_bits: u64,
198    _simd_binary: extern "C" fn(*const f64, *const f64, u64) -> *mut f64,
199    _simd_scalar: extern "C" fn(*const f64, f64, u64) -> *mut f64,
200) -> u64 {
201    TAG_NULL
202}
203
204/// Fallback helper for series binary operations (for non-SIMD ops)
205#[allow(dead_code)]
206fn series_binary_op<F>(_a_bits: u64, _b_bits: u64, _op: F) -> u64
207where
208    F: Fn(f64, f64) -> f64,
209{
210    TAG_NULL
211}
212
213/// Generic comparison for Series > Series, Series > number, etc.
214/// Returns a Series of 1.0/0.0 for series comparisons, or a boolean for scalars.
215pub extern "C" fn jit_series_gt(a_bits: u64, b_bits: u64) -> u64 {
216    series_comparison_op(a_bits, b_bits, |a, b| a > b)
217}
218
219pub extern "C" fn jit_series_lt(a_bits: u64, b_bits: u64) -> u64 {
220    series_comparison_op(a_bits, b_bits, |a, b| a < b)
221}
222
223pub extern "C" fn jit_series_gte(a_bits: u64, b_bits: u64) -> u64 {
224    series_comparison_op(a_bits, b_bits, |a, b| a >= b)
225}
226
227pub extern "C" fn jit_series_lte(a_bits: u64, b_bits: u64) -> u64 {
228    series_comparison_op(a_bits, b_bits, |a, b| a <= b)
229}
230
231/// Helper for series comparison operations
232fn series_comparison_op<F>(a_bits: u64, b_bits: u64, op: F) -> u64
233where
234    F: Fn(f64, f64) -> bool,
235{
236    // Fallback: numeric comparison
237    if is_number(a_bits) && is_number(b_bits) {
238        let a = unbox_number(a_bits);
239        let b = unbox_number(b_bits);
240        return if op(a, b) {
241            TAG_BOOL_TRUE
242        } else {
243            TAG_BOOL_FALSE
244        };
245    }
246    TAG_BOOL_FALSE
247}
248
249// (R7.1) `jit_generic_lt` / `le` / `gt` / `ge` / `mod` / `eq` / `neq` were
250// deleted together with the add/sub/mul/div trampolines above. They had
251// no callers outside `compile_binop`, which now surfaces an error for
252// any dynamic arithmetic / comparison op that reaches it after R5.
253
254// `duration_to_seconds` (the last private helper in this file) went
255// away with the Time/Duration branches in `jit_generic_add` / `sub`
256// as part of the R7.1 deletion above.
257
258// Tests for the former `jit_generic_add` / `sub` / `mul` / `div`
259// trampolines were removed alongside the functions themselves in R7.1:
260// those paths are unreachable from MIR after R5 and exercising them
261// directly only confirmed the deleted helper's behaviour.