diff --git a/Cargo.lock b/Cargo.lock index 285fdfc2..ecd09800 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,7 +553,7 @@ dependencies = [ ] [[package]] -name = "linalg_externfns" +name = "linalg" version = "0.1.0" dependencies = [ "cslice", @@ -688,7 +688,7 @@ version = "0.1.0" dependencies = [ "clap", "inkwell", - "linalg_externfns", + "linalg", "nac3core", "nac3parser", "parking_lot", diff --git a/Cargo.toml b/Cargo.toml index 96fc975c..765ab391 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "nac3ast", "nac3parser", "nac3core", - "nac3standalone/linalg_externfns", "nac3standalone", "nac3artiq", "runkernel", diff --git a/nac3standalone/Cargo.toml b/nac3standalone/Cargo.toml index ccf69ba5..a639c120 100644 --- a/nac3standalone/Cargo.toml +++ b/nac3standalone/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" parking_lot = "0.12" nac3parser = { path = "../nac3parser" } nac3core = { path = "../nac3core" } -linalg_externfns = { path = "./linalg_externfns" } +linalg = { path = "./demo/linalg" } [dependencies.clap] version = "4.5" diff --git a/nac3standalone/linalg_externfns/Cargo.toml b/nac3standalone/demo/linalg/Cargo.toml similarity index 88% rename from nac3standalone/linalg_externfns/Cargo.toml rename to nac3standalone/demo/linalg/Cargo.toml index 03329dc7..69d15bdb 100644 --- a/nac3standalone/linalg_externfns/Cargo.toml +++ b/nac3standalone/demo/linalg/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "linalg_externfns" +name = "linalg" version = "0.1.0" edition = "2021" diff --git a/nac3standalone/linalg_externfns/src/lib.rs b/nac3standalone/demo/linalg/src/lib.rs similarity index 80% rename from nac3standalone/linalg_externfns/src/lib.rs rename to nac3standalone/demo/linalg/src/lib.rs index 5d6b4c9e..1e609100 100644 --- a/nac3standalone/linalg_externfns/src/lib.rs +++ b/nac3standalone/demo/linalg/src/lib.rs @@ -1,36 +1,27 @@ -/// Uses `nalgebra` crate to invoke `np_linalg` and `sp_linalg` functions -/// When converting between `nalgebra::Matrix` and `NDArray` following considerations are necessary -/// -/// * Both `nalgebra::Matrix` and `NDArray` require their content to be stored in row-major order -/// * `NDArray` data pointer can be directly read and converted to `nalgebra::Matrix` (row and column number must be known) -/// * `nalgebra::Matrix::as_slice` returns the content of matrix in column-major order and initial data needs to be transposed before storing it in `NDArray` data pointer -mod runtime_exception; +// Uses `nalgebra` crate to invoke `np_linalg` and `sp_linalg` functions +// When converting between `nalgebra::Matrix` and `NDArray` following considerations are necessary +// +// * Both `nalgebra::Matrix` and `NDArray` require their content to be stored in row-major order +// * `NDArray` data pointer can be directly read and converted to `nalgebra::Matrix` (row and column number must be known) +// * `nalgebra::Matrix::as_slice` returns the content of matrix in column-major order and initial data needs to be transposed before storing it in `NDArray` data pointer + use core::slice; use nalgebra::DMatrix; -macro_rules! raise_exn { - ($name:expr, $fn_name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => {{ - use cslice::AsCSlice; - let name_id = $crate::runtime_exception::get_exception_id($name); - let exn = $crate::runtime_exception::Exception { - id: name_id, - file: file!().as_c_slice(), - line: line!(), - column: column!(), - // https://github.com/rust-lang/rfcs/pull/1719 - function: $fn_name.as_c_slice(), - message: $message.as_c_slice(), - param: [$param0, $param1, $param2], - }; - #[allow(unused_unsafe)] - unsafe { - $crate::runtime_exception::raise(&exn) - } - }}; - ($name:expr, $fn_name:expr, $message:expr) => {{ - raise_exn!($name, $fn_name, $message, 0, 0, 0) - }}; +fn report_error( + error_name: &str, + fn_name: &str, + file_name: &str, + line_num: u32, + col_num: u32, + err_msg: &str, +) -> ! { + panic!( + "Exception {} from {} in {}:{}:{}, message: {}", + error_name, fn_name, file_name, line_num, col_num, err_msg + ); } + pub struct InputMatrix { pub ndims: usize, pub dims: *const usize, @@ -56,7 +47,7 @@ pub unsafe extern "C" fn np_dot(mat1: *mut InputMatrix, mat2: *mut InputMatrix) "expected 1D Vector Input, but received {}D and {}D input", mat1.ndims, mat2.ndims ); - raise_exn!("ValueError", "np_dot", err_msg); + report_error("ValueError", "np_dot", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -64,7 +55,7 @@ pub unsafe extern "C" fn np_dot(mat1: *mut InputMatrix, mat2: *mut InputMatrix) if dim1[0] != dim2[0] { let err_msg = format!("shapes ({},) and ({},) not aligned", dim1[0], dim2[0]); - raise_exn!("ValueError", "np_dot", err_msg); + report_error("ValueError", "np_dot", file!(), line!(), column!(), &err_msg); } let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0]) }; let data_slice2 = unsafe { slice::from_raw_parts_mut(mat2.data, dim2[0]) }; @@ -93,7 +84,7 @@ pub unsafe extern "C" fn np_linalg_matmul( "expected 2D Vector Input, but received {}D and {}D input", mat1.ndims, mat2.ndims ); - raise_exn!("ValueError", "np_matmul", err_msg); + report_error("ValueError", "np_matmul", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -104,7 +95,7 @@ pub unsafe extern "C" fn np_linalg_matmul( "shapes ({},{}) and ({},{}) not aligned: {} (dim 1) != {} (dim 0)", dim1[0], dim1[1], dim2[0], dim2[1], dim1[1], dim2[0] ); - raise_exn!("ValueError", "np_matmul", err_msg); + report_error("ValueError", "np_matmul", file!(), line!(), column!(), &err_msg); } let outdim = out.get_dims(); @@ -130,14 +121,14 @@ pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut In if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "np_linalg_cholesky", err_msg); + report_error("ValueError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); if dim1[0] != dim1[1] { let err_msg = format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]); - raise_exn!("LinAlgError", "np_linalg_cholesky", err_msg); + report_error("LinAlgError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg); } let outdim = out.get_dims(); @@ -151,7 +142,14 @@ pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut In out_slice.copy_from_slice(res.unpack().transpose().as_slice()); } None => { - raise_exn!("LinAlgError", "np_linalg_cholesky", "Matrix is not positive definite"); + report_error( + "LinAlgError", + "np_linalg_cholesky", + file!(), + line!(), + column!(), + "Matrix is not positive definite", + ); } }; } @@ -171,7 +169,7 @@ pub unsafe extern "C" fn np_linalg_qr( if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "np_linalg_cholesky", err_msg); + report_error("ValueError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -210,7 +208,7 @@ pub unsafe extern "C" fn np_linalg_svd( if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "np_linalg_svd", err_msg); + report_error("ValueError", "np_linalg_svd", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -241,14 +239,14 @@ pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMa if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "np_linalg_inv", err_msg); + report_error("ValueError", "np_linalg_inv", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); if dim1[0] != dim1[1] { let err_msg = format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]); - raise_exn!("LinAlgError", "np_linalg_inv", err_msg); + report_error("LinAlgError", "np_linalg_inv", file!(), line!(), column!(), &err_msg); } let outdim = out.get_dims(); @@ -257,7 +255,14 @@ pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMa let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1); if !matrix.is_invertible() { - raise_exn!("LinAlgError", "np_linalg_inv", "no inverse for Singular Matrix"); + report_error( + "LinAlgError", + "np_linalg_inv", + file!(), + line!(), + column!(), + "no inverse for Singular Matrix", + ); } let inv = matrix.try_inverse().unwrap(); out_slice.copy_from_slice(inv.transpose().as_slice()); @@ -273,7 +278,7 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "np_linalg_pinv", err_msg); + report_error("ValueError", "np_linalg_pinv", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); let outdim = out.get_dims(); @@ -288,8 +293,8 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM Ok(m) => { out_slice.copy_from_slice(m.transpose().as_slice()); } - Err(e) => { - raise_exn!("LinAlgError", "np_linalg_pinv", e); + Err(err_msg) => { + report_error("LinAlgError", "np_linalg_pinv", file!(), line!(), column!(), err_msg); } } } @@ -309,7 +314,7 @@ pub unsafe extern "C" fn sp_linalg_lu( if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "sp_linalg_lu", err_msg); + report_error("ValueError", "sp_linalg_lu", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -342,7 +347,7 @@ pub unsafe extern "C" fn sp_linalg_schur( if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "sp_linalg_schur", err_msg); + report_error("ValueError", "sp_linalg_schur", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -350,7 +355,7 @@ pub unsafe extern "C" fn sp_linalg_schur( if dim1[0] != dim1[1] { let err_msg = format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]); - raise_exn!("LinAlgError", "np_linalg_schur", err_msg); + report_error("LinAlgError", "np_linalg_schur", file!(), line!(), column!(), &err_msg); } let out_t_dim = (*out_t).get_dims(); @@ -382,7 +387,7 @@ pub unsafe extern "C" fn sp_linalg_hessenberg( if mat1.ndims != 2 { let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims); - raise_exn!("ValueError", "sp_linalg_hessenberg", err_msg); + report_error("ValueError", "sp_linalg_hessenberg", file!(), line!(), column!(), &err_msg); } let dim1 = (*mat1).get_dims(); @@ -390,7 +395,7 @@ pub unsafe extern "C" fn sp_linalg_hessenberg( if dim1[0] != dim1[1] { let err_msg = format!("last 2 dimensions of the array must be square: {} != {}", dim1[0], dim1[1]); - raise_exn!("LinAlgError", "sp_linalg_hessenberg", err_msg); + report_error("LinAlgError", "sp_linalg_hessenberg", file!(), line!(), column!(), &err_msg); } let out_h_dim = (*out_h).get_dims(); diff --git a/nac3standalone/linalg_externfns/src/runtime_exception.rs b/nac3standalone/linalg_externfns/src/runtime_exception.rs deleted file mode 100644 index 7179f521..00000000 --- a/nac3standalone/linalg_externfns/src/runtime_exception.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(unused)] - -// ARTIQ Exception struct declaration -use cslice::CSlice; - -// Note: CSlice within an exception may not be actual cslice, they may be strings that exist only -// in the host. If the length == usize:MAX, the pointer is actually a string key in the host. -#[repr(C)] -#[derive(Clone)] -pub struct Exception<'a> { - pub id: u32, - pub file: CSlice<'a, u8>, - pub line: u32, - pub column: u32, - pub function: CSlice<'a, u8>, - pub message: CSlice<'a, u8>, - pub param: [i64; 3], -} - -fn str_err(_: core::str::Utf8Error) -> core::fmt::Error { - core::fmt::Error -} - -fn exception_str<'a>(s: &'a CSlice<'a, u8>) -> Result<&'a str, core::str::Utf8Error> { - if s.len() == usize::MAX { - Ok("") - } else { - core::str::from_utf8(s.as_ref()) - } -} - -pub unsafe fn raise(exception: *const Exception) -> ! { - let e = &*exception; - let f1 = exception_str(&e.function).map_err(str_err).unwrap(); - let f2 = exception_str(&e.file).map_err(str_err).unwrap(); - let f3 = exception_str(&e.message).map_err(str_err).unwrap(); - - panic!("Exception {} from {} in {}:{}:{}, message: {}", e.id, f1, f2, e.line, e.column, f3); -} - -static EXCEPTION_ID_LOOKUP: [(&str, u32); 14] = [ - ("RuntimeError", 0), - ("RTIOUnderflow", 1), - ("RTIOOverflow", 2), - ("RTIODestinationUnreachable", 3), - ("DMAError", 4), - ("I2CError", 5), - ("CacheError", 6), - ("SPIError", 7), - ("ZeroDivisionError", 8), - ("IndexError", 9), - ("UnwrapNoneError", 10), - ("Value", 11), - ("ValueError", 12), - ("LinAlgError", 13), -]; - -pub fn get_exception_id(name: &str) -> u32 { - for (n, id) in EXCEPTION_ID_LOOKUP.iter() { - if *n == name { - return *id; - } - } - unimplemented!("unallocated internal exception id") -}