lightning_sys/lib.rs
1//! lightning-sys aims provides safe (as safe as a jit can be) rust bindings to GNU Lightning
2//!
3//! ## Examples:
4//! ### a function that increments a number by one
5//! ```
6//! use lightning_sys::{Jit, Reg, JitPointer, JitWord};
7//!
8//! let mut jit = Jit::new();
9//! let mut js = jit.new_state();
10//!
11//! js.prolog();
12//! let inarg = js.arg();
13//! js.getarg(Reg::R(0), &inarg);
14//! js.addi(Reg::R(0), Reg::R(0), 1);
15//! js.retr(Reg::R(0));
16//!
17//! let incr = unsafe { js.emit::<extern fn(JitWord) -> JitWord>() };
18//! js.clear();
19//!
20//! assert_eq!(incr(5), 6);
21//! assert_eq!(incr(6), 7);
22//!
23//! ```
24//!
25//! ### A simple function call to `printf`
26//! ```
27//! extern crate libc;
28//!
29//! use std::ffi::CString;
30//! use lightning_sys::{Jit, JitWord, Reg, JitPointer};
31//! use std::convert::TryInto;
32//!
33//! fn main() {
34//! let mut jit = Jit::new();
35//! let mut js = jit.new_state();
36//!
37//! // make sure this outlives any calls
38//! let cs = CString::new("generated %d bytes\n").unwrap();
39//!
40//! let start = js.note(Some(file!()), line!());
41//! js.prolog();
42//! let inarg = js.arg();
43//! js.getarg(Reg::R(1), &inarg);
44//! js.prepare();
45//! js.pushargi(cs.as_ptr() as JitWord);
46//! js.ellipsis();
47//! js.pushargr(Reg::R(1));
48//! js.finishi(libc::printf as JitPointer);
49//! js.ret();
50//! js.epilog();
51//! let end = js.note(Some(file!()), line!());
52//!
53//! let my_function = unsafe{ js.emit::<extern fn(JitWord)>() };
54//! /* call the generated code, passing its size as argument */
55//! my_function((js.address(&end) as u64 - js.address(&start) as u64).try_into().unwrap());
56//! js.clear();
57//!
58//! // TODO: dissasembly has not been implemented yet
59//! // js.dissasemble();
60//! }
61//!
62//! ```
63//!
64//! ### Fibonacci numbers
65//! ```
66//! use lightning_sys::{Jit, JitWord, Reg, JitPointer, NULL};
67//!
68//! fn main() {
69//! let mut jit = Jit::new();
70//! let mut js = jit.new_state();
71//!
72//! let label = js.label();
73//! js.prolog();
74//! let inarg = js.arg();
75//! js.getarg(Reg::R(0), &inarg);
76//! let zero = js.beqi(Reg::R(0), 0);
77//! js.movr(Reg::V(0), Reg::R(0));
78//! js.movi(Reg::R(0), 1);
79//! let refr = js.blei(Reg::V(0), 2);
80//! js.subi(Reg::V(1), Reg::V(0), 1);
81//! js.subi(Reg::V(2), Reg::V(0), 2);
82//! js.prepare();
83//! js.pushargr(Reg::V(1));
84//! let call = js.finishi(NULL);
85//! js.patch_at(&call, &label);
86//! js.retval(Reg::V(1));
87//! js.prepare();
88//! js.pushargr(Reg::V(2));
89//! let call2 = js.finishi(NULL);
90//! js.patch_at(&call2, &label);
91//! js.retval(Reg::R(0));
92//! js.addr(Reg::R(0), Reg::R(0), Reg::V(1));
93//!
94//! js.patch(&refr);
95//! js.patch(&zero);
96//! js.retr(Reg::R(0));
97//! js.epilog();
98//!
99//! let fib = unsafe{ js.emit::<extern fn(JitWord) -> JitWord>() };
100//! js.clear();
101//!
102//! println!("fib({})={}", 32, fib(32));
103//! assert_eq!(0, fib(0));
104//! assert_eq!(1, fib(1));
105//! assert_eq!(1, fib(2));
106//! assert_eq!(2178309, fib(32));
107//! }
108//! ```
109//!
110//! ### Tail Call Optimized factorial
111//! ```
112//! use lightning_sys::{Jit, JitWord, Reg, NULL};
113//!
114//! fn main() {
115//! let mut jit = Jit::new();
116//! let mut js = jit.new_state();
117//!
118//! let fact = js.forward();
119//!
120//! js.prolog();
121//! let inarg = js.arg();
122//! js.getarg(Reg::R(0), &inarg);
123//! js.prepare();
124//! js.pushargi(1);
125//! js.pushargr(Reg::R(0));
126//! let call = js.finishi(NULL);
127//! js.patch_at(&call, &fact);
128//!
129//! js.retval(Reg::R(0));
130//! js.retr(Reg::R(0));
131//! js.epilog();
132//!
133//! js.link(&fact);
134//! js.prolog();
135//! js.frame(16);
136//! let f_ent = js.label(); // TCO entry point
137//! let ac = js.arg();
138//! let ina = js.arg();
139//! js.getarg(Reg::R(0), &ac);
140//! js.getarg(Reg::R(1), &ina);
141//! let f_out = js.blei(Reg::R(1), 1);
142//! js.mulr(Reg::R(0), Reg::R(0), Reg::R(1));
143//! js.putargr(Reg::R(0), &ac);
144//! js.subi(Reg::R(1), Reg::R(1), 1);
145//! js.putargr(Reg::R(1), &ina);
146//! let jump = js.jmpi(); // tail call optimiation
147//! js.patch_at(&jump, &f_ent);
148//! js.patch(&f_out);
149//! js.retr(Reg::R(0));
150//!
151//! let factorial = unsafe{ js.emit::<extern fn(JitWord) -> JitWord>() };
152//! js.clear();
153//!
154//! println!("factorial({}) = {}", 5, factorial(5));
155//! assert_eq!(1, factorial(1));
156//! assert_eq!(2, factorial(2));
157//! assert_eq!(6, factorial(3));
158//! assert_eq!(24, factorial(4));
159//! assert_eq!(120, factorial(5));
160//! }
161//! ```
162// Enforce some lints for the whole crate.
163#![deny(clippy::needless_lifetimes)]
164#![deny(clippy::transmute_ptr_to_ptr)]
165#![allow(clippy::needless_doctest_main)] // remain faithful to original examples
166
167// Suppress some lints for bindings specifically.
168#[allow(non_upper_case_globals)]
169#[allow(non_camel_case_types)]
170#[allow(dead_code)]
171#[allow(clippy::unreadable_literal)]
172#[allow(clippy::trivially_copy_pass_by_ref)]
173#[allow(clippy::useless_transmute)]
174#[allow(clippy::too_many_arguments)]
175mod bindings;
176
177#[macro_use]
178extern crate lazy_static;
179
180// The `raw` module comes first so that it can provide macros during parsing of
181// other modules. It is not yet part of the crate's public API, but in the
182// spirit of *-sys modules exposing lowest-level bindings, it may someday be so.
183#[macro_use]
184pub(crate) mod raw;
185
186pub mod jit;
187pub use jit::Jit;
188
189pub mod jitstate;
190pub use jitstate::JitState;
191
192pub mod types;
193pub use types::NULL;
194pub use types::Reg;
195pub use types::JitNode;
196pub use types::{JitWord, JitUword, JitPointer};
197pub(crate) use types::ToFFI;