#![allow(uncommon_codepoints)]
use std::collections::HashSet;
use std::ffi::{c_char, CStr, CString};
use std::fmt::Debug;
use std::str::FromStr;
mod allocator;
mod amd;
mod applet;
mod arm;
mod assembler;
mod block;
mod builder;
mod code;
mod compactor;
pub mod compiler;
mod complexify;
mod composer;
mod config;
mod defuns;
pub mod expr;
mod generator;
pub mod instruction;
mod machine;
mod matrix;
mod memory;
mod mir;
mod model;
mod node;
mod parser;
mod runnable;
mod serializer;
mod statement;
mod symbol;
mod types;
mod utils;
#[allow(non_upper_case_globals)]
mod riscv64;
use matrix::Matrix;
use model::{CellModel, Program};
pub use applet::Applet;
pub use compiler::{Compiler, FastFunc, Translator};
pub use composer::{Composer, Transliterator};
pub use config::Config;
pub use defuns::Defuns;
pub use expr::{double, int, var, Expr};
pub use instruction::{BuiltinSymbol, Instruction, Slot, SymbolicaModel};
pub use num_complex::{Complex, ComplexFloat};
pub use runnable::{Application, CompilerType};
pub use serializer::MirWriter;
pub use types::{ElemType, Element};
pub use utils::{Compiled, Storage};
#[derive(Debug, Clone, Copy)]
pub enum CompilerStatus {
Ok,
Incomplete,
InvalidUtf8,
ParseError,
InvalidCompiler,
CompilationError,
}
pub struct CompilerResult {
app: Option<Application>,
status: CompilerStatus,
msg: CString,
}
fn error_message<E: Debug>(msg: &str, err: E) -> CString {
let s = format!("{:?}: {:?}", msg, err);
CString::from_str(&s).unwrap()
}
#[no_mangle]
pub unsafe extern "C" fn compile(
model: *const c_char,
ty: *const c_char,
opt: u32,
df: *const Defuns,
) -> *const CompilerResult {
let mut res = CompilerResult {
app: None,
status: CompilerStatus::Incomplete,
msg: CString::from_str("Success").unwrap(),
};
let model = unsafe {
match CStr::from_ptr(model).to_str() {
Ok(model) => model,
Err(msg) => {
res.status = CompilerStatus::InvalidUtf8;
res.msg = error_message("Invalid encoding", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
}
};
let ty = unsafe {
match CStr::from_ptr(ty).to_str() {
Ok(ty) => ty,
Err(msg) => {
res.status = CompilerStatus::InvalidUtf8;
res.msg = error_message("Invalid compiler type", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
}
};
let ml = match CellModel::load(model) {
Ok(ml) => ml,
Err(msg) => {
res.status = CompilerStatus::ParseError;
res.msg = error_message("Cannot parse JSON", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
};
if let Ok(mut config) = Config::from_name(ty, opt) {
let df: Defuns = unsafe {
if df.is_null() {
Defuns::new()
} else {
(&*df).clone()
}
};
config.set_defuns(df);
let prog = match Program::new(&ml, config) {
Ok(prog) => prog,
Err(msg) => {
res.status = CompilerStatus::CompilationError;
res.msg = error_message("Compilation error (prog)", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
};
let app = Application::new(prog, HashSet::new());
match app {
Ok(app) => {
res.status = CompilerStatus::Ok;
res.app = Some(app);
}
Err(msg) => {
res.status = CompilerStatus::CompilationError;
res.msg = error_message("Compilation error (app)", &msg);
}
}
} else {
res.status = CompilerStatus::InvalidCompiler;
res.msg = error_message("Config error", opt);
}
Box::into_raw(Box::new(res)) as *const _
}
#[no_mangle]
pub unsafe extern "C" fn translate(
json: *const c_char,
ty: *const c_char,
opt: u32,
df: *mut Defuns,
num_params: usize,
) -> *const CompilerResult {
let mut res = CompilerResult {
app: None,
status: CompilerStatus::Incomplete,
msg: CString::from_str("Success").unwrap(),
};
let json = unsafe {
match CStr::from_ptr(json).to_str() {
Ok(json) => json,
Err(msg) => {
res.status = CompilerStatus::InvalidUtf8;
res.msg = error_message("Invalid encoding", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
}
};
let ty = unsafe {
match CStr::from_ptr(ty).to_str() {
Ok(ty) => ty,
Err(msg) => {
res.status = CompilerStatus::InvalidUtf8;
res.msg = error_message("Invalid compiler type", msg);
return Box::into_raw(Box::new(res)) as *const _;
}
}
};
if let Ok(mut config) = Config::from_name(ty, opt) {
let df: Defuns = unsafe {
if df.is_null() {
Defuns::new()
} else {
(&*df).clone()
}
};
config.set_defuns(df);
let mut comp = Compiler::with_config(config);
let app = comp.translate(json.to_string(), num_params);
match app {
Ok(app) => {
res.app = Some(app);
res.status = CompilerStatus::Ok;
}
Err(msg) => {
res.status = CompilerStatus::InvalidCompiler;
res.msg = error_message("Compilation error", msg);
}
}
} else {
res.status = CompilerStatus::InvalidCompiler;
res.msg = error_message("Config error", opt);
}
Box::into_raw(Box::new(res)) as *const _
}
#[no_mangle]
pub unsafe extern "C" fn check_status(q: *const CompilerResult) -> *const c_char {
let q: &CompilerResult = unsafe { &*q };
q.msg.as_ptr() as *const _
}
#[no_mangle]
pub unsafe extern "C" fn save(q: *const CompilerResult, file: *const c_char) -> bool {
let q: &CompilerResult = unsafe { &*q };
let file = unsafe {
match CStr::from_ptr(file).to_str() {
Ok(file) => file,
Err(_) => return false,
}
};
if let Some(app) = &q.app {
if let Ok(mut fs) = std::fs::File::create(file) {
app.save(&mut fs).is_ok()
} else {
false
}
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn load(file: *const c_char, df: *mut Defuns) -> *const CompilerResult {
let mut res = CompilerResult {
app: None,
status: CompilerStatus::Incomplete,
msg: CString::from_str("Success").unwrap(),
};
let df: Defuns = unsafe {
if df.is_null() {
Defuns::new()
} else {
(&*df).clone()
}
};
let file = unsafe {
match CStr::from_ptr(file).to_str() {
Ok(file) => file,
Err(_) => return Box::into_raw(Box::new(res)) as *const _,
}
};
let fs = std::fs::File::open(file);
match fs {
Ok(mut fs) => match Application::load(&mut fs, &Config::from_defuns(df).unwrap()) {
Ok(app) => {
res.app = Some(app);
res.status = CompilerStatus::Ok;
}
Err(err) => {
res.status = CompilerStatus::ParseError;
res.msg = error_message("File parse error", &err);
}
},
Err(err) => {
res.msg = error_message("File I/O error", &err);
}
}
Box::into_raw(Box::new(res)) as *const _
}
#[no_mangle]
pub unsafe extern "C" fn get_config(q: *const CompilerResult) -> usize {
let q: &CompilerResult = unsafe { &*q };
match &q.app {
Some(app) => {
let config = app.prog.config();
let ty: usize = match config.ty {
CompilerType::Native => 0,
CompilerType::Amd => 1,
CompilerType::AmdAVX => 2,
CompilerType::AmdSSE => 3,
CompilerType::Arm => 4,
CompilerType::RiscV => 5,
CompilerType::ByteCode => 6,
CompilerType::Debug => 7,
};
(config.opt as usize) | (ty << 32)
}
None => 0,
}
}
#[no_mangle]
pub unsafe extern "C" fn count_states(q: *const CompilerResult) -> usize {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
app.count_states
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn count_params(q: *const CompilerResult) -> usize {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
app.count_params
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn count_obs(q: *const CompilerResult) -> usize {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
app.count_obs
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn count_diffs(q: *const CompilerResult) -> usize {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
app.count_diffs
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn run(
_q: *mut CompilerResult,
_du: *mut f64,
_u: *const f64,
_ns: usize,
_p: *const f64,
_np: usize,
_t: f64,
) -> bool {
false
}
#[no_mangle]
pub unsafe extern "C" fn execute(q: *mut CompilerResult) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
app.exec();
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn execute_vectorized(
q: *mut CompilerResult,
buf: *mut f64,
n: usize,
) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
let h = usize::max(app.count_states, app.count_obs);
let p: &mut [f64] = unsafe { std::slice::from_raw_parts_mut(buf, h * n) };
let mut states = Matrix::from_buf(p, h, n);
let p: &mut [f64] = unsafe { std::slice::from_raw_parts_mut(buf, h * n) };
let mut obs = Matrix::from_buf(p, h, n);
app.exec_vectorized(&mut states, &mut obs);
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn evaluate(
q: *mut CompilerResult,
args: *const f64,
nargs: usize,
outs: *mut f64,
nouts: usize,
) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
let args: &[f64] = unsafe { std::slice::from_raw_parts(args, nargs) };
let outs: &mut [f64] = unsafe { std::slice::from_raw_parts_mut(outs, nouts) };
app.evaluate(args, outs);
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn evaluate_matrix(
q: *mut CompilerResult,
args: *const f64,
nargs: usize,
outs: *mut f64,
nouts: usize,
) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
if app.count_params == 0 {
return false;
}
let args: &[f64] = unsafe { std::slice::from_raw_parts(args, nargs) };
let outs: &mut [f64] = unsafe { std::slice::from_raw_parts_mut(outs, nouts) };
let n = nargs / app.count_params;
app.evaluate_matrix(args, outs, n);
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn ptr_states(q: *mut CompilerResult) -> *mut f64 {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
if let Some(f) = &mut app.compiled {
&mut f.mem_mut()[app.first_state] as *mut f64
} else {
&mut app.bytecode.mem_mut()[app.first_state] as *mut f64
}
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ptr_params(q: *mut CompilerResult) -> *mut f64 {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
&mut app.params[app.first_param] as *mut f64
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn ptr_obs(q: *mut CompilerResult) -> *const f64 {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
if let Some(f) = &app.compiled {
&f.mem()[app.first_obs] as *const f64
} else {
&app.bytecode.mem()[app.first_obs] as *const f64
}
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn ptr_diffs(q: *mut CompilerResult) -> *const f64 {
let q: &CompilerResult = unsafe { &*q };
if let Some(app) = &q.app {
if let Some(f) = &app.compiled {
&f.mem()[app.first_diff] as *const f64
} else {
&app.bytecode.mem()[app.first_diff] as *const f64
}
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn dump(
q: *mut CompilerResult,
name: *const c_char,
what: *const c_char,
) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
let name = unsafe { CStr::from_ptr(name).to_str().unwrap() };
let what = unsafe { CStr::from_ptr(what).to_str().unwrap() };
app.dump(name, what)
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn finalize(q: *mut CompilerResult) {
if !q.is_null() {
let _ = unsafe { Box::from_raw(q) };
}
}
#[no_mangle]
pub unsafe extern "C" fn info() -> *const c_char {
let msg = CString::new(env!("CARGO_PKG_VERSION")).unwrap();
msg.into_raw() as *const _
}
#[no_mangle]
pub unsafe extern "C" fn fast_func(q: *mut CompilerResult) -> *const usize {
let q: &mut CompilerResult = unsafe { &mut *q };
if let Some(app) = &mut q.app {
match app.get_fast() {
Some(f) => f as *const usize,
None => std::ptr::null(),
}
} else {
std::ptr::null()
}
}
#[no_mangle]
pub unsafe extern "C" fn callable_quad(n: usize, xx: *const f64, q: *mut CompilerResult) -> f64 {
let q: &mut CompilerResult = unsafe { &mut *q };
let xx: &[f64] = unsafe { std::slice::from_raw_parts(xx, n) };
if let Some(app) = &mut q.app {
app.exec_callable(xx)
} else {
f64::NAN
}
}
#[no_mangle]
pub unsafe extern "C" fn callable_quad_fast(n: usize, xx: *const f64, f: *const usize) -> f64 {
let xx: &[f64] = unsafe { std::slice::from_raw_parts(xx, n) };
match n {
0 => {
let f: fn() -> f64 = unsafe { std::mem::transmute(f) };
f()
}
1 => {
let f: fn(f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0])
}
2 => {
let f: fn(f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1])
}
3 => {
let f: fn(f64, f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1], xx[2])
}
4 => {
let f: fn(f64, f64, f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1], xx[2], xx[3])
}
5 => {
let f: fn(f64, f64, f64, f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1], xx[2], xx[3], xx[4])
}
6 => {
let f: fn(f64, f64, f64, f64, f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1], xx[2], xx[3], xx[4], xx[5])
}
7 => {
let f: fn(f64, f64, f64, f64, f64, f64, f64) -> f64 = unsafe { std::mem::transmute(f) };
f(xx[0], xx[1], xx[2], xx[3], xx[4], xx[5], xx[6])
}
_ => {
panic!("too many parameters for a fast func");
}
}
}
#[no_mangle]
pub unsafe extern "C" fn callable_filter(
buffer: *const f64,
filter_size: usize,
return_value: *mut f64,
q: *mut CompilerResult,
) -> i64 {
let q: &mut CompilerResult = unsafe { &mut *q };
let xx: &[f64] = unsafe { std::slice::from_raw_parts(buffer, filter_size) };
if let Some(app) = &mut q.app {
let p: &mut f64 = unsafe { &mut *return_value };
*p = app.exec_callable(xx);
1
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn create_matrix<'a>() -> *const Matrix<'a> {
let mat = Matrix::new();
Box::into_raw(Box::new(mat)) as *const Matrix
}
#[no_mangle]
pub unsafe extern "C" fn finalize_matrix(mat: *mut Matrix) {
if !mat.is_null() {
let _ = unsafe { Box::from_raw(mat) };
}
}
#[no_mangle]
pub unsafe extern "C" fn add_row(mat: *mut Matrix, v: *mut f64, n: usize) {
let mat: &mut Matrix = unsafe { &mut *mat };
mat.add_row(v, n);
}
#[no_mangle]
pub unsafe extern "C" fn execute_matrix(
q: *mut CompilerResult,
states: *mut Matrix,
obs: *mut Matrix,
) -> bool {
let q: &mut CompilerResult = unsafe { &mut *q };
let states: &mut Matrix = unsafe { &mut *states };
let obs: &mut Matrix = unsafe { &mut *obs };
if let Some(app) = &mut q.app {
app.exec_vectorized(states, obs);
true
} else {
false
}
}
#[no_mangle]
pub unsafe extern "C" fn create_defuns() -> *const Defuns {
let df = Defuns::new();
Box::into_raw(Box::new(df)) as *const Defuns
}
#[no_mangle]
pub unsafe extern "C" fn finalize_defuns(df: *mut Defuns) {
}
#[no_mangle]
pub unsafe extern "C" fn add_func(
df: *mut Defuns,
name: *const c_char,
p: *const usize,
num_args: usize,
) {
let df: &mut Defuns = unsafe { &mut *df };
let name = unsafe { CStr::from_ptr(name).to_str().unwrap() };
df.add_func(name, p, num_args);
}