gnu_libjit/
function.rs

1use std::ffi::CString;
2use std::os::raw::c_uint;
3use gnu_libjit_sys::{jit_function_compile, jit_insn_pow, jit_insn_acos, jit_insn_asin, jit_insn_atan, jit_insn_cos, jit_insn_cosh, jit_insn_log, jit_insn_log10, jit_insn_sin, jit_insn_sinh, jit_insn_sqrt, jit_insn_tan, jit_insn_tanh, jit_value_create_float64_constant, jit_insn_not, jit_insn_ge, jit_insn_le, jit_insn_gt, jit_insn_lt, jit_insn_ne, jit_insn_and, jit_insn_or, jit_insn_xor, jit_function_t, jit_value_create_long_constant, jit_value_create_float32_constant, jit_value_create_nint_constant, jit_value_create, jit_type_float32, jit_insn_eq, jit_type_nint, jit_type_int, jit_type_uint, jit_type_ushort, jit_type_short, jit_insn_add, jit_insn_div, jit_insn_sub, jit_insn_call_native, jit_insn_mul, jit_insn_return, jit_type_create_signature, jit_type_void, jit_value_get_param, jit_dump_function, jit_abi_t, jit_function_to_closure, jit_insn_branch_if, jit_label_t, jit_insn_label, jit_insn_branch_if_not, jit_type_long, jit_type_ulong, jit_type_sbyte, jit_type_float64, jit_type_ubyte, jit_type_void_ptr, jit_insn_alloca, jit_insn_load, jit_insn_store, jit_insn_branch, jit_insn_load_relative, jit_insn_call, jit_value_t, jit_type_t, jit_insn_rem, jit_insn_exp, jit_float32_rint, jit_insn_ceil, jit_insn_floor, jit_insn_rint, jit_insn_round, jit_insn_trunc, jit_insn_load_elem_address};
4use libc::{c_char, c_void};
5use crate::context::Exception;
6use crate::{Abi, JitType};
7use crate::label::Label;
8use crate::util::dump;
9use crate::value::Value;
10
11macro_rules! op {
12    ($fn_name:ident, $jit_op:ident) => {
13        pub fn $fn_name(&mut self, left: &Value, right: &Value) -> Value {
14            unsafe {
15                let v = $jit_op(self.function, left.value, right.value);
16                Value::new(v)
17            }
18        }
19    }
20}
21
22macro_rules! ret_op {
23    ($fn_name:ident, $jit_op:ident) => {
24        pub fn $fn_name(&mut self, value:& Value) {
25            unsafe {
26                $jit_op(self.function, value.value);
27            }
28        }
29    }
30}
31
32macro_rules! unary_op {
33    ($fn_name:ident, $jit_op:ident) => {
34        pub fn $fn_name(&mut self, value: &Value) -> Value {
35            unsafe {
36                let v =$jit_op(self.function, value.value);
37                Value::new(v)
38            }
39        }
40    }
41}
42
43#[derive(Clone)]
44pub struct Function {
45    params: Vec<JitType>,
46    function: jit_function_t,
47    signature: jit_type_t,
48}
49
50macro_rules! constant_fn {
51    ($fn_name:ident, $const_ty:ty, $typ: expr, $creator:expr) => {
52        pub fn $fn_name(&mut self, constant_value: $const_ty) -> Value {
53            let val = unsafe {
54                $creator(self.function, $typ, constant_value)
55            };
56            Value::new(val)
57
58        }
59    }
60}
61
62macro_rules! constant_fn_long {
63    ($fn_name:ident, $const_ty:ty, $typ: expr, $creator:expr) => {
64        pub fn $fn_name(&mut self, constant_value: $const_ty) -> Value {
65            let val = unsafe {
66                $creator(self.function, $typ, constant_value as ::std::os::raw::c_long)
67            };
68            Value::new(val)
69
70        }
71    }
72}
73
74
75impl Function {
76    // Use Context::new().function  to create a new function. This method is private.
77    pub(crate) fn new(function: jit_function_t, signature: jit_type_t, params: Vec<JitType>) -> Function {
78        Function { function, params, signature }
79    }
80
81    pub fn compile(&self) {
82        unsafe {
83            if jit_function_compile(self.function) == 0 {
84                panic!("Failed to compile function");
85            }
86        }
87    }
88
89    pub fn alloca(&self, size: ::std::os::raw::c_long) -> Value {
90        unsafe {
91            let bytes = jit_value_create_nint_constant(self.function, jit_type_ubyte, size);
92            Value::new(jit_insn_alloca(self.function, bytes))
93        }
94    }
95
96    pub fn dump(&self) -> Result<String, std::fmt::Error> {
97        dump(|fd| unsafe {
98            jit_dump_function(std::mem::transmute(fd), self.function, "no-name-func".as_ptr() as *const ::std::os::raw::c_char);
99        })
100    }
101
102    // T must be a extern "C" fn() pointer to avoid disaster.
103    // Also don't mess up the arg/return types lest you invite chaos.
104    pub fn to_closure<T>(&self) -> T {
105        unsafe {
106            let void_ptr = jit_function_to_closure(self.function);
107            std::mem::transmute_copy::<*mut c_void, T>(&void_ptr)
108        }
109    }
110
111    // Call a native rust function
112    pub fn insn_call_native(&self, native_func: *mut ::std::os::raw::c_void, params: Vec<Value>, return_type: Option<JitType>) -> Value {
113        let c_str = CString::new("native-func").unwrap();
114        let c_str_ptr = c_str.as_ptr();
115        let mut sig_args = vec![];
116        let mut args = vec![];
117        for param in params.iter() {
118            sig_args.push(param.value_type().inner);
119            args.push(param.value);
120        }
121        unsafe {
122            let signature = jit_type_create_signature(
123                Abi::Cdecl as jit_abi_t,
124                if let Some(jtype) = return_type { jtype.inner } else { jit_type_void },
125                sig_args.as_mut_ptr(),
126                params.len() as c_uint,
127                1,
128            );
129            Value::new(jit_insn_call_native(self.function,
130                                            c_str_ptr,
131                                            native_func,
132                                            signature,
133                                            args.as_mut_ptr(),
134                                            params.len() as c_uint,
135                                            0,
136            ))
137        }
138    }
139
140    // Get the value of the idx'th arg to the function
141    pub fn arg(&self, idx: i32) -> Result<Value, Exception> {
142        let _arg_type = match self.params.get(idx as usize) {
143            Some(arg_type) => arg_type,
144            None => {
145                return Err(Exception::ArgIndexTooLarge(format!("Function has {} args but you requested index {}", self.params.len(), idx)));
146            }
147        };
148        let value = unsafe {
149            jit_value_get_param(self.function, idx as c_uint)
150        };
151        Ok(Value::new(value))
152    }
153
154    op!(insn_mult, jit_insn_mul);
155    op!(insn_add, jit_insn_add);
156    op!(insn_pow, jit_insn_pow);
157    op!(insn_rem, jit_insn_rem);
158    op!(insn_div, jit_insn_div);
159    op!(insn_sub, jit_insn_sub);
160    op!(insn_eq, jit_insn_eq);
161    op!(insn_and, jit_insn_and);
162    op!(insn_or, jit_insn_or);
163    op!(insn_xor, jit_insn_xor);
164    op!(insn_le, jit_insn_le);
165    op!(insn_lt, jit_insn_lt);
166    op!(insn_ge, jit_insn_ge);
167    op!(insn_gt, jit_insn_gt);
168    op!(insn_ne, jit_insn_ne);
169
170    unary_op!(insn_acos, jit_insn_acos);
171    unary_op!(insn_asin, jit_insn_asin);
172    unary_op!(insn_atan, jit_insn_atan);
173    unary_op!(insn_cos, jit_insn_cos);
174    unary_op!(insn_cosh, jit_insn_cosh);
175    unary_op!(insn_exp, jit_insn_exp);
176    unary_op!(insn_log, jit_insn_log);
177    unary_op!(insn_log10, jit_insn_log10);
178    unary_op!(insn_sin, jit_insn_sin);
179    unary_op!(insn_sinh, jit_insn_sinh);
180    unary_op!(insn_sqrt, jit_insn_sqrt);
181    unary_op!(insn_tan, jit_insn_tan);
182    unary_op!(insn_tanh, jit_insn_tanh);
183
184    ret_op!(insn_return, jit_insn_return);
185
186    unary_op!(insn_not, jit_insn_not);
187
188    pub fn insn_branch(&self, label: &mut Label) {
189        unsafe { jit_insn_branch(self.function, &mut label.inner as *mut jit_label_t); }
190    }
191
192    pub fn insn_branch_if(&self, value: &Value, label: &mut Label) {
193        unsafe { jit_insn_branch_if(self.function, value.value, &mut label.inner as *mut jit_label_t); }
194    }
195
196    pub fn insn_branch_if_not(&self, value: &Value, label: &mut Label) {
197        unsafe { jit_insn_branch_if_not(self.function, value.value, &mut label.inner as *mut jit_label_t); }
198    }
199
200    pub fn insn_load(&mut self, ptr: &Value) -> Value {
201        unsafe {
202            let value = jit_insn_load(self.function, ptr.value);
203            // let value_type = jit_value_get_type(value);
204            Value::new(value)
205        }
206    }
207
208    pub fn insn_store(&mut self, ptr: &Value, value: &Value) {
209        unsafe {
210            jit_insn_store(self.function, ptr.value, value.value);
211        }
212    }
213
214    pub fn insn_call(&mut self, function: &Function, args: Vec<Value>) -> Value {
215        let mut values: Vec<jit_value_t> = args.iter().map(|arg| arg.value.clone()).collect();
216        let val = unsafe {
217            jit_insn_call(self.function, "-no-name-".as_ptr() as *mut c_char, function.function, function.signature, values.as_mut_ptr(), args.len() as c_uint, 0)
218        };
219        Value::new(val)
220    }
221
222    pub fn insn_load_relative(&mut self, base_ptr: &Value, offset_bytes: ::std::os::raw::c_long, typ: &JitType) -> Value {
223        let res = unsafe {
224            jit_insn_load_relative(self.function, base_ptr.value, offset_bytes, typ.inner)
225        };
226        Value::new(res)
227    }
228
229    pub fn create_value_int(&mut self) -> Value {
230        Value::new(unsafe {
231            jit_value_create(self.function, jit_type_int)
232        })
233    }
234
235    pub fn create_value_void_ptr(&mut self) -> Value {
236        Value::new(unsafe {
237            jit_value_create(self.function, jit_type_void_ptr)
238        })
239    }
240    pub fn create_value_float32(&mut self) -> Value {
241        Value::new(unsafe {
242            jit_value_create(self.function, jit_type_float32)
243        })
244    }
245    pub fn create_value_float64(&mut self) -> Value {
246        Value::new(unsafe {
247            jit_value_create(self.function, jit_type_float64)
248        })
249    }
250
251    pub fn insn_label(&self, label: &mut Label) {
252        let lbl_ptr = (&mut label.inner) as *mut jit_label_t;
253        unsafe { jit_insn_label(self.function, lbl_ptr); }
254    }
255
256    // Round value up towards positive infinity.
257    pub fn insn_ceil(&self, value: &Value) -> Value {
258        Value::new(unsafe { jit_insn_ceil(self.function, value.value) })
259    }
260
261    // Round value down towards negative infinity.
262    pub fn insn_floor(&self, value: &Value) -> Value {
263        Value::new(unsafe { jit_insn_floor(self.function, value.value) })
264    }
265
266    //  Round value to the nearest integer. Half-way cases are rounded to the even number.
267    pub fn insn_rint(&self, value: &Value) -> Value {
268        Value::new(unsafe { jit_insn_rint(self.function, value.value) })
269    }
270
271    // Round value to the nearest integer. Half-way cases are rounded away from zero.
272    pub fn insn_round(&self, value: &Value) -> Value {
273        Value::new(unsafe { jit_insn_round(self.function, value.value) })
274    }
275
276    // Round value towards zero.
277    pub fn insn_trunc(&self, value: &Value) -> Value {
278        Value::new(unsafe { jit_insn_trunc(self.function, value.value) })
279    }
280
281    // Load the effective address of an element of type elem_type at position index within the
282    // array starting at base_addr. Essentially, this computes the expression base_addr + index *
283    // sizeof(elem_type), but may be more efficient than performing the steps with jit_insn_mul and jit_insn_add.
284    pub fn insn_load_elem_address(&self, base_addr: &Value, index: &Value, elem_type: &JitType) -> Value {
285        Value::new(unsafe { jit_insn_load_elem_address(self.function, base_addr.value, index.value, elem_type.inner) })
286    }
287
288    constant_fn!(create_float32_constant, ::std::os::raw::c_float, jit_type_float32, jit_value_create_float32_constant);
289    constant_fn!(create_float64_constant, ::std::os::raw::c_double, jit_type_float64, jit_value_create_float64_constant);
290    constant_fn!(create_long_constant, ::std::os::raw::c_long, jit_type_long, jit_value_create_long_constant);
291
292    constant_fn_long!(create_sbyte_constant, ::std::os::raw::c_char, jit_type_sbyte, jit_value_create_long_constant);
293    constant_fn_long!(create_ubyte_constant, ::std::os::raw::c_uchar, jit_type_ubyte, jit_value_create_long_constant);
294    constant_fn_long!(create_short_constant, ::std::os::raw::c_long, jit_type_short, jit_value_create_long_constant);
295    constant_fn_long!(create_ushort_constant, ::std::os::raw::c_ulong, jit_type_ushort, jit_value_create_long_constant);
296    constant_fn_long!(create_int_constant, ::std::os::raw::c_int, jit_type_int, jit_value_create_long_constant);
297    constant_fn_long!(create_ulong_constant, ::std::os::raw::c_ulong, jit_type_ulong, jit_value_create_long_constant);
298    constant_fn_long!(create_uint_constant, ::std::os::raw::c_uint, jit_type_uint, jit_value_create_long_constant);
299    constant_fn_long!(create_nint_constant, ::std::os::raw::c_int, jit_type_nint, jit_value_create_long_constant);
300    constant_fn_long!(create_nuint_constant, ::std::os::raw::c_int, jit_type_nint, jit_value_create_long_constant);
301    constant_fn_long!(create_void_ptr_constant, *mut ::std::os::raw::c_void, jit_type_void_ptr, jit_value_create_long_constant);
302}
303