sljit_sys/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![allow(non_upper_case_globals)]
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5
6use core::{ffi::CStr, ptr::null_mut, str::Utf8Error};
7
8use const_default::ConstDefault;
9use derive_more::From;
10use typed_builder::TypedBuilder;
11
12include!("./wrapper.rs");
13
14#[inline(always)]
15pub fn has_cpu_feature(feature_type: sljit_s32) -> sljit_s32 {
16    unsafe { sljit_has_cpu_feature(feature_type) }
17}
18
19#[inline(always)]
20pub fn cmp_info(type_: sljit_s32) -> sljit_s32 {
21    unsafe { sljit_cmp_info(type_) }
22}
23
24#[inline(always)]
25pub fn set_jump_addr(addr: sljit_uw, new_target: sljit_uw, executable_offset: sljit_sw) {
26    unsafe { sljit_set_jump_addr(addr, new_target, executable_offset) }
27}
28
29#[inline(always)]
30pub fn set_const(
31    addr: sljit_uw,
32    op: sljit_s32,
33    new_constant: sljit_sw,
34    executable_offset: sljit_sw,
35) {
36    unsafe { sljit_set_const(addr, op, new_constant, executable_offset) }
37}
38
39#[inline(always)]
40pub fn get_register_index(type_: sljit_s32, reg: sljit_s32) -> sljit_s32 {
41    unsafe { sljit_get_register_index(type_, reg) }
42}
43
44#[inline(always)]
45pub fn get_platform_name() -> Result<&'static str, Utf8Error> {
46    unsafe { CStr::from_ptr(sljit_get_platform_name()).to_str() }
47}
48
49#[repr(transparent)]
50#[derive(From)]
51pub struct Constant(*mut sljit_const);
52
53impl Constant {
54    #[inline(always)]
55    pub fn addr(&self) -> sljit_uw {
56        unsafe { sljit_get_const_addr(self.0) }
57    }
58}
59
60#[repr(transparent)]
61#[derive(From)]
62pub struct Label(*mut sljit_label);
63
64impl Label {
65    #[inline(always)]
66    pub fn addr(&self) -> sljit_uw {
67        unsafe { sljit_get_label_addr(self.0) }
68    }
69}
70
71#[repr(transparent)]
72#[derive(From)]
73pub struct Jump(*mut sljit_jump);
74
75impl Jump {
76    #[inline(always)]
77    pub fn set_label(&mut self, label: &Label) {
78        unsafe { sljit_set_label(self.0, label.0) }
79    }
80
81    #[inline(always)]
82    pub fn set_target(&mut self, target: sljit_uw) {
83        unsafe { sljit_set_target(self.0, target) }
84    }
85
86    #[inline(always)]
87    pub fn addr(&self) -> sljit_uw {
88        unsafe { sljit_get_jump_addr(self.0) }
89    }
90}
91
92#[repr(transparent)]
93#[derive(From)]
94pub struct GeneratedCode(*mut ::core::ffi::c_void);
95
96impl GeneratedCode {
97    #[inline(always)]
98    pub fn get(&self) -> *const ::core::ffi::c_void {
99        self.0
100    }
101}
102
103impl Drop for GeneratedCode {
104    #[inline(always)]
105    fn drop(&mut self) {
106        unsafe {
107            sljit_free_code(self.0, null_mut());
108        }
109    }
110}
111
112#[repr(transparent)]
113#[derive(From)]
114pub struct Compiler(*mut sljit_compiler);
115
116impl Default for Compiler {
117    #[inline(always)]
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl Compiler {
124    #[inline(always)]
125    pub fn new() -> Self {
126        Self(unsafe { sljit_create_compiler(null_mut()) })
127    }
128}
129
130impl Compiler {
131    #[inline(always)]
132    pub fn generate_code(self) -> GeneratedCode {
133        let code = unsafe { sljit_generate_code(self.0, 0, null_mut()) };
134        drop(self);
135        GeneratedCode(code)
136    }
137}
138
139impl Drop for Compiler {
140    #[inline(always)]
141    fn drop(&mut self) {
142        unsafe {
143            sljit_free_compiler(self.0);
144        }
145    }
146}
147
148include!("./generated.mid.rs");
149
150#[cfg(test)]
151mod integration_tests {
152    use core::{ffi::c_int, mem::transmute};
153
154    use super::*;
155
156    #[test]
157    fn test_add3() {
158        unsafe {
159            let mut compiler = Compiler::new();
160            compiler.emit_enter(
161                0,
162                SLJIT_ARG_TYPE_W
163                    | (SLJIT_ARG_TYPE_W << 4)
164                    | (SLJIT_ARG_TYPE_W << (2 * 4))
165                    | (SLJIT_ARG_TYPE_W << (3 * 4)),
166                1,
167                3,
168                0,
169            );
170            compiler.emit_op1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0);
171
172            /* R0 = R0 + second */
173            compiler.emit_op2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0);
174
175            /* R0 = R0 + third */
176            compiler.emit_op2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0);
177
178            /* This statement mov R0 to RETURN REG and return */
179            /* in fact, R0 is RETURN REG itself */
180            compiler.emit_return(SLJIT_MOV, SLJIT_R0, 0);
181
182            let code = compiler.generate_code();
183            let func: fn(c_int, c_int, c_int) -> c_int = transmute(code.get());
184            assert_eq!(func(4, 5, 6), 4 + 5 + 6);
185        }
186    }
187
188    #[test]
189    fn test_array_access() {
190        extern "C" fn print_num(a: isize) {
191            println!("num = {a}");
192        }
193
194        unsafe {
195            let arr: &[isize] = &[3, -10, 4, 6, 8, 12, 2000, 0];
196            let mut compiler = Compiler::new();
197            compiler.emit_enter(
198                0,
199                SLJIT_ARG_TYPE_W
200                    | (SLJIT_ARG_TYPE_P << 4)
201                    | (SLJIT_ARG_TYPE_W << (2 * 4))
202                    | (SLJIT_ARG_TYPE_W << (3 * 4)),
203                4,
204                3,
205                0,
206            );
207
208            /* S2 = 0 */
209            compiler.emit_op2(SLJIT_XOR, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_S2, 0);
210
211            /* S1 = narr */
212            compiler.emit_op1(
213                SLJIT_MOV,
214                SLJIT_S1,
215                0,
216                SLJIT_IMM,
217                arr.len().try_into().unwrap(),
218            );
219
220            /* loopstart:              */
221            let loop_start = compiler.emit_label();
222
223            /* S2 >= narr --> jumo out */
224            let mut out = compiler.emit_cmp(SLJIT_GREATER_EQUAL, SLJIT_S2, 0, SLJIT_S1, 0);
225
226            /* R0 = (long *)S0[S2];    */
227            compiler.emit_op1(
228                SLJIT_MOV,
229                SLJIT_R0,
230                0,
231                SLJIT_MEM | SLJIT_S0 | (SLJIT_S2 << 8),
232                SLJIT_WORD_SHIFT.into(),
233            );
234
235            /* print_num(R0)           */
236            compiler.emit_icall(
237                SLJIT_CALL,
238                SLJIT_ARG_TYPE_RET_VOID | (SLJIT_ARG_TYPE_W << 4),
239                SLJIT_IMM,
240                print_num as _,
241            );
242            /* S2 += 1                 */
243            compiler.emit_op2(SLJIT_ADD, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_IMM, 1);
244            /* jump loopstart          */
245            compiler.emit_jump(SLJIT_JUMP).set_label(&loop_start);
246            /* out:                    */
247            out.set_label(&compiler.emit_label());
248            /* return S1               */
249            compiler.emit_return(SLJIT_MOV, SLJIT_S1, 0);
250
251            let code = compiler.generate_code();
252            let func: fn(*const isize, isize, isize) -> isize = transmute(code.get());
253
254            assert_eq!(
255                func(arr.as_ptr(), arr.len().try_into().unwrap(), 0),
256                arr.len().try_into().unwrap()
257            );
258        }
259    }
260}