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::{self, NonNull};
use std::str::Utf8Error;
use gccjit_sys::gcc_jit_bool_option::*;
use gccjit_sys::gcc_jit_int_option::*;
use gccjit_sys::gcc_jit_str_option::*;
use block::{self, BinaryOp, Block, ComparisonOp, UnaryOp};
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 types;
use Type;
use crate::{with_lib, with_lib_handle, with_lib_without_error_check};
pub(crate) trait ContextGetter<'ctx> {
fn context(&self) -> crate::ContextRef<'ctx>;
}
impl<'ctx> ContextGetter<'ctx> for Context<'ctx> {
fn context(&self) -> crate::ContextRef<'ctx> {
unsafe {
crate::ContextRef {
context: std::mem::ManuallyDrop::new(
from_ptr(get_ptr(self)).expect("Failed to get Context from Context"),
),
}
}
}
}
#[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: NonNull<gccjit_sys::gcc_jit_result>,
}
impl CompileResult {
pub fn get_function<S: AsRef<str>>(&self, name: S) -> Option<NonNull<()>> {
let c_str = CString::new(name.as_ref()).unwrap();
NonNull::new(with_lib_without_error_check(|lib| unsafe {
let func = lib.gcc_jit_result_get_code(self.get_ptr(), c_str.as_ptr());
mem::transmute(func)
}))
}
pub fn get_global<S: AsRef<str>>(&self, name: S) -> Option<NonNull<()>> {
let c_str = CString::new(name.as_ref()).unwrap();
NonNull::new(with_lib_without_error_check(|lib| unsafe {
let ptr = lib.gcc_jit_result_get_global(self.get_ptr(), c_str.as_ptr());
mem::transmute(ptr)
}))
}
pub(crate) fn get_ptr(&self) -> *mut gccjit_sys::gcc_jit_result {
self.ptr.as_ptr()
}
}
impl Drop for CompileResult {
fn drop(&mut self) {
with_lib_without_error_check(|lib| unsafe {
lib.gcc_jit_result_release(self.get_ptr());
})
}
}
pub struct Case<'ctx> {
marker: PhantomData<&'ctx Case<'ctx>>,
ptr: NonNull<gccjit_sys::gcc_jit_case>,
}
impl<'ctx> ToObject<'ctx> for Case<'ctx> {
fn to_object(&self) -> Object<'ctx> {
with_lib_without_error_check(|lib| unsafe {
let ptr = lib.gcc_jit_case_as_object(self.get_ptr());
object::from_ptr(ptr).expect("Failed to get Object from Case")
})
}
}
impl<'ctx> ContextGetter<'ctx> for Case<'ctx> {
fn context(&self) -> crate::ContextRef<'ctx> {
self.to_object().context()
}
}
impl<'ctx> Case<'ctx> {
pub(crate) fn get_ptr(&self) -> *mut gccjit_sys::gcc_jit_case {
self.ptr.as_ptr()
}
}
#[derive(Debug)]
pub struct Context<'ctx> {
marker: PhantomData<&'ctx Context<'ctx>>,
ptr: NonNull<gccjit_sys::gcc_jit_context>,
}
impl Default for Context<'static> {
fn default() -> Context<'static> {
with_lib_without_error_check(|lib| unsafe {
Context {
marker: PhantomData,
ptr: NonNull::new(lib.gcc_jit_context_acquire())
.expect("failed to acquire gccjit context"),
}
})
}
}
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(self, |lib| unsafe {
lib.gcc_jit_context_set_str_option(
get_ptr(self),
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(self, |lib| unsafe {
lib.gcc_jit_context_add_command_line_option(get_ptr(self), 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(self, |lib| unsafe {
lib.gcc_jit_context_add_driver_option(get_ptr(self), c_str.as_ptr())
})
}
pub fn set_optimization_level(&self, level: OptimizationLevel) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_int_option(
get_ptr(self),
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(self, |lib| unsafe {
lib.gcc_jit_context_set_output_ident(get_ptr(self), 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(self, |lib| unsafe {
lib.gcc_jit_context_set_str_option(
get_ptr(self),
GCC_JIT_STR_OPTION_SPECIAL_CHARS_IN_FUNC_NAMES,
c_str.as_ptr(),
);
})
}
pub fn set_debug_info(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_option(
get_ptr(self),
GCC_JIT_BOOL_OPTION_DEBUGINFO,
value as i32,
);
})
}
pub fn set_keep_intermediates(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_option(
get_ptr(self),
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
value as i32,
);
})
}
pub fn set_print_errors_to_stderr(&self, enabled: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_print_errors_to_stderr(get_ptr(self), enabled as c_int);
})
}
pub fn set_dump_everything(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_option(
get_ptr(self),
GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
value as i32,
);
})
}
pub fn set_dump_initial_gimple(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_option(
get_ptr(self),
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
value as i32,
);
})
}
pub fn set_dump_code_on_compile(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_option(
get_ptr(self),
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
value as i32,
);
})
}
pub fn set_allow_unreachable_blocks(&self, value: bool) {
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_bool_allow_unreachable_blocks(get_ptr(self), value as i32);
})
}
pub fn compile(&self) -> Result<CompileResult, String> {
let result = with_lib(self, |lib| unsafe {
NonNull::new(lib.gcc_jit_context_compile(get_ptr(self)))
.map(|ptr| CompileResult { ptr })
});
match result {
Some(result) => Ok(result),
None => Err(match self.get_last_error() {
Ok(Some(error)) => error.to_string(),
_ => "gcc_jit_context_compile failed (libgccjit recorded no error; see stderr)"
.to_string(),
}),
}
}
pub fn compile_to_file<S: AsRef<str>>(&self, kind: OutputKind, file: S) {
with_lib(self, |lib| unsafe {
let file_ref = file.as_ref();
let cstr = CString::new(file_ref).unwrap();
lib.gcc_jit_context_compile_to_file(
get_ptr(self),
mem::transmute::<OutputKind, gccjit_sys::gcc_jit_output_kind>(kind),
cstr.as_ptr(),
);
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn get_target_info(&self) -> TargetInfo {
with_lib_handle(self, |lib| unsafe {
target_info::from_ptr(lib.gcc_jit_context_get_target_info(get_ptr(self)))
})
}
#[track_caller]
pub fn new_child_context<'b>(&'b self) -> Context<'b> {
with_lib_handle(self, |lib| unsafe {
Some(Context {
marker: PhantomData,
ptr: NonNull::new(lib.gcc_jit_context_new_child_context(get_ptr(self)))?,
})
})
}
#[track_caller]
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();
with_lib_handle(self, |lib| unsafe {
Some(Case {
marker: PhantomData,
ptr: NonNull::new(lib.gcc_jit_context_new_case(
get_ptr(self),
rvalue::get_ptr(&min_value),
rvalue::get_ptr(&max_value),
block::get_ptr(&dest_block),
))?,
})
})
}
pub fn new_location<'a, S: AsRef<str>>(
&'a self,
filename: S,
line: i32,
col: i32,
) -> Location<'a> {
with_lib(self, |lib| unsafe {
let filename_ref = filename.as_ref();
let cstr = CString::new(filename_ref).unwrap();
let ptr = lib.gcc_jit_context_new_location(get_ptr(self), cstr.as_ptr(), line, col);
location::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_global<'a, S: AsRef<str>>(
&self,
loc: Option<Location<'a>>,
kind: GlobalKind,
ty: Type<'a>,
name: S,
) -> LValue<'a> {
with_lib_handle(self, |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(
get_ptr(self),
loc_ptr,
mem::transmute::<GlobalKind, gccjit_sys::gcc_jit_global_kind>(kind),
types::get_ptr(&ty),
cstr.as_ptr(),
);
lvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_type<'a, T: types::Typeable>(&'a self) -> types::Type<'a> {
<T as types::Typeable>::get_type(self)
}
#[track_caller]
pub fn new_c_type<'a>(&'a self, c_type: CType) -> types::Type<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_get_type(get_ptr(self), c_type.to_sys());
types::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_int_type<'a>(&'a self, num_bytes: i32, signed: bool) -> types::Type<'a> {
with_lib_handle(self, |lib| unsafe {
let ctx_ptr = get_ptr(self);
let ptr = lib.gcc_jit_context_get_int_type(ctx_ptr, num_bytes, signed as i32);
types::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_field(
get_ptr(self),
loc_ptr,
types::get_ptr(&ty),
cstr.as_ptr(),
);
field::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_array_type(
get_ptr(self),
loc_ptr,
types::get_ptr(&ty),
num_elements as c_ulong,
);
types::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_array_type_u64(
get_ptr(self),
loc_ptr,
types::get_ptr(&ty),
num_elements,
);
types::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_vector_type<'a>(&'a self, ty: types::Type<'a>, num_units: u64) -> types::Type<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_type_get_vector(types::get_ptr(&ty), num_units as _);
types::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
cname.as_ptr(),
num_fields,
fields_ptrs.as_mut_ptr(),
);
structs::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_opaque_struct(get_ptr(self), loc_ptr, cstr.as_ptr());
structs::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
cname.as_ptr(),
num_fields,
fields_ptrs.as_mut_ptr(),
);
types::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
types::get_ptr(&return_type),
num_types,
types_ptrs.as_mut_ptr(),
is_variadic as i32,
);
types::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
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,
);
function::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_binary_op(
get_ptr(self),
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),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_unary_op(
get_ptr(self),
loc_ptr,
mem::transmute::<UnaryOp, gccjit_sys::gcc_jit_unary_op>(op),
types::get_ptr(&ty),
rvalue::get_ptr(&rvalue),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_comparison(
get_ptr(self),
loc_ptr,
mem::transmute::<ComparisonOp, gccjit_sys::gcc_jit_comparison>(op),
rvalue::get_ptr(&left_rvalue),
rvalue::get_ptr(&right_rvalue),
);
rvalue::from_ptr(ptr)
})
}
#[must_use]
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
function::get_ptr(&func),
num_params,
params_ptrs.as_mut_ptr(),
);
rvalue::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&fun_ptr_rvalue),
num_params,
params_ptrs.as_mut_ptr(),
);
rvalue::from_ptr(ptr)
}
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_cast(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&rvalue),
types::get_ptr(&dest_type),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_bitcast(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&rvalue),
types::get_ptr(&dest_type),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_va_arg<'a, T: ToRValue<'a>>(
&'a self,
loc: Option<Location<'a>>,
ap: T,
arg_type: types::Type<'a>,
) -> RValue<'a> {
let ap = ap.to_rvalue();
let loc_ptr = match loc {
Some(loc) => unsafe { location::get_ptr(&loc) },
None => ptr::null_mut(),
};
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_va_arg(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&ap),
types::get_ptr(&arg_type),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_array_access(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&array_rvalue),
rvalue::get_ptr(&idx_rvalue),
);
lvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_rvalue_from_long<'a>(&'a self, ty: types::Type<'a>, value: i64) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_long(
get_ptr(self),
types::get_ptr(&ty),
value as _,
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
types::get_ptr(&vec_type),
elements.len() as _,
elements.as_ptr() as *mut *mut _,
);
rvalue::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&elements1),
rvalue::get_ptr(&elements2),
rvalue::get_ptr(&mask),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
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_handle(self, |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(
get_ptr(self),
loc_ptr,
types::get_ptr(&struct_type),
values.len() as _,
fields_ptr as *mut *mut _,
values.as_ptr() as *mut *mut _,
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_array_constructor<'a>(
&'a self,
loc: Option<Location<'a>>,
array_type: types::Type<'a>,
elements: &[RValue<'a>],
) -> RValue<'a> {
with_lib_handle(self, |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(
get_ptr(self),
loc_ptr,
types::get_ptr(&array_type),
elements.len() as _,
elements.as_ptr() as *mut *mut _,
);
rvalue::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn new_vector_access<'a>(
&'a self,
loc: Option<Location<'a>>,
vector: RValue<'a>,
index: RValue<'a>,
) -> LValue<'a> {
with_lib_handle(self, |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(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&vector),
rvalue::get_ptr(&index),
);
lvalue::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn convert_vector<'a>(
&'a self,
loc: Option<Location<'a>>,
vector: RValue<'a>,
type_: Type<'a>,
) -> RValue<'a> {
with_lib_handle(self, |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(
get_ptr(self),
loc_ptr,
rvalue::get_ptr(&vector),
types::get_ptr(&type_),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_rvalue_from_int<'a>(&'a self, ty: types::Type<'a>, value: i32) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr =
lib.gcc_jit_context_new_rvalue_from_int(get_ptr(self), types::get_ptr(&ty), value);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_rvalue_from_double<'a>(&'a self, ty: types::Type<'a>, value: f64) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_double(
get_ptr(self),
types::get_ptr(&ty),
value,
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_rvalue_zero<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_zero(get_ptr(self), types::get_ptr(&ty));
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_rvalue_one<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_one(get_ptr(self), types::get_ptr(&ty));
rvalue::from_ptr(ptr)
})
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[track_caller]
pub fn new_rvalue_from_ptr<'a>(&'a self, ty: types::Type<'a>, value: *mut ()) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_rvalue_from_ptr(
get_ptr(self),
types::get_ptr(&ty),
mem::transmute::<*mut (), *mut c_void>(value),
);
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_null<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_null(get_ptr(self), types::get_ptr(&ty));
rvalue::from_ptr(ptr)
})
}
#[track_caller]
pub fn new_string_literal<'a, S: AsRef<str>>(&'a self, value: S) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let cstr = CString::new(value.as_ref()).unwrap();
let ptr = lib.gcc_jit_context_new_string_literal(get_ptr(self), cstr.as_ptr());
rvalue::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn new_sizeof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_sizeof(get_ptr(self), types::get_ptr(&ty));
rvalue::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn get_error_count<'a>(&'a self) -> i32 {
with_lib_without_error_check(|lib| unsafe {
lib.gcc_jit_context_get_error_count(get_ptr(self))
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn new_alignof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> {
with_lib_handle(self, |lib| unsafe {
let ptr = lib.gcc_jit_context_new_alignof(get_ptr(self), types::get_ptr(&ty));
rvalue::from_ptr(ptr)
})
}
pub fn dump_reproducer_to_file<S: AsRef<str>>(&self, path: S) {
with_lib(self, |lib| unsafe {
let path_ref = path.as_ref();
let cstr = CString::new(path_ref).unwrap();
lib.gcc_jit_context_dump_reproducer_to_file(get_ptr(self), cstr.as_ptr());
})
}
pub fn dump_to_file<S: AsRef<str>>(&self, path: S, update_locations: bool) {
with_lib(self, |lib| unsafe {
let path_ref = path.as_ref();
let cstr = CString::new(path_ref).unwrap();
lib.gcc_jit_context_dump_to_file(
get_ptr(self),
cstr.as_ptr(),
update_locations as c_int,
);
})
}
#[track_caller]
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_handle(self, |lib| unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_new_param(
get_ptr(self),
loc_ptr,
types::get_ptr(&ty),
cstr.as_ptr(),
);
parameter::from_ptr(ptr)
})
}
#[track_caller]
pub fn get_builtin_function<'a, S: AsRef<str>>(&'a self, name: S) -> Function<'a> {
let name_ref = name.as_ref();
with_lib_handle(self, |lib| unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_get_builtin_function(get_ptr(self), cstr.as_ptr());
function::from_ptr(ptr)
})
}
#[cfg(feature = "master")]
#[track_caller]
pub fn get_target_builtin_function<'a, S: AsRef<str>>(&'a self, name: S) -> Function<'a> {
let name_ref = name.as_ref();
with_lib_handle(self, |lib| unsafe {
let cstr = CString::new(name_ref).unwrap();
let ptr = lib.gcc_jit_context_get_target_builtin_function(get_ptr(self), cstr.as_ptr());
function::from_ptr(ptr)
})
}
pub fn get_first_error(&self) -> Result<Option<&'ctx str>, Utf8Error> {
with_lib_without_error_check(|lib| unsafe {
let str = lib.gcc_jit_context_get_first_error(get_ptr(self));
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_without_error_check(|lib| unsafe {
let str = lib.gcc_jit_context_get_last_error(get_ptr(self));
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(self, |lib| unsafe {
lib.gcc_jit_context_set_logfile(get_ptr(self), 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(self, |lib| unsafe {
lib.gcc_jit_context_add_top_level_asm(get_ptr(self), loc_ptr, asm_stmts.as_ptr());
});
}
#[cfg(feature = "master")]
pub fn set_filename(&self, filename: &str) {
let c_str = CString::new(filename).unwrap();
with_lib(self, |lib| unsafe {
lib.gcc_jit_context_set_filename(get_ptr(self), c_str.as_ptr());
})
}
}
impl<'ctx> Drop for Context<'ctx> {
fn drop(&mut self) {
with_lib_without_error_check(|lib| unsafe {
lib.gcc_jit_context_release(get_ptr(self));
})
}
}
#[doc(hidden)]
pub unsafe fn get_ptr<'ctx>(ctx: &'ctx Context<'ctx>) -> *mut gccjit_sys::gcc_jit_context {
ctx.ptr.as_ptr()
}
pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_context) -> Option<Context<'ctx>> {
Some(Context {
marker: PhantomData,
ptr: NonNull::new(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().expect("failed to get compile code");
unsafe {
let func_ptr = result
.get_function("square")
.expect("failed to get `square` function");
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,
VaList,
}
impl CType {
pub(crate) fn to_sys(self) -> gccjit_sys::gcc_jit_types {
use self::CType::*;
use gccjit_sys::gcc_jit_types::*;
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,
VaList => GCC_JIT_TYPE_VA_LIST,
}
}
}