diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3eb44b7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,66 @@ +name: CI + +on: + - pull_request + +permissions: + contents: read + +env: + # Enable backtraces for easier debugging + RUST_BACKTRACE: 1 + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + - name: Download and install GCC fork + run: | + curl -LO https://github.com/antoyo/gcc/releases/latest/download/gcc-15.deb + sudo dpkg --force-overwrite -i gcc-15.deb + + - name: Set env + run: | + echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV + + - name: Cache cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v3 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} + + - name: Build + run: | + cargo build + cargo build --features master + cargo build --examples + + - name: Test + run: | + cd examples/factorial + cargo build + + - name: clippy + run: | + cargo clippy --all-targets -- -D warnings + cargo clippy --all-targets --features master -- -D warnings diff --git a/Cargo.toml b/Cargo.toml index 793c49a..4c8fe6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,19 @@ [package] name = "gccjit" -version = "1.0.0" -authors = ["Sean Gillespie "] +version = "2.9.0" +authors = ["Sean Gillespie ", "Antoni Boucher "] description = "Higher-level Rust bindings for libgccjit." keywords = ["compiler", "jit", "gcc"] license = "GPL-3.0" -repository = "https://github.com/swgillespie/gccjit.rs" -documentation = "http://swgillespie.github.io/gccjit.rs/gccjit/" +repository = "https://github.com/rust-lang/gccjit.rs" +documentation = "https://docs.rs/gccjit/latest/gccjit/" readme = "README.md" +[features] +master = ["gccjit_sys/master"] [dependencies] -gccjit_sys = "0.0.1" +gccjit_sys = { version = "0.8.2", path = "gccjit_sys" } +[package.metadata.docs.rs] +features = ["master"] diff --git a/README.md b/README.md index 4b6c50f..5d83c8d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ There are four examples right now living in the `examples/` directory: * `square_function` - A square function, as a simple example for code generation, * `factorial` - A factorial function, as a more complicated example involving recursion and conditional jumps. gcc removes all recursion at O3. * `hello_world` - An example that invokes a function written in Rust from JIT-compiled code. -* `brainfuck` - An ahead-of-time compiler for brainfuck. The speed is very impressive given how easy it was to setup with libgccjit. Some benchmarks, my compiler vs a naive interpreter I wrote in Haskell: +* `brainfuck` - An ahead-of-time compiler for brainfuck. The speed is very impressive given how easy it was to setup with libgccjit. + +## Some benchmarks, my compiler vs a naive interpreter I wrote in Haskell: ``` sierpinski_triangle, haskell: real 0m0.052s diff --git a/examples/brainfuck/src/main.rs b/examples/brainfuck/src/main.rs index 6a47a13..c4c2b60 100644 --- a/examples/brainfuck/src/main.rs +++ b/examples/brainfuck/src/main.rs @@ -107,6 +107,7 @@ fn codegen<'a, 'ctx>(ops: &[Op], context: &'a gccjit::Context<'ctx>) -> bool { let mut current_block = brainf_main.new_block("entry_block"); // now we have to zero out the giant buffer we just allocated on the stack. let zero_access = context.new_array_access(None, array.to_rvalue(), context.new_rvalue_zero(int_ty)); + // A function call that is done for its side effects must be sent to add_eval. current_block.add_eval(None, context.new_call(None, memset, &[zero_access.get_address(None), context.new_rvalue_zero(int_ty), size])); let mut block_stack = vec![]; let mut blocks = 0; diff --git a/examples/factorial/factorial.dot b/examples/factorial/factorial.dot index f3c5c6f..33f9113 100644 --- a/examples/factorial/factorial.dot +++ b/examples/factorial/factorial.dot @@ -4,7 +4,7 @@ if\ (n\ ==\ (int)0)\ goto\ ret_block;\ else\ goto\ recurse_block;\l\ }"]; block_1 [shape=record,style=filled,fillcolor=white,label="{recurse_block:\l\ -return\ n\ *\ factorial\ (n\ -\ (int)1);\l\ +return\ n\ *\ factorial\ ((n\ -\ (int)1));\l\ }"]; block_2 [shape=record,style=filled,fillcolor=white,label="{ret_block:\l\ diff --git a/examples/factorial/src/main.rs b/examples/factorial/src/main.rs index e36df8e..f0a0e29 100644 --- a/examples/factorial/src/main.rs +++ b/examples/factorial/src/main.rs @@ -9,7 +9,6 @@ use gccjit::ComparisonOp; use std::default::Default; use std::mem; - fn main() { let context = Context::default(); context.set_dump_code_on_compile(true); diff --git a/gccjit_sys/Cargo.toml b/gccjit_sys/Cargo.toml index 77999bd..33d91e7 100644 --- a/gccjit_sys/Cargo.toml +++ b/gccjit_sys/Cargo.toml @@ -1,12 +1,15 @@ [package] name = "gccjit_sys" -version = "0.0.1" -authors = ["Sean Gillespie "] -links = "gccjit" +version = "0.8.2" +authors = ["Sean Gillespie ", "Antoni Boucher "] +#links = "gccjit" description = "Raw bindings to libgccjit. Companion to the gccjit crate." keywords = ["compiler", "jit", "gcc"] license = "GPL-3.0" -repository = "https://github.com/swgillespie/gccjit.rs" +repository = "https://github.com/rust-lang/gccjit.rs" + +[features] +master = [] [dependencies] -libc = "0.1.6" +libc = "0.2" diff --git a/gccjit_sys/src/lib.rs b/gccjit_sys/src/lib.rs index 7944867..c75110d 100644 --- a/gccjit_sys/src/lib.rs +++ b/gccjit_sys/src/lib.rs @@ -2,7 +2,7 @@ extern crate libc; -use libc::{c_char, c_int, FILE, c_void, c_long, c_double}; +use libc::{c_char, c_int, FILE, c_void, c_long, c_double, c_ulong, size_t, ssize_t}; // opaque pointers pub enum gcc_jit_context {} @@ -17,11 +17,26 @@ pub enum gcc_jit_block {} pub enum gcc_jit_rvalue {} pub enum gcc_jit_lvalue {} pub enum gcc_jit_param {} +pub enum gcc_jit_case {} +pub enum gcc_jit_function_type {} +pub enum gcc_jit_vector_type {} +pub enum gcc_jit_extended_asm {} +pub enum gcc_jit_target_info {} + +#[repr(C)] +pub enum gcc_jit_tls_model { + GCC_JIT_TLS_MODEL_NONE, + GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC, + GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC, + GCC_JIT_TLS_MODEL_INITIAL_EXEC, + GCC_JIT_TLS_MODEL_LOCAL_EXEC, +} #[repr(C)] pub enum gcc_jit_str_option { GCC_JIT_STR_OPTION_PROGNAME, - GCC_JIT_NUM_STR_OPTIONS + GCC_JIT_STR_OPTION_SPECIAL_CHARS_IN_FUNC_NAMES, + GCC_JIT_NUM_STR_OPTIONS, } #[repr(C)] @@ -77,6 +92,7 @@ pub enum gcc_jit_types { /* C99's "long long" and "unsigned long long". */ GCC_JIT_TYPE_LONG_LONG, /* signed */ GCC_JIT_TYPE_UNSIGNED_LONG_LONG, + /* Floating-point types */ GCC_JIT_TYPE_FLOAT, GCC_JIT_TYPE_DOUBLE, @@ -90,7 +106,24 @@ pub enum gcc_jit_types { /* Complex numbers. */ GCC_JIT_TYPE_COMPLEX_FLOAT, GCC_JIT_TYPE_COMPLEX_DOUBLE, - GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + + GCC_JIT_TYPE_UINT8_T, + GCC_JIT_TYPE_UINT16_T, + GCC_JIT_TYPE_UINT32_T, + GCC_JIT_TYPE_UINT64_T, + GCC_JIT_TYPE_UINT128_T, + GCC_JIT_TYPE_INT8_T, + GCC_JIT_TYPE_INT16_T, + GCC_JIT_TYPE_INT32_T, + GCC_JIT_TYPE_INT64_T, + GCC_JIT_TYPE_INT128_T, + + GCC_JIT_TYPE_BFLOAT16, + GCC_JIT_TYPE_FLOAT16, + GCC_JIT_TYPE_FLOAT32, + GCC_JIT_TYPE_FLOAT64, + GCC_JIT_TYPE_FLOAT128, } #[repr(C)] @@ -226,8 +259,51 @@ pub enum gcc_jit_comparison GCC_JIT_COMPARISON_GE } +#[cfg(feature="master")] +#[repr(C)] +pub enum gcc_jit_fn_attribute +{ + GCC_JIT_FN_ATTRIBUTE_ALIAS, + GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, + GCC_JIT_FN_ATTRIBUTE_INLINE, + GCC_JIT_FN_ATTRIBUTE_NOINLINE, + GCC_JIT_FN_ATTRIBUTE_TARGET, + GCC_JIT_FN_ATTRIBUTE_USED, + GCC_JIT_FN_ATTRIBUTE_VISIBILITY, + GCC_JIT_FN_ATTRIBUTE_COLD, + GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, + GCC_JIT_FN_ATTRIBUTE_PURE, + GCC_JIT_FN_ATTRIBUTE_CONST, + GCC_JIT_FN_ATTRIBUTE_WEAK, + GCC_JIT_FN_ATTRIBUTE_NONNULL, + GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_CALL, + GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_ENTRY, + GCC_JIT_FN_ATTRIBUTE_ARM_PCS, + GCC_JIT_FN_ATTRIBUTE_AVR_INTERRUPT, + GCC_JIT_FN_ATTRIBUTE_AVR_NOBLOCK, + GCC_JIT_FN_ATTRIBUTE_AVR_SIGNAL, + GCC_JIT_FN_ATTRIBUTE_GCN_AMDGPU_HSA_KERNEL, + GCC_JIT_FN_ATTRIBUTE_MSP430_INTERRUPT, + GCC_JIT_FN_ATTRIBUTE_NVPTX_KERNEL, + GCC_JIT_FN_ATTRIBUTE_RISCV_INTERRUPT, + GCC_JIT_FN_ATTRIBUTE_X86_FAST_CALL, + GCC_JIT_FN_ATTRIBUTE_X86_INTERRUPT, + GCC_JIT_FN_ATTRIBUTE_X86_MS_ABI, + GCC_JIT_FN_ATTRIBUTE_X86_STDCALL, + GCC_JIT_FN_ATTRIBUTE_X86_SYSV_ABI, + GCC_JIT_FN_ATTRIBUTE_X86_THIS_CALL, +} + +#[cfg(feature="master")] +#[repr(C)] +pub enum gcc_jit_variable_attribute +{ + GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, + GCC_JIT_VARIABLE_ATTRIBUTE_WEAK, +} + #[link(name = "gccjit")] -extern { +extern "C" { // context operations pub fn gcc_jit_context_acquire() -> *mut gcc_jit_context; pub fn gcc_jit_context_release(ctx: *mut gcc_jit_context); @@ -240,6 +316,8 @@ extern { pub fn gcc_jit_context_set_bool_option(ctx: *mut gcc_jit_context, option: gcc_jit_bool_option, value: c_int); + pub fn gcc_jit_context_set_bool_allow_unreachable_blocks(ctx: *mut gcc_jit_context, + value: c_int); pub fn gcc_jit_context_compile(ctx: *mut gcc_jit_context) -> *mut gcc_jit_result; pub fn gcc_jit_context_compile_to_file(ctx: *mut gcc_jit_context, kind: gcc_jit_output_kind, @@ -252,6 +330,7 @@ extern { flags: c_int, verbosity: c_int); pub fn gcc_jit_context_get_first_error(ctx: *mut gcc_jit_context) -> *const c_char; + pub fn gcc_jit_context_get_last_error(ctx: *mut gcc_jit_context) -> *const c_char; // result operations pub fn gcc_jit_result_get_code(result: *mut gcc_jit_result, @@ -283,10 +362,12 @@ extern { pub fn gcc_jit_type_get_pointer(ty: *mut gcc_jit_type) -> *mut gcc_jit_type; pub fn gcc_jit_type_get_const(ty: *mut gcc_jit_type) -> *mut gcc_jit_type; pub fn gcc_jit_type_get_volatile(ty: *mut gcc_jit_type) -> *mut gcc_jit_type; + #[cfg(feature="master")] + pub fn gcc_jit_type_get_restrict(ty: *mut gcc_jit_type) -> *mut gcc_jit_type; pub fn gcc_jit_context_new_array_type(ctx: *mut gcc_jit_context, loc: *mut gcc_jit_location, ty: *mut gcc_jit_type, - num_elements: c_int) -> *mut gcc_jit_type; + num_elements: c_ulong) -> *mut gcc_jit_type; // struct handling pub fn gcc_jit_context_new_field(ctx: *mut gcc_jit_context, loc: *mut gcc_jit_location, @@ -425,7 +506,7 @@ extern { pub fn gcc_jit_rvalue_access_field(struct_or_union: *mut gcc_jit_rvalue, loc: *mut gcc_jit_location, - field: *mut gcc_jit_field) -> *mut gcc_jit_lvalue; + field: *mut gcc_jit_field) -> *mut gcc_jit_rvalue; pub fn gcc_jit_rvalue_dereference_field(ptr: *mut gcc_jit_rvalue, loc: *mut gcc_jit_location, field: *mut gcc_jit_field) -> *mut gcc_jit_lvalue; @@ -468,4 +549,160 @@ extern { pub fn gcc_jit_context_new_child_context(parent: *mut gcc_jit_context) -> *mut gcc_jit_context; pub fn gcc_jit_context_dump_reproducer_to_file(parent: *mut gcc_jit_context, path: *const c_char); + + pub fn gcc_jit_context_new_case(ctxt: *mut gcc_jit_context, min_value: *mut gcc_jit_rvalue, max_value: *mut gcc_jit_rvalue, dest_block: *mut gcc_jit_block) -> *mut gcc_jit_case; + pub fn gcc_jit_block_end_with_switch(block: *mut gcc_jit_block, loc: *mut gcc_jit_location, expr: *mut gcc_jit_rvalue, default_block: *mut gcc_jit_block, num_cases: c_int, cases: *mut *mut gcc_jit_case); + pub fn gcc_jit_case_as_object(case_: *mut gcc_jit_case) -> *mut gcc_jit_object; + + pub fn gcc_jit_function_get_address(fun: *mut gcc_jit_function, loc: *mut gcc_jit_location) -> *mut gcc_jit_rvalue; + + pub fn gcc_jit_type_get_vector(typ: *mut gcc_jit_type, num_units: size_t) -> *mut gcc_jit_type; + pub fn gcc_jit_context_new_rvalue_from_vector(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, vec_type: *mut gcc_jit_type, num_elements: size_t, elements: *mut *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + + pub fn gcc_jit_context_add_command_line_option(ctxt: *mut gcc_jit_context, optname: *const c_char); + pub fn gcc_jit_context_add_driver_option(ctxt: *mut gcc_jit_context, optname: *const c_char); + + pub fn gcc_jit_type_get_aligned(typ: *mut gcc_jit_type, alignment_in_bytes: size_t) -> *mut gcc_jit_type; + + pub fn gcc_jit_function_get_return_type(func: *mut gcc_jit_function) -> *mut gcc_jit_type; + pub fn gcc_jit_function_get_param_count(func: *mut gcc_jit_function) -> ssize_t; + + pub fn gcc_jit_type_dyncast_array(typ: *mut gcc_jit_type) -> *mut gcc_jit_type; + pub fn gcc_jit_type_is_bool(typ: *mut gcc_jit_type) -> c_int; + pub fn gcc_jit_type_is_integral(typ: *mut gcc_jit_type) -> c_int; + #[cfg(feature = "master")] + pub fn gcc_jit_type_is_floating_point(typ: *mut gcc_jit_type) -> c_int; + pub fn gcc_jit_type_unqualified(typ: *mut gcc_jit_type) -> *mut gcc_jit_type; + pub fn gcc_jit_type_is_pointer(typ: *mut gcc_jit_type) -> *mut gcc_jit_type; + pub fn gcc_jit_type_dyncast_function_ptr_type(typ: *mut gcc_jit_type) -> *mut gcc_jit_function_type; + pub fn gcc_jit_function_type_get_return_type(function_type: *mut gcc_jit_function_type) -> *mut gcc_jit_type; + pub fn gcc_jit_function_type_get_param_count(function_type: *mut gcc_jit_function_type) -> ssize_t; + pub fn gcc_jit_type_dyncast_vector(typ: *mut gcc_jit_type) -> *mut gcc_jit_vector_type; + pub fn gcc_jit_function_type_get_param_type(function_type: *mut gcc_jit_function_type, index: c_int) -> *mut gcc_jit_type; + pub fn gcc_jit_vector_type_get_num_units(vector_type: *mut gcc_jit_vector_type) -> ssize_t; + pub fn gcc_jit_vector_type_get_element_type(vector_type: *mut gcc_jit_vector_type) -> *mut gcc_jit_type; + pub fn gcc_jit_struct_get_field(struct_type: *mut gcc_jit_struct, index: c_int) -> *mut gcc_jit_field; + pub fn gcc_jit_type_is_struct(typ: *mut gcc_jit_type) -> *mut gcc_jit_struct; + pub fn gcc_jit_struct_get_field_count(struct_type: *mut gcc_jit_struct) -> ssize_t; + + pub fn gcc_jit_global_set_initializer(global: *mut gcc_jit_lvalue, blob: *const c_void, num_bytes: size_t) -> *mut gcc_jit_lvalue; + + pub fn gcc_jit_block_end_with_extended_asm_goto(block: *mut gcc_jit_block, loc: *mut gcc_jit_location, asm_template: *const c_char, num_goto_blocks: c_int, goto_blocks: *mut *mut gcc_jit_block, fallthrough_block: *mut gcc_jit_block) -> *mut gcc_jit_extended_asm; + pub fn gcc_jit_extended_asm_as_object(ext_asm: *mut gcc_jit_extended_asm) -> *mut gcc_jit_object; + pub fn gcc_jit_extended_asm_set_volatile_flag(ext_asm: *mut gcc_jit_extended_asm, flag: c_int); + pub fn gcc_jit_extended_asm_set_inline_flag(ext_asm: *mut gcc_jit_extended_asm, flag: c_int); + pub fn gcc_jit_extended_asm_add_output_operand(ext_asm: *mut gcc_jit_extended_asm, asm_symbolic_name: *const c_char, constraint: *const c_char, dest: *mut gcc_jit_lvalue); + pub fn gcc_jit_extended_asm_add_input_operand(ext_asm: *mut gcc_jit_extended_asm, asm_symbolic_name: *const c_char, constraint: *const c_char, src: *mut gcc_jit_rvalue); + pub fn gcc_jit_extended_asm_add_clobber(ext_asm: *mut gcc_jit_extended_asm, victim: *const c_char); + pub fn gcc_jit_context_add_top_level_asm(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, asm_stmts: *const c_char); + pub fn gcc_jit_block_add_extended_asm(block: *mut gcc_jit_block, loc: *mut gcc_jit_location, asm_template: *const c_char) -> *mut gcc_jit_extended_asm; + + pub fn gcc_jit_lvalue_set_tls_model(lvalue: *mut gcc_jit_lvalue, model: gcc_jit_tls_model); + pub fn gcc_jit_lvalue_set_link_section(lvalue: *mut gcc_jit_lvalue, name: *const c_char); + + pub fn gcc_jit_context_new_bitcast(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, rvalue: *mut gcc_jit_rvalue, type_: *mut gcc_jit_type) -> *mut gcc_jit_rvalue; + + pub fn gcc_jit_lvalue_set_register_name(lvalue: *mut gcc_jit_lvalue, reg_name: *const c_char); + + pub fn gcc_jit_context_new_struct_constructor(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, typ: *mut gcc_jit_type, num_values: c_int, fields: *mut *mut gcc_jit_field, values: *mut *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + pub fn gcc_jit_context_new_union_constructor(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, typ: *mut gcc_jit_type, field: *mut gcc_jit_field, value: *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + pub fn gcc_jit_context_new_array_constructor(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, typ: *mut gcc_jit_type, arr_length: c_int, values: *mut *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + pub fn gcc_jit_global_set_initializer_rvalue(global: *mut gcc_jit_lvalue, init_value: *mut gcc_jit_rvalue) -> *mut gcc_jit_lvalue; + + pub fn gcc_jit_type_get_size(typ: *mut gcc_jit_type) -> ssize_t; + pub fn gcc_jit_compatible_types(ltype: *mut gcc_jit_type, rtype: *mut gcc_jit_type) -> bool; + + pub fn gcc_jit_context_set_bool_print_errors_to_stderr(ctxt: *mut gcc_jit_context, enabled: c_int); + + pub fn gcc_jit_lvalue_set_alignment(lvalue: *mut gcc_jit_lvalue, alignment: c_int); + pub fn gcc_jit_lvalue_get_alignment(lvalue: *mut gcc_jit_lvalue) -> c_int; + + + #[cfg(feature="master")] + pub fn gcc_jit_context_get_target_builtin_function(ctxt: *mut gcc_jit_context, name: *const c_char) -> *mut gcc_jit_function; + + #[cfg(feature="master")] + pub fn gcc_jit_context_new_rvalue_vector_perm(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, elements1: *mut gcc_jit_rvalue, elements2: *mut gcc_jit_rvalue, mask: *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + #[cfg(feature="master")] + pub fn gcc_jit_context_new_vector_access(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, vector: *mut gcc_jit_rvalue, index: *mut gcc_jit_rvalue) -> *mut gcc_jit_lvalue; + + #[cfg(feature="master")] + pub fn gcc_jit_type_set_packed(typ: *mut gcc_jit_type); + + #[cfg(feature="master")] + pub fn gcc_jit_context_convert_vector(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, vector: *mut gcc_jit_rvalue, type_: *mut gcc_jit_type) -> *mut gcc_jit_rvalue; + + #[cfg(feature="master")] + pub fn gcc_jit_global_set_readonly(global: *mut gcc_jit_lvalue); + + #[cfg(feature="master")] + pub fn gcc_jit_function_add_attribute(func: *mut gcc_jit_function, attribute: gcc_jit_fn_attribute); + + #[cfg(feature="master")] + pub fn gcc_jit_function_add_string_attribute(func: *mut gcc_jit_function, attribute: gcc_jit_fn_attribute, value: *const c_char); + + #[cfg(feature="master")] + pub fn gcc_jit_function_add_integer_array_attribute(func: *mut gcc_jit_function, attribute: gcc_jit_fn_attribute, value: *const c_int, length: size_t); + + #[cfg(feature="master")] + pub fn gcc_jit_lvalue_add_string_attribute(variable: *mut gcc_jit_lvalue, attribute: gcc_jit_variable_attribute, value: *const c_char); + + #[cfg(feature="master")] + pub fn gcc_jit_block_add_try_catch(block: *mut gcc_jit_block, loc: *mut gcc_jit_location, try_block: *mut gcc_jit_block, catch_block: *mut gcc_jit_block); + + #[cfg(feature="master")] + pub fn gcc_jit_block_add_try_finally(block: *mut gcc_jit_block, loc: *mut gcc_jit_location, try_block: *mut gcc_jit_block, finally_block: *mut gcc_jit_block); + + #[cfg(feature="master")] + pub fn gcc_jit_function_set_personality_function(func: *mut gcc_jit_function, personality_func: *mut gcc_jit_function); + + #[cfg(feature="master")] + pub fn gcc_jit_set_global_personality_function_name(name: *const c_char); + + #[cfg(feature="master")] + pub fn gcc_jit_context_get_target_info(ctxt: *mut gcc_jit_context) -> *mut gcc_jit_target_info; + + #[cfg(feature="master")] + pub fn gcc_jit_target_info_release(info: *mut gcc_jit_target_info); + + #[cfg(feature="master")] + pub fn gcc_jit_target_info_cpu_supports(info: *mut gcc_jit_target_info, feature: *const c_char) -> c_int; + + #[cfg(feature="master")] + pub fn gcc_jit_target_info_arch(info: *mut gcc_jit_target_info) -> *const c_char; + + #[cfg(feature="master")] + pub fn gcc_jit_target_info_supports_target_dependent_type(info: *mut gcc_jit_target_info, ty: gcc_jit_types) -> c_int; + + #[cfg(feature="master")] + pub fn gcc_jit_context_new_sizeof(ctxt: *mut gcc_jit_context, typ: *mut gcc_jit_type) -> *mut gcc_jit_rvalue; + + #[cfg(feature="master")] + pub fn gcc_jit_context_set_output_ident(ctxt: *mut gcc_jit_context, output_ident: *const c_char); + + pub fn gcc_jit_version_major() -> c_int; + pub fn gcc_jit_version_minor() -> c_int; + pub fn gcc_jit_version_patchlevel() -> c_int; + + #[cfg(feature="master")] + pub fn gcc_jit_function_new_temp(func: *mut gcc_jit_function, loc: *mut gcc_jit_location, ty: *mut gcc_jit_type) -> *mut gcc_jit_lvalue; + + #[cfg(feature="master")] + pub fn gcc_jit_rvalue_set_location(rvalue: *mut gcc_jit_rvalue, + loc: *mut gcc_jit_location); + + #[cfg(feature="master")] + pub fn gcc_jit_context_new_alignof(ctxt: *mut gcc_jit_context, typ: *mut gcc_jit_type) -> *mut gcc_jit_rvalue; + + #[cfg(feature="master")] + pub fn gcc_jit_rvalue_set_type(rvalue: *mut gcc_jit_rvalue, new_type: *mut gcc_jit_type); + + #[cfg(feature="master")] + pub fn gcc_jit_lvalue_add_attribute(variable: *mut gcc_jit_lvalue, attribute: gcc_jit_variable_attribute); + + #[cfg(feature="master")] + pub fn gcc_jit_lvalue_get_name(lvalue: *mut gcc_jit_lvalue) -> *const c_char; + + #[cfg(feature="master")] + pub fn gcc_jit_lvalue_set_name(lvalue: *mut gcc_jit_lvalue, new_name: *const c_char); } diff --git a/src/asm.rs b/src/asm.rs new file mode 100644 index 0000000..44ece02 --- /dev/null +++ b/src/asm.rs @@ -0,0 +1,74 @@ +use std::ffi::CString; +use std::marker::PhantomData; +use std::os::raw::c_int; + +use {Context, LValue, Object, RValue, ToObject, lvalue, object, rvalue}; + +#[derive(Copy, Clone)] +pub struct ExtendedAsm<'ctx> { + marker: PhantomData<&'ctx Context<'ctx>>, + ptr: *mut gccjit_sys::gcc_jit_extended_asm +} + +impl<'ctx> ToObject<'ctx> for ExtendedAsm<'ctx> { + fn to_object(&self) -> Object<'ctx> { + unsafe { + let ptr = gccjit_sys::gcc_jit_extended_asm_as_object(self.ptr); + object::from_ptr(ptr) + } + } +} + +impl<'ctx> ExtendedAsm<'ctx> { + pub fn set_volatile_flag(&self, flag: bool) { + unsafe { + gccjit_sys::gcc_jit_extended_asm_set_volatile_flag(self.ptr, flag as c_int); + } + } + + pub fn set_inline_flag(&self, flag: bool) { + unsafe { + gccjit_sys::gcc_jit_extended_asm_set_inline_flag(self.ptr, flag as c_int); + } + } + + pub fn add_output_operand(&self, asm_symbolic_name: Option<&str>, constraint: &str, dest: LValue<'ctx>) { + let asm_symbolic_name = asm_symbolic_name.map(|name| CString::new(name).unwrap()); + let asm_symbolic_name = + match asm_symbolic_name { + Some(name) => name.as_ptr(), + None => std::ptr::null_mut(), + }; + let constraint = CString::new(constraint).unwrap(); + unsafe { + gccjit_sys::gcc_jit_extended_asm_add_output_operand(self.ptr, asm_symbolic_name, constraint.as_ptr(), lvalue::get_ptr(&dest)); + } + } + + pub fn add_input_operand(&self, asm_symbolic_name: Option<&str>, constraint: &str, src: RValue<'ctx>) { + let asm_symbolic_name = asm_symbolic_name.map(|name| CString::new(name).unwrap()); + let asm_symbolic_name = + match asm_symbolic_name { + Some(name) => name.as_ptr(), + None => std::ptr::null_mut(), + }; + let constraint = CString::new(constraint).unwrap(); + unsafe { + gccjit_sys::gcc_jit_extended_asm_add_input_operand(self.ptr, asm_symbolic_name, constraint.as_ptr(), rvalue::get_ptr(&src)); + } + } + + pub fn add_clobber(&self, victim: &str) { + let victim = CString::new(victim).unwrap(); + unsafe { + gccjit_sys::gcc_jit_extended_asm_add_clobber(self.ptr, victim.as_ptr()); + } + } + + pub unsafe fn from_ptr(ptr: *mut gccjit_sys::gcc_jit_extended_asm) -> Self { + Self { + marker: PhantomData, + ptr + } + } +} diff --git a/src/block.rs b/src/block.rs index e5713d8..1502350 100644 --- a/src/block.rs +++ b/src/block.rs @@ -3,8 +3,11 @@ use std::ffi::CString; use std::fmt; use std::ptr; use std::mem; -use context::Context; -use gccjit_sys; +use std::os::raw::c_int; + +use asm::ExtendedAsm; +use block; +use context::{Case, Context}; use object::{self, ToObject, Object}; use function::{self, Function}; use location::{self, Location}; @@ -14,6 +17,7 @@ use lvalue::{self, ToLValue}; /// BinaryOp is a enum representing the various binary operations /// that gccjit knows how to codegen. #[repr(C)] +#[derive(Clone, Copy, Debug)] pub enum BinaryOp { Plus, Minus, @@ -32,6 +36,7 @@ pub enum BinaryOp { /// UnaryOp is an enum representing the various unary operations /// that gccjit knows how to codegen. #[repr(C)] +#[derive(Clone, Copy)] pub enum UnaryOp { Minus, BitwiseNegate, @@ -42,6 +47,7 @@ pub enum UnaryOp { /// ComparisonOp is an enum representing the various comparisons that /// gccjit is capable of doing. #[repr(C)] +#[derive(Debug)] pub enum ComparisonOp { Equals, NotEquals, @@ -55,7 +61,7 @@ pub enum ComparisonOp { /// A basic block consists of a series of instructions terminated by a terminator /// instruction, which can be either a jump to one block, a conditional branch to /// two blocks (true/false branches), a return, or a void return. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct Block<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_block @@ -71,7 +77,7 @@ impl<'ctx> ToObject<'ctx> for Block<'ctx> { } impl<'ctx> fmt::Debug for Block<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -100,6 +106,32 @@ impl<'ctx> Block<'ctx> { loc_ptr, rvalue::get_ptr(&rvalue)); } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + } + + #[cfg(feature="master")] + pub fn add_try_catch(&self, loc: Option>, try_block: Block<'ctx>, catch_block: Block<'ctx>) { + let loc_ptr = match loc { + Some(loc) => unsafe { location::get_ptr(&loc) }, + None => ptr::null_mut() + }; + unsafe { + gccjit_sys::gcc_jit_block_add_try_catch(self.ptr, loc_ptr, try_block.ptr, catch_block.ptr); + } + } + + #[cfg(feature="master")] + pub fn add_try_finally(&self, loc: Option>, try_block: Block<'ctx>, finally_block: Block<'ctx>) { + let loc_ptr = match loc { + Some(loc) => unsafe { location::get_ptr(&loc) }, + None => ptr::null_mut() + }; + unsafe { + gccjit_sys::gcc_jit_block_add_try_finally(self.ptr, loc_ptr, try_block.ptr, finally_block.ptr); + } } /// Assigns the value of an rvalue to an lvalue directly. Equivalent @@ -120,6 +152,11 @@ impl<'ctx> Block<'ctx> { lvalue::get_ptr(&lvalue), rvalue::get_ptr(&rvalue)); } + + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } } /// Performs a binary operation on an LValue and an RValue, assigning @@ -138,10 +175,10 @@ impl<'ctx> Block<'ctx> { }; unsafe { gccjit_sys::gcc_jit_block_add_assignment_op(self.ptr, - loc_ptr, - lvalue::get_ptr(&lvalue), - mem::transmute(op), - rvalue::get_ptr(&rvalue)); + loc_ptr, + lvalue::get_ptr(&lvalue), + mem::transmute::(op), + rvalue::get_ptr(&rvalue)); } } @@ -182,6 +219,10 @@ impl<'ctx> Block<'ctx> { on_true.ptr, on_false.ptr); } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } } /// Terminates a block by unconditionally jumping to another block. @@ -197,6 +238,10 @@ impl<'ctx> Block<'ctx> { loc_ptr, target.ptr); } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } } /// Terminates a block by returning from the containing function, setting @@ -215,6 +260,10 @@ impl<'ctx> Block<'ctx> { gccjit_sys::gcc_jit_block_end_with_return(self.ptr, loc_ptr, rvalue::get_ptr(&ret_rvalue)); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } } } @@ -231,12 +280,67 @@ impl<'ctx> Block<'ctx> { gccjit_sys::gcc_jit_block_end_with_void_return(self.ptr, loc_ptr); } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + } + + pub fn end_with_switch>(&self, loc: Option>, expr: T, default_block: Block<'ctx>, cases: &[Case<'ctx>]) { + let expr = expr.to_rvalue(); + let loc_ptr = match loc { + Some(loc) => unsafe { location::get_ptr(&loc) }, + None => ptr::null_mut() + }; + unsafe { + gccjit_sys::gcc_jit_block_end_with_switch(self.ptr, loc_ptr, rvalue::get_ptr(&expr), block::get_ptr(&default_block), + cases.len() as c_int, cases.as_ptr() as *mut *mut _); + } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + } + + pub fn add_extended_asm(&self, loc: Option>, asm_template: &str) -> ExtendedAsm<'ctx> { + let asm_template = CString::new(asm_template).unwrap(); + let loc_ptr = + match loc { + Some(loc) => unsafe { location::get_ptr(&loc) }, + None => ptr::null_mut(), + }; + unsafe { + ExtendedAsm::from_ptr(gccjit_sys::gcc_jit_block_add_extended_asm(self.ptr, loc_ptr, asm_template.as_ptr())) + } + } + + pub fn end_with_extended_asm_goto(&self, loc: Option>, asm_template: &str, goto_blocks: &[Block<'ctx>], fallthrough_block: Option>) -> ExtendedAsm<'ctx> { + let asm_template = CString::new(asm_template).unwrap(); + let loc_ptr = + match loc { + Some(loc) => unsafe { location::get_ptr(&loc) }, + None => ptr::null_mut(), + }; + let fallthrough_block_ptr = + match fallthrough_block { + Some(ref block) => unsafe { get_ptr(block) }, + None => ptr::null_mut(), + }; + unsafe { + ExtendedAsm::from_ptr(gccjit_sys::gcc_jit_block_end_with_extended_asm_goto(self.ptr, loc_ptr, asm_template.as_ptr(), goto_blocks.len() as c_int, goto_blocks.as_ptr() as *mut _, fallthrough_block_ptr)) + } } } + + pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_block) -> Block<'ctx> { Block { marker: PhantomData, - ptr: ptr + ptr } } + +pub unsafe fn get_ptr<'ctx>(block: &Block<'ctx>) -> *mut gccjit_sys::gcc_jit_block { + block.ptr +} diff --git a/src/context.rs b/src/context.rs index 605238f..2619dc8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,27 +1,40 @@ -use std::default::Default; -use std::ops::Drop; -use std::ffi::CString; +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 location::{self, Location}; -use structs::{self, Struct}; -use types; -use field::{self, Field}; -use rvalue::{self, RValue, ToRValue}; -use function::{self, Function, FunctionType}; -use block::{BinaryOp, UnaryOp, ComparisonOp}; -use parameter::{self, Parameter}; -use lvalue::{self, LValue}; -use gccjit_sys; 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; + +#[repr(C)] +#[derive(Debug)] +pub enum GlobalKind { + Exported, + Internal, + Imported, +} + /// Represents an optimization level that the JIT compiler /// will use when compiling your code. #[repr(C)] +#[derive(Debug)] pub enum OptimizationLevel { /// No optimizations are applied. None, @@ -29,7 +42,7 @@ pub enum OptimizationLevel { /// any optimizations that take extended periods of time. Limited, /// Performs all optimizations that do not involve a tradeoff - /// of code size for speed. + /// of code size for speed. Standard, /// Performs all optimizations at the Standard level, as well /// as function inlining, loop vectorization, some loop unrolling, @@ -101,6 +114,20 @@ impl Drop for CompileResult { } } +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> { + unsafe { + let ptr = gccjit_sys::gcc_jit_case_as_object(self.ptr); + object::from_ptr(ptr) + } + } +} + /// Wrapper around a GCC JIT context object that keeps /// the state of the JIT compiler. In GCCJIT, this object /// is responsible for all memory management of JIT data @@ -110,6 +137,7 @@ impl Drop for CompileResult { /// It's possible to create a child context from a parent context. /// In that case, the child context must have a lifetime strictly /// less than the parent context. +#[derive(Debug)] pub struct Context<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_context @@ -120,7 +148,7 @@ impl Default for Context<'static> { unsafe { Context { marker: PhantomData, - ptr: gccjit_sys::gcc_jit_context_acquire() + ptr: gccjit_sys::gcc_jit_context_acquire(), } } } @@ -137,7 +165,21 @@ impl<'ctx> Context<'ctx> { c_str.as_ptr()); } } - + + pub fn add_command_line_option>(&self, name: S) { + let c_str = CString::new(name.as_ref()).unwrap(); + unsafe { + gccjit_sys::gcc_jit_context_add_command_line_option(self.ptr, c_str.as_ptr()) + } + } + + pub fn add_driver_option>(&self, name: S) { + let c_str = CString::new(name.as_ref()).unwrap(); + unsafe { + gccjit_sys::gcc_jit_context_add_driver_option(self.ptr, c_str.as_ptr()) + } + } + /// Sets the optimization level that the JIT compiler will use. /// The higher the optimization level, the longer compilation will /// take. @@ -148,7 +190,61 @@ impl<'ctx> Context<'ctx> { level as i32); } } - + + #[cfg(feature="master")] + pub fn set_output_ident(&self, ident: &str) { + let c_str = CString::new(ident).unwrap(); + unsafe { + gccjit_sys::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(); + unsafe { + gccjit_sys::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) { + unsafe { + gccjit_sys::gcc_jit_context_set_bool_option(self.ptr, + GCC_JIT_BOOL_OPTION_DEBUGINFO, + value as i32); + } + } + + pub fn set_keep_intermediates(&self, value: bool) { + unsafe { + gccjit_sys::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) { + unsafe { + gccjit_sys::gcc_jit_context_set_bool_print_errors_to_stderr(self.ptr, enabled as c_int); + } + } + + pub fn set_dump_everything(&self, value: bool) { + unsafe { + gccjit_sys::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) { + unsafe { + gccjit_sys::gcc_jit_context_set_bool_option(self.ptr, + GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, + value as i32); + } + } + /// When set to true, dumps the code that the JIT generates to standard /// out during compilation. pub fn set_dump_code_on_compile(&self, value: bool) { @@ -159,6 +255,12 @@ impl<'ctx> Context<'ctx> { } } + pub fn set_allow_unreachable_blocks(&self, value: bool) { + unsafe { + gccjit_sys::gcc_jit_context_set_bool_allow_unreachable_blocks(self.ptr, value as i32); + } + } + /// Compiles the context and returns a CompileResult that contains /// the means to access functions and globals that have currently /// been JIT compiled. @@ -169,7 +271,7 @@ impl<'ctx> Context<'ctx> { } } } - + /// Compiles the context and saves the result to a file. The /// type of the file is controlled by the OutputKind parameter. pub fn compile_to_file>(&self, kind: OutputKind, file: S) { @@ -177,13 +279,18 @@ impl<'ctx> Context<'ctx> { let file_ref = file.as_ref(); let cstr = CString::new(file_ref).unwrap(); gccjit_sys::gcc_jit_context_compile_to_file(self.ptr, - mem::transmute(kind), - cstr.as_ptr()); + mem::transmute::(kind), + cstr.as_ptr()); + } + } + + #[cfg(feature="master")] + pub fn get_target_info(&self) -> TargetInfo { + unsafe { + target_info::from_ptr(gccjit_sys::gcc_jit_context_get_target_info(self.ptr)) } } - - - + /// Creates a new child context from this context. The child context /// is a fully-featured context, but it has a lifetime that is strictly /// less than the lifetime that spawned it. @@ -195,7 +302,24 @@ impl<'ctx> Context<'ctx> { } } } - + + pub fn new_case, 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 = unsafe { + Case { + marker: PhantomData, + ptr: gccjit_sys::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 + } + /// Creates a new location for use by gdb when debugging a JIT compiled /// program. The filename, line, and col are used by gdb to "show" your /// source when in a debugger. @@ -210,10 +334,35 @@ impl<'ctx> Context<'ctx> { 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>(&self, loc: Option>, kind: GlobalKind, ty: Type<'a>, name: S) -> LValue<'a> { + 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 = gccjit_sys::gcc_jit_context_new_global( + self.ptr, + loc_ptr, + mem::transmute::(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) + } + } + /// Constructs a new type for any type that implements the Typeable trait. /// This library only provides a handful of implementations of Typeable /// for some primitive types - utilizers of this library are encouraged @@ -222,7 +371,30 @@ impl<'ctx> Context<'ctx> { pub fn new_type<'a, T: types::Typeable>(&'a self) -> types::Type<'a> { ::get_type(self) } - + + pub fn new_c_type<'a>(&'a self, c_type: CType) -> types::Type<'a> { + unsafe { + let ptr = gccjit_sys::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> { + unsafe { + let ctx_ptr = get_ptr(self); + let ptr = gccjit_sys::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) + } + } + /// Constructs a new field with an optional source location, type, and name. /// This field can be used to compose unions or structs. pub fn new_field<'a, S: AsRef>(&'a self, @@ -240,16 +412,20 @@ impl<'ctx> Context<'ctx> { 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) } } - + /// Constructs a new array type with a given base element type and a /// size. pub fn new_array_type<'a>(&'a self, loc: Option>, ty: types::Type<'a>, - num_elements: i32) -> 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() @@ -258,7 +434,22 @@ impl<'ctx> Context<'ctx> { let ptr = gccjit_sys::gcc_jit_context_new_array_type(self.ptr, loc_ptr, types::get_ptr(&ty), - num_elements); + num_elements as c_ulong); + #[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> { + unsafe { + let ptr = gccjit_sys::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) } } @@ -277,7 +468,7 @@ impl<'ctx> Context<'ctx> { }; let num_fields = fields.len() as i32; let mut fields_ptrs : Vec<_> = fields.iter() - .map(|x| unsafe { field::get_ptr(&x) }) + .map(|x| unsafe { field::get_ptr(x) }) .collect(); unsafe { let cname = CString::new(name_ref).unwrap(); @@ -286,10 +477,14 @@ impl<'ctx> Context<'ctx> { 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) } } - + /// Constructs a new struct type whose fields are not known. Fields can /// be added to this struct later, but only once. pub fn new_opaque_struct_type<'a, S: AsRef>(&'a self, @@ -305,10 +500,14 @@ impl<'ctx> Context<'ctx> { let ptr = gccjit_sys::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) } } - + /// Creates a new union type from a set of fields. pub fn new_union_type<'a, S: AsRef>(&'a self, loc: Option>, @@ -321,7 +520,7 @@ impl<'ctx> Context<'ctx> { }; let num_fields = fields.len() as i32; let mut fields_ptrs : Vec<_> = fields.iter() - .map(|x| unsafe { field::get_ptr(&x) }) + .map(|x| unsafe { field::get_ptr(x) }) .collect(); unsafe { let cname = CString::new(name_ref).unwrap(); @@ -330,10 +529,14 @@ impl<'ctx> Context<'ctx> { 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) } } - + /// Creates a new function pointer type with the given return type /// parameter types, and an optional location. The last flag can /// make the function variadic, although Rust can't really handle @@ -349,7 +552,7 @@ impl<'ctx> Context<'ctx> { }; let num_types = param_types.len() as i32; let mut types_ptrs : Vec<_> = param_types.iter() - .map(|x| unsafe { types::get_ptr(&x) }) + .map(|x| unsafe { types::get_ptr(x) }) .collect(); unsafe { let ptr = gccjit_sys::gcc_jit_context_new_function_ptr_type(self.ptr, @@ -358,6 +561,10 @@ impl<'ctx> Context<'ctx> { 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) } } @@ -378,18 +585,22 @@ impl<'ctx> Context<'ctx> { }; let num_params = params.len() as i32; let mut params_ptrs : Vec<_> = params.iter() - .map(|x| unsafe { parameter::get_ptr(&x) }) + .map(|x| unsafe { parameter::get_ptr(x) }) .collect(); unsafe { let cstr = CString::new(name_ref).unwrap(); let ptr = gccjit_sys::gcc_jit_context_new_function(self.ptr, - loc_ptr, - mem::transmute(kind), - types::get_ptr(&return_ty), - cstr.as_ptr(), - num_params, - params_ptrs.as_mut_ptr(), - is_variadic as i32); + loc_ptr, + mem::transmute::(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) } } @@ -409,11 +620,15 @@ impl<'ctx> Context<'ctx> { }; unsafe { let ptr = gccjit_sys::gcc_jit_context_new_binary_op(self.ptr, - loc_ptr, - mem::transmute(op), - types::get_ptr(&ty), - rvalue::get_ptr(&left_rvalue), - rvalue::get_ptr(&right_rvalue)); + loc_ptr, + mem::transmute::(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) } } @@ -431,10 +646,14 @@ impl<'ctx> Context<'ctx> { }; unsafe { let ptr = gccjit_sys::gcc_jit_context_new_unary_op(self.ptr, - loc_ptr, - mem::transmute(op), - types::get_ptr(&ty), - rvalue::get_ptr(&rvalue)); + loc_ptr, + mem::transmute::(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) } } @@ -452,10 +671,14 @@ impl<'ctx> Context<'ctx> { }; unsafe { let ptr = gccjit_sys::gcc_jit_context_new_comparison(self.ptr, - loc_ptr, - mem::transmute(op), - rvalue::get_ptr(&left_rvalue), - rvalue::get_ptr(&right_rvalue)); + loc_ptr, + mem::transmute::(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) } } @@ -467,6 +690,7 @@ impl<'ctx> Context<'ctx> { /// together with LValues and Parameters, for example), so in order to /// mix the types of the arguments it may be necessary to call to_rvalue() /// before calling this function. + #[must_use] pub fn new_call<'a>(&'a self, loc: Option>, func: Function<'a>, @@ -477,7 +701,7 @@ impl<'ctx> Context<'ctx> { }; let num_params = args.len() as i32; let mut params_ptrs : Vec<_> = args.iter() - .map(|x| unsafe { rvalue::get_ptr(&x) }) + .map(|x| unsafe { rvalue::get_ptr(x) }) .collect(); unsafe { let ptr = gccjit_sys::gcc_jit_context_new_call(self.ptr, @@ -485,6 +709,10 @@ impl<'ctx> Context<'ctx> { 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) } } @@ -512,6 +740,10 @@ impl<'ctx> Context<'ctx> { 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) } } @@ -531,6 +763,33 @@ impl<'ctx> Context<'ctx> { 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) + } + } + + /// Bitcast an RValue to a specific type. + pub fn new_bitcast<'a, T: ToRValue<'a>>(&'a self, + loc: Option>, + 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() + }; + unsafe { + let ptr = gccjit_sys::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) } } @@ -552,6 +811,10 @@ impl<'ctx> Context<'ctx> { 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) } } @@ -563,7 +826,113 @@ impl<'ctx> Context<'ctx> { unsafe { let ptr = gccjit_sys::gcc_jit_context_new_rvalue_from_long(self.ptr, types::get_ptr(&ty), - value); + 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>, vec_type: types::Type<'a>, elements: &[RValue<'a>]) -> RValue<'a> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::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>, elements1: RValue<'a>, elements2: RValue<'a>, mask: RValue<'a>) -> RValue<'a> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::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 gcc_jit_context_new_union_constructor(ctxt: *mut gcc_jit_context, loc: *mut gcc_jit_location, typ: *mut gcc_jit_type, field: *mut gcc_jit_field, value: *mut gcc_jit_rvalue) -> *mut gcc_jit_rvalue; + + pub fn new_struct_constructor<'a>(&'a self, loc: Option>, struct_type: types::Type<'a>, fields: Option<&[Field<'a>]>, values: &[RValue<'a>]) -> RValue<'a> { + 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 = gccjit_sys::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>, array_type: types::Type<'a>, elements: &[RValue<'a>]) -> RValue<'a> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::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>, vector: RValue<'a>, index: RValue<'a>) -> LValue<'a> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + + let ptr = gccjit_sys::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>, vector: RValue<'a>, type_: Type<'a>) -> RValue<'a> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::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) } } @@ -577,6 +946,10 @@ impl<'ctx> Context<'ctx> { let ptr = gccjit_sys::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) } } @@ -589,6 +962,10 @@ impl<'ctx> Context<'ctx> { let ptr = gccjit_sys::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) } } @@ -599,6 +976,10 @@ impl<'ctx> Context<'ctx> { unsafe { let ptr = gccjit_sys::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) } } @@ -609,6 +990,10 @@ impl<'ctx> Context<'ctx> { unsafe { let ptr = gccjit_sys::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) } } @@ -616,13 +1001,18 @@ impl<'ctx> Context<'ctx> { /// Creates an RValue for a raw pointer. This function /// requires that the lifetime of the pointer be greater /// than that of the jitted program. + #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn new_rvalue_from_ptr<'a>(&'a self, ty: types::Type<'a>, value: *mut ()) -> RValue<'a> { unsafe { let ptr = gccjit_sys::gcc_jit_context_new_rvalue_from_ptr(self.ptr, - types::get_ptr(&ty), - mem::transmute(value)); + 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) } } @@ -633,6 +1023,10 @@ impl<'ctx> Context<'ctx> { unsafe { let ptr = gccjit_sys::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) } } @@ -644,6 +1038,36 @@ impl<'ctx> Context<'ctx> { let cstr = CString::new(value.as_ref()).unwrap(); let ptr = gccjit_sys::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")] + /// Creates a new RValue from a sizeof(type). + pub fn new_sizeof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> { + unsafe { + let ptr = gccjit_sys::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")] + /// Creates a new RValue from a _Alignof(type). + pub fn new_alignof<'a>(&'a self, ty: types::Type<'a>) -> RValue<'a> { + unsafe { + let ptr = gccjit_sys::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) } } @@ -661,6 +1085,14 @@ impl<'ctx> Context<'ctx> { } } + pub fn dump_to_file>(&self, path: S, update_locations: bool) { + unsafe { + let path_ref = path.as_ref(); + let cstr = CString::new(path_ref).unwrap(); + gccjit_sys::gcc_jit_context_dump_to_file(self.ptr, cstr.as_ptr(), update_locations as c_int); + } + } + /// Creates a new parameter with a given type, name, and location. pub fn new_parameter<'a, S: AsRef>(&'a self, loc: Option>, @@ -677,6 +1109,10 @@ impl<'ctx> Context<'ctx> { 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) } } @@ -690,9 +1126,84 @@ impl<'ctx> Context<'ctx> { let cstr = CString::new(name_ref).unwrap(); let ptr = gccjit_sys::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")] + /// Get a target-dependant builtin function from gcc. It's not clear what functions are + /// builtin and you'll likely need to consult the GCC internal docs + /// for a full list. + pub fn get_target_builtin_function<'a, S: AsRef>(&'a self, name: S) -> Function<'a> { + let name_ref = name.as_ref(); + unsafe { + let cstr = CString::new(name_ref).unwrap(); + let ptr = gccjit_sys::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, Utf8Error> { + unsafe { + let str = gccjit_sys::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, Utf8Error> { + unsafe { + let str = gccjit_sys::gcc_jit_context_get_last_error(self.ptr); + if str.is_null() { + Ok(None) + } + else { + Ok(Some(CStr::from_ptr(str).to_str()?)) + } + } + } + + // TODO: use the logfile argument. + pub fn set_logfile>(&self, _logfile: S) { + use std::os::raw::c_void; + + extern "C" { + static stderr: *mut c_void; + } + + unsafe { + gccjit_sys::gcc_jit_context_set_logfile(self.ptr, stderr as *mut _, 0, 0); + } + } + + pub fn add_top_level_asm(&self, loc: Option>, 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(), + }; + unsafe { + gccjit_sys::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); + } + } } impl<'ctx> Drop for Context<'ctx> { @@ -708,10 +1219,16 @@ pub unsafe fn get_ptr<'ctx>(ctx: &'ctx Context<'ctx>) -> *mut gccjit_sys::gcc_ji 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::default::Default; use std::mem; #[test] @@ -787,3 +1304,75 @@ mod tests { }; }*/ } + +#[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, + } + } +} diff --git a/src/field.rs b/src/field.rs index 311e229..5ac2c16 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,5 +1,3 @@ -use gccjit_sys; - use std::marker::PhantomData; use std::fmt; @@ -9,7 +7,7 @@ use object; /// Field represents a field that composes structs or unions. A number of fields /// can be combined to create either a struct or a union. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct Field<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_field @@ -24,7 +22,7 @@ impl<'ctx> ToObject<'ctx> for Field<'ctx> { } impl<'ctx> fmt::Debug for Field<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -33,7 +31,7 @@ impl<'ctx> fmt::Debug for Field<'ctx> { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_field) -> Field<'ctx> { Field { marker: PhantomData, - ptr: ptr + ptr } } diff --git a/src/function.rs b/src/function.rs index 22505da..f391f8d 100644 --- a/src/function.rs +++ b/src/function.rs @@ -1,19 +1,22 @@ use std::marker::PhantomData; use std::fmt; use std::ptr; + +use block::Block; +use block; use context::Context; -use gccjit_sys; +use location::Location; +use location; +#[cfg(feature="master")] +use lvalue::{AttributeValue, Visibility}; +use lvalue::LValue; +use lvalue; use object::{ToObject, Object}; use object; use parameter::Parameter; use parameter; +use rvalue::{self, RValue}; use std::ffi::CString; -use block::Block; -use block; -use lvalue::LValue; -use lvalue; -use location::Location; -use location; use types::Type; use types; @@ -24,6 +27,7 @@ use types; /// is a function with external linkage, and always inline is a function that is /// always inlined wherever it is called and cannot be accessed outside of the jit. #[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum FunctionType { /// Defines a function that is "exported" by the JIT and can be called from /// Rust. @@ -40,10 +44,119 @@ pub enum FunctionType { AlwaysInline } +#[cfg(feature="master")] +#[derive(Clone, Debug)] +pub enum FnAttribute<'a> { + Alias(&'a str), + AlwaysInline, + Inline, + NoInline, + Target(&'a str), + Used, + Visibility(Visibility), + Cold, + ReturnsTwice, + Pure, + Const, + Weak, + NonNull(Vec), + ArmCmseNonsecureCall, + ArmCmseNonsecureEntry, + ArmPcs(&'a str), + AvrInterrupt, + AvrNoblock, + AvrSignal, + GcnAmdGpuHsaKernel, + Msp430Interrupt, + NvptxKernel, + RiscvInterrupt(&'a str), + X86FastCall, + X86Interrupt, + X86MsAbi, + X86Stdcall, + X86SysvAbi, + X86ThisCall, +} + +#[cfg(feature="master")] +impl<'a> FnAttribute<'a> { + fn get_value(&self) -> AttributeValue<'_> { + match *self { + FnAttribute::Alias(value) | FnAttribute::ArmPcs(value)| FnAttribute::RiscvInterrupt(value) + | FnAttribute::Target(value) => AttributeValue::String(value), + FnAttribute::Visibility(visibility) => AttributeValue::String(visibility.as_str()), + FnAttribute::AlwaysInline + | FnAttribute::Inline + | FnAttribute::NoInline + | FnAttribute::Used + | FnAttribute::Cold + | FnAttribute::ReturnsTwice + | FnAttribute::Pure + | FnAttribute::Const + | FnAttribute::Weak + | FnAttribute::ArmCmseNonsecureCall + | FnAttribute::ArmCmseNonsecureEntry + | FnAttribute::AvrInterrupt + | FnAttribute::AvrNoblock + | FnAttribute::AvrSignal + | FnAttribute::GcnAmdGpuHsaKernel + | FnAttribute::Msp430Interrupt + | FnAttribute::NvptxKernel + | FnAttribute::X86FastCall + | FnAttribute::X86Interrupt + | FnAttribute::X86MsAbi + | FnAttribute::X86Stdcall + | FnAttribute::X86SysvAbi + | FnAttribute::X86ThisCall => AttributeValue::None, + FnAttribute::NonNull(ref value) => { + debug_assert!( + value.iter().all(|attr| *attr > 0), + "all values must be > 0 for non-null attribute", + ); + AttributeValue::IntArray(value) + } + } + } + + fn as_sys(&self) -> gccjit_sys::gcc_jit_fn_attribute { + match *self { + FnAttribute::Alias(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_ALIAS, + FnAttribute::AlwaysInline => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, + FnAttribute::Inline => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_INLINE, + FnAttribute::NoInline => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_NOINLINE, + FnAttribute::Target(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_TARGET, + FnAttribute::Used => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_USED, + FnAttribute::Visibility(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_VISIBILITY, + FnAttribute::Cold => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_COLD, + FnAttribute::ReturnsTwice => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, + FnAttribute::Pure => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_PURE, + FnAttribute::Const => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_CONST, + FnAttribute::Weak => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_WEAK, + FnAttribute::NonNull(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_NONNULL, + FnAttribute::ArmCmseNonsecureCall => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_CALL, + FnAttribute::ArmCmseNonsecureEntry => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_ENTRY, + FnAttribute::ArmPcs(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_ARM_PCS, + FnAttribute::AvrInterrupt => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_AVR_INTERRUPT, + FnAttribute::AvrNoblock => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_AVR_NOBLOCK, + FnAttribute::AvrSignal => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_AVR_SIGNAL, + FnAttribute::GcnAmdGpuHsaKernel => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_GCN_AMDGPU_HSA_KERNEL, + FnAttribute::Msp430Interrupt => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_MSP430_INTERRUPT, + FnAttribute::NvptxKernel => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_NVPTX_KERNEL, + FnAttribute::RiscvInterrupt(_) => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_RISCV_INTERRUPT, + FnAttribute::X86FastCall => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_FAST_CALL, + FnAttribute::X86Interrupt => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_INTERRUPT, + FnAttribute::X86MsAbi => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_MS_ABI, + FnAttribute::X86Stdcall => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_STDCALL, + FnAttribute::X86SysvAbi => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_SYSV_ABI, + FnAttribute::X86ThisCall => gccjit_sys::gcc_jit_fn_attribute::GCC_JIT_FN_ATTRIBUTE_X86_THIS_CALL, + } + } +} + /// Function is gccjit's representation of a function. Functions are constructed /// by constructing basic blocks and connecting them together. Locals are declared /// at the function level. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct Function<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_function @@ -59,7 +172,7 @@ impl<'ctx> ToObject<'ctx> for Function<'ctx> { } impl<'ctx> fmt::Debug for Function<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -69,10 +182,37 @@ impl<'ctx> Function<'ctx> { pub fn get_param(&self, idx: i32) -> Parameter<'ctx> { unsafe { let ptr = gccjit_sys::gcc_jit_function_get_param(self.ptr, idx); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{} ({:?})", error, self); + } parameter::from_ptr(ptr) } } + pub fn get_param_count(&self) -> usize { + unsafe { + gccjit_sys::gcc_jit_function_get_param_count(self.ptr) as usize + } + } + + pub fn get_return_type(&self) -> Type<'ctx> { + unsafe { + types::from_ptr(gccjit_sys::gcc_jit_function_get_return_type(self.ptr)) + } + } + + pub fn get_address(&self, loc: Option>) -> RValue<'ctx> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::gcc_jit_function_get_address(self.ptr, loc_ptr); + rvalue::from_ptr(ptr) + } + } + pub fn dump_to_dot>(&self, path: S) { unsafe { let cstr = CString::new(path.as_ref()).unwrap(); @@ -85,10 +225,21 @@ impl<'ctx> Function<'ctx> { let cstr = CString::new(name.as_ref()).unwrap(); let ptr = gccjit_sys::gcc_jit_function_new_block(self.ptr, cstr.as_ptr()); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{} ({:?})", error, self); + } block::from_ptr(ptr) } } + #[cfg(feature="master")] + pub fn set_personality_function(&self, personality_func: Function<'ctx>) { + unsafe { + gccjit_sys::gcc_jit_function_set_personality_function(self.ptr, personality_func.ptr); + } + } + pub fn new_local>(&self, loc: Option>, ty: Type<'ctx>, @@ -103,20 +254,79 @@ impl<'ctx> Function<'ctx> { loc_ptr, types::get_ptr(&ty), cstr.as_ptr()); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{} ({:?})", error, self); + } + lvalue::from_ptr(ptr) + } + } + + #[cfg(feature="master")] + pub fn new_temp(&self, loc: Option>, ty: Type<'ctx>) -> LValue<'ctx> { + unsafe { + let loc_ptr = match loc { + Some(loc) => location::get_ptr(&loc), + None => ptr::null_mut() + }; + let ptr = gccjit_sys::gcc_jit_function_new_temp(self.ptr, loc_ptr, types::get_ptr(&ty)); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{} ({:?})", error, self); + } lvalue::from_ptr(ptr) } } + + #[cfg(feature="master")] + pub fn add_attribute<'a>(&self, attribute: FnAttribute<'a>) { + let value = attribute.get_value(); + match value { + AttributeValue::Int(value) => { + // Basically the same as `IntArray` but for only one element. + let value = &[value]; + unsafe { + gccjit_sys::gcc_jit_function_add_integer_array_attribute( + self.ptr, + attribute.as_sys(), + value.as_ptr(), + value.len() as _, + ); + } + + } + AttributeValue::IntArray(value) => { + unsafe { + gccjit_sys::gcc_jit_function_add_integer_array_attribute( + self.ptr, + attribute.as_sys(), + value.as_ptr(), + value.len() as _, + ); + } + } + AttributeValue::None => { + unsafe { + gccjit_sys::gcc_jit_function_add_attribute(self.ptr, attribute.as_sys()); + } + }, + AttributeValue::String(string) => { + let cstr = CString::new(string).unwrap(); + unsafe { + gccjit_sys::gcc_jit_function_add_string_attribute(self.ptr, attribute.as_sys(), cstr.as_ptr()); + } + }, + } + } } pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_function) -> Function<'ctx> { Function { marker: PhantomData, - ptr: ptr + ptr } } pub unsafe fn get_ptr<'ctx>(loc: &Function<'ctx>) -> *mut gccjit_sys::gcc_jit_function { loc.ptr } - - diff --git a/src/lib.rs b/src/lib.rs index 45db6d3..8c96db7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,11 @@ //! never outlive the Context object from which they came, a requirement //! to using libgccjit correctly. -#![allow(raw_pointer_derive)] +#![allow(clippy::needless_lifetimes)] extern crate gccjit_sys; +mod asm; mod types; mod context; mod object; @@ -29,20 +30,58 @@ mod rvalue; mod parameter; mod function; mod block; +#[cfg(feature="master")] +mod target_info; pub use context::Context; +pub use context::CType; +pub use context::GlobalKind; pub use context::OptimizationLevel; pub use context::CompileResult; pub use context::OutputKind; pub use location::Location; pub use object::Object; pub use object::ToObject; +pub use types::FunctionPtrType; pub use types::Type; pub use types::Typeable; pub use field::Field; pub use structs::Struct; -pub use lvalue::{LValue, ToLValue}; +#[cfg(feature="master")] +pub use lvalue::{VarAttribute, Visibility}; +pub use lvalue::{LValue, TlsModel, ToLValue}; pub use rvalue::{RValue, ToRValue}; pub use parameter::Parameter; +#[cfg(feature="master")] +pub use function::FnAttribute; pub use function::{Function, FunctionType}; pub use block::{Block, BinaryOp, UnaryOp, ComparisonOp}; +#[cfg(feature="master")] +pub use target_info::TargetInfo; + +#[cfg(feature="master")] +pub fn set_global_personality_function_name(name: &'static [u8]) { + debug_assert!(name.ends_with(b"\0"), "Expecting a NUL-terminated C string"); + unsafe { + gccjit_sys::gcc_jit_set_global_personality_function_name(name.as_ptr() as *const _); + } +} + +#[derive(Debug)] +pub struct Version { + pub major: i32, + pub minor: i32, + pub patch: i32, +} + +impl Version { + pub fn get() -> Self { + unsafe { + Self { + major: gccjit_sys::gcc_jit_version_major(), + minor: gccjit_sys::gcc_jit_version_minor(), + patch: gccjit_sys::gcc_jit_version_patchlevel(), + } + } + } +} diff --git a/src/location.rs b/src/location.rs index f35669a..1356062 100644 --- a/src/location.rs +++ b/src/location.rs @@ -1,4 +1,3 @@ -use gccjit_sys; use std::marker::PhantomData; use std::fmt; use context::Context; @@ -21,16 +20,25 @@ impl<'ctx> ToObject<'ctx> for Location<'ctx> { } impl<'ctx> fmt::Debug for Location<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } } +impl<'ctx> Location<'ctx> { + pub fn null() -> Self { + Location { + marker: std::marker::PhantomData, + ptr: core::ptr::null_mut(), + } + } +} + pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_location) -> Location<'ctx> { Location { marker: PhantomData, - ptr: ptr + ptr } } diff --git a/src/lvalue.rs b/src/lvalue.rs index 84e193f..0ae54f3 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -1,7 +1,7 @@ -use std::marker::PhantomData; +use std::{ffi::CString, marker::PhantomData}; use std::fmt; use std::ptr; -use gccjit_sys; + use context::Context; use rvalue::{RValue, ToRValue}; use rvalue; @@ -12,11 +12,88 @@ use field; use location::Location; use location; +#[cfg(feature="master")] +#[derive(Clone, Copy, Debug)] +pub enum Visibility { + Default, + Hidden, + Internal, + Protected, +} + +#[cfg(feature="master")] +impl Visibility { + pub fn as_str(&self) -> &'static str { + match *self { + Visibility::Default => "default", + Visibility::Hidden => "hidden", + Visibility::Internal => "internal", + Visibility::Protected => "protected", + } + } +} + +#[cfg(feature="master")] +pub enum AttributeValue<'a> { + #[allow(dead_code)] + Int(i32), + None, + String(&'a str), + IntArray(&'a [std::ffi::c_int]), +} + +#[cfg(feature="master")] +#[derive(Clone, Copy, Debug)] +pub enum VarAttribute { + Visibility(Visibility), + Weak, +} + +#[cfg(feature="master")] +impl VarAttribute { + fn get_value(&self) -> AttributeValue<'_> { + match *self { + Self::Visibility(visibility) => AttributeValue::String(visibility.as_str()), + Self::Weak => AttributeValue::None, + } + } + + fn to_sys(self) -> gccjit_sys::gcc_jit_variable_attribute { + match self { + VarAttribute::Visibility(_) => gccjit_sys::gcc_jit_variable_attribute::GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, + VarAttribute::Weak => gccjit_sys::gcc_jit_variable_attribute::GCC_JIT_VARIABLE_ATTRIBUTE_WEAK, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum TlsModel { + GlobalDynamic, + LocalDynamic, + InitialExec, + LocalExec, + None, +} + +impl TlsModel { + fn to_sys(self) -> gccjit_sys::gcc_jit_tls_model { + use gccjit_sys::gcc_jit_tls_model::*; + + match self { + TlsModel::GlobalDynamic => GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC, + TlsModel::LocalDynamic => GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC, + TlsModel::InitialExec => GCC_JIT_TLS_MODEL_INITIAL_EXEC, + TlsModel::LocalExec => GCC_JIT_TLS_MODEL_LOCAL_EXEC, + TlsModel::None => GCC_JIT_TLS_MODEL_NONE, + } + } +} + /// An LValue in gccjit represents a value that has a concrete /// location in memory. A LValue can be converted into an RValue /// through the ToRValue trait. /// It is also possible to get the address of an LValue. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct LValue<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_lvalue @@ -37,7 +114,7 @@ impl<'ctx> ToObject<'ctx> for LValue<'ctx> { } impl<'ctx> fmt::Debug for LValue<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -89,12 +166,105 @@ impl<'ctx> LValue<'ctx> { rvalue::from_ptr(ptr) } } + + /// Set the initialization value for a global variable. + pub fn global_set_initializer(&self, blob: &[u8]) { + unsafe { + gccjit_sys::gcc_jit_global_set_initializer(self.ptr, blob.as_ptr() as _, blob.len() as _); + } + } + + /// Set the initialization value for a global variable. + pub fn global_set_initializer_rvalue(&self, value: RValue<'ctx>) -> LValue<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_global_set_initializer_rvalue(self.ptr, rvalue::get_ptr(&value))) + } + } + + pub fn set_tls_model(&self, model: TlsModel) { + unsafe { + gccjit_sys::gcc_jit_lvalue_set_tls_model(self.ptr, model.to_sys()); + } + } + + pub fn set_link_section(&self, name: &str) { + let name = CString::new(name).unwrap(); + unsafe { + gccjit_sys::gcc_jit_lvalue_set_link_section(self.ptr, name.as_ptr()); + } + } + + #[cfg(feature="master")] + pub fn global_set_readonly(&self) { + unsafe { + gccjit_sys::gcc_jit_global_set_readonly(self.ptr); + } + } + + pub fn set_register_name(&self, reg_name: &str) { + let name = CString::new(reg_name).unwrap(); + unsafe { + gccjit_sys::gcc_jit_lvalue_set_register_name(self.ptr, name.as_ptr()); + } + } + + pub fn set_alignment(&self, alignment: i32) { + unsafe { + gccjit_sys::gcc_jit_lvalue_set_alignment(self.ptr, alignment); + } + } + + pub fn get_alignment(&self) -> i32 { + unsafe { + gccjit_sys::gcc_jit_lvalue_get_alignment(self.ptr) + } + } + + #[cfg(feature="master")] + pub fn add_attribute(&self, attribute: VarAttribute) { + let value = attribute.get_value(); + match value { + AttributeValue::Int(_) => unimplemented!(), + AttributeValue::IntArray(_) => unimplemented!(), + AttributeValue::None => { + unsafe { + gccjit_sys::gcc_jit_lvalue_add_attribute(self.ptr, attribute.to_sys()); + } + }, + AttributeValue::String(string) => { + let cstr = CString::new(string).unwrap(); + unsafe { + gccjit_sys::gcc_jit_lvalue_add_string_attribute(self.ptr, attribute.to_sys(), cstr.as_ptr()); + } + }, + } + } + + #[cfg(feature = "master")] + pub fn get_name(&self) -> Option<&'ctx str> { + unsafe { + let str = gccjit_sys::gcc_jit_lvalue_get_name(self.ptr); + if str.is_null() { + None + } else { + Some(std::ffi::CStr::from_ptr(str).to_str().expect("invalid lvalue name")) + } + } + } + + #[cfg(feature = "master")] + pub fn set_name(&self, new_name: &str) { + let new_name = CString::new(new_name).unwrap(); + unsafe { + gccjit_sys::gcc_jit_lvalue_set_name(self.ptr, new_name.as_ptr()); + } + } } pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_lvalue) -> LValue<'ctx> { LValue { marker: PhantomData, - ptr: ptr + ptr } } diff --git a/src/object.rs b/src/object.rs index 992a114..5190157 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,10 +1,11 @@ -use gccjit_sys; use context::Context; use std::marker::PhantomData; use std::fmt; use std::ffi::CStr; use std::str; +use crate::context; + /// Object represents the root of all objects in gccjit. It is not useful /// in and of itself, but it provides the implementation for Debug /// used by most objects in this library. @@ -15,7 +16,7 @@ pub struct Object<'ctx> { } impl<'ctx> fmt::Debug for Object<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { unsafe { let ptr = gccjit_sys::gcc_jit_object_get_debug_string(self.ptr); let cstr = CStr::from_ptr(ptr); @@ -25,6 +26,32 @@ impl<'ctx> fmt::Debug for Object<'ctx> { } } +use std::mem::ManuallyDrop; +use std::ops::Deref; + +#[derive(Debug)] +pub struct ContextRef<'ctx> { + context: ManuallyDrop>, +} + +impl<'ctx> Deref for ContextRef<'ctx> { + type Target = Context<'ctx>; + + fn deref(&self) -> &Self::Target { + &self.context + } +} + +impl<'ctx> Object<'ctx> { + pub fn get_context(&self) -> ContextRef<'ctx> { + unsafe { + ContextRef { + context: ManuallyDrop::new(context::from_ptr(gccjit_sys::gcc_jit_object_get_context(self.ptr))), + } + } + } +} + /// ToObject is a trait implemented by types that can be upcast to Object. pub trait ToObject<'ctx> { fn to_object(&self) -> Object<'ctx>; @@ -39,7 +66,7 @@ impl<'ctx> ToObject<'ctx> for Object<'ctx> { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_object) -> Object<'ctx> { Object { marker: PhantomData, - ptr: ptr + ptr } } diff --git a/src/parameter.rs b/src/parameter.rs index 38394e4..f5e1bf4 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -1,6 +1,5 @@ use std::marker::PhantomData; use std::fmt; -use gccjit_sys; use context::Context; use object::{ToObject, Object}; use object; @@ -11,7 +10,7 @@ use lvalue; /// Parameter represents a parameter to a function. A series of parameteres /// can be combined to form a function signature. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub struct Parameter<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_param @@ -26,7 +25,7 @@ impl<'ctx> ToObject<'ctx> for Parameter<'ctx> { } impl<'ctx> fmt::Debug for Parameter<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -54,7 +53,7 @@ impl<'ctx> ToLValue<'ctx> for Parameter<'ctx> { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_param) -> Parameter<'ctx> { Parameter { marker: PhantomData, - ptr: ptr + ptr } } diff --git a/src/rvalue.rs b/src/rvalue.rs index a380366..bb91c18 100644 --- a/src/rvalue.rs +++ b/src/rvalue.rs @@ -3,7 +3,6 @@ use std::fmt; use std::ptr; use std::mem; use std::ops::{Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shl, Shr}; -use gccjit_sys; use context::Context; use object::{ToObject, Object}; use object; @@ -20,7 +19,7 @@ use block::BinaryOp; /// An RValue is a value that may or may not have a storage address in gccjit. /// RValues can be dereferenced, used for field accesses, and are the parameters /// given to a majority of the gccjit API calls. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct RValue<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_rvalue @@ -41,7 +40,7 @@ impl<'ctx> ToObject<'ctx> for RValue<'ctx> { } impl<'ctx> fmt::Debug for RValue<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -65,11 +64,15 @@ macro_rules! binary_operator_for { let ctx_ptr = gccjit_sys::gcc_jit_object_get_context(obj_ptr); let ty = rhs.get_type(); let ptr = gccjit_sys::gcc_jit_context_new_binary_op(ctx_ptr, - ptr::null_mut(), - mem::transmute($op), - types::get_ptr(&ty), - self.ptr, - rhs_rvalue.ptr); + ptr::null_mut(), + mem::transmute::($op), + types::get_ptr(&ty), + self.ptr, + rhs_rvalue.ptr); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } from_ptr(ptr) } } @@ -98,11 +101,29 @@ impl<'ctx> RValue<'ctx> { } } + /// Sets the location of this RValue. + #[cfg(feature="master")] + pub fn set_location(&self, loc: Location) { + unsafe { + let loc_ptr = location::get_ptr(&loc); + gccjit_sys::gcc_jit_rvalue_set_location(self.ptr, loc_ptr); + } + } + + /// Change the type of this RValue. + #[cfg(feature="master")] + pub fn set_type(&self, typ: Type<'ctx>) { + unsafe { + let type_ptr = types::get_ptr(&typ); + gccjit_sys::gcc_jit_rvalue_set_type(self.ptr, type_ptr); + } + } + /// Given an RValue x and a Field f, returns an RValue representing /// C's x.f. pub fn access_field(&self, loc: Option>, - field: Field<'ctx>) -> LValue<'ctx> { + field: Field<'ctx>) -> RValue<'ctx> { let loc_ptr = match loc { Some(loc) => unsafe { location::get_ptr(&loc) }, None => ptr::null_mut() @@ -111,7 +132,7 @@ impl<'ctx> RValue<'ctx> { let ptr = gccjit_sys::gcc_jit_rvalue_access_field(self.ptr, loc_ptr, field::get_ptr(&field)); - lvalue::from_ptr(ptr) + from_ptr(ptr) } } @@ -128,6 +149,10 @@ impl<'ctx> RValue<'ctx> { let ptr = gccjit_sys::gcc_jit_rvalue_dereference_field(self.ptr, loc_ptr, field::get_ptr(&field)); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } lvalue::from_ptr(ptr) } } @@ -142,7 +167,11 @@ impl<'ctx> RValue<'ctx> { unsafe { let ptr = gccjit_sys::gcc_jit_rvalue_dereference(self.ptr, loc_ptr); - + + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } lvalue::from_ptr(ptr) } } @@ -151,11 +180,10 @@ impl<'ctx> RValue<'ctx> { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_rvalue) -> RValue<'ctx> { RValue { marker: PhantomData, - ptr: ptr + ptr } } pub unsafe fn get_ptr<'ctx>(rvalue: &RValue<'ctx>) -> *mut gccjit_sys::gcc_jit_rvalue { rvalue.ptr } - diff --git a/src/structs.rs b/src/structs.rs index afd3a41..16981b3 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,5 +1,3 @@ -use gccjit_sys; - use std::marker::PhantomData; use std::fmt; use std::ptr; @@ -15,7 +13,7 @@ use object::{ToObject, Object}; /// A Struct is gccjit's representation of a composite type. Despite the name, /// Struct can represent either a struct, an union, or an opaque named type. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct Struct<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_struct @@ -38,7 +36,7 @@ impl<'ctx> Struct<'ctx> { }; let num_fields = fields.len() as i32; let mut fields_ptrs : Vec<_> = fields.iter() - .map(|x| unsafe { field::get_ptr(&x) }) + .map(|x| unsafe { field::get_ptr(x) }) .collect(); unsafe { gccjit_sys::gcc_jit_struct_set_fields(self.ptr, @@ -46,6 +44,37 @@ impl<'ctx> Struct<'ctx> { num_fields, fields_ptrs.as_mut_ptr()); } + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + } + + pub fn get_field(&self, index: i32) -> Field<'ctx> { + let field = unsafe { + let ptr = gccjit_sys::gcc_jit_struct_get_field(self.ptr, index); + #[cfg(debug_assertions)] + if ptr.is_null() { + panic!("Null ptr in get_field() from struct: {:?}", self); + } + field::from_ptr(ptr) + }; + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + field + } + + pub fn get_field_count(&self) -> usize { + unsafe { + let count = gccjit_sys::gcc_jit_struct_get_field_count(self.ptr) as usize; + #[cfg(debug_assertions)] + if let Ok(Some(error)) = self.to_object().get_context().get_last_error() { + panic!("{}", error); + } + count + } } } @@ -57,7 +86,7 @@ impl<'ctx> ToObject<'ctx> for Struct<'ctx> { } impl<'ctx> fmt::Debug for Struct<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.as_type(); obj.fmt(fmt) } @@ -66,10 +95,6 @@ impl<'ctx> fmt::Debug for Struct<'ctx> { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_struct) -> Struct<'ctx> { Struct { marker: PhantomData, - ptr: ptr + ptr } } - - - - diff --git a/src/target_info.rs b/src/target_info.rs new file mode 100644 index 0000000..9b98b74 --- /dev/null +++ b/src/target_info.rs @@ -0,0 +1,59 @@ +use context::CType; +use std::{ffi::{CStr, CString}, fmt}; + +pub struct TargetInfo { + ptr: *mut gccjit_sys::gcc_jit_target_info, +} + +unsafe impl Send for TargetInfo {} +unsafe impl Sync for TargetInfo {} + +impl fmt::Debug for TargetInfo { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { + "TargetInfo".fmt(fmt) + } +} + +impl TargetInfo { + pub fn cpu_supports(&self, feature: &str) -> bool { + let feature = + match CString::new(feature) { + Ok(feature) => feature, + Err(_) => return false, + }; + unsafe { + gccjit_sys::gcc_jit_target_info_cpu_supports(self.ptr, feature.as_ptr()) != 0 + } + } + + pub fn arch(&self) -> Option<&'static CStr> { + unsafe { + let arch = gccjit_sys::gcc_jit_target_info_arch(self.ptr); + if arch.is_null() { + return None; + } + Some(CStr::from_ptr(arch)) + } + } + + #[cfg(feature="master")] + pub fn supports_target_dependent_type(&self, c_type: CType) -> bool { + unsafe { + gccjit_sys::gcc_jit_target_info_supports_target_dependent_type(self.ptr, c_type.to_sys()) != 0 + } + } +} + +impl Drop for TargetInfo { + fn drop(&mut self) { + unsafe { + gccjit_sys::gcc_jit_target_info_release(self.ptr); + } + } +} + +pub unsafe fn from_ptr(ptr: *mut gccjit_sys::gcc_jit_target_info) -> TargetInfo { + TargetInfo { + ptr, + } +} diff --git a/src/types.rs b/src/types.rs index 967f6e2..8dcd9f8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,24 +1,94 @@ use std::marker::PhantomData; use std::fmt; -use gccjit_sys; - use context::Context; use context; use object; use object::{Object, ToObject}; +use structs::{self, Struct}; use gccjit_sys::gcc_jit_types::*; /// A representation of a type, as it is known to the JIT compiler. /// Types can be created through the Typeable trait or they can /// be created dynamically by composing Field types. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, Hash, PartialEq)] pub struct Type<'ctx> { marker: PhantomData<&'ctx Context<'ctx>>, ptr: *mut gccjit_sys::gcc_jit_type } +#[derive(Copy, Clone, Eq, Hash, PartialEq)] +pub struct VectorType<'ctx> { + marker: PhantomData<&'ctx Context<'ctx>>, + ptr: *mut gccjit_sys::gcc_jit_vector_type +} + +impl<'ctx> VectorType<'ctx> { + unsafe fn from_ptr(ptr: *mut gccjit_sys::gcc_jit_vector_type) -> VectorType<'ctx> { + VectorType { + marker: PhantomData, + ptr + } + } + + pub fn get_element_type(&self) -> Type<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_vector_type_get_element_type(self.ptr)) + } + } + + pub fn get_num_units(&self) -> usize { + unsafe { + gccjit_sys::gcc_jit_vector_type_get_num_units(self.ptr) as usize + } + } +} + +#[derive(Copy, Clone, Eq, Hash, PartialEq)] +pub struct FunctionPtrType<'ctx> { + marker: PhantomData<&'ctx Context<'ctx>>, + ptr: *mut gccjit_sys::gcc_jit_function_type +} + +impl<'ctx> fmt::Debug for FunctionPtrType<'ctx> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { + write!(fmt, "{:?} (", self.get_return_type())?; + for i in 0..self.get_param_count() { + write!(fmt, "{:?}, ", self.get_param_type(i))?; + } + write!(fmt, ")") + } +} + +impl<'ctx> FunctionPtrType<'ctx> { + unsafe fn from_ptr(ptr: *mut gccjit_sys::gcc_jit_function_type) -> FunctionPtrType<'ctx> { + FunctionPtrType { + marker: PhantomData, + ptr + } + } + + pub fn get_return_type(&self) -> Type<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_function_type_get_return_type(self.ptr)) + } + } + + pub fn get_param_count(&self) -> usize { + unsafe { + gccjit_sys::gcc_jit_function_type_get_param_count(self.ptr) as usize + } + } + + pub fn get_param_type(&self, index: usize) -> Type<'ctx> { + // TODO: return Option? + unsafe { + from_ptr(gccjit_sys::gcc_jit_function_type_get_param_type(self.ptr, index as _)) + } + } +} + impl<'ctx> ToObject<'ctx> for Type<'ctx> { fn to_object(&self) -> Object<'ctx> { unsafe { @@ -29,7 +99,7 @@ impl<'ctx> ToObject<'ctx> for Type<'ctx> { } impl<'ctx> fmt::Debug for Type<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt<'a>(&self, fmt: &mut fmt::Formatter<'a>) -> Result<(), fmt::Error> { let obj = self.to_object(); obj.fmt(fmt) } @@ -43,6 +113,13 @@ impl<'ctx> Type<'ctx> { } } + #[cfg(feature="master")] + pub fn set_packed(&self) { + unsafe { + gccjit_sys::gcc_jit_type_set_packed(self.ptr); + } + } + /// Given a type T, creates a type of const T. pub fn make_const(self) -> Type<'ctx> { unsafe { @@ -57,6 +134,110 @@ impl<'ctx> Type<'ctx> { from_ptr(gccjit_sys::gcc_jit_type_get_volatile(self.ptr)) } } + + /// Given a type T, creates a new type of restrict T, which + /// has the semantics of C's restrict. + #[cfg(feature="master")] + pub fn make_restrict(self) -> Type<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_type_get_restrict(self.ptr)) + } + } + + pub fn get_aligned(self, alignment_in_bytes: u64) -> Type<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_type_get_aligned(self.ptr, alignment_in_bytes as _)) + } + } + + pub fn dyncast_array(self) -> Option> { + unsafe { + let array_type = gccjit_sys::gcc_jit_type_dyncast_array(self.ptr); + if array_type.is_null() { + return None; + } + Some(from_ptr(array_type)) + } + } + + pub fn is_bool(self) -> bool { + unsafe { + gccjit_sys::gcc_jit_type_is_bool(self.ptr) != 0 + } + } + + pub fn is_integral(self) -> bool { + unsafe { + gccjit_sys::gcc_jit_type_is_integral(self.ptr) != 0 + } + } + + #[cfg(feature = "master")] + pub fn is_floating_point(self) -> bool { + unsafe { + gccjit_sys::gcc_jit_type_is_floating_point(self.ptr) != 0 + } + } + + pub fn dyncast_vector(self) -> Option> { + unsafe { + let vector_type = gccjit_sys::gcc_jit_type_dyncast_vector(self.ptr); + if vector_type.is_null() { + return None; + } + Some(VectorType::from_ptr(vector_type)) + } + } + + pub fn is_struct(self) -> Option> { + unsafe { + let struct_type = gccjit_sys::gcc_jit_type_is_struct(self.ptr); + if struct_type.is_null() { + return None; + } + Some(structs::from_ptr(struct_type)) + } + } + + pub fn dyncast_function_ptr_type(self) -> Option> { + unsafe { + let function_ptr_type = gccjit_sys::gcc_jit_type_dyncast_function_ptr_type(self.ptr); + if function_ptr_type.is_null() { + return None; + } + Some(FunctionPtrType::from_ptr(function_ptr_type)) + } + } + + pub fn get_size(&self) -> u32 { + unsafe { + let size = gccjit_sys::gcc_jit_type_get_size(self.ptr); + assert_ne!(size, -1, "called get_size of unsupported type: {self:?}"); + size as u32 + } + } + + pub fn unqualified(&self) -> Type<'ctx> { + unsafe { + from_ptr(gccjit_sys::gcc_jit_type_unqualified(self.ptr)) + } + } + + pub fn get_pointee(&self) -> Option> { + unsafe { + let value = gccjit_sys::gcc_jit_type_is_pointer(self.ptr); + if value.is_null() { + return None; + } + Some(from_ptr(value)) + } + } + + pub fn is_compatible_with(&self, typ: Type<'ctx>) -> bool { + unsafe { + gccjit_sys::gcc_jit_compatible_types(self.ptr, typ.ptr) + } + } } /// Typeable is a trait for types that have a corresponding type within @@ -64,7 +245,7 @@ impl<'ctx> Type<'ctx> { /// but it's also possible to implement this trait for more complex types /// that will use the API on Context to construct analagous struct/union types. pub trait Typeable { - fn get_type<'a, 'ctx>(&'a Context<'ctx>) -> Type<'a>; + fn get_type<'a, 'ctx>(ctx: &'a Context<'ctx>) -> Type<'a>; } macro_rules! typeable_def { @@ -74,6 +255,10 @@ macro_rules! typeable_def { unsafe { let ctx_ptr = context::get_ptr(ctx); let ptr = gccjit_sys::gcc_jit_context_get_type(ctx_ptr, $expr); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = ctx.get_last_error() { + panic!("{}", error); + } from_ptr(ptr) } } @@ -84,18 +269,35 @@ macro_rules! typeable_def { typeable_def!((), GCC_JIT_TYPE_VOID); typeable_def!(bool, GCC_JIT_TYPE_BOOL); typeable_def!(char, GCC_JIT_TYPE_CHAR); -typeable_def!(i8, GCC_JIT_TYPE_SIGNED_CHAR); -typeable_def!(u8, GCC_JIT_TYPE_UNSIGNED_CHAR); -typeable_def!(i16, GCC_JIT_TYPE_SHORT); -typeable_def!(u16, GCC_JIT_TYPE_UNSIGNED_SHORT); -typeable_def!(i32, GCC_JIT_TYPE_INT); -typeable_def!(u32, GCC_JIT_TYPE_UNSIGNED_INT); -typeable_def!(i64, GCC_JIT_TYPE_LONG); -typeable_def!(u64, GCC_JIT_TYPE_UNSIGNED_LONG); typeable_def!(f32, GCC_JIT_TYPE_FLOAT); typeable_def!(f64, GCC_JIT_TYPE_DOUBLE); typeable_def!(usize, GCC_JIT_TYPE_SIZE_T); +macro_rules! typeable_int_def { + ($ty:ty, $num_bytes:expr, $signed:expr) => { + impl Typeable for $ty { + fn get_type<'a, 'ctx>(ctx: &'a Context<'ctx>) -> Type<'a> { + unsafe { + let ctx_ptr = context::get_ptr(ctx); + let ptr = gccjit_sys::gcc_jit_context_get_int_type(ctx_ptr, $num_bytes, $signed as i32); + from_ptr(ptr) + } + } + } + } +} + +typeable_int_def!(i8, 1, true); +typeable_int_def!(u8, 1, false); +typeable_int_def!(i16, 2, true); +typeable_int_def!(u16, 2, false); +typeable_int_def!(i32, 4, true); +typeable_int_def!(u32, 4, false); +typeable_int_def!(i64, 8, true); +typeable_int_def!(u64, 8, false); +//typeable_int_def!(i128, 16, true); // FIXME: unsupported by libgccjit for now. +//typeable_int_def!(u128, 16, false); // FIXME: unsupported by libgccjit for now. + /// Specific implementations of Typeable for *mut T and *const T that /// represent void* and const void*, respectively. These impls should /// only be used to expose opaque pointers to gccjit, not to create @@ -106,6 +308,10 @@ impl Typeable for *mut T { unsafe { let ctx_ptr = context::get_ptr(ctx); let ptr = gccjit_sys::gcc_jit_context_get_type(ctx_ptr, GCC_JIT_TYPE_VOID_PTR); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = ctx.get_last_error() { + panic!("{}", error); + } from_ptr(ptr) } } @@ -116,6 +322,10 @@ impl Typeable for *const T { unsafe { let ctx_ptr = context::get_ptr(ctx); let ptr = gccjit_sys::gcc_jit_context_get_type(ctx_ptr, GCC_JIT_TYPE_VOID_PTR); + #[cfg(debug_assertions)] + if let Ok(Some(error)) = ctx.get_last_error() { + panic!("{}", error); + } from_ptr(ptr).make_const() } } @@ -124,7 +334,7 @@ impl Typeable for *const T { pub unsafe fn from_ptr<'ctx>(ptr: *mut gccjit_sys::gcc_jit_type) -> Type<'ctx> { Type { marker: PhantomData, - ptr: ptr + ptr } }