#![cfg_attr(not(test), no_std)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use core::{ffi::CStr, ptr::null_mut, str::Utf8Error};
use const_default::ConstDefault;
use derive_more::From;
use typed_builder::TypedBuilder;
include!("./wrapper.rs");
#[inline(always)]
pub fn has_cpu_feature(feature_type: sljit_s32) -> sljit_s32 {
unsafe { sljit_has_cpu_feature(feature_type) }
}
#[inline(always)]
pub fn cmp_info(type_: sljit_s32) -> sljit_s32 {
unsafe { sljit_cmp_info(type_) }
}
#[inline(always)]
pub fn set_jump_addr(addr: sljit_uw, new_target: sljit_uw, executable_offset: sljit_sw) {
unsafe { sljit_set_jump_addr(addr, new_target, executable_offset) }
}
#[inline(always)]
pub fn set_const(
addr: sljit_uw,
op: sljit_s32,
new_constant: sljit_sw,
executable_offset: sljit_sw,
) {
unsafe { sljit_set_const(addr, op, new_constant, executable_offset) }
}
#[inline(always)]
pub fn get_register_index(type_: sljit_s32, reg: sljit_s32) -> sljit_s32 {
unsafe { sljit_get_register_index(type_, reg) }
}
#[inline(always)]
pub fn get_platform_name() -> Result<&'static str, Utf8Error> {
unsafe { CStr::from_ptr(sljit_get_platform_name()).to_str() }
}
#[repr(transparent)]
#[derive(From)]
pub struct Constant(*mut sljit_const);
impl Constant {
#[inline(always)]
pub fn addr(&self) -> sljit_uw {
unsafe { sljit_get_const_addr(self.0) }
}
}
#[repr(transparent)]
#[derive(From)]
pub struct Label(*mut sljit_label);
impl Label {
#[inline(always)]
pub fn addr(&self) -> sljit_uw {
unsafe { sljit_get_label_addr(self.0) }
}
}
#[repr(transparent)]
#[derive(From)]
pub struct Jump(*mut sljit_jump);
impl Jump {
#[inline(always)]
pub fn set_label(&mut self, label: &Label) {
unsafe { sljit_set_label(self.0, label.0) }
}
#[inline(always)]
pub fn set_target(&mut self, target: sljit_uw) {
unsafe { sljit_set_target(self.0, target) }
}
#[inline(always)]
pub fn addr(&self) -> sljit_uw {
unsafe { sljit_get_jump_addr(self.0) }
}
}
#[repr(transparent)]
#[derive(From)]
pub struct GeneratedCode(*mut ::core::ffi::c_void);
impl GeneratedCode {
#[inline(always)]
pub fn get(&self) -> *const ::core::ffi::c_void {
self.0
}
}
impl Drop for GeneratedCode {
#[inline(always)]
fn drop(&mut self) {
unsafe {
sljit_free_code(self.0, null_mut());
}
}
}
#[repr(transparent)]
#[derive(From)]
pub struct Compiler(*mut sljit_compiler);
impl Default for Compiler {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl Compiler {
#[inline(always)]
pub fn new() -> Self {
Self(unsafe { sljit_create_compiler(null_mut()) })
}
}
impl Compiler {
#[inline(always)]
pub fn generate_code(self) -> GeneratedCode {
let code = unsafe { sljit_generate_code(self.0, 0, null_mut()) };
drop(self);
GeneratedCode(code)
}
}
impl Drop for Compiler {
#[inline(always)]
fn drop(&mut self) {
unsafe {
sljit_free_compiler(self.0);
}
}
}
include!("./generated.mid.rs");
#[cfg(test)]
mod integration_tests {
use core::{ffi::c_int, mem::transmute};
use super::*;
#[test]
fn test_add3() {
unsafe {
let mut compiler = Compiler::new();
compiler.emit_enter(
0,
SLJIT_ARG_TYPE_W
| (SLJIT_ARG_TYPE_W << 4)
| (SLJIT_ARG_TYPE_W << (2 * 4))
| (SLJIT_ARG_TYPE_W << (3 * 4)),
1,
3,
0,
);
compiler.emit_op1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_S0, 0);
compiler.emit_op2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S1, 0);
compiler.emit_op2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_S2, 0);
compiler.emit_return(SLJIT_MOV, SLJIT_R0, 0);
let code = compiler.generate_code();
let func: fn(c_int, c_int, c_int) -> c_int = transmute(code.get());
assert_eq!(func(4, 5, 6), 4 + 5 + 6);
}
}
#[test]
fn test_array_access() {
extern "C" fn print_num(a: isize) {
println!("num = {a}");
}
unsafe {
let arr: &[isize] = &[3, -10, 4, 6, 8, 12, 2000, 0];
let mut compiler = Compiler::new();
compiler.emit_enter(
0,
SLJIT_ARG_TYPE_W
| (SLJIT_ARG_TYPE_P << 4)
| (SLJIT_ARG_TYPE_W << (2 * 4))
| (SLJIT_ARG_TYPE_W << (3 * 4)),
4,
3,
0,
);
compiler.emit_op2(SLJIT_XOR, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_S2, 0);
compiler.emit_op1(
SLJIT_MOV,
SLJIT_S1,
0,
SLJIT_IMM,
arr.len().try_into().unwrap(),
);
let loop_start = compiler.emit_label();
let mut out = compiler.emit_cmp(SLJIT_GREATER_EQUAL, SLJIT_S2, 0, SLJIT_S1, 0);
compiler.emit_op1(
SLJIT_MOV,
SLJIT_R0,
0,
SLJIT_MEM | SLJIT_S0 | (SLJIT_S2 << 8),
SLJIT_WORD_SHIFT.into(),
);
compiler.emit_icall(
SLJIT_CALL,
SLJIT_ARG_TYPE_RET_VOID | (SLJIT_ARG_TYPE_W << 4),
SLJIT_IMM,
print_num as _,
);
compiler.emit_op2(SLJIT_ADD, SLJIT_S2, 0, SLJIT_S2, 0, SLJIT_IMM, 1);
compiler.emit_jump(SLJIT_JUMP).set_label(&loop_start);
out.set_label(&compiler.emit_label());
compiler.emit_return(SLJIT_MOV, SLJIT_S1, 0);
let code = compiler.generate_code();
let func: fn(*const isize, isize, isize) -> isize = transmute(code.get());
assert_eq!(
func(arr.as_ptr(), arr.len().try_into().unwrap(), 0),
arr.len().try_into().unwrap()
);
}
}
}