use std::ffi::{c_void, CStr, CString};
use std::marker::PhantomData;
use std::mem;
use std::os::raw::{c_int, c_ulong};
use std::ptr;
use std::str::Utf8Error;
use gccjit_sys::gcc_jit_int_option::*;
use gccjit_sys::gcc_jit_str_option::*;
use gccjit_sys::gcc_jit_bool_option::*;
use block::{self, BinaryOp, Block, UnaryOp, ComparisonOp};
use field::{self, Field};
use function::{self, Function, FunctionType};
use location::{self, Location};
use lvalue::{self, LValue};
use object::{self, Object, ToObject};
use parameter::{self, Parameter};
use rvalue::{self, RValue, ToRValue};
use structs::{self, Struct};
#[cfg(feature="master")]
use target_info::{self, TargetInfo};
use Type;
use types;
use crate::with_lib;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub enum GlobalKind {
Exported,
Internal,
Imported,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub enum OptimizationLevel {
None,
Limited,
Standard,
Aggressive
}
#[repr(C)]
#[derive(Copy, Clone)]
pub enum OutputKind {
Assembler,
ObjectFile,
DynamicLibrary,
Executable
}
pub struct CompileResult {
ptr: *mut gccjit_sys::gcc_jit_result
}
impl CompileResult {
pub fn get_function<S: AsRef<str>>(&self, name: S) -> *mut () {
let c_str = CString::new(name.as_ref()).unwrap();
with_lib(|lib| {
unsafe {
let func = lib.gcc_jit_result_get_code(self.ptr, c_str.as_ptr());
mem::transmute(func)
}
})
}
pub fn get_global<S: AsRef<str>>(&self, name: S) -> *mut () {
let c_str = CString::new(name.as_ref()).unwrap();
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_result_get_global(self.ptr, c_str.as_ptr());
mem::transmute(ptr)
}
})
}
}
impl Drop for CompileResult {
fn drop(&mut self) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_result_release(self.ptr);
}
})
}
}
pub struct Case<'ctx> {
marker: PhantomData<&'ctx Case<'ctx>>,
ptr: *mut gccjit_sys::gcc_jit_case,
}
impl<'ctx> ToObject<'ctx> for Case<'ctx> {
fn to_object(&self) -> Object<'ctx> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_case_as_object(self.ptr);
object::from_ptr(ptr)
}
})
}
}
#[derive(Debug)]
pub struct Context<'ctx> {
marker: PhantomData<&'ctx Context<'ctx>>,
ptr: *mut gccjit_sys::gcc_jit_context
}
impl Default for Context<'static> {
fn default() -> Context<'static> {
with_lib(|lib| {
unsafe {
Context {
marker: PhantomData,
ptr: lib.gcc_jit_context_acquire(),
}
}
})
}
}
impl<'ctx> Context<'ctx> {
pub fn set_program_name<S: AsRef<str>>(&self, name: S) {
let name_ref = name.as_ref();
let c_str = CString::new(name_ref).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_str_option(self.ptr, GCC_JIT_STR_OPTION_PROGNAME, c_str.as_ptr());
}
})
}
pub fn add_command_line_option<S: AsRef<str>>(&self, name: S) {
let c_str = CString::new(name.as_ref()).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_add_command_line_option(self.ptr, c_str.as_ptr())
}
})
}
pub fn add_driver_option<S: AsRef<str>>(&self, name: S) {
let c_str = CString::new(name.as_ref()).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_add_driver_option(self.ptr, c_str.as_ptr())
}
})
}
pub fn set_optimization_level(&self, level: OptimizationLevel) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_int_option(self.ptr, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, level as i32);
}
})
}
#[cfg(feature="master")]
pub fn set_output_ident(&self, ident: &str) {
let c_str = CString::new(ident).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_output_ident(self.ptr, c_str.as_ptr());
}
})
}
#[cfg(feature="master")]
pub fn set_special_chars_allowed_in_func_names(&self, value: &str) {
let c_str = CString::new(value).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_str_option(self.ptr, GCC_JIT_STR_OPTION_SPECIAL_CHARS_IN_FUNC_NAMES, c_str.as_ptr());
}
})
}
pub fn set_debug_info(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_option(self.ptr, GCC_JIT_BOOL_OPTION_DEBUGINFO, value as i32);
}
})
}
pub fn set_keep_intermediates(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_option(self.ptr, GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, value as i32);
}
})
}
pub fn set_print_errors_to_stderr(&self, enabled: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_print_errors_to_stderr(self.ptr, enabled as c_int);
}
})
}
pub fn set_dump_everything(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_option(self.ptr, GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, value as i32);
}
})
}
pub fn set_dump_initial_gimple(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_option(self.ptr, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, value as i32);
}
})
}
pub fn set_dump_code_on_compile(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_option(self.ptr, GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, value as i32);
}
})
}
pub fn set_allow_unreachable_blocks(&self, value: bool) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_bool_allow_unreachable_blocks(self.ptr, value as i32);
}
})
}
pub fn compile(&self) -> CompileResult {
with_lib(|lib| {
unsafe {
CompileResult {
ptr: lib.gcc_jit_context_compile(self.ptr)
}
}
})
}
pub fn compile_to_file<S: AsRef<str>>(&self, kind: OutputKind, file: S) {
with_lib(|lib| {
unsafe {
let file_ref = file.as_ref();
let cstr = CString::new(file_ref).unwrap();
lib.gcc_jit_context_compile_to_file(self.ptr,
mem::transmute::<OutputKind, gccjit_sys::gcc_jit_output_kind>(kind),
cstr.as_ptr());
}
})
}
#[cfg(feature="master")]
pub fn get_target_info(&self) -> TargetInfo {
with_lib(|lib| {
unsafe {
target_info::from_ptr(lib.gcc_jit_context_get_target_info(self.ptr))
}
})
}
pub fn new_child_context<'b>(&'b self) -> Context<'b> {
with_lib(|lib| {
unsafe {
Context {
marker: PhantomData,
ptr: lib.gcc_jit_context_new_child_context(self.ptr)
}
}
})
}
pub fn new_case<S: ToRValue<'ctx>, T: ToRValue<'ctx>>(&self, min_value: S, max_value: T, dest_block: Block<'ctx>) -> Case<'ctx> {
let min_value = min_value.to_rvalue();
let max_value = max_value.to_rvalue();
let result =
with_lib(|lib| {
unsafe {
Case {
marker: PhantomData,
ptr: lib.gcc_jit_context_new_case(self.ptr, rvalue::get_ptr(&min_value), rvalue::get_ptr(&max_value),
block::get_ptr(&dest_block)),
}
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
result
}
pub fn new_location<'a, S: AsRef<str>>(&'a self,
filename: S,
line: i32,
col: i32) -> Location<'a> {
with_lib(|lib| {
unsafe {
let filename_ref = filename.as_ref();
let cstr = CString::new(filename_ref).unwrap();
let ptr = lib.gcc_jit_context_new_location(self.ptr, cstr.as_ptr(), line, col);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
location::from_ptr(ptr)
}
})
}
pub fn new_global<'a, S: AsRef<str>>(&self, loc: Option<Location<'a>>, kind: GlobalKind, ty: Type<'a>, name: S) -> LValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let cstr = CString::new(name.as_ref()).unwrap();
let ptr = lib.gcc_jit_context_new_global(self.ptr, loc_ptr,
mem::transmute::<GlobalKind, gccjit_sys::gcc_jit_global_kind>(kind),
types::get_ptr(&ty), cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
lvalue::from_ptr(ptr)
}
})
}
pub fn new_type<'a, T: types::Typeable>(&'a self) -> types::Type<'a> {
<T as types::Typeable>::get_type(self)
}
pub fn new_c_type<'a>(&'a self, c_type: CType) -> types::Type<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_get_type(get_ptr(self), c_type.to_sys());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_int_type<'a>(&'a self, num_bytes: i32, signed: bool) -> types::Type<'a> {
with_lib(|lib| {
unsafe {
let ctx_ptr = get_ptr(self);
let ptr = lib.gcc_jit_context_get_int_type(ctx_ptr, num_bytes, signed as i32);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_field<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
ty: types::Type<'a>,
name: S) -> Field<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_field(self.ptr, loc_ptr, types::get_ptr(&ty), cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
field::from_ptr(ptr)
}
})
}
pub fn new_array_type<'a>(&'a self,
loc: Option<Location<'a>>,
ty: types::Type<'a>,
num_elements: u64) -> types::Type<'a> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_array_type(self.ptr, loc_ptr, types::get_ptr(&ty), num_elements as c_ulong);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn new_array_type_u64<'a>(&'a self,
loc: Option<Location<'a>>,
ty: types::Type<'a>,
num_elements: u64) -> types::Type<'a> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_array_type_u64(self.ptr, loc_ptr, types::get_ptr(&ty), num_elements);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_vector_type<'a>(&'a self, ty: types::Type<'a>, num_units: u64) -> types::Type<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_type_get_vector(types::get_ptr(&ty), num_units as _);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_struct_type<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
name: S,
fields: &[Field<'a>]) -> Struct<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_fields = fields.len() as i32;
with_lib(|lib| {
let mut fields_ptrs : Vec<_> = fields.iter()
.map(|x| unsafe { field::get_ptr(x) })
.collect();
unsafe {
let cname = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_struct_type(self.ptr, loc_ptr, cname.as_ptr(), num_fields,
fields_ptrs.as_mut_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
structs::from_ptr(ptr)
}
})
}
pub fn new_opaque_struct_type<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
name: S) -> Struct<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_opaque_struct(self.ptr, loc_ptr, cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
structs::from_ptr(ptr)
}
})
}
pub fn new_union_type<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
name: S,
fields: &[Field<'a>]) -> types::Type<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_fields = fields.len() as i32;
with_lib(|lib| {
let mut fields_ptrs : Vec<_> = fields.iter()
.map(|x| unsafe { field::get_ptr(x) })
.collect();
unsafe {
let cname = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_union_type(self.ptr, loc_ptr, cname.as_ptr(), num_fields,
fields_ptrs.as_mut_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_function_pointer_type<'a>(&'a self,
loc: Option<Location<'a>>,
return_type: types::Type<'a>,
param_types: &[types::Type<'a>],
is_variadic: bool) -> types::Type<'a> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_types = param_types.len() as i32;
with_lib(|lib| {
let mut types_ptrs : Vec<_> = param_types.iter()
.map(|x| unsafe { types::get_ptr(x) })
.collect();
unsafe {
let ptr = lib.gcc_jit_context_new_function_ptr_type(self.ptr, loc_ptr, types::get_ptr(&return_type),
num_types, types_ptrs.as_mut_ptr(), is_variadic as i32);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
types::from_ptr(ptr)
}
})
}
pub fn new_function<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
kind: FunctionType,
return_ty: types::Type<'a>,
params: &[Parameter<'a>],
name: S,
is_variadic: bool) -> Function<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_params = params.len() as i32;
with_lib(|lib| {
let mut params_ptrs : Vec<_> = params.iter()
.map(|x| unsafe { parameter::get_ptr(x) })
.collect();
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_function(self.ptr,
loc_ptr,
mem::transmute::<FunctionType, gccjit_sys::gcc_jit_function_kind>(kind),
types::get_ptr(&return_ty),
cstr.as_ptr(),
num_params,
params_ptrs.as_mut_ptr(),
is_variadic as i32);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
function::from_ptr(ptr)
}
})
}
pub fn new_binary_op<'a, L: ToRValue<'a>, R: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
op: BinaryOp,
ty: types::Type<'a>,
left: L,
right: R) -> RValue<'a> {
let left_rvalue = left.to_rvalue();
let right_rvalue = right.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_binary_op(self.ptr, loc_ptr,
mem::transmute::<BinaryOp, gccjit_sys::gcc_jit_binary_op>(op),
types::get_ptr(&ty), rvalue::get_ptr(&left_rvalue), rvalue::get_ptr(&right_rvalue));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_unary_op<'a, T: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
op: UnaryOp,
ty: types::Type<'a>,
target: T) -> RValue<'a> {
let rvalue = target.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_unary_op(self.ptr, loc_ptr,
mem::transmute::<UnaryOp, gccjit_sys::gcc_jit_unary_op>(op),
types::get_ptr(&ty), rvalue::get_ptr(&rvalue));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_comparison<'a, L: ToRValue<'a>, R: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
op: ComparisonOp,
left: L,
right: R) -> RValue<'a> {
let left_rvalue = left.to_rvalue();
let right_rvalue = right.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_comparison(self.ptr, loc_ptr,
mem::transmute::<ComparisonOp, gccjit_sys::gcc_jit_comparison>(op),
rvalue::get_ptr(&left_rvalue), rvalue::get_ptr(&right_rvalue));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[must_use]
pub fn new_call<'a>(&'a self,
loc: Option<Location<'a>>,
func: Function<'a>,
args: &[RValue<'a>]) -> RValue<'a> {
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_params = args.len() as i32;
with_lib(|lib| {
let mut params_ptrs : Vec<_> = args.iter()
.map(|x| unsafe { rvalue::get_ptr(x) })
.collect();
unsafe {
let ptr = lib.gcc_jit_context_new_call(self.ptr, loc_ptr, function::get_ptr(&func), num_params,
params_ptrs.as_mut_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_call_through_ptr<'a, F: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
fun_ptr: F,
args: &[RValue<'a>]) -> RValue<'a> {
let fun_ptr_rvalue = fun_ptr.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
let num_params = args.len() as i32;
with_lib(|lib| {
let mut params_ptrs : Vec<_> = args.iter()
.map(|x| x.to_rvalue())
.map(|x| unsafe { rvalue::get_ptr(&x) })
.collect();
unsafe {
let ptr = lib.gcc_jit_context_new_call_through_ptr(self.ptr, loc_ptr, rvalue::get_ptr(&fun_ptr_rvalue),
num_params, params_ptrs.as_mut_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_cast<'a, T: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
value: T,
dest_type: types::Type<'a>) -> RValue<'a> {
let rvalue = value.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_cast(self.ptr, loc_ptr, rvalue::get_ptr(&rvalue), types::get_ptr(&dest_type));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_bitcast<'a, T: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
value: T,
dest_type: types::Type<'a>) -> RValue<'a> {
let rvalue = value.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_bitcast(self.ptr, loc_ptr, rvalue::get_ptr(&rvalue),
types::get_ptr(&dest_type));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_array_access<'a, A: ToRValue<'a>, I: ToRValue<'a>>(&'a self,
loc: Option<Location<'a>>,
array_ptr: A,
index: I) -> LValue<'a> {
let array_rvalue = array_ptr.to_rvalue();
let idx_rvalue = index.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_array_access(self.ptr, loc_ptr, rvalue::get_ptr(&array_rvalue),
rvalue::get_ptr(&idx_rvalue));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
lvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_from_long<'a>(&'a self,
ty: types::Type<'a>,
value: i64) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_long(self.ptr, types::get_ptr(&ty), value as _);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_from_vector<'a>(&'a self, loc: Option<Location<'a>>, vec_type: types::Type<'a>, elements: &[RValue<'a>]) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let ptr = lib.gcc_jit_context_new_rvalue_from_vector(self.ptr, loc_ptr, types::get_ptr(&vec_type),
elements.len() as _, elements.as_ptr() as *mut *mut _);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn new_rvalue_vector_perm<'a>(&'a self, loc: Option<Location<'a>>, elements1: RValue<'a>, elements2: RValue<'a>, mask: RValue<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let ptr = lib.gcc_jit_context_new_rvalue_vector_perm(self.ptr, loc_ptr, rvalue::get_ptr(&elements1),
rvalue::get_ptr(&elements2), rvalue::get_ptr(&mask));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_struct_constructor<'a>(&'a self, loc: Option<Location<'a>>, struct_type: types::Type<'a>, fields: Option<&[Field<'a>]>, values: &[RValue<'a>]) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let fields_ptr =
match fields {
Some(fields) => fields.as_ptr(),
None => ptr::null_mut(),
};
let ptr = lib.gcc_jit_context_new_struct_constructor(self.ptr, loc_ptr, types::get_ptr(&struct_type),
values.len() as _, fields_ptr as *mut *mut _, values.as_ptr() as *mut *mut _);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_array_constructor<'a>(&'a self, loc: Option<Location<'a>>, array_type: types::Type<'a>, elements: &[RValue<'a>]) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let ptr = lib.gcc_jit_context_new_array_constructor(self.ptr, loc_ptr, types::get_ptr(&array_type),
elements.len() as _, elements.as_ptr() as *mut *mut _);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn new_vector_access<'a>(&'a self, loc: Option<Location<'a>>, vector: RValue<'a>, index: RValue<'a>) -> LValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let ptr = lib.gcc_jit_context_new_vector_access(self.ptr, loc_ptr, rvalue::get_ptr(&vector), rvalue::get_ptr(&index));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
lvalue::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn convert_vector<'a>(&'a self, loc: Option<Location<'a>>, vector: RValue<'a>, type_: Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let loc_ptr = match loc {
Some(loc) => location::get_ptr(&loc),
None => ptr::null_mut()
};
let ptr = lib.gcc_jit_context_convert_vector(self.ptr, loc_ptr, rvalue::get_ptr(&vector), types::get_ptr(&type_));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_from_int<'a>(&'a self,
ty: types::Type<'a>,
value: i32) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_int(self.ptr, types::get_ptr(&ty), value);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_from_double<'a>(&'a self,
ty: types::Type<'a>,
value: f64) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_double(self.ptr, types::get_ptr(&ty), value);
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_zero<'a>(&'a self,
ty: types::Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_zero(self.ptr, types::get_ptr(&ty));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_rvalue_one<'a>(&'a self,
ty: types::Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_one(self.ptr, types::get_ptr(&ty));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn new_rvalue_from_ptr<'a>(&'a self,
ty: types::Type<'a>,
value: *mut ()) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_ptr(self.ptr, types::get_ptr(&ty),
mem::transmute::<*mut (), *mut c_void>(value));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_null<'a>(&'a self,
ty: types::Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_null(self.ptr, types::get_ptr(&ty));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn new_string_literal<'a, S: AsRef<str>>(&'a self,
value: S) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let cstr = CString::new(value.as_ref()).unwrap();
let ptr = lib.gcc_jit_context_new_string_literal(self.ptr, cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn new_sizeof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_sizeof(self.ptr, types::get_ptr(&ty));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn new_alignof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib(|lib| {
unsafe {
let ptr = lib.gcc_jit_context_new_alignof(self.ptr, types::get_ptr(&ty));
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
rvalue::from_ptr(ptr)
}
})
}
pub fn dump_reproducer_to_file<S: AsRef<str>>(&self,
path: S) {
with_lib(|lib| {
unsafe {
let path_ref = path.as_ref();
let cstr = CString::new(path_ref).unwrap();
lib.gcc_jit_context_dump_reproducer_to_file(self.ptr, cstr.as_ptr());
}
})
}
pub fn dump_to_file<S: AsRef<str>>(&self, path: S, update_locations: bool) {
with_lib(|lib| {
unsafe {
let path_ref = path.as_ref();
let cstr = CString::new(path_ref).unwrap();
lib.gcc_jit_context_dump_to_file(self.ptr, cstr.as_ptr(), update_locations as c_int);
}
})
}
pub fn new_parameter<'a, S: AsRef<str>>(&'a self,
loc: Option<Location<'a>>,
ty: types::Type<'a>,
name: S) -> Parameter<'a> {
let name_ref = name.as_ref();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut()
};
with_lib(|lib| {
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_param(self.ptr, loc_ptr, types::get_ptr(&ty), cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
parameter::from_ptr(ptr)
}
})
}
pub fn get_builtin_function<'a, S: AsRef<str>>(&'a self, name: S) -> Function<'a> {
let name_ref = name.as_ref();
with_lib(|lib| {
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_get_builtin_function(self.ptr, cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
function::from_ptr(ptr)
}
})
}
#[cfg(feature="master")]
pub fn get_target_builtin_function<'a, S: AsRef<str>>(&'a self, name: S) -> Function<'a> {
let name_ref = name.as_ref();
with_lib(|lib| {
unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_get_target_builtin_function(self.ptr, cstr.as_ptr());
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
function::from_ptr(ptr)
}
})
}
pub fn get_first_error(&self) -> Result<Option<&'ctx str>, Utf8Error> {
with_lib(|lib| {
unsafe {
let str = lib.gcc_jit_context_get_first_error(self.ptr);
if str.is_null() {
Ok(None)
}
else {
Ok(Some(CStr::from_ptr(str).to_str()?))
}
}
})
}
pub fn get_last_error(&self) -> Result<Option<&'ctx str>, Utf8Error> {
with_lib(|lib| {
unsafe {
let str = lib.gcc_jit_context_get_last_error(self.ptr);
if str.is_null() {
Ok(None)
}
else {
Ok(Some(CStr::from_ptr(str).to_str()?))
}
}
})
}
pub fn set_logfile<S: AsRef<str>>(&self, _logfile: S) {
use std::os::raw::c_void;
extern "C" {
static stderr: *mut c_void;
}
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_logfile(self.ptr, stderr as *mut _, 0, 0);
}
})
}
pub fn add_top_level_asm(&self, loc: Option<Location<'ctx>>, asm_stmts: &str) {
let asm_stmts = CString::new(asm_stmts).unwrap();
let loc_ptr =
match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut(),
};
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_add_top_level_asm(self.ptr, loc_ptr, asm_stmts.as_ptr());
}
});
#[cfg(debug_assertions)]
if let Ok(Some(error)) = self.get_last_error() {
panic!("{}", error);
}
}
#[cfg(feature="master")]
pub fn set_filename(&self, filename: &str) {
let c_str = CString::new(filename).unwrap();
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_set_filename(self.ptr, c_str.as_ptr());
}
})
}
}
impl<'ctx> Drop for Context<'ctx> {
fn drop(&mut self) {
with_lib(|lib| {
unsafe {
lib.gcc_jit_context_release(self.ptr);
}
})
}
}
#[doc(hidden)]
pub unsafe fn get_ptr<'ctx>(ctx: &'ctx Context<'ctx>) -> *mut gccjit_sys::gcc_jit_context {
ctx.ptr
}
pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_context) -> Context<'ctx> {
Context {
marker: PhantomData,
ptr
}
}
#[cfg(test)]
mod tests {
use super::super::*;
use std::mem;
#[test]
fn create_context() {
let _ctx = Context::default();
}
#[test]
fn create_child_context() {
let ctx = Context::default();
let _child = ctx.new_child_context();
}
#[test]
fn create_location() {
let ctx = Context::default();
let _location = ctx.new_location("hello.rs", 1, 32);
}
#[test]
fn create_type() {
let ctx = Context::default();
let _int_type = ctx.new_type::<i32>();
}
#[test]
fn create_field() {
let ctx = Context::default();
let int_type = ctx.new_type::<i32>();
let _int_field = ctx.new_field(None, int_type, "x");
}
#[test]
fn basic_function() {
let context = Context::default();
let int_ty = context.new_type::<i32>();
let parameter = context.new_parameter(None, int_ty, "x");
let fun = context.new_function(None, FunctionType::Exported, int_ty, &[parameter], "square", false);
let block = fun.new_block("main_block");
let parm = fun.get_param(0).to_rvalue();
let square = parm * parm;
block.end_with_return(None, square);
let result = context.compile();
unsafe {
let func_ptr = result.get_function("square");
assert!(!func_ptr.is_null());
let func : extern "C" fn(i32) -> i32 = mem::transmute(func_ptr);
assert_eq!(func(4), 16);
assert_eq!(func(9), 81);
assert_eq!(func(-2), 4);
}
}
}
#[derive(Clone, Copy)]
pub enum CType {
Bool,
Char,
UChar,
SChar,
Short,
UShort,
Int,
UInt,
Long,
ULong,
LongLong,
ULongLong,
SizeT,
Int8t,
Int16t,
Int32t,
Int64t,
Int128t,
UInt8t,
UInt16t,
UInt32t,
UInt64t,
UInt128t,
ConstCharPtr,
BFloat16,
Float16,
Float32,
Float64,
Float128,
}
impl CType {
pub(crate) fn to_sys(self) -> gccjit_sys::gcc_jit_types {
use gccjit_sys::gcc_jit_types::*;
use self::CType::*;
match self {
Bool => GCC_JIT_TYPE_BOOL,
Char => GCC_JIT_TYPE_CHAR,
UChar => GCC_JIT_TYPE_UNSIGNED_CHAR,
SChar => GCC_JIT_TYPE_SIGNED_CHAR,
Short => GCC_JIT_TYPE_SHORT,
UShort => GCC_JIT_TYPE_UNSIGNED_SHORT,
Int => GCC_JIT_TYPE_INT,
UInt => GCC_JIT_TYPE_UNSIGNED_INT,
Long => GCC_JIT_TYPE_LONG,
ULong => GCC_JIT_TYPE_UNSIGNED_LONG,
LongLong => GCC_JIT_TYPE_LONG_LONG,
ULongLong => GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
SizeT => GCC_JIT_TYPE_SIZE_T,
Int8t => GCC_JIT_TYPE_INT8_T,
Int16t => GCC_JIT_TYPE_INT16_T,
Int32t => GCC_JIT_TYPE_INT32_T,
Int64t => GCC_JIT_TYPE_INT64_T,
Int128t => GCC_JIT_TYPE_INT128_T,
UInt8t => GCC_JIT_TYPE_UINT8_T,
UInt16t => GCC_JIT_TYPE_UINT16_T,
UInt32t => GCC_JIT_TYPE_UINT32_T,
UInt64t => GCC_JIT_TYPE_UINT64_T,
UInt128t => GCC_JIT_TYPE_UINT128_T,
ConstCharPtr => GCC_JIT_TYPE_CONST_CHAR_PTR,
BFloat16 => GCC_JIT_TYPE_BFLOAT16,
Float16 => GCC_JIT_TYPE_FLOAT16,
Float32 => GCC_JIT_TYPE_FLOAT32,
Float64 => GCC_JIT_TYPE_FLOAT64,
Float128 => GCC_JIT_TYPE_FLOAT128,
}
}
}