forked from M-Labs/nac3
Compare commits
3 Commits
ndarray-st
...
misc/updat
Author | SHA1 | Date |
---|---|---|
David Mak | f2dc1814e0 | |
David Mak | 053f74bc7e | |
David Mak | 317503679e |
|
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.0"
|
version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
|
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
|
@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.9"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -139,9 +139,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.9"
|
version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
@ -155,10 +155,10 @@ version = "4.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -361,12 +361,6 @@ dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -421,7 +415,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -749,7 +743,7 @@ dependencies = [
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -805,15 +799,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.21.2"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8"
|
checksum = "1962a33ed2a201c637fc14a4e0fd4e06e6edfdeee6a5fede0dab55507ad74cf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"indoc",
|
"indoc",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
"parking_lot",
|
"once_cell",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"pyo3-ffi",
|
"pyo3-ffi",
|
||||||
|
@ -823,9 +817,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.21.2"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50"
|
checksum = "ab7164b2202753bd33afc7f90a10355a719aa973d1f94502c50d06f3488bc420"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
|
@ -833,9 +827,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-ffi"
|
name = "pyo3-ffi"
|
||||||
version = "0.21.2"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403"
|
checksum = "c6424906ca49013c0829c5c1ed405e20e2da2dc78b82d198564880a704e6a7b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
|
@ -843,27 +837,27 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.21.2"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c"
|
checksum = "82b2f19e153122d64afd8ce7aaa72f06a00f52e34e1d1e74b6d71baea396460a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.21.2"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c"
|
checksum = "dd698c04cac17cf0fe63d47790ab311b8b25542f5cb976b65c374035c50f1eef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.4.1",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1029,22 +1023,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.204"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.204"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1130,11 +1124,11 @@ version = "0.26.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1150,9 +1144,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.70"
|
version = "2.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1161,9 +1155,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.12.15"
|
version = "0.12.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2"
|
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
|
@ -1218,7 +1212,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1486,5 +1480,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720418205,
|
"lastModified": 1718530797,
|
||||||
"narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=",
|
"narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "655a58a72a6601292512670343087c2d75d859c1",
|
"rev": "b60ebf54c15553b393d144357375ea956f89e9a9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
''
|
''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
ln -s ${pkgs.llvmPackages_14.clang-unwrapped}/bin/clang $out/bin/clang-irrt
|
ln -s ${pkgs.llvmPackages_14.clang-unwrapped}/bin/clang $out/bin/clang-irrt
|
||||||
ln -s ${pkgs.llvmPackages_14.clang}/bin/clang $out/bin/clang-irrt-test
|
|
||||||
ln -s ${pkgs.llvmPackages_14.llvm.out}/bin/llvm-as $out/bin/llvm-as-irrt
|
ln -s ${pkgs.llvmPackages_14.llvm.out}/bin/llvm-as $out/bin/llvm-as-irrt
|
||||||
'';
|
'';
|
||||||
nac3artiq = pkgs.python3Packages.toPythonModule (
|
nac3artiq = pkgs.python3Packages.toPythonModule (
|
||||||
|
@ -24,7 +23,6 @@
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = ./Cargo.lock;
|
lockFile = ./Cargo.lock;
|
||||||
};
|
};
|
||||||
cargoTestFlags = [ "--features" "test" ];
|
|
||||||
passthru.cargoLock = cargoLock;
|
passthru.cargoLock = cargoLock;
|
||||||
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_14.clang llvm-tools-irrt pkgs.llvmPackages_14.llvm.out llvm-nac3 ];
|
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_14.clang llvm-tools-irrt pkgs.llvmPackages_14.llvm.out llvm-nac3 ];
|
||||||
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
||||||
|
@ -163,10 +161,7 @@
|
||||||
clippy
|
clippy
|
||||||
pre-commit
|
pre-commit
|
||||||
rustfmt
|
rustfmt
|
||||||
rust-analyzer
|
|
||||||
];
|
];
|
||||||
# https://nixos.wiki/wiki/Rust#Shell.nix_example
|
|
||||||
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
|
||||||
};
|
};
|
||||||
devShells.x86_64-linux.msys2 = pkgs.mkShell {
|
devShells.x86_64-linux.msys2 = pkgs.mkShell {
|
||||||
name = "nac3-dev-shell-msys2";
|
name = "nac3-dev-shell-msys2";
|
||||||
|
|
|
@ -10,7 +10,7 @@ crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
pyo3 = { version = "0.21", features = ["extension-module", "gil-refs"] }
|
pyo3 = { version = "0.22", features = ["extension-module", "py-clone"] }
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
tempfile = "3.10"
|
tempfile = "3.10"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
|
|
|
@ -17,8 +17,8 @@ use inkwell::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
|
prelude::*,
|
||||||
types::{PyDict, PyList},
|
types::{PyDict, PyList},
|
||||||
PyObject, PyResult, Python,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
use crate::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
||||||
|
@ -624,7 +624,7 @@ pub fn attributes_writeback(
|
||||||
host_attributes: &PyObject,
|
host_attributes: &PyObject,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
Python::with_gil(|py| -> PyResult<Result<(), String>> {
|
Python::with_gil(|py| -> PyResult<Result<(), String>> {
|
||||||
let host_attributes: &PyList = host_attributes.downcast(py)?;
|
let host_attributes = host_attributes.downcast_bound::<PyList>(py)?;
|
||||||
let top_levels = ctx.top_level.definitions.read();
|
let top_levels = ctx.top_level.definitions.read();
|
||||||
let globals = inner_resolver.global_value_ids.read();
|
let globals = inner_resolver.global_value_ids.read();
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
|
@ -632,7 +632,7 @@ pub fn attributes_writeback(
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
let mut scratch_buffer = Vec::new();
|
let mut scratch_buffer = Vec::new();
|
||||||
for val in (*globals).values() {
|
for val in (*globals).values() {
|
||||||
let val = val.as_ref(py);
|
let val = val.bind_borrowed(py);
|
||||||
let ty = inner_resolver.get_obj_type(
|
let ty = inner_resolver.get_obj_type(
|
||||||
py,
|
py,
|
||||||
val,
|
val,
|
||||||
|
@ -670,7 +670,7 @@ pub fn attributes_writeback(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !attributes.is_empty() {
|
if !attributes.is_empty() {
|
||||||
let pydict = PyDict::new(py);
|
let pydict = PyDict::new_bound(py);
|
||||||
pydict.set_item("obj", val)?;
|
pydict.set_item("obj", val)?;
|
||||||
pydict.set_item("fields", attributes)?;
|
pydict.set_item("fields", attributes)?;
|
||||||
host_attributes.append(pydict)?;
|
host_attributes.append(pydict)?;
|
||||||
|
@ -680,7 +680,7 @@ pub fn attributes_writeback(
|
||||||
let elem_ty = iter_type_vars(params).next().unwrap().ty;
|
let elem_ty = iter_type_vars(params).next().unwrap().ty;
|
||||||
|
|
||||||
if gen_rpc_tag(ctx, elem_ty, &mut scratch_buffer).is_ok() {
|
if gen_rpc_tag(ctx, elem_ty, &mut scratch_buffer).is_ok() {
|
||||||
let pydict = PyDict::new(py);
|
let pydict = PyDict::new_bound(py);
|
||||||
pydict.set_item("obj", val)?;
|
pydict.set_item("obj", val)?;
|
||||||
host_attributes.append(pydict)?;
|
host_attributes.append(pydict)?;
|
||||||
values.push((
|
values.push((
|
||||||
|
|
|
@ -39,9 +39,11 @@ use nac3parser::{
|
||||||
ast::{ExprKind, Stmt, StmtKind, StrRef},
|
ast::{ExprKind, Stmt, StmtKind, StrRef},
|
||||||
parser::parse_program,
|
parser::parse_program,
|
||||||
};
|
};
|
||||||
use pyo3::create_exception;
|
use pyo3::{
|
||||||
use pyo3::prelude::*;
|
create_exception, exceptions,
|
||||||
use pyo3::{exceptions, types::PyBytes, types::PyDict, types::PySet};
|
prelude::*,
|
||||||
|
types::{PyBytes, PyDict, PySet},
|
||||||
|
};
|
||||||
|
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
|
||||||
|
@ -147,7 +149,7 @@ impl Nac3 {
|
||||||
registered_class_ids: &HashSet<u64>,
|
registered_class_ids: &HashSet<u64>,
|
||||||
) -> PyResult<()> {
|
) -> PyResult<()> {
|
||||||
let (module_name, source_file) = Python::with_gil(|py| -> PyResult<(String, String)> {
|
let (module_name, source_file) = Python::with_gil(|py| -> PyResult<(String, String)> {
|
||||||
let module: &PyAny = module.extract(py)?;
|
let module = module.bind_borrowed(py);
|
||||||
Ok((module.getattr("__name__")?.extract()?, module.getattr("__file__")?.extract()?))
|
Ok((module.getattr("__name__")?.extract()?, module.getattr("__file__")?.extract()?))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -173,14 +175,14 @@ impl Nac3 {
|
||||||
// Drop unregistered (i.e. host-only) base classes.
|
// Drop unregistered (i.e. host-only) base classes.
|
||||||
bases.retain(|base| {
|
bases.retain(|base| {
|
||||||
Python::with_gil(|py| -> PyResult<bool> {
|
Python::with_gil(|py| -> PyResult<bool> {
|
||||||
let id_fn = PyModule::import(py, "builtins")?.getattr("id")?;
|
let module = module.bind_borrowed(py);
|
||||||
|
let id_fn = PyModule::import_bound(py, "builtins")?.getattr("id")?;
|
||||||
match &base.node {
|
match &base.node {
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
if *id == "Exception".into() {
|
if *id == "Exception".into() {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
let base_obj =
|
let base_obj = module.getattr(id.to_string().as_str())?;
|
||||||
module.getattr(py, id.to_string().as_str())?;
|
|
||||||
let base_id = id_fn.call1((base_obj,))?.extract()?;
|
let base_id = id_fn.call1((base_obj,))?.extract()?;
|
||||||
Ok(registered_class_ids.contains(&base_id))
|
Ok(registered_class_ids.contains(&base_id))
|
||||||
}
|
}
|
||||||
|
@ -302,10 +304,10 @@ impl Nac3 {
|
||||||
|
|
||||||
fn compile_method<T>(
|
fn compile_method<T>(
|
||||||
&self,
|
&self,
|
||||||
obj: &PyAny,
|
obj: &Bound<PyAny>,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<&PyAny>,
|
args: Vec<Bound<PyAny>>,
|
||||||
embedding_map: &PyAny,
|
embedding_map: &Bound<PyAny>,
|
||||||
py: Python,
|
py: Python,
|
||||||
link_fn: &dyn Fn(&Module) -> PyResult<T>,
|
link_fn: &dyn Fn(&Module) -> PyResult<T>,
|
||||||
) -> PyResult<T> {
|
) -> PyResult<T> {
|
||||||
|
@ -316,8 +318,8 @@ impl Nac3 {
|
||||||
size_t,
|
size_t,
|
||||||
);
|
);
|
||||||
|
|
||||||
let builtins = PyModule::import(py, "builtins")?;
|
let builtins = PyModule::import_bound(py, "builtins")?;
|
||||||
let typings = PyModule::import(py, "typing")?;
|
let typings = PyModule::import_bound(py, "typing")?;
|
||||||
let id_fn = builtins.getattr("id")?;
|
let id_fn = builtins.getattr("id")?;
|
||||||
let issubclass = builtins.getattr("issubclass")?;
|
let issubclass = builtins.getattr("issubclass")?;
|
||||||
let exn_class = builtins.getattr("Exception")?;
|
let exn_class = builtins.getattr("Exception")?;
|
||||||
|
@ -355,13 +357,17 @@ impl Nac3 {
|
||||||
|
|
||||||
let mut rpc_ids = vec![];
|
let mut rpc_ids = vec![];
|
||||||
for (stmt, path, module) in &self.top_levels {
|
for (stmt, path, module) in &self.top_levels {
|
||||||
let py_module: &PyAny = module.extract(py)?;
|
let py_module = module.bind_borrowed(py);
|
||||||
let module_id: u64 = id_fn.call1((py_module,))?.extract()?;
|
let module_id: u64 = id_fn.call1((py_module,))?.extract()?;
|
||||||
let helper = helper.clone();
|
let helper = helper.clone();
|
||||||
let class_obj;
|
let class_obj;
|
||||||
if let StmtKind::ClassDef { name, .. } = &stmt.node {
|
if let StmtKind::ClassDef { name, .. } = &stmt.node {
|
||||||
let class = py_module.getattr(name.to_string().as_str()).unwrap();
|
let class = py_module.getattr(name.to_string().as_str()).unwrap();
|
||||||
if issubclass.call1((class, exn_class)).unwrap().extract().unwrap()
|
if issubclass
|
||||||
|
.call1((class.as_borrowed(), exn_class.as_borrowed()))
|
||||||
|
.unwrap()
|
||||||
|
.extract()
|
||||||
|
.unwrap()
|
||||||
&& class.getattr("artiq_builtin").is_err()
|
&& class.getattr("artiq_builtin").is_err()
|
||||||
{
|
{
|
||||||
class_obj = Some(class);
|
class_obj = Some(class);
|
||||||
|
@ -374,8 +380,8 @@ impl Nac3 {
|
||||||
let (name_to_pyid, resolver) =
|
let (name_to_pyid, resolver) =
|
||||||
module_to_resolver_cache.get(&module_id).cloned().unwrap_or_else(|| {
|
module_to_resolver_cache.get(&module_id).cloned().unwrap_or_else(|| {
|
||||||
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
||||||
let members: &PyDict =
|
let members = py_module.getattr("__dict__").unwrap();
|
||||||
py_module.getattr("__dict__").unwrap().downcast().unwrap();
|
let members = members.downcast::<PyDict>().unwrap();
|
||||||
for (key, val) in members {
|
for (key, val) in members {
|
||||||
let key: &str = key.extract().unwrap();
|
let key: &str = key.extract().unwrap();
|
||||||
let val = id_fn.call1((val,)).unwrap().extract().unwrap();
|
let val = id_fn.call1((val,)).unwrap().extract().unwrap();
|
||||||
|
@ -454,15 +460,15 @@ impl Nac3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let id_fun = PyModule::import(py, "builtins")?.getattr("id")?;
|
let id_fun = PyModule::import_bound(py, "builtins")?.getattr("id")?;
|
||||||
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
||||||
let module = PyModule::new(py, "tmp")?;
|
let module = PyModule::new_bound(py, "tmp")?;
|
||||||
module.add("base", obj)?;
|
module.add("base", obj)?;
|
||||||
name_to_pyid.insert("base".into(), id_fun.call1((obj,))?.extract()?);
|
name_to_pyid.insert("base".into(), id_fun.call1((obj,))?.extract()?);
|
||||||
let mut arg_names = vec![];
|
let mut arg_names = vec![];
|
||||||
for (i, arg) in args.into_iter().enumerate() {
|
for (i, arg) in args.into_iter().enumerate() {
|
||||||
let name = format!("tmp{i}");
|
let name = format!("tmp{i}");
|
||||||
module.add(&name, arg)?;
|
module.add(&*name, arg.clone())?;
|
||||||
name_to_pyid.insert(name.clone().into(), id_fun.call1((arg,))?.extract()?);
|
name_to_pyid.insert(name.clone().into(), id_fun.call1((arg,))?.extract()?);
|
||||||
arg_names.push(name);
|
arg_names.push(name);
|
||||||
}
|
}
|
||||||
|
@ -834,7 +840,7 @@ fn add_exceptions(
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl Nac3 {
|
impl Nac3 {
|
||||||
#[new]
|
#[new]
|
||||||
fn new(isa: &str, artiq_builtins: &PyDict, py: Python) -> PyResult<Self> {
|
fn new(isa: &str, artiq_builtins: &Bound<PyDict>, py: Python) -> PyResult<Self> {
|
||||||
let isa = match isa {
|
let isa = match isa {
|
||||||
"host" => Isa::Host,
|
"host" => Isa::Host,
|
||||||
"rv32g" => Isa::RiscV32G,
|
"rv32g" => Isa::RiscV32G,
|
||||||
|
@ -896,43 +902,50 @@ impl Nac3 {
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
let builtins_mod = PyModule::import(py, "builtins").unwrap();
|
let builtins_mod = PyModule::import_bound(py, "builtins").unwrap();
|
||||||
let id_fn = builtins_mod.getattr("id").unwrap();
|
let id_fn = builtins_mod.getattr("id").unwrap();
|
||||||
let numpy_mod = PyModule::import(py, "numpy").unwrap();
|
let numpy_mod = PyModule::import_bound(py, "numpy").unwrap();
|
||||||
let typing_mod = PyModule::import(py, "typing").unwrap();
|
let typing_mod = PyModule::import_bound(py, "typing").unwrap();
|
||||||
let types_mod = PyModule::import(py, "types").unwrap();
|
let types_mod = PyModule::import_bound(py, "types").unwrap();
|
||||||
|
|
||||||
let get_id = |x: &PyAny| id_fn.call1((x,)).and_then(PyAny::extract).unwrap();
|
let get_id = |x: Borrowed<PyAny>| id_fn.call1((x,)).and_then(|id| id.extract()).unwrap();
|
||||||
let get_attr_id = |obj: &PyModule, attr| {
|
let get_attr_id = |obj: Borrowed<PyModule>, attr| {
|
||||||
id_fn.call1((obj.getattr(attr).unwrap(),)).unwrap().extract().unwrap()
|
id_fn.call1((obj.getattr(attr).unwrap(),)).unwrap().extract().unwrap()
|
||||||
};
|
};
|
||||||
let primitive_ids = PrimitivePythonId {
|
let primitive_ids = PrimitivePythonId {
|
||||||
virtual_id: get_id(artiq_builtins.get_item("virtual").ok().flatten().unwrap()),
|
virtual_id: get_id(
|
||||||
|
artiq_builtins.get_item("virtual").ok().flatten().unwrap().as_borrowed(),
|
||||||
|
),
|
||||||
generic_alias: (
|
generic_alias: (
|
||||||
get_attr_id(typing_mod, "_GenericAlias"),
|
get_attr_id(typing_mod.as_borrowed(), "_GenericAlias"),
|
||||||
get_attr_id(types_mod, "GenericAlias"),
|
get_attr_id(types_mod.as_borrowed(), "GenericAlias"),
|
||||||
),
|
),
|
||||||
none: get_id(artiq_builtins.get_item("none").ok().flatten().unwrap()),
|
none: get_id(artiq_builtins.get_item("none").ok().flatten().unwrap().as_borrowed()),
|
||||||
typevar: get_attr_id(typing_mod, "TypeVar"),
|
typevar: get_attr_id(typing_mod.as_borrowed(), "TypeVar"),
|
||||||
const_generic_marker: get_id(
|
const_generic_marker: get_id(
|
||||||
artiq_builtins.get_item("_ConstGenericMarker").ok().flatten().unwrap(),
|
artiq_builtins
|
||||||
|
.get_item("_ConstGenericMarker")
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.unwrap()
|
||||||
|
.as_borrowed(),
|
||||||
),
|
),
|
||||||
int: get_attr_id(builtins_mod, "int"),
|
int: get_attr_id(builtins_mod.as_borrowed(), "int"),
|
||||||
int32: get_attr_id(numpy_mod, "int32"),
|
int32: get_attr_id(numpy_mod.as_borrowed(), "int32"),
|
||||||
int64: get_attr_id(numpy_mod, "int64"),
|
int64: get_attr_id(numpy_mod.as_borrowed(), "int64"),
|
||||||
uint32: get_attr_id(numpy_mod, "uint32"),
|
uint32: get_attr_id(numpy_mod.as_borrowed(), "uint32"),
|
||||||
uint64: get_attr_id(numpy_mod, "uint64"),
|
uint64: get_attr_id(numpy_mod.as_borrowed(), "uint64"),
|
||||||
bool: get_attr_id(builtins_mod, "bool"),
|
bool: get_attr_id(builtins_mod.as_borrowed(), "bool"),
|
||||||
np_bool_: get_attr_id(numpy_mod, "bool_"),
|
np_bool_: get_attr_id(numpy_mod.as_borrowed(), "bool_"),
|
||||||
string: get_attr_id(builtins_mod, "str"),
|
string: get_attr_id(builtins_mod.as_borrowed(), "str"),
|
||||||
np_str_: get_attr_id(numpy_mod, "str_"),
|
np_str_: get_attr_id(numpy_mod.as_borrowed(), "str_"),
|
||||||
float: get_attr_id(builtins_mod, "float"),
|
float: get_attr_id(builtins_mod.as_borrowed(), "float"),
|
||||||
float64: get_attr_id(numpy_mod, "float64"),
|
float64: get_attr_id(numpy_mod.as_borrowed(), "float64"),
|
||||||
list: get_attr_id(builtins_mod, "list"),
|
list: get_attr_id(builtins_mod.as_borrowed(), "list"),
|
||||||
ndarray: get_attr_id(numpy_mod, "ndarray"),
|
ndarray: get_attr_id(numpy_mod.as_borrowed(), "ndarray"),
|
||||||
tuple: get_attr_id(builtins_mod, "tuple"),
|
tuple: get_attr_id(builtins_mod.as_borrowed(), "tuple"),
|
||||||
exception: get_attr_id(builtins_mod, "Exception"),
|
exception: get_attr_id(builtins_mod.as_borrowed(), "Exception"),
|
||||||
option: get_id(artiq_builtins.get_item("Option").ok().flatten().unwrap()),
|
option: get_id(artiq_builtins.get_item("Option").ok().flatten().unwrap().as_borrowed()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
|
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
|
||||||
|
@ -957,21 +970,21 @@ impl Nac3 {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze(&mut self, functions: &PySet, classes: &PySet) -> PyResult<()> {
|
fn analyze(&mut self, functions: &Bound<PySet>, classes: &Bound<PySet>) -> PyResult<()> {
|
||||||
let (modules, class_ids) =
|
let (modules, class_ids) =
|
||||||
Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> {
|
Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> {
|
||||||
let mut modules: HashMap<u64, PyObject> = HashMap::new();
|
let mut modules: HashMap<u64, PyObject> = HashMap::new();
|
||||||
let mut class_ids: HashSet<u64> = HashSet::new();
|
let mut class_ids: HashSet<u64> = HashSet::new();
|
||||||
|
|
||||||
let id_fn = PyModule::import(py, "builtins")?.getattr("id")?;
|
let id_fn = PyModule::import_bound(py, "builtins")?.getattr("id")?;
|
||||||
let getmodule_fn = PyModule::import(py, "inspect")?.getattr("getmodule")?;
|
let getmodule_fn = PyModule::import_bound(py, "inspect")?.getattr("getmodule")?;
|
||||||
|
|
||||||
for function in functions {
|
for function in functions {
|
||||||
let module = getmodule_fn.call1((function,))?.extract()?;
|
let module = getmodule_fn.call1((function,))?.extract()?;
|
||||||
modules.insert(id_fn.call1((&module,))?.extract()?, module);
|
modules.insert(id_fn.call1((&module,))?.extract()?, module);
|
||||||
}
|
}
|
||||||
for class in classes {
|
for class in classes {
|
||||||
let module = getmodule_fn.call1((class,))?.extract()?;
|
let module = getmodule_fn.call1((class.as_borrowed(),))?.extract()?;
|
||||||
modules.insert(id_fn.call1((&module,))?.extract()?, module);
|
modules.insert(id_fn.call1((&module,))?.extract()?, module);
|
||||||
class_ids.insert(id_fn.call1((class,))?.extract()?);
|
class_ids.insert(id_fn.call1((class,))?.extract()?);
|
||||||
}
|
}
|
||||||
|
@ -986,11 +999,11 @@ impl Nac3 {
|
||||||
|
|
||||||
fn compile_method_to_file(
|
fn compile_method_to_file(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: &PyAny,
|
obj: &Bound<PyAny>,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<&PyAny>,
|
args: Vec<Bound<PyAny>>,
|
||||||
filename: &str,
|
filename: &str,
|
||||||
embedding_map: &PyAny,
|
embedding_map: &Bound<PyAny>,
|
||||||
py: Python,
|
py: Python,
|
||||||
) -> PyResult<()> {
|
) -> PyResult<()> {
|
||||||
let target_machine = self.get_llvm_target_machine();
|
let target_machine = self.get_llvm_target_machine();
|
||||||
|
@ -1032,10 +1045,10 @@ impl Nac3 {
|
||||||
|
|
||||||
fn compile_method_to_mem(
|
fn compile_method_to_mem(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: &PyAny,
|
obj: &Bound<PyAny>,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<&PyAny>,
|
args: Vec<Bound<PyAny>>,
|
||||||
embedding_map: &PyAny,
|
embedding_map: &Bound<PyAny>,
|
||||||
py: Python,
|
py: Python,
|
||||||
) -> PyResult<PyObject> {
|
) -> PyResult<PyObject> {
|
||||||
let target_machine = self.get_llvm_target_machine();
|
let target_machine = self.get_llvm_target_machine();
|
||||||
|
@ -1054,7 +1067,7 @@ impl Nac3 {
|
||||||
working_directory.join("module.o").to_string_lossy().to_string(),
|
working_directory.join("module.o").to_string_lossy().to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(PyBytes::new(py, &fs::read(filename).unwrap()).into())
|
Ok(PyBytes::new_bound(py, &fs::read(filename).unwrap()).into())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
self.compile_method(obj, method_name, args, embedding_map, py, &link_fn)
|
||||||
|
@ -1064,7 +1077,7 @@ impl Nac3 {
|
||||||
.write_to_memory_buffer(module, FileType::Object)
|
.write_to_memory_buffer(module, FileType::Object)
|
||||||
.expect("couldn't write module to object file buffer");
|
.expect("couldn't write module to object file buffer");
|
||||||
if let Ok(dyn_lib) = Linker::ld(object_mem.as_slice()) {
|
if let Ok(dyn_lib) = Linker::ld(object_mem.as_slice()) {
|
||||||
Ok(PyBytes::new(py, &dyn_lib).into())
|
Ok(PyBytes::new_bound(py, &dyn_lib).into())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::new_err("linker failed to process object file"))
|
Err(CompileError::new_err("linker failed to process object file"))
|
||||||
}
|
}
|
||||||
|
@ -1081,14 +1094,14 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn nac3artiq(py: Python, m: &PyModule) -> PyResult<()> {
|
fn nac3artiq(py: Python, m: &Bound<PyModule>) -> PyResult<()> {
|
||||||
#[cfg(feature = "init-llvm-profile")]
|
#[cfg(feature = "init-llvm-profile")]
|
||||||
unsafe {
|
unsafe {
|
||||||
__llvm_profile_initialize();
|
__llvm_profile_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Target::initialize_all(&InitializationConfig::default());
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
m.add("CompileError", py.get_type::<CompileError>())?;
|
m.add("CompileError", py.get_type_bound::<CompileError>())?;
|
||||||
m.add_class::<Nac3>()?;
|
m.add_class::<Nac3>()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::PrimitivePythonId;
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{BasicType, BasicTypeEnum},
|
types::{BasicType, BasicTypeEnum},
|
||||||
values::BasicValueEnum,
|
values::BasicValueEnum,
|
||||||
|
@ -23,8 +24,8 @@ use nac3core::{
|
||||||
use nac3parser::ast::{self, StrRef};
|
use nac3parser::ast::{self, StrRef};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
|
prelude::*,
|
||||||
types::{PyDict, PyTuple},
|
types::{PyDict, PyTuple},
|
||||||
PyAny, PyObject, PyResult, Python,
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
@ -34,8 +35,6 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::PrimitivePythonId;
|
|
||||||
|
|
||||||
pub enum PrimitiveValue {
|
pub enum PrimitiveValue {
|
||||||
I32(i32),
|
I32(i32),
|
||||||
I64(i64),
|
I64(i64),
|
||||||
|
@ -172,7 +171,7 @@ impl StaticValue for PythonValue {
|
||||||
|
|
||||||
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
||||||
self.resolver
|
self.resolver
|
||||||
.get_obj_value(py, self.value.as_ref(py), ctx, generator, expected_ty)
|
.get_obj_value(py, self.value.bind_borrowed(py), ctx, generator, expected_ty)
|
||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
})
|
})
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
|
@ -241,10 +240,10 @@ impl StaticValue for PythonValue {
|
||||||
let ty = helper.type_fn.call1(py, (&self.value,))?;
|
let ty = helper.type_fn.call1(py, (&self.value,))?;
|
||||||
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
|
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
|
||||||
assert_eq!(ty_id, self.resolver.primitive_ids.tuple);
|
assert_eq!(ty_id, self.resolver.primitive_ids.tuple);
|
||||||
let tup: &PyTuple = self.value.extract(py)?;
|
let tup = self.value.downcast_bound::<PyTuple>(py)?;
|
||||||
let elem = tup.get_item(index as usize)?;
|
let elem = tup.get_item(index as usize)?;
|
||||||
let id = self.resolver.helper.id_fn.call1(py, (elem,))?.extract(py)?;
|
let id = self.resolver.helper.id_fn.call1(py, (elem.as_borrowed(),))?.extract(py)?;
|
||||||
Ok(Some((id, elem.into())))
|
Ok(Some((id, elem.unbind())))
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|(id, obj)| {
|
.map(|(id, obj)| {
|
||||||
|
@ -262,21 +261,26 @@ impl InnerResolver {
|
||||||
fn get_list_elem_type(
|
fn get_list_elem_type(
|
||||||
&self,
|
&self,
|
||||||
py: Python,
|
py: Python,
|
||||||
list: &PyAny,
|
list: Borrowed<PyAny>,
|
||||||
len: usize,
|
len: usize,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
defs: &[Arc<RwLock<TopLevelDef>>],
|
defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
primitives: &PrimitiveStore,
|
primitives: &PrimitiveStore,
|
||||||
) -> PyResult<Result<Type, String>> {
|
) -> PyResult<Result<Type, String>> {
|
||||||
let mut ty = match self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)? {
|
let mut ty = match self.get_obj_type(
|
||||||
|
py,
|
||||||
|
list.get_item(0)?.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => return Ok(Err(format!("type error ({e}) at element #0 of the list"))),
|
Err(e) => return Ok(Err(format!("type error ({e}) at element #0 of the list"))),
|
||||||
};
|
};
|
||||||
for i in 1..len {
|
for i in 1..len {
|
||||||
let b = match list
|
let b = match list.get_item(i).map(|elem| {
|
||||||
.get_item(i)
|
self.get_obj_type(py, elem.as_borrowed(), unifier, defs, primitives)
|
||||||
.map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))??
|
})?? {
|
||||||
{
|
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => return Ok(Err(format!("type error ({e}) at element #{i} of the list"))),
|
Err(e) => return Ok(Err(format!("type error ({e}) at element #{i} of the list"))),
|
||||||
};
|
};
|
||||||
|
@ -302,7 +306,7 @@ impl InnerResolver {
|
||||||
fn get_pyty_obj_type(
|
fn get_pyty_obj_type(
|
||||||
&self,
|
&self,
|
||||||
py: Python,
|
py: Python,
|
||||||
pyty: &PyAny,
|
pyty: Borrowed<PyAny>,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
defs: &[Arc<RwLock<TopLevelDef>>],
|
defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
primitives: &PrimitiveStore,
|
primitives: &PrimitiveStore,
|
||||||
|
@ -390,7 +394,8 @@ impl InnerResolver {
|
||||||
(unifier.add_ty(ty), false)
|
(unifier.add_ty(ty), false)
|
||||||
}))
|
}))
|
||||||
} else if ty_ty_id == self.primitive_ids.typevar {
|
} else if ty_ty_id == self.primitive_ids.typevar {
|
||||||
let name: &str = pyty.getattr("__name__").unwrap().extract().unwrap();
|
let name = pyty.getattr("__name__").unwrap();
|
||||||
|
let name: &str = name.extract().unwrap();
|
||||||
let (constraint_types, is_const_generic) = {
|
let (constraint_types, is_const_generic) = {
|
||||||
let constraints = pyty.getattr("__constraints__").unwrap();
|
let constraints = pyty.getattr("__constraints__").unwrap();
|
||||||
let mut result: Vec<Type> = vec![];
|
let mut result: Vec<Type> = vec![];
|
||||||
|
@ -399,7 +404,8 @@ impl InnerResolver {
|
||||||
let mut is_const_generic = false;
|
let mut is_const_generic = false;
|
||||||
for i in 0usize.. {
|
for i in 0usize.. {
|
||||||
if let Ok(constr) = constraints.get_item(i) {
|
if let Ok(constr) = constraints.get_item(i) {
|
||||||
let constr_id: u64 = self.helper.id_fn.call1(py, (constr,))?.extract(py)?;
|
let constr_id: u64 =
|
||||||
|
self.helper.id_fn.call1(py, (constr.as_borrowed(),))?.extract(py)?;
|
||||||
if constr_id == self.primitive_ids.const_generic_marker {
|
if constr_id == self.primitive_ids.const_generic_marker {
|
||||||
is_const_generic = true;
|
is_const_generic = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -409,7 +415,7 @@ impl InnerResolver {
|
||||||
result.push(unifier.get_dummy_var().ty);
|
result.push(unifier.get_dummy_var().ty);
|
||||||
} else {
|
} else {
|
||||||
result.push({
|
result.push({
|
||||||
match self.get_pyty_obj_type(py, constr, unifier, defs, primitives)? {
|
match self.get_pyty_obj_type(py, constr.as_borrowed(), unifier, defs, primitives)? {
|
||||||
Ok((ty, _)) => {
|
Ok((ty, _)) => {
|
||||||
if unifier.is_concrete(ty, &[]) {
|
if unifier.is_concrete(ty, &[]) {
|
||||||
ty
|
ty
|
||||||
|
@ -460,9 +466,14 @@ impl InnerResolver {
|
||||||
{
|
{
|
||||||
let origin = self.helper.origin_ty_fn.call1(py, (pyty,))?;
|
let origin = self.helper.origin_ty_fn.call1(py, (pyty,))?;
|
||||||
let args = self.helper.args_ty_fn.call1(py, (pyty,))?;
|
let args = self.helper.args_ty_fn.call1(py, (pyty,))?;
|
||||||
let args: &PyTuple = args.downcast(py)?;
|
let args = args.downcast_bound::<PyTuple>(py)?;
|
||||||
let origin_ty =
|
let origin_ty = match self.get_pyty_obj_type(
|
||||||
match self.get_pyty_obj_type(py, origin.as_ref(py), unifier, defs, primitives)? {
|
py,
|
||||||
|
origin.bind_borrowed(py),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok((ty, false)) => ty,
|
Ok((ty, false)) => ty,
|
||||||
Ok((_, true)) => {
|
Ok((_, true)) => {
|
||||||
return Ok(Err("instantiated type does not take type parameters".into()))
|
return Ok(Err("instantiated type does not take type parameters".into()))
|
||||||
|
@ -475,7 +486,7 @@ impl InnerResolver {
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let ty = match self.get_pyty_obj_type(
|
let ty = match self.get_pyty_obj_type(
|
||||||
py,
|
py,
|
||||||
args.get_item(0)?,
|
args.get_item(0)?.as_borrowed(),
|
||||||
unifier,
|
unifier,
|
||||||
defs,
|
defs,
|
||||||
primitives,
|
primitives,
|
||||||
|
@ -521,9 +532,15 @@ impl InnerResolver {
|
||||||
// npt.NDArray[T] == np.ndarray[Any, np.dtype[T]]
|
// npt.NDArray[T] == np.ndarray[Any, np.dtype[T]]
|
||||||
let ndarray_dtype_pyty =
|
let ndarray_dtype_pyty =
|
||||||
self.helper.args_ty_fn.call1(py, (args.get_item(1)?,))?;
|
self.helper.args_ty_fn.call1(py, (args.get_item(1)?,))?;
|
||||||
let dtype = ndarray_dtype_pyty.downcast::<PyTuple>(py)?.get_item(0)?;
|
let dtype = ndarray_dtype_pyty.downcast_bound::<PyTuple>(py)?.get_item(0)?;
|
||||||
|
|
||||||
let ty = match self.get_pyty_obj_type(py, dtype, unifier, defs, primitives)? {
|
let ty = match self.get_pyty_obj_type(
|
||||||
|
py,
|
||||||
|
dtype.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok(ty) => ty,
|
Ok(ty) => ty,
|
||||||
Err(err) => return Ok(Err(err)),
|
Err(err) => return Ok(Err(err)),
|
||||||
};
|
};
|
||||||
|
@ -539,7 +556,7 @@ impl InnerResolver {
|
||||||
TypeEnum::TTuple { .. } => {
|
TypeEnum::TTuple { .. } => {
|
||||||
let args = match args
|
let args = match args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| self.get_pyty_obj_type(py, x, unifier, defs, primitives))
|
.map(|x| self.get_pyty_obj_type(py, x.as_borrowed(), unifier, defs, primitives))
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, _>>() {
|
.collect::<Result<Vec<_>, _>>() {
|
||||||
|
@ -569,7 +586,7 @@ impl InnerResolver {
|
||||||
}
|
}
|
||||||
let args = match args
|
let args = match args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| self.get_pyty_obj_type(py, x, unifier, defs, primitives))
|
.map(|x| self.get_pyty_obj_type(py, x.as_borrowed(), unifier, defs, primitives))
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, _>>() {
|
.collect::<Result<Vec<_>, _>>() {
|
||||||
|
@ -596,7 +613,7 @@ impl InnerResolver {
|
||||||
if args.len() == 1 {
|
if args.len() == 1 {
|
||||||
let ty = match self.get_pyty_obj_type(
|
let ty = match self.get_pyty_obj_type(
|
||||||
py,
|
py,
|
||||||
args.get_item(0)?,
|
args.get_item(0)?.as_borrowed(),
|
||||||
unifier,
|
unifier,
|
||||||
defs,
|
defs,
|
||||||
primitives,
|
primitives,
|
||||||
|
@ -627,8 +644,7 @@ impl InnerResolver {
|
||||||
false,
|
false,
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
let str_fn =
|
let str_fn = PyModule::import_bound(py, "builtins").unwrap().getattr("repr").unwrap();
|
||||||
pyo3::types::PyModule::import(py, "builtins").unwrap().getattr("repr").unwrap();
|
|
||||||
let str_repr: String = str_fn.call1((pyty,)).unwrap().extract().unwrap();
|
let str_repr: String = str_fn.call1((pyty,)).unwrap().extract().unwrap();
|
||||||
Ok(Err(format!("{str_repr} is not registered with NAC3 (@nac3 decorator missing?)")))
|
Ok(Err(format!("{str_repr} is not registered with NAC3 (@nac3 decorator missing?)")))
|
||||||
}
|
}
|
||||||
|
@ -637,7 +653,7 @@ impl InnerResolver {
|
||||||
pub fn get_obj_type(
|
pub fn get_obj_type(
|
||||||
&self,
|
&self,
|
||||||
py: Python,
|
py: Python,
|
||||||
obj: &PyAny,
|
obj: Borrowed<PyAny>,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
defs: &[Arc<RwLock<TopLevelDef>>],
|
defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
primitives: &PrimitiveStore,
|
primitives: &PrimitiveStore,
|
||||||
|
@ -684,7 +700,7 @@ impl InnerResolver {
|
||||||
{
|
{
|
||||||
obj
|
obj
|
||||||
} else {
|
} else {
|
||||||
ty.as_ref(py)
|
ty.bind_borrowed(py)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unifier,
|
unifier,
|
||||||
|
@ -772,7 +788,8 @@ impl InnerResolver {
|
||||||
Ok(Ok(extracted_ty))
|
Ok(Ok(extracted_ty))
|
||||||
} else {
|
} else {
|
||||||
let dtype = obj.getattr("dtype")?.getattr("type")?;
|
let dtype = obj.getattr("dtype")?.getattr("type")?;
|
||||||
let dtype_ty = self.get_pyty_obj_type(py, dtype, unifier, defs, primitives)?;
|
let dtype_ty =
|
||||||
|
self.get_pyty_obj_type(py, dtype.as_borrowed(), unifier, defs, primitives)?;
|
||||||
match dtype_ty {
|
match dtype_ty {
|
||||||
Ok((t, _)) => match unifier.unify(ty, t) {
|
Ok((t, _)) => match unifier.unify(ty, t) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
@ -791,10 +808,12 @@ impl InnerResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(TypeEnum::TTuple { .. }, false) => {
|
(TypeEnum::TTuple { .. }, false) => {
|
||||||
let elements: &PyTuple = obj.downcast()?;
|
let elements = obj.downcast::<PyTuple>()?;
|
||||||
let types: Result<Result<Vec<_>, _>, _> = elements
|
let types: Result<Result<Vec<_>, _>, _> = elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))
|
.map(|elem| {
|
||||||
|
self.get_obj_type(py, elem.as_borrowed(), unifier, defs, primitives)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let types = types?;
|
let types = types?;
|
||||||
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
|
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
|
||||||
|
@ -828,7 +847,13 @@ impl InnerResolver {
|
||||||
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()));
|
return Ok(Ok(unifier.subst(primitives.option, &var_map).unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = match self.get_obj_type(py, field_data, unifier, defs, primitives)? {
|
let ty = match self.get_obj_type(
|
||||||
|
py,
|
||||||
|
field_data.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(Err(format!(
|
return Ok(Err(format!(
|
||||||
|
@ -863,8 +888,13 @@ impl InnerResolver {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => return Ok(Err(format!("{e}"))),
|
Err(e) => return Ok(Err(format!("{e}"))),
|
||||||
};
|
};
|
||||||
let ty =
|
let ty = match self.get_obj_type(
|
||||||
match self.get_obj_type(py, field_data, unifier, defs, primitives)? {
|
py,
|
||||||
|
field_data.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(Err(format!(
|
return Ok(Err(format!(
|
||||||
|
@ -903,32 +933,32 @@ impl InnerResolver {
|
||||||
// check integer bounds
|
// check integer bounds
|
||||||
if unifier.unioned(extracted_ty, primitives.int32) {
|
if unifier.unioned(extracted_ty, primitives.int32) {
|
||||||
obj.extract::<i32>().map_or_else(
|
obj.extract::<i32>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of int32"))),
|
|_| Ok(Err(format!("{} is not in the range of int32", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else if unifier.unioned(extracted_ty, primitives.int64) {
|
} else if unifier.unioned(extracted_ty, primitives.int64) {
|
||||||
obj.extract::<i64>().map_or_else(
|
obj.extract::<i64>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of int64"))),
|
|_| Ok(Err(format!("{} is not in the range of int64", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else if unifier.unioned(extracted_ty, primitives.uint32) {
|
} else if unifier.unioned(extracted_ty, primitives.uint32) {
|
||||||
obj.extract::<u32>().map_or_else(
|
obj.extract::<u32>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of uint32"))),
|
|_| Ok(Err(format!("{} is not in the range of uint32", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else if unifier.unioned(extracted_ty, primitives.uint64) {
|
} else if unifier.unioned(extracted_ty, primitives.uint64) {
|
||||||
obj.extract::<u64>().map_or_else(
|
obj.extract::<u64>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of uint64"))),
|
|_| Ok(Err(format!("{} is not in the range of uint64", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else if unifier.unioned(extracted_ty, primitives.bool) {
|
} else if unifier.unioned(extracted_ty, primitives.bool) {
|
||||||
obj.extract::<bool>().map_or_else(
|
obj.extract::<bool>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of bool"))),
|
|_| Ok(Err(format!("{} is not in the range of bool", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else if unifier.unioned(extracted_ty, primitives.float) {
|
} else if unifier.unioned(extracted_ty, primitives.float) {
|
||||||
obj.extract::<f64>().map_or_else(
|
obj.extract::<f64>().map_or_else(
|
||||||
|_| Ok(Err(format!("{obj} is not in the range of float64"))),
|
|_| Ok(Err(format!("{} is not in the range of float64", obj.as_unbound()))),
|
||||||
|_| Ok(Ok(extracted_ty)),
|
|_| Ok(Ok(extracted_ty)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -941,7 +971,7 @@ impl InnerResolver {
|
||||||
pub fn get_obj_value<'ctx>(
|
pub fn get_obj_value<'ctx>(
|
||||||
&self,
|
&self,
|
||||||
py: Python,
|
py: Python,
|
||||||
obj: &PyAny,
|
obj: Borrowed<PyAny>,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
expected_ty: Type,
|
expected_ty: Type,
|
||||||
|
@ -1004,15 +1034,19 @@ impl InnerResolver {
|
||||||
});
|
});
|
||||||
return Ok(Some(global.as_pointer_value().into()));
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
}
|
}
|
||||||
self.global_value_ids.write().insert(id, obj.into());
|
self.global_value_ids.write().insert(id, obj.as_unbound().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
let arr: Result<Option<Vec<_>>, _> = (0..len)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
obj.get_item(i).and_then(|elem| {
|
obj.get_item(i).and_then(|elem| {
|
||||||
self.get_obj_value(py, elem, ctx, generator, elem_ty).map_err(|e| {
|
self.get_obj_value(py, elem.as_borrowed(), ctx, generator, elem_ty).map_err(
|
||||||
super::CompileError::new_err(format!("Error getting element {i}: {e}"))
|
|e| {
|
||||||
})
|
super::CompileError::new_err(format!(
|
||||||
|
"Error getting element {i}: {e}"
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -1087,7 +1121,7 @@ impl InnerResolver {
|
||||||
});
|
});
|
||||||
return Ok(Some(global.as_pointer_value().into()));
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
}
|
}
|
||||||
self.global_value_ids.write().insert(id, obj.into());
|
self.global_value_ids.write().insert(id, obj.as_unbound().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndarray_ndims)
|
let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndarray_ndims)
|
||||||
|
@ -1105,15 +1139,23 @@ impl InnerResolver {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Obtain the shape of the ndarray
|
// Obtain the shape of the ndarray
|
||||||
let shape_tuple: &PyTuple = obj.getattr("shape")?.downcast()?;
|
let shape_tuple = obj.getattr("shape")?;
|
||||||
|
let shape_tuple = shape_tuple.downcast::<PyTuple>()?;
|
||||||
assert_eq!(shape_tuple.len(), ndarray_ndims as usize);
|
assert_eq!(shape_tuple.len(), ndarray_ndims as usize);
|
||||||
let shape_values: Result<Option<Vec<_>>, _> = shape_tuple
|
let shape_values: Result<Option<Vec<_>>, _> = shape_tuple
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, elem)| {
|
.map(|(i, elem)| {
|
||||||
self.get_obj_value(py, elem, ctx, generator, ctx.primitives.usize()).map_err(
|
self.get_obj_value(
|
||||||
|e| super::CompileError::new_err(format!("Error getting element {i}: {e}")),
|
py,
|
||||||
|
elem.as_borrowed(),
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
ctx.primitives.usize(),
|
||||||
)
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
super::CompileError::new_err(format!("Error getting element {i}: {e}"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let shape_values = shape_values?.unwrap();
|
let shape_values = shape_values?.unwrap();
|
||||||
|
@ -1134,8 +1176,11 @@ impl InnerResolver {
|
||||||
let data: Result<Option<Vec<_>>, _> = (0..sz)
|
let data: Result<Option<Vec<_>>, _> = (0..sz)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
obj.getattr("flat")?.get_item(i).and_then(|elem| {
|
obj.getattr("flat")?.get_item(i).and_then(|elem| {
|
||||||
self.get_obj_value(py, elem, ctx, generator, ndarray_dtype).map_err(|e| {
|
self.get_obj_value(py, elem.as_borrowed(), ctx, generator, ndarray_dtype)
|
||||||
super::CompileError::new_err(format!("Error getting element {i}: {e}"))
|
.map_err(|e| {
|
||||||
|
super::CompileError::new_err(format!(
|
||||||
|
"Error getting element {i}: {e}"
|
||||||
|
))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1199,14 +1244,14 @@ impl InnerResolver {
|
||||||
let TypeEnum::TTuple { ty } = expected_ty_enum.as_ref() else { unreachable!() };
|
let TypeEnum::TTuple { ty } = expected_ty_enum.as_ref() else { unreachable!() };
|
||||||
|
|
||||||
let tup_tys = ty.iter();
|
let tup_tys = ty.iter();
|
||||||
let elements: &PyTuple = obj.downcast()?;
|
let elements = obj.downcast::<PyTuple>()?;
|
||||||
assert_eq!(elements.len(), tup_tys.len());
|
assert_eq!(elements.len(), tup_tys.len());
|
||||||
let val: Result<Option<Vec<_>>, _> = elements
|
let val: Result<Option<Vec<_>>, _> = elements
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.zip(tup_tys)
|
.zip(tup_tys)
|
||||||
.map(|((i, elem), ty)| {
|
.map(|((i, elem), ty)| {
|
||||||
self.get_obj_value(py, elem, ctx, generator, *ty).map_err(|e| {
|
self.get_obj_value(py, elem.as_borrowed(), ctx, generator, *ty).map_err(|e| {
|
||||||
super::CompileError::new_err(format!("Error getting element {i}: {e}"))
|
super::CompileError::new_err(format!("Error getting element {i}: {e}"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1235,7 +1280,7 @@ impl InnerResolver {
|
||||||
match self
|
match self
|
||||||
.get_obj_value(
|
.get_obj_value(
|
||||||
py,
|
py,
|
||||||
obj.getattr("_nac3_option").unwrap(),
|
obj.getattr("_nac3_option").unwrap().as_borrowed(),
|
||||||
ctx,
|
ctx,
|
||||||
generator,
|
generator,
|
||||||
option_val_ty,
|
option_val_ty,
|
||||||
|
@ -1259,7 +1304,7 @@ impl InnerResolver {
|
||||||
});
|
});
|
||||||
return Ok(Some(global.as_pointer_value().into()));
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
}
|
}
|
||||||
self.global_value_ids.write().insert(id, obj.into());
|
self.global_value_ids.write().insert(id, obj.as_unbound().clone());
|
||||||
}
|
}
|
||||||
let global = ctx.module.add_global(
|
let global = ctx.module.add_global(
|
||||||
v.get_type(),
|
v.get_type(),
|
||||||
|
@ -1295,7 +1340,7 @@ impl InnerResolver {
|
||||||
});
|
});
|
||||||
return Ok(Some(global.as_pointer_value().into()));
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
}
|
}
|
||||||
self.global_value_ids.write().insert(id, obj.into());
|
self.global_value_ids.write().insert(id, obj.as_unbound().clone());
|
||||||
}
|
}
|
||||||
// should be classes
|
// should be classes
|
||||||
let definition =
|
let definition =
|
||||||
|
@ -1307,7 +1352,7 @@ impl InnerResolver {
|
||||||
.map(|(name, ty, _)| {
|
.map(|(name, ty, _)| {
|
||||||
self.get_obj_value(
|
self.get_obj_value(
|
||||||
py,
|
py,
|
||||||
obj.getattr(name.to_string().as_str())?,
|
obj.getattr(name.to_string().as_str())?.as_borrowed(),
|
||||||
ctx,
|
ctx,
|
||||||
generator,
|
generator,
|
||||||
*ty,
|
*ty,
|
||||||
|
@ -1334,7 +1379,7 @@ impl InnerResolver {
|
||||||
fn get_default_param_obj_value(
|
fn get_default_param_obj_value(
|
||||||
&self,
|
&self,
|
||||||
py: Python,
|
py: Python,
|
||||||
obj: &PyAny,
|
obj: Borrowed<PyAny>,
|
||||||
) -> PyResult<Result<SymbolValue, String>> {
|
) -> PyResult<Result<SymbolValue, String>> {
|
||||||
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
|
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
|
||||||
let ty_id: u64 =
|
let ty_id: u64 =
|
||||||
|
@ -1361,15 +1406,20 @@ impl InnerResolver {
|
||||||
let val: f64 = obj.extract()?;
|
let val: f64 = obj.extract()?;
|
||||||
Ok(SymbolValue::Double(val))
|
Ok(SymbolValue::Double(val))
|
||||||
} else if ty_id == self.primitive_ids.tuple {
|
} else if ty_id == self.primitive_ids.tuple {
|
||||||
let elements: &PyTuple = obj.downcast()?;
|
let elements = obj.downcast::<PyTuple>()?;
|
||||||
let elements: Result<Result<Vec<_>, String>, _> =
|
let elements: Result<Result<Vec<_>, String>, _> = elements
|
||||||
elements.iter().map(|elem| self.get_default_param_obj_value(py, elem)).collect();
|
.iter()
|
||||||
|
.map(|elem| self.get_default_param_obj_value(py, elem.as_borrowed()))
|
||||||
|
.collect();
|
||||||
elements?.map(SymbolValue::Tuple)
|
elements?.map(SymbolValue::Tuple)
|
||||||
} else if ty_id == self.primitive_ids.option {
|
} else if ty_id == self.primitive_ids.option {
|
||||||
if id == self.primitive_ids.none {
|
if id == self.primitive_ids.none {
|
||||||
Ok(SymbolValue::OptionNone)
|
Ok(SymbolValue::OptionNone)
|
||||||
} else {
|
} else {
|
||||||
self.get_default_param_obj_value(py, obj.getattr("_nac3_option").unwrap())?
|
self.get_default_param_obj_value(
|
||||||
|
py,
|
||||||
|
obj.getattr("_nac3_option").unwrap().as_borrowed(),
|
||||||
|
)?
|
||||||
.map(|v| SymbolValue::OptionSome(Box::new(v)))
|
.map(|v| SymbolValue::OptionSome(Box::new(v)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1385,13 +1435,14 @@ impl SymbolResolver for Resolver {
|
||||||
};
|
};
|
||||||
|
|
||||||
Python::with_gil(|py| -> PyResult<Option<SymbolValue>> {
|
Python::with_gil(|py| -> PyResult<Option<SymbolValue>> {
|
||||||
let obj: &PyAny = self.0.module.extract(py)?;
|
let obj = self.0.module.downcast_bound::<PyAny>(py)?;
|
||||||
let members: &PyDict = obj.getattr("__dict__").unwrap().downcast().unwrap();
|
let members = obj.getattr("__dict__").unwrap();
|
||||||
|
let members = members.downcast::<PyDict>().unwrap();
|
||||||
let mut sym_value = None;
|
let mut sym_value = None;
|
||||||
for (key, val) in members {
|
for (key, val) in members {
|
||||||
let key: &str = key.extract()?;
|
let key: &str = key.extract()?;
|
||||||
if key == id.to_string() {
|
if key == id.to_string() {
|
||||||
if let Ok(Ok(v)) = self.0.get_default_param_obj_value(py, val) {
|
if let Ok(Ok(v)) = self.0.get_default_param_obj_value(py, val.as_borrowed()) {
|
||||||
sym_value = Some(v);
|
sym_value = Some(v);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1425,13 +1476,20 @@ impl SymbolResolver for Resolver {
|
||||||
Ok(t)
|
Ok(t)
|
||||||
} else {
|
} else {
|
||||||
Python::with_gil(|py| -> PyResult<Result<Type, String>> {
|
Python::with_gil(|py| -> PyResult<Result<Type, String>> {
|
||||||
let obj: &PyAny = self.0.module.extract(py)?;
|
let obj = self.0.module.downcast_bound::<PyAny>(py)?;
|
||||||
let mut sym_ty = Err(format!("cannot find symbol `{str}`"));
|
let mut sym_ty = Err(format!("cannot find symbol `{str}`"));
|
||||||
let members: &PyDict = obj.getattr("__dict__").unwrap().downcast().unwrap();
|
let members = obj.getattr("__dict__").unwrap();
|
||||||
|
let members = members.downcast::<PyDict>().unwrap();
|
||||||
for (key, val) in members {
|
for (key, val) in members {
|
||||||
let key: &str = key.extract()?;
|
let key: &str = key.extract()?;
|
||||||
if key == str.to_string() {
|
if key == str.to_string() {
|
||||||
sym_ty = self.0.get_obj_type(py, val, unifier, defs, primitives)?;
|
sym_ty = self.0.get_obj_type(
|
||||||
|
py,
|
||||||
|
val.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1459,13 +1517,15 @@ impl SymbolResolver for Resolver {
|
||||||
}
|
}
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
Python::with_gil(|py| -> PyResult<Option<(u64, PyObject)>> {
|
Python::with_gil(|py| -> PyResult<Option<(u64, PyObject)>> {
|
||||||
let obj: &PyAny = self.0.module.extract(py)?;
|
let obj = self.0.module.downcast_bound::<PyAny>(py)?;
|
||||||
let mut sym_value: Option<(u64, PyObject)> = None;
|
let mut sym_value: Option<(u64, PyObject)> = None;
|
||||||
let members: &PyDict = obj.getattr("__dict__").unwrap().downcast().unwrap();
|
let members = obj.getattr("__dict__").unwrap();
|
||||||
|
let members = members.downcast::<PyDict>().unwrap();
|
||||||
for (key, val) in members {
|
for (key, val) in members {
|
||||||
let key: &str = key.extract()?;
|
let key: &str = key.extract()?;
|
||||||
if key == id.to_string() {
|
if key == id.to_string() {
|
||||||
let id = self.0.helper.id_fn.call1(py, (val,))?.extract(py)?;
|
let id =
|
||||||
|
self.0.helper.id_fn.call1(py, (val.as_borrowed(),))?.extract(py)?;
|
||||||
sym_value = Some((id, val.extract()?));
|
sym_value = Some((id, val.extract()?));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1534,10 +1594,16 @@ impl SymbolResolver for Resolver {
|
||||||
let store = self.0.deferred_eval_store.store.read();
|
let store = self.0.deferred_eval_store.store.read();
|
||||||
Python::with_gil(|py| -> PyResult<Result<(), String>> {
|
Python::with_gil(|py| -> PyResult<Result<(), String>> {
|
||||||
for (variables, constraints, name) in store.iter() {
|
for (variables, constraints, name) in store.iter() {
|
||||||
let constraints: &PyAny = constraints.as_ref(py);
|
let constraints = constraints.bind(py);
|
||||||
for (i, var) in variables.iter().enumerate() {
|
for (i, var) in variables.iter().enumerate() {
|
||||||
if let Ok(constr) = constraints.get_item(i) {
|
if let Ok(constr) = constraints.get_item(i) {
|
||||||
match self.0.get_pyty_obj_type(py, constr, unifier, defs, primitives)? {
|
match self.0.get_pyty_obj_type(
|
||||||
|
py,
|
||||||
|
constr.as_borrowed(),
|
||||||
|
unifier,
|
||||||
|
defs,
|
||||||
|
primitives,
|
||||||
|
)? {
|
||||||
Ok((ty, _)) => {
|
Ok((ty, _)) => {
|
||||||
if !unifier.is_concrete(ty, &[]) {
|
if !unifier.is_concrete(ty, &[]) {
|
||||||
return Ok(Err(format!(
|
return Ok(Err(format!(
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[features]
|
|
||||||
test = []
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nac3core"
|
name = "nac3core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::{
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
fn main() {
|
||||||
let irrt_cpp_path = irrt_dir.join("irrt.cpp");
|
const FILE: &str = "src/codegen/irrt/irrt.cpp";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HACK: Sadly, clang doesn't let us emit generic LLVM bitcode.
|
* HACK: Sadly, clang doesn't let us emit generic LLVM bitcode.
|
||||||
|
@ -16,9 +16,8 @@ fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
||||||
*/
|
*/
|
||||||
let flags: &[&str] = &[
|
let flags: &[&str] = &[
|
||||||
"--target=wasm32",
|
"--target=wasm32",
|
||||||
irrt_cpp_path.to_str().unwrap(),
|
FILE,
|
||||||
"-x",
|
"-x", "c++",
|
||||||
"c++",
|
|
||||||
"-fno-discard-value-names",
|
"-fno-discard-value-names",
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
@ -31,14 +30,13 @@ fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
||||||
"-S",
|
"-S",
|
||||||
"-Wall",
|
"-Wall",
|
||||||
"-Wextra",
|
"-Wextra",
|
||||||
"-Werror=return-type",
|
|
||||||
"-I",
|
|
||||||
irrt_dir.to_str().unwrap(),
|
|
||||||
"-o",
|
"-o",
|
||||||
"-",
|
"-",
|
||||||
];
|
];
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed={}", out_dir.to_str().unwrap());
|
println!("cargo:rerun-if-changed={FILE}");
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let out_path = Path::new(&out_dir);
|
||||||
|
|
||||||
let output = Command::new("clang-irrt")
|
let output = Command::new("clang-irrt")
|
||||||
.args(flags)
|
.args(flags)
|
||||||
|
@ -53,11 +51,7 @@ fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
||||||
let output = std::str::from_utf8(&output.stdout).unwrap().replace("\r\n", "\n");
|
let output = std::str::from_utf8(&output.stdout).unwrap().replace("\r\n", "\n");
|
||||||
let mut filtered_output = String::with_capacity(output.len());
|
let mut filtered_output = String::with_capacity(output.len());
|
||||||
|
|
||||||
// (?ms:^define.*?\}$) to capture `define` blocks
|
let regex_filter = Regex::new(r"(?ms:^define.*?\}$)|(?m:^declare.*?$)").unwrap();
|
||||||
// (?m:^declare.*?$) to capture `declare` blocks
|
|
||||||
// (?m:^%.+?=\s*type\s*\{.+?\}$) to capture `type` declarations
|
|
||||||
let regex_filter =
|
|
||||||
Regex::new(r"(?ms:^define.*?\}$)|(?m:^declare.*?$)|(?m:^%.+?=\s*type\s*\{.+?\}$)").unwrap();
|
|
||||||
for f in regex_filter.captures_iter(&output) {
|
for f in regex_filter.captures_iter(&output) {
|
||||||
assert_eq!(f.len(), 1);
|
assert_eq!(f.len(), 1);
|
||||||
filtered_output.push_str(&f[0]);
|
filtered_output.push_str(&f[0]);
|
||||||
|
@ -70,65 +64,18 @@ fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=DEBUG_DUMP_IRRT");
|
println!("cargo:rerun-if-env-changed=DEBUG_DUMP_IRRT");
|
||||||
if env::var("DEBUG_DUMP_IRRT").is_ok() {
|
if env::var("DEBUG_DUMP_IRRT").is_ok() {
|
||||||
let mut file = File::create(out_dir.join("irrt.ll")).unwrap();
|
let mut file = File::create(out_path.join("irrt.ll")).unwrap();
|
||||||
file.write_all(output.as_bytes()).unwrap();
|
file.write_all(output.as_bytes()).unwrap();
|
||||||
let mut file = File::create(out_dir.join("irrt-filtered.ll")).unwrap();
|
let mut file = File::create(out_path.join("irrt-filtered.ll")).unwrap();
|
||||||
file.write_all(filtered_output.as_bytes()).unwrap();
|
file.write_all(filtered_output.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut llvm_as = Command::new("llvm-as-irrt")
|
let mut llvm_as = Command::new("llvm-as-irrt")
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(out_dir.join("irrt.bc"))
|
.arg(out_path.join("irrt.bc"))
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
llvm_as.stdin.as_mut().unwrap().write_all(filtered_output.as_bytes()).unwrap();
|
llvm_as.stdin.as_mut().unwrap().write_all(filtered_output.as_bytes()).unwrap();
|
||||||
assert!(llvm_as.wait().unwrap().success());
|
assert!(llvm_as.wait().unwrap().success());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_irrt_test(irrt_dir: &Path, out_dir: &Path) {
|
|
||||||
let irrt_test_cpp_path = irrt_dir.join("irrt_test.cpp");
|
|
||||||
let exe_path = out_dir.join("irrt_test.out");
|
|
||||||
|
|
||||||
let flags: &[&str] = &[
|
|
||||||
irrt_test_cpp_path.to_str().unwrap(),
|
|
||||||
"-x",
|
|
||||||
"c++",
|
|
||||||
"-I",
|
|
||||||
irrt_dir.to_str().unwrap(),
|
|
||||||
"-g",
|
|
||||||
"-fno-discard-value-names",
|
|
||||||
"-O0",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Werror=return-type",
|
|
||||||
"-lm", // for `tgamma()`, `lgamma()`
|
|
||||||
"-o",
|
|
||||||
exe_path.to_str().unwrap(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Command::new("clang-irrt-test")
|
|
||||||
.args(flags)
|
|
||||||
.output()
|
|
||||||
.map(|o| {
|
|
||||||
assert!(o.status.success(), "{}", std::str::from_utf8(&o.stderr).unwrap());
|
|
||||||
o
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
println!("cargo:rerun-if-changed={}", out_dir.to_str().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
|
||||||
let out_dir = Path::new(&out_dir);
|
|
||||||
|
|
||||||
let irrt_dir = Path::new("./irrt");
|
|
||||||
|
|
||||||
compile_irrt(irrt_dir, out_dir);
|
|
||||||
|
|
||||||
// https://github.com/rust-lang/cargo/issues/2549
|
|
||||||
// `cargo test -F test` to also build `irrt_test.cpp
|
|
||||||
if cfg!(feature = "test") {
|
|
||||||
compile_irrt_test(irrt_dir, out_dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#include "irrt_everything.hpp"
|
|
||||||
|
|
||||||
/*
|
|
||||||
This file will be read by `clang-irrt` to conveniently produce LLVM IR for `nac3core/codegen`.
|
|
||||||
*/
|
|
|
@ -1,216 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrt_utils.hpp"
|
|
||||||
#include "irrt_typedefs.hpp"
|
|
||||||
|
|
||||||
/*
|
|
||||||
This header contains IRRT implementations
|
|
||||||
that do not deserved to be categorized (e.g., into numpy, etc.)
|
|
||||||
|
|
||||||
Check out other *.hpp files before including them here!!
|
|
||||||
*/
|
|
||||||
|
|
||||||
// The type of an index or a value describing the length of a range/slice is
|
|
||||||
// always `int32_t`.
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// adapted from GNU Scientific Library: https://git.savannah.gnu.org/cgit/gsl.git/tree/sys/pow_int.c
|
|
||||||
// need to make sure `exp >= 0` before calling this function
|
|
||||||
template <typename T>
|
|
||||||
T __nac3_int_exp_impl(T base, T exp) {
|
|
||||||
T res = 1;
|
|
||||||
/* repeated squaring method */
|
|
||||||
do {
|
|
||||||
if (exp & 1) {
|
|
||||||
res *= base; /* for n odd */
|
|
||||||
}
|
|
||||||
exp >>= 1;
|
|
||||||
base *= base;
|
|
||||||
} while (exp);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#define DEF_nac3_int_exp_(T) \
|
|
||||||
T __nac3_int_exp_##T(T base, T exp) {\
|
|
||||||
return __nac3_int_exp_impl(base, exp);\
|
|
||||||
}
|
|
||||||
|
|
||||||
DEF_nac3_int_exp_(int32_t)
|
|
||||||
DEF_nac3_int_exp_(int64_t)
|
|
||||||
DEF_nac3_int_exp_(uint32_t)
|
|
||||||
DEF_nac3_int_exp_(uint64_t)
|
|
||||||
|
|
||||||
SliceIndex __nac3_slice_index_bound(SliceIndex i, const SliceIndex len) {
|
|
||||||
if (i < 0) {
|
|
||||||
i = len + i;
|
|
||||||
}
|
|
||||||
if (i < 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (i > len) {
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
SliceIndex __nac3_range_slice_len(
|
|
||||||
const SliceIndex start,
|
|
||||||
const SliceIndex end,
|
|
||||||
const SliceIndex step
|
|
||||||
) {
|
|
||||||
SliceIndex diff = end - start;
|
|
||||||
if (diff > 0 && step > 0) {
|
|
||||||
return ((diff - 1) / step) + 1;
|
|
||||||
} else if (diff < 0 && step < 0) {
|
|
||||||
return ((diff + 1) / step) + 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle list assignment and dropping part of the list when
|
|
||||||
// both dest_step and src_step are +1.
|
|
||||||
// - All the index must *not* be out-of-bound or negative,
|
|
||||||
// - The end index is *inclusive*,
|
|
||||||
// - The length of src and dest slice size should already
|
|
||||||
// be checked: if dest.step == 1 then len(src) <= len(dest) else len(src) == len(dest)
|
|
||||||
SliceIndex __nac3_list_slice_assign_var_size(
|
|
||||||
SliceIndex dest_start,
|
|
||||||
SliceIndex dest_end,
|
|
||||||
SliceIndex dest_step,
|
|
||||||
uint8_t *dest_arr,
|
|
||||||
SliceIndex dest_arr_len,
|
|
||||||
SliceIndex src_start,
|
|
||||||
SliceIndex src_end,
|
|
||||||
SliceIndex src_step,
|
|
||||||
uint8_t *src_arr,
|
|
||||||
SliceIndex src_arr_len,
|
|
||||||
const SliceIndex size
|
|
||||||
) {
|
|
||||||
/* if dest_arr_len == 0, do nothing since we do not support extending list */
|
|
||||||
if (dest_arr_len == 0) return dest_arr_len;
|
|
||||||
/* if both step is 1, memmove directly, handle the dropping of the list, and shrink size */
|
|
||||||
if (src_step == dest_step && dest_step == 1) {
|
|
||||||
const SliceIndex src_len = (src_end >= src_start) ? (src_end - src_start + 1) : 0;
|
|
||||||
const SliceIndex dest_len = (dest_end >= dest_start) ? (dest_end - dest_start + 1) : 0;
|
|
||||||
if (src_len > 0) {
|
|
||||||
__builtin_memmove(
|
|
||||||
dest_arr + dest_start * size,
|
|
||||||
src_arr + src_start * size,
|
|
||||||
src_len * size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (dest_len > 0) {
|
|
||||||
/* dropping */
|
|
||||||
__builtin_memmove(
|
|
||||||
dest_arr + (dest_start + src_len) * size,
|
|
||||||
dest_arr + (dest_end + 1) * size,
|
|
||||||
(dest_arr_len - dest_end - 1) * size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/* shrink size */
|
|
||||||
return dest_arr_len - (dest_len - src_len);
|
|
||||||
}
|
|
||||||
/* if two range overlaps, need alloca */
|
|
||||||
uint8_t need_alloca =
|
|
||||||
(dest_arr == src_arr)
|
|
||||||
&& !(
|
|
||||||
max(dest_start, dest_end) < min(src_start, src_end)
|
|
||||||
|| max(src_start, src_end) < min(dest_start, dest_end)
|
|
||||||
);
|
|
||||||
if (need_alloca) {
|
|
||||||
uint8_t *tmp = reinterpret_cast<uint8_t *>(__builtin_alloca(src_arr_len * size));
|
|
||||||
__builtin_memcpy(tmp, src_arr, src_arr_len * size);
|
|
||||||
src_arr = tmp;
|
|
||||||
}
|
|
||||||
SliceIndex src_ind = src_start;
|
|
||||||
SliceIndex dest_ind = dest_start;
|
|
||||||
for (;
|
|
||||||
(src_step > 0) ? (src_ind <= src_end) : (src_ind >= src_end);
|
|
||||||
src_ind += src_step, dest_ind += dest_step
|
|
||||||
) {
|
|
||||||
/* for constant optimization */
|
|
||||||
if (size == 1) {
|
|
||||||
__builtin_memcpy(dest_arr + dest_ind, src_arr + src_ind, 1);
|
|
||||||
} else if (size == 4) {
|
|
||||||
__builtin_memcpy(dest_arr + dest_ind * 4, src_arr + src_ind * 4, 4);
|
|
||||||
} else if (size == 8) {
|
|
||||||
__builtin_memcpy(dest_arr + dest_ind * 8, src_arr + src_ind * 8, 8);
|
|
||||||
} else {
|
|
||||||
/* memcpy for var size, cannot overlap after previous alloca */
|
|
||||||
__builtin_memcpy(dest_arr + dest_ind * size, src_arr + src_ind * size, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* only dest_step == 1 can we shrink the dest list. */
|
|
||||||
/* size should be ensured prior to calling this function */
|
|
||||||
if (dest_step == 1 && dest_end >= dest_start) {
|
|
||||||
__builtin_memmove(
|
|
||||||
dest_arr + dest_ind * size,
|
|
||||||
dest_arr + (dest_end + 1) * size,
|
|
||||||
(dest_arr_len - dest_end - 1) * size
|
|
||||||
);
|
|
||||||
return dest_arr_len - (dest_end - dest_ind) - 1;
|
|
||||||
}
|
|
||||||
return dest_arr_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t __nac3_isinf(double x) {
|
|
||||||
return __builtin_isinf(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t __nac3_isnan(double x) {
|
|
||||||
return __builtin_isnan(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
double tgamma(double arg);
|
|
||||||
|
|
||||||
double __nac3_gamma(double z) {
|
|
||||||
// Handling for denormals
|
|
||||||
// | x | Python gamma(x) | C tgamma(x) |
|
|
||||||
// --- | ----------------- | --------------- | ----------- |
|
|
||||||
// (1) | nan | nan | nan |
|
|
||||||
// (2) | -inf | -inf | inf |
|
|
||||||
// (3) | inf | inf | inf |
|
|
||||||
// (4) | 0.0 | inf | inf |
|
|
||||||
// (5) | {-1.0, -2.0, ...} | inf | nan |
|
|
||||||
|
|
||||||
// (1)-(3)
|
|
||||||
if (__builtin_isinf(z) || __builtin_isnan(z)) {
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
double v = tgamma(z);
|
|
||||||
|
|
||||||
// (4)-(5)
|
|
||||||
return __builtin_isinf(v) || __builtin_isnan(v) ? __builtin_inf() : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
double lgamma(double arg);
|
|
||||||
|
|
||||||
double __nac3_gammaln(double x) {
|
|
||||||
// libm's handling of value overflows differs from scipy:
|
|
||||||
// - scipy: gammaln(-inf) -> -inf
|
|
||||||
// - libm : lgamma(-inf) -> inf
|
|
||||||
|
|
||||||
if (__builtin_isinf(x)) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lgamma(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
double j0(double x);
|
|
||||||
|
|
||||||
double __nac3_j0(double x) {
|
|
||||||
// libm's handling of value overflows differs from scipy:
|
|
||||||
// - scipy: j0(inf) -> nan
|
|
||||||
// - libm : j0(inf) -> 0.0
|
|
||||||
|
|
||||||
if (__builtin_isinf(x)) {
|
|
||||||
return __builtin_nan("");
|
|
||||||
}
|
|
||||||
|
|
||||||
return j0(x);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrt_utils.hpp"
|
|
||||||
#include "irrt_typedefs.hpp"
|
|
||||||
#include "irrt_basic.hpp"
|
|
||||||
#include "irrt_slice.hpp"
|
|
||||||
#include "irrt_numpy_ndarray.hpp"
|
|
||||||
|
|
||||||
/*
|
|
||||||
All IRRT implementations.
|
|
||||||
|
|
||||||
We don't have any pre-compiled objects, so we are writing all implementations in headers and
|
|
||||||
concatenate them with `#include` into one massive source file that contains all the IRRT stuff.
|
|
||||||
*/
|
|
|
@ -1,466 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrt_utils.hpp"
|
|
||||||
#include "irrt_typedefs.hpp"
|
|
||||||
#include "irrt_slice.hpp"
|
|
||||||
|
|
||||||
/*
|
|
||||||
NDArray-related implementations.
|
|
||||||
`*/
|
|
||||||
|
|
||||||
// NDArray indices are always `uint32_t`.
|
|
||||||
using NDIndex = uint32_t;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
namespace ndarray_util {
|
|
||||||
template <typename SizeT>
|
|
||||||
static void set_indices_by_nth(SizeT ndims, const SizeT* shape, SizeT* indices, SizeT nth) {
|
|
||||||
for (int32_t i = 0; i < ndims; i++) {
|
|
||||||
int32_t dim_i = ndims - i - 1;
|
|
||||||
int32_t dim = shape[dim_i];
|
|
||||||
|
|
||||||
indices[dim_i] = nth % dim;
|
|
||||||
nth /= dim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the strides of an ndarray given an ndarray `shape`
|
|
||||||
// and assuming that the ndarray is *fully C-contagious*.
|
|
||||||
//
|
|
||||||
// You might want to read up on https://ajcr.net/stride-guide-part-1/.
|
|
||||||
template <typename SizeT>
|
|
||||||
static void set_strides_by_shape(SizeT itemsize, SizeT ndims, SizeT* dst_strides, const SizeT* shape) {
|
|
||||||
SizeT stride_product = 1;
|
|
||||||
for (SizeT i = 0; i < ndims; i++) {
|
|
||||||
int dim_i = ndims - i - 1;
|
|
||||||
dst_strides[dim_i] = stride_product * itemsize;
|
|
||||||
stride_product *= shape[dim_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the size/# of elements of an ndarray given its shape
|
|
||||||
template <typename SizeT>
|
|
||||||
static SizeT calc_size_from_shape(SizeT ndims, const SizeT* shape) {
|
|
||||||
SizeT size = 1;
|
|
||||||
for (SizeT dim_i = 0; dim_i < ndims; dim_i++) size *= shape[dim_i];
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename SizeT>
|
|
||||||
static bool can_broadcast_shape_to(
|
|
||||||
const SizeT target_ndims,
|
|
||||||
const SizeT *target_shape,
|
|
||||||
const SizeT src_ndims,
|
|
||||||
const SizeT *src_shape
|
|
||||||
) {
|
|
||||||
/*
|
|
||||||
// See https://numpy.org/doc/stable/user/basics.broadcasting.html
|
|
||||||
|
|
||||||
This function handles this example:
|
|
||||||
```
|
|
||||||
Image (3d array): 256 x 256 x 3
|
|
||||||
Scale (1d array): 3
|
|
||||||
Result (3d array): 256 x 256 x 3
|
|
||||||
```
|
|
||||||
|
|
||||||
Other interesting examples to consider:
|
|
||||||
- `can_broadcast_shape_to([3], [1, 1, 1, 1, 3]) == true`
|
|
||||||
- `can_broadcast_shape_to([3], [3, 1]) == false`
|
|
||||||
- `can_broadcast_shape_to([256, 256, 3], [256, 1, 3]) == true`
|
|
||||||
|
|
||||||
In cases when the shapes contain zero(es):
|
|
||||||
- `can_broadcast_shape_to([0], [1]) == true`
|
|
||||||
- `can_broadcast_shape_to([0], [2]) == false`
|
|
||||||
- `can_broadcast_shape_to([0, 4, 0, 0], [1]) == true`
|
|
||||||
- `can_broadcast_shape_to([0, 4, 0, 0], [1, 1, 1, 1]) == true`
|
|
||||||
- `can_broadcast_shape_to([0, 4, 0, 0], [1, 4, 1, 1]) == true`
|
|
||||||
- `can_broadcast_shape_to([4, 3], [0, 3]) == false`
|
|
||||||
- `can_broadcast_shape_to([4, 3], [0, 0]) == false`
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This is essentially doing the following in Python:
|
|
||||||
// `for target_dim, src_dim in itertools.zip_longest(target_shape[::-1], src_shape[::-1], fillvalue=1)`
|
|
||||||
for (SizeT i = 0; i < max(target_ndims, src_ndims); i++) {
|
|
||||||
SizeT target_dim_i = target_ndims - i - 1;
|
|
||||||
SizeT src_dim_i = src_ndims - i - 1;
|
|
||||||
|
|
||||||
bool target_dim_exists = target_dim_i >= 0;
|
|
||||||
bool src_dim_exists = src_dim_i >= 0;
|
|
||||||
|
|
||||||
SizeT target_dim = target_dim_exists ? target_shape[target_dim_i] : 1;
|
|
||||||
SizeT src_dim = src_dim_exists ? src_shape[src_dim_i] : 1;
|
|
||||||
|
|
||||||
bool ok = src_dim == 1 || target_dim == src_dim;
|
|
||||||
if (!ok) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef uint8_t NDSliceType;
|
|
||||||
extern "C" {
|
|
||||||
const NDSliceType INPUT_SLICE_TYPE_INDEX = 0;
|
|
||||||
const NDSliceType INPUT_SLICE_TYPE_SLICE = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NDSlice {
|
|
||||||
// A poor-man's `std::variant<int, UserRange>`
|
|
||||||
NDSliceType type;
|
|
||||||
|
|
||||||
/*
|
|
||||||
if type == INPUT_SLICE_TYPE_INDEX => `slice` points to a single `SizeT`
|
|
||||||
if type == INPUT_SLICE_TYPE_SLICE => `slice` points to a single `UserRange`
|
|
||||||
*/
|
|
||||||
uint8_t *slice;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ndarray_util {
|
|
||||||
template<typename SizeT>
|
|
||||||
SizeT deduce_ndims_after_slicing(SizeT ndims, SizeT num_slices, const NDSlice *slices) {
|
|
||||||
irrt_assert(num_slices <= ndims);
|
|
||||||
|
|
||||||
SizeT final_ndims = ndims;
|
|
||||||
for (SizeT i = 0; i < num_slices; i++) {
|
|
||||||
if (slices[i].type == INPUT_SLICE_TYPE_INDEX) {
|
|
||||||
final_ndims--; // An integer slice demotes the rank by 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return final_ndims;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename SizeT>
|
|
||||||
struct NDArrayIndicesIter {
|
|
||||||
SizeT ndims;
|
|
||||||
const SizeT *shape;
|
|
||||||
SizeT *indices;
|
|
||||||
|
|
||||||
void set_indices_zero() {
|
|
||||||
__builtin_memset(indices, 0, sizeof(SizeT) * ndims);
|
|
||||||
}
|
|
||||||
|
|
||||||
void next() {
|
|
||||||
for (SizeT i = 0; i < ndims; i++) {
|
|
||||||
SizeT dim_i = ndims - i - 1;
|
|
||||||
|
|
||||||
indices[dim_i]++;
|
|
||||||
if (indices[dim_i] < shape[dim_i]) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
indices[dim_i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The NDArray object. `SizeT` is the *signed* size type of this ndarray.
|
|
||||||
//
|
|
||||||
// NOTE: The order of fields is IMPORTANT. DON'T TOUCH IT
|
|
||||||
//
|
|
||||||
// Some resources you might find helpful:
|
|
||||||
// - The official numpy implementations:
|
|
||||||
// - https://github.com/numpy/numpy/blob/735a477f0bc2b5b84d0e72d92f224bde78d4e069/doc/source/reference/c-api/types-and-structures.rst
|
|
||||||
// - On strides (about reshaping, slicing, C-contagiousness, etc)
|
|
||||||
// - https://ajcr.net/stride-guide-part-1/.
|
|
||||||
// - https://ajcr.net/stride-guide-part-2/.
|
|
||||||
// - https://ajcr.net/stride-guide-part-3/.
|
|
||||||
template <typename SizeT>
|
|
||||||
struct NDArray {
|
|
||||||
// The underlying data this `ndarray` is pointing to.
|
|
||||||
//
|
|
||||||
// NOTE: Formally this should be of type `void *`, but clang
|
|
||||||
// translates `void *` to `i8 *` when run with `-S -emit-llvm`,
|
|
||||||
// so we will put `uint8_t *` here for clarity.
|
|
||||||
uint8_t *data;
|
|
||||||
|
|
||||||
// The number of bytes of a single element in `data`.
|
|
||||||
//
|
|
||||||
// The `SizeT` is treated as `unsigned`.
|
|
||||||
SizeT itemsize;
|
|
||||||
|
|
||||||
// The number of dimensions of this shape.
|
|
||||||
//
|
|
||||||
// The `SizeT` is treated as `unsigned`.
|
|
||||||
SizeT ndims;
|
|
||||||
|
|
||||||
// Array shape, with length equal to `ndims`.
|
|
||||||
//
|
|
||||||
// The `SizeT` is treated as `unsigned`.
|
|
||||||
//
|
|
||||||
// NOTE: `shape` can contain 0.
|
|
||||||
// (those appear when the user makes an out of bounds slice into an ndarray, e.g., `np.zeros((3, 3))[400:].shape == (0, 3)`)
|
|
||||||
SizeT *shape;
|
|
||||||
|
|
||||||
// Array strides (stride value is in number of bytes, NOT number of elements), with length equal to `ndims`.
|
|
||||||
//
|
|
||||||
// The `SizeT` is treated as `signed`.
|
|
||||||
//
|
|
||||||
// NOTE: `strides` can have negative numbers.
|
|
||||||
// (those appear when there is a slice with a negative step, e.g., `my_array[::-1]`)
|
|
||||||
SizeT *strides;
|
|
||||||
|
|
||||||
// Calculate the size/# of elements of an `ndarray`.
|
|
||||||
// This function corresponds to `np.size(<ndarray>)` or `ndarray.size`
|
|
||||||
SizeT size() {
|
|
||||||
return ndarray_util::calc_size_from_shape(ndims, shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the number of bytes of its content of an `ndarray` *in its view*.
|
|
||||||
// This function corresponds to `ndarray.nbytes`
|
|
||||||
SizeT nbytes() {
|
|
||||||
return this->size() * itemsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_value_at_pelement(uint8_t* pelement, const uint8_t* pvalue) {
|
|
||||||
__builtin_memcpy(pelement, pvalue, itemsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* get_pelement(const SizeT *indices) {
|
|
||||||
uint8_t* element = data;
|
|
||||||
for (SizeT dim_i = 0; dim_i < ndims; dim_i++)
|
|
||||||
element += indices[dim_i] * strides[dim_i];
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* get_nth_pelement(SizeT nth) {
|
|
||||||
irrt_assert(0 <= nth);
|
|
||||||
irrt_assert(nth < this->size());
|
|
||||||
|
|
||||||
SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * this->ndims);
|
|
||||||
ndarray_util::set_indices_by_nth(this->ndims, this->shape, indices, nth);
|
|
||||||
return get_pelement(indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get pointer to the first element of this ndarray, assuming
|
|
||||||
// `this->size() > 0`, i.e., not "degenerate" due to zeroes in `this->shape`)
|
|
||||||
//
|
|
||||||
// This is particularly useful for when the ndarray is just containing a single scalar.
|
|
||||||
uint8_t* get_first_pelement() {
|
|
||||||
irrt_assert(this->size() > 0);
|
|
||||||
return this->data; // ...It is simply `this->data`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the given `indices` valid/in-bounds?
|
|
||||||
bool in_bounds(const SizeT *indices) {
|
|
||||||
for (SizeT dim_i = 0; dim_i < ndims; dim_i++) {
|
|
||||||
bool dim_ok = indices[dim_i] < shape[dim_i];
|
|
||||||
if (!dim_ok) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the ndarray with a value
|
|
||||||
void fill_generic(const uint8_t* pvalue) {
|
|
||||||
NDArrayIndicesIter<SizeT> iter;
|
|
||||||
iter.ndims = this->ndims;
|
|
||||||
iter.shape = this->shape;
|
|
||||||
iter.indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * ndims);
|
|
||||||
iter.set_indices_zero();
|
|
||||||
|
|
||||||
for (SizeT i = 0; i < this->size(); i++, iter.next()) {
|
|
||||||
uint8_t* pelement = get_pelement(iter.indices);
|
|
||||||
set_value_at_pelement(pelement, pvalue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the strides of the ndarray with `ndarray_util::set_strides_by_shape`
|
|
||||||
void set_strides_by_shape() {
|
|
||||||
ndarray_util::set_strides_by_shape(itemsize, ndims, strides, shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://numpy.org/doc/stable/reference/generated/numpy.eye.html
|
|
||||||
void set_to_eye(SizeT k, const uint8_t* zero_pvalue, const uint8_t* one_pvalue) {
|
|
||||||
__builtin_assume(ndims == 2);
|
|
||||||
|
|
||||||
// TODO: Better implementation
|
|
||||||
|
|
||||||
fill_generic(zero_pvalue);
|
|
||||||
for (SizeT i = 0; i < min(shape[0], shape[1]); i++) {
|
|
||||||
SizeT row = i;
|
|
||||||
SizeT col = i + k;
|
|
||||||
SizeT indices[2] = { row, col };
|
|
||||||
|
|
||||||
if (!in_bounds(indices)) continue;
|
|
||||||
|
|
||||||
uint8_t* pelement = get_pelement(indices);
|
|
||||||
set_value_at_pelement(pelement, one_pvalue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To support numpy complex slices (e.g., `my_array[:50:2,4,:2:-1]`)
|
|
||||||
//
|
|
||||||
// Things assumed by this function:
|
|
||||||
// - `dst_ndarray` is allocated by the caller
|
|
||||||
// - `dst_ndarray.ndims` has the correct value (according to `ndarray_util::deduce_ndims_after_slicing`).
|
|
||||||
// - ... and `dst_ndarray.shape` and `dst_ndarray.strides` have been allocated by the caller as well
|
|
||||||
//
|
|
||||||
// Other notes:
|
|
||||||
// - `dst_ndarray->data` does not have to be set, it will be derived.
|
|
||||||
// - `dst_ndarray->itemsize` does not have to be set, it will be set to `this->itemsize`
|
|
||||||
// - `dst_ndarray->shape` and `dst_ndarray.strides` can contain empty values
|
|
||||||
void slice(SizeT num_ndslices, NDSlice* ndslices, NDArray<SizeT>* dst_ndarray) {
|
|
||||||
// REFERENCE CODE (check out `_index_helper` in `__getitem__`):
|
|
||||||
// https://github.com/wadetb/tinynumpy/blob/0d23d22e07062ffab2afa287374c7b366eebdda1/tinynumpy/tinynumpy.py#L652
|
|
||||||
|
|
||||||
irrt_assert(dst_ndarray->ndims == ndarray_util::deduce_ndims_after_slicing(this->ndims, num_ndslices, ndslices));
|
|
||||||
|
|
||||||
dst_ndarray->data = this->data;
|
|
||||||
|
|
||||||
SizeT this_axis = 0;
|
|
||||||
SizeT dst_axis = 0;
|
|
||||||
|
|
||||||
for (SizeT i = 0; i < num_ndslices; i++) {
|
|
||||||
NDSlice *ndslice = &ndslices[i];
|
|
||||||
if (ndslice->type == INPUT_SLICE_TYPE_INDEX) {
|
|
||||||
// Handle when the ndslice is just a single (possibly negative) integer
|
|
||||||
// e.g., `my_array[::2, -5, ::-1]`
|
|
||||||
// ^^------ like this
|
|
||||||
SizeT index_user = *((SizeT*) ndslice->slice);
|
|
||||||
SizeT index = resolve_index_in_length(this->shape[this_axis], index_user);
|
|
||||||
dst_ndarray->data += index * this->strides[this_axis]; // Add offset
|
|
||||||
|
|
||||||
// Next
|
|
||||||
this_axis++;
|
|
||||||
} else if (ndslice->type == INPUT_SLICE_TYPE_SLICE) {
|
|
||||||
// Handle when the ndslice is a slice (represented by UserSlice in IRRT)
|
|
||||||
// e.g., `my_array[::2, -5, ::-1]`
|
|
||||||
// ^^^------^^^^----- like these
|
|
||||||
UserSlice<SizeT>* user_slice = (UserSlice<SizeT>*) ndslice->slice;
|
|
||||||
Slice<SizeT> slice = user_slice->indices(this->shape[this_axis]); // To resolve negative indices and other funny stuff written by the user
|
|
||||||
|
|
||||||
// NOTE: There is no need to write special code to handle negative steps/strides.
|
|
||||||
// This simple implementation meticulously handles both positive and negative steps/strides.
|
|
||||||
// Check out the tinynumpy and IRRT's test cases if you are not convinced.
|
|
||||||
dst_ndarray->data += slice.start * this->strides[this_axis]; // Add offset (NOTE: no need to `* itemsize`, strides count in # of bytes)
|
|
||||||
dst_ndarray->strides[dst_axis] = slice.step * this->strides[this_axis]; // Determine stride
|
|
||||||
dst_ndarray->shape[dst_axis] = slice.len(); // Determine shape dimension
|
|
||||||
|
|
||||||
// Next
|
|
||||||
dst_axis++;
|
|
||||||
this_axis++;
|
|
||||||
} else {
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irrt_assert(dst_axis == dst_ndarray->ndims); // Sanity check on the implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to `np.broadcast_to(<ndarray>, <target_shape>)`
|
|
||||||
// Assumptions:
|
|
||||||
// - `this` has to be fully initialized.
|
|
||||||
// - `dst_ndarray->ndims` has to be set.
|
|
||||||
// - `dst_ndarray->shape` has to be set, this determines the shape `this` broadcasts to.
|
|
||||||
//
|
|
||||||
// Other notes:
|
|
||||||
// - `dst_ndarray->data` does not have to be set, it will be set to `this->data`.
|
|
||||||
// - `dst_ndarray->itemsize` does not have to be set, it will be set to `this->data`.
|
|
||||||
// - `dst_ndarray->strides` does not have to be set, it will be overwritten.
|
|
||||||
//
|
|
||||||
// Cautions:
|
|
||||||
// ```
|
|
||||||
// xs = np.zeros((4,))
|
|
||||||
// ys = np.zero((4, 1))
|
|
||||||
// ys[:] = xs # ok
|
|
||||||
//
|
|
||||||
// xs = np.zeros((1, 4))
|
|
||||||
// ys = np.zero((4,))
|
|
||||||
// ys[:] = xs # allowed
|
|
||||||
// # However `np.broadcast_to(xs, (4,))` would fails, as per numpy's broadcasting rule.
|
|
||||||
// # and apparently numpy will "deprecate" this? SEE https://github.com/numpy/numpy/issues/21744
|
|
||||||
// # This implementation will NOT support this assignment.
|
|
||||||
// ```
|
|
||||||
void broadcast_to(NDArray<SizeT>* dst_ndarray) {
|
|
||||||
dst_ndarray->data = this->data;
|
|
||||||
dst_ndarray->itemsize = this->itemsize;
|
|
||||||
|
|
||||||
irrt_assert(
|
|
||||||
ndarray_util::can_broadcast_shape_to(
|
|
||||||
dst_ndarray->ndims,
|
|
||||||
dst_ndarray->shape,
|
|
||||||
this->ndims,
|
|
||||||
this->shape
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
SizeT stride_product = 1;
|
|
||||||
for (SizeT i = 0; i < max(this->ndims, dst_ndarray->ndims); i++) {
|
|
||||||
SizeT this_dim_i = this->ndims - i - 1;
|
|
||||||
SizeT dst_dim_i = dst_ndarray->ndims - i - 1;
|
|
||||||
|
|
||||||
bool this_dim_exists = this_dim_i >= 0;
|
|
||||||
bool dst_dim_exists = dst_dim_i >= 0;
|
|
||||||
|
|
||||||
// TODO: Explain how this works
|
|
||||||
bool c1 = this_dim_exists && this->shape[this_dim_i] == 1;
|
|
||||||
bool c2 = dst_dim_exists && dst_ndarray->shape[dst_dim_i] != 1;
|
|
||||||
if (!this_dim_exists || (c1 && c2)) {
|
|
||||||
dst_ndarray->strides[dst_dim_i] = 0; // Freeze it in-place
|
|
||||||
} else {
|
|
||||||
dst_ndarray->strides[dst_dim_i] = stride_product * this->itemsize;
|
|
||||||
stride_product *= this->shape[this_dim_i]; // NOTE: this_dim_exist must be true here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulates `this_ndarray[:] = src_ndarray`, with automatic broadcasting.
|
|
||||||
// Caution on https://github.com/numpy/numpy/issues/21744
|
|
||||||
// Also see `NDArray::broadcast_to`
|
|
||||||
void assign_with(NDArray<SizeT>* src_ndarray) {
|
|
||||||
irrt_assert(
|
|
||||||
ndarray_util::can_broadcast_shape_to(
|
|
||||||
this->ndims,
|
|
||||||
this->shape,
|
|
||||||
src_ndarray->ndims,
|
|
||||||
src_ndarray->shape
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Broadcast the `src_ndarray` to make the reading process *much* easier
|
|
||||||
SizeT* broadcasted_src_ndarray_strides = __builtin_alloca(sizeof(SizeT) * this->ndims); // Remember to allocate strides beforehand
|
|
||||||
NDArray<SizeT> broadcasted_src_ndarray = {
|
|
||||||
.ndims = this->ndims,
|
|
||||||
.shape = this->shape,
|
|
||||||
.strides = broadcasted_src_ndarray_strides
|
|
||||||
};
|
|
||||||
src_ndarray->broadcast_to(&broadcasted_src_ndarray);
|
|
||||||
|
|
||||||
// Using iter instead of `get_nth_pelement` because it is slightly faster
|
|
||||||
SizeT* indices = __builtin_alloca(sizeof(SizeT) * this->ndims);
|
|
||||||
auto iter = NDArrayIndicesIter<SizeT> {
|
|
||||||
.ndims = this->ndims,
|
|
||||||
.shape = this->shape,
|
|
||||||
.indices = indices
|
|
||||||
};
|
|
||||||
const SizeT this_size = this->size();
|
|
||||||
for (SizeT i = 0; i < this_size; i++, iter.next()) {
|
|
||||||
uint8_t* src_pelement = broadcasted_src_ndarray_strides->get_pelement(indices);
|
|
||||||
uint8_t* this_pelement = this->get_pelement(indices);
|
|
||||||
this->set_value_at_pelement(src_pelement, src_pelement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
uint32_t __nac3_ndarray_size(NDArray<int32_t>* ndarray) {
|
|
||||||
return ndarray->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t __nac3_ndarray_size64(NDArray<int64_t>* ndarray) {
|
|
||||||
return ndarray->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void __nac3_ndarray_fill_generic(NDArray<int32_t>* ndarray, uint8_t* pvalue) {
|
|
||||||
ndarray->fill_generic(pvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __nac3_ndarray_fill_generic64(NDArray<int64_t>* ndarray, uint8_t* pvalue) {
|
|
||||||
ndarray->fill_generic(pvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// void __nac3_ndarray_slice(NDArray<int32_t>* ndarray, int32_t num_slices, NDSlice<int32_t> *slices, NDArray<int32_t> *dst_ndarray) {
|
|
||||||
// // ndarray->slice(num_slices, slices, dst_ndarray);
|
|
||||||
// }
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrt_utils.hpp"
|
|
||||||
#include "irrt_typedefs.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// A proper slice in IRRT, all negative indices have be resolved to absolute values.
|
|
||||||
// Even though nac3core's slices are always `int32_t`, we will template slice anyway
|
|
||||||
// since this struct is used as a general utility.
|
|
||||||
template <typename T>
|
|
||||||
struct Slice {
|
|
||||||
T start;
|
|
||||||
T stop;
|
|
||||||
T step;
|
|
||||||
|
|
||||||
// The length/The number of elements of the slice if it were a range,
|
|
||||||
// i.e., the value of `len(range(this->start, this->stop, this->end))`
|
|
||||||
T len() {
|
|
||||||
T diff = stop - start;
|
|
||||||
if (diff > 0 && step > 0) {
|
|
||||||
return ((diff - 1) / step) + 1;
|
|
||||||
} else if (diff < 0 && step < 0) {
|
|
||||||
return ((diff + 1) / step) + 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T resolve_index_in_length(T length, T index) {
|
|
||||||
irrt_assert(length >= 0);
|
|
||||||
if (index < 0) {
|
|
||||||
// Remember that index is negative, so do a plus here
|
|
||||||
return max(length + index, 0);
|
|
||||||
} else {
|
|
||||||
return min(length, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: using a bitfield for the `*_defined` is better, at the
|
|
||||||
// cost of a more annoying implementation in nac3core inkwell
|
|
||||||
template <typename T>
|
|
||||||
struct UserSlice {
|
|
||||||
uint8_t start_defined;
|
|
||||||
T start;
|
|
||||||
|
|
||||||
uint8_t stop_defined;
|
|
||||||
T stop;
|
|
||||||
|
|
||||||
uint8_t step_defined;
|
|
||||||
T step;
|
|
||||||
|
|
||||||
// Like Python's `slice(start, stop, step).indices(length)`
|
|
||||||
Slice<T> indices(T length) {
|
|
||||||
// NOTE: This function implements Python's `slice.indices` *FAITHFULLY*.
|
|
||||||
// SEE: https://github.com/python/cpython/blob/f62161837e68c1c77961435f1b954412dd5c2b65/Objects/sliceobject.c#L546
|
|
||||||
irrt_assert(length >= 0);
|
|
||||||
irrt_assert(!step_defined || step != 0); // step_defined -> step != 0; step cannot be zero if specified by user
|
|
||||||
|
|
||||||
Slice<T> result;
|
|
||||||
result.step = step_defined ? step : 1;
|
|
||||||
bool step_is_negative = result.step < 0;
|
|
||||||
|
|
||||||
if (start_defined) {
|
|
||||||
result.start = resolve_index_in_length(length, start);
|
|
||||||
} else {
|
|
||||||
result.start = step_is_negative ? length - 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop_defined) {
|
|
||||||
result.stop = resolve_index_in_length(length, stop);
|
|
||||||
} else {
|
|
||||||
result.stop = step_is_negative ? -1 : length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,658 +0,0 @@
|
||||||
// This file will be compiled like a real C++ program,
|
|
||||||
// and we do have the luxury to use the standard libraries.
|
|
||||||
// That is if the nix flakes do not have issues... especially on msys2...
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
// Set `IRRT_DONT_TYPEDEF_INTS` because `cstdint` defines them
|
|
||||||
#define IRRT_DONT_TYPEDEF_INTS
|
|
||||||
#include "irrt_everything.hpp"
|
|
||||||
|
|
||||||
void test_fail() {
|
|
||||||
printf("[!] Test failed\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __begin_test(const char* function_name, const char* file, int line) {
|
|
||||||
printf("######### Running %s @ %s:%d\n", function_name, file, line);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BEGIN_TEST() __begin_test(__FUNCTION__, __FILE__, __LINE__)
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void debug_print_array(const char* format, int len, T* as) {
|
|
||||||
printf("[");
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (i != 0) printf(", ");
|
|
||||||
printf(format, as[i]);
|
|
||||||
}
|
|
||||||
printf("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void assert_arrays_match(const char* label, const char* format, int len, T* expected, T* got) {
|
|
||||||
if (!arrays_match(len, expected, got)) {
|
|
||||||
printf(">>>>>>> %s\n", label);
|
|
||||||
printf(" Expecting = ");
|
|
||||||
debug_print_array(format, len, expected);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Got = ");
|
|
||||||
debug_print_array(format, len, got);
|
|
||||||
printf("\n");
|
|
||||||
test_fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void assert_values_match(const char* label, const char* format, T expected, T got) {
|
|
||||||
if (expected != got) {
|
|
||||||
printf(">>>>>>> %s\n", label);
|
|
||||||
printf(" Expecting = ");
|
|
||||||
printf(format, expected);
|
|
||||||
printf("\n");
|
|
||||||
printf(" Got = ");
|
|
||||||
printf(format, got);
|
|
||||||
printf("\n");
|
|
||||||
test_fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_repeated(const char *str, int count) {
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
printf("%s", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename SizeT, typename ElementT>
|
|
||||||
void __print_ndarray_aux(const char *format, bool first, bool last, SizeT* cursor, SizeT depth, NDArray<SizeT>* ndarray) {
|
|
||||||
// A really lazy recursive implementation
|
|
||||||
|
|
||||||
// Add left padding unless its the first entry (since there would be "[[[" before it)
|
|
||||||
if (!first) {
|
|
||||||
print_repeated(" ", depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
const SizeT dim = ndarray->shape[depth];
|
|
||||||
if (depth + 1 == ndarray->ndims) {
|
|
||||||
// Recursed down to last dimension, print the values in a nice list
|
|
||||||
printf("[");
|
|
||||||
|
|
||||||
SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * ndarray->ndims);
|
|
||||||
for (SizeT i = 0; i < dim; i++) {
|
|
||||||
ndarray_util::set_indices_by_nth(ndarray->ndims, ndarray->shape, indices, *cursor);
|
|
||||||
ElementT* pelement = (ElementT*) ndarray->get_pelement(indices);
|
|
||||||
ElementT element = *pelement;
|
|
||||||
|
|
||||||
if (i != 0) printf(", "); // List delimiter
|
|
||||||
printf(format, element);
|
|
||||||
printf("(@");
|
|
||||||
debug_print_array("%d", ndarray->ndims, indices);
|
|
||||||
printf(")");
|
|
||||||
|
|
||||||
(*cursor)++;
|
|
||||||
}
|
|
||||||
printf("]");
|
|
||||||
} else {
|
|
||||||
printf("[");
|
|
||||||
for (SizeT i = 0; i < ndarray->shape[depth]; i++) {
|
|
||||||
__print_ndarray_aux<SizeT, ElementT>(
|
|
||||||
format,
|
|
||||||
i == 0, // first?
|
|
||||||
i + 1 == dim, // last?
|
|
||||||
cursor,
|
|
||||||
depth + 1,
|
|
||||||
ndarray
|
|
||||||
);
|
|
||||||
}
|
|
||||||
printf("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add newline unless its the last entry (since there will be "]]]" after it)
|
|
||||||
if (!last) {
|
|
||||||
print_repeated("\n", depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename SizeT, typename ElementT>
|
|
||||||
void print_ndarray(const char *format, NDArray<SizeT>* ndarray) {
|
|
||||||
if (ndarray->ndims == 0) {
|
|
||||||
printf("<empty ndarray>");
|
|
||||||
} else {
|
|
||||||
SizeT cursor = 0;
|
|
||||||
__print_ndarray_aux<SizeT, ElementT>(format, true, true, &cursor, 0, ndarray);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_calc_size_from_shape_normal() {
|
|
||||||
// Test shapes with normal values
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
int32_t shape[4] = { 2, 3, 5, 7 };
|
|
||||||
assert_values_match("size", "%d", 210, ndarray_util::calc_size_from_shape<int32_t>(4, shape));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_calc_size_from_shape_has_zero() {
|
|
||||||
// Test shapes with 0 in them
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
int32_t shape[4] = { 2, 0, 5, 7 };
|
|
||||||
assert_values_match("size", "%d", 0, ndarray_util::calc_size_from_shape<int32_t>(4, shape));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_set_strides_by_shape() {
|
|
||||||
// Test `set_strides_by_shape()`
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
int32_t shape[4] = { 99, 3, 5, 7 };
|
|
||||||
int32_t strides[4] = { 0 };
|
|
||||||
ndarray_util::set_strides_by_shape((int32_t) sizeof(int32_t), 4, strides, shape);
|
|
||||||
|
|
||||||
int32_t expected_strides[4] = {
|
|
||||||
105 * sizeof(int32_t),
|
|
||||||
35 * sizeof(int32_t),
|
|
||||||
7 * sizeof(int32_t),
|
|
||||||
1 * sizeof(int32_t)
|
|
||||||
};
|
|
||||||
assert_arrays_match("strides", "%u", 4u, expected_strides, strides);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndarray_indices_iter_normal() {
|
|
||||||
// Test NDArrayIndicesIter normal behavior
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
int32_t shape[3] = { 1, 2, 3 };
|
|
||||||
int32_t indices[3] = { 0, 0, 0 };
|
|
||||||
auto iter = NDArrayIndicesIter<int32_t> {
|
|
||||||
.ndims = 3,
|
|
||||||
.shape = shape,
|
|
||||||
.indices = indices
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_arrays_match("indices #0", "%u", 3u, iter.indices, (int32_t[3]) { 0, 0, 0 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #1", "%u", 3u, iter.indices, (int32_t[3]) { 0, 0, 1 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #2", "%u", 3u, iter.indices, (int32_t[3]) { 0, 0, 2 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #3", "%u", 3u, iter.indices, (int32_t[3]) { 0, 1, 0 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #4", "%u", 3u, iter.indices, (int32_t[3]) { 0, 1, 1 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #5", "%u", 3u, iter.indices, (int32_t[3]) { 0, 1, 2 });
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #6", "%u", 3u, iter.indices, (int32_t[3]) { 0, 0, 0 }); // Loops back
|
|
||||||
iter.next();
|
|
||||||
assert_arrays_match("indices #7", "%u", 3u, iter.indices, (int32_t[3]) { 0, 0, 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndarray_fill_generic() {
|
|
||||||
// Test ndarray fill_generic
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
// Choose a type that's neither int32_t nor uint64_t (candidates of SizeT) to spice it up
|
|
||||||
// Also make all the octets non-zero, to see if `memcpy` in `fill_generic` is working perfectly.
|
|
||||||
uint16_t fill_value = 0xFACE;
|
|
||||||
|
|
||||||
uint16_t in_data[6] = { 100, 101, 102, 103, 104, 105 }; // Fill `data` with values that != `999`
|
|
||||||
int32_t in_itemsize = sizeof(uint16_t);
|
|
||||||
const int32_t in_ndims = 2;
|
|
||||||
int32_t in_shape[in_ndims] = { 2, 3 };
|
|
||||||
int32_t in_strides[in_ndims] = {};
|
|
||||||
NDArray<int32_t> ndarray = {
|
|
||||||
.data = (uint8_t*) in_data,
|
|
||||||
.itemsize = in_itemsize,
|
|
||||||
.ndims = in_ndims,
|
|
||||||
.shape = in_shape,
|
|
||||||
.strides = in_strides,
|
|
||||||
};
|
|
||||||
ndarray.set_strides_by_shape();
|
|
||||||
ndarray.fill_generic((uint8_t*) &fill_value); // `fill_generic` here
|
|
||||||
|
|
||||||
uint16_t expected_data[6] = { fill_value, fill_value, fill_value, fill_value, fill_value, fill_value };
|
|
||||||
assert_arrays_match("data", "0x%hX", 6, expected_data, in_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndarray_set_to_eye() {
|
|
||||||
// Test `set_to_eye` behavior (helper function to implement `np.eye()`)
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
double in_data[9] = { 99.0, 99.0, 99.0, 99.0, 99.0, 99.0, 99.0, 99.0, 99.0 };
|
|
||||||
int32_t in_itemsize = sizeof(double);
|
|
||||||
const int32_t in_ndims = 2;
|
|
||||||
int32_t in_shape[in_ndims] = { 3, 3 };
|
|
||||||
int32_t in_strides[in_ndims] = {};
|
|
||||||
NDArray<int32_t> ndarray = {
|
|
||||||
.data = (uint8_t*) in_data,
|
|
||||||
.itemsize = in_itemsize,
|
|
||||||
.ndims = in_ndims,
|
|
||||||
.shape = in_shape,
|
|
||||||
.strides = in_strides,
|
|
||||||
};
|
|
||||||
ndarray.set_strides_by_shape();
|
|
||||||
|
|
||||||
double zero = 0.0;
|
|
||||||
double one = 1.0;
|
|
||||||
ndarray.set_to_eye(1, (uint8_t*) &zero, (uint8_t*) &one);
|
|
||||||
|
|
||||||
assert_values_match("in_data[0]", "%f", 0.0, in_data[0]);
|
|
||||||
assert_values_match("in_data[1]", "%f", 1.0, in_data[1]);
|
|
||||||
assert_values_match("in_data[2]", "%f", 0.0, in_data[2]);
|
|
||||||
assert_values_match("in_data[3]", "%f", 0.0, in_data[3]);
|
|
||||||
assert_values_match("in_data[4]", "%f", 0.0, in_data[4]);
|
|
||||||
assert_values_match("in_data[5]", "%f", 1.0, in_data[5]);
|
|
||||||
assert_values_match("in_data[6]", "%f", 0.0, in_data[6]);
|
|
||||||
assert_values_match("in_data[7]", "%f", 0.0, in_data[7]);
|
|
||||||
assert_values_match("in_data[8]", "%f", 0.0, in_data[8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_slice_1() {
|
|
||||||
// Test `slice(5, None, None).indices(100) == slice(5, 100, 1)`
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
UserSlice<int> user_slice = {
|
|
||||||
.start_defined = 1,
|
|
||||||
.start = 5,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto slice = user_slice.indices(100);
|
|
||||||
assert_values_match("start", "%d", 5, slice.start);
|
|
||||||
assert_values_match("stop", "%d", 100, slice.stop);
|
|
||||||
assert_values_match("step", "%d", 1, slice.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_slice_2() {
|
|
||||||
// Test `slice(400, 999, None).indices(100) == slice(100, 100, 1)`
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
UserSlice<int> user_slice = {
|
|
||||||
.start_defined = 1,
|
|
||||||
.start = 400,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto slice = user_slice.indices(100);
|
|
||||||
assert_values_match("start", "%d", 100, slice.start);
|
|
||||||
assert_values_match("stop", "%d", 100, slice.stop);
|
|
||||||
assert_values_match("step", "%d", 1, slice.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_slice_3() {
|
|
||||||
// Test `slice(-10, -5, None).indices(100) == slice(90, 95, 1)`
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
UserSlice<int> user_slice = {
|
|
||||||
.start_defined = 1,
|
|
||||||
.start = -10,
|
|
||||||
.stop_defined = 1,
|
|
||||||
.stop = -5,
|
|
||||||
.step_defined = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto slice = user_slice.indices(100);
|
|
||||||
assert_values_match("start", "%d", 90, slice.start);
|
|
||||||
assert_values_match("stop", "%d", 95, slice.stop);
|
|
||||||
assert_values_match("step", "%d", 1, slice.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_slice_4() {
|
|
||||||
// Test `slice(None, None, -5).indices(100) == (99, -1, -5)`
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
UserSlice<int> user_slice = {
|
|
||||||
.start_defined = 0,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 1,
|
|
||||||
.step = -5
|
|
||||||
};
|
|
||||||
|
|
||||||
auto slice = user_slice.indices(100);
|
|
||||||
assert_values_match("start", "%d", 99, slice.start);
|
|
||||||
assert_values_match("stop", "%d", -1, slice.stop);
|
|
||||||
assert_values_match("step", "%d", -5, slice.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndslice_1() {
|
|
||||||
/*
|
|
||||||
Reference Python code:
|
|
||||||
```python
|
|
||||||
ndarray = np.arange(12, dtype=np.float64).reshape((3, 4));
|
|
||||||
# array([[ 0., 1., 2., 3.],
|
|
||||||
# [ 4., 5., 6., 7.],
|
|
||||||
# [ 8., 9., 10., 11.]])
|
|
||||||
|
|
||||||
dst_ndarray = ndarray[-2:, 1::2]
|
|
||||||
# array([[ 5., 7.],
|
|
||||||
# [ 9., 11.]])
|
|
||||||
|
|
||||||
assert dst_ndarray.shape == (2, 2)
|
|
||||||
assert dst_ndarray.strides == (32, 16)
|
|
||||||
assert dst_ndarray[0, 0] == 5.0
|
|
||||||
assert dst_ndarray[0, 1] == 7.0
|
|
||||||
assert dst_ndarray[1, 0] == 9.0
|
|
||||||
assert dst_ndarray[1, 1] == 11.0
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
double in_data[12] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 };
|
|
||||||
int32_t in_itemsize = sizeof(double);
|
|
||||||
const int32_t in_ndims = 2;
|
|
||||||
int32_t in_shape[in_ndims] = { 3, 4 };
|
|
||||||
int32_t in_strides[in_ndims] = {};
|
|
||||||
NDArray<int32_t> ndarray = {
|
|
||||||
.data = (uint8_t*) in_data,
|
|
||||||
.itemsize = in_itemsize,
|
|
||||||
.ndims = in_ndims,
|
|
||||||
.shape = in_shape,
|
|
||||||
.strides = in_strides
|
|
||||||
};
|
|
||||||
ndarray.set_strides_by_shape();
|
|
||||||
|
|
||||||
// Destination ndarray
|
|
||||||
// As documented, ndims and shape & strides must be allocated and determined by the caller.
|
|
||||||
const int32_t dst_ndims = 2;
|
|
||||||
int32_t dst_shape[dst_ndims] = {999, 999}; // Empty values
|
|
||||||
int32_t dst_strides[dst_ndims] = {999, 999}; // Empty values
|
|
||||||
NDArray<int32_t> dst_ndarray = {
|
|
||||||
.data = nullptr,
|
|
||||||
.ndims = dst_ndims,
|
|
||||||
.shape = dst_shape,
|
|
||||||
.strides = dst_strides
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the slice in `ndarray[-2::, 1::2]`
|
|
||||||
UserSlice<int32_t> user_slice_1 = {
|
|
||||||
.start_defined = 1,
|
|
||||||
.start = -2,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
UserSlice<int32_t> user_slice_2 = {
|
|
||||||
.start_defined = 1,
|
|
||||||
.start = 1,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 1,
|
|
||||||
.step = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
const int32_t num_ndslices = 2;
|
|
||||||
NDSlice ndslices[num_ndslices] = {
|
|
||||||
{ .type = INPUT_SLICE_TYPE_SLICE, .slice = (uint8_t*) &user_slice_1 },
|
|
||||||
{ .type = INPUT_SLICE_TYPE_SLICE, .slice = (uint8_t*) &user_slice_2 }
|
|
||||||
};
|
|
||||||
|
|
||||||
ndarray.slice(num_ndslices, ndslices, &dst_ndarray);
|
|
||||||
|
|
||||||
int32_t expected_shape[dst_ndims] = { 2, 2 };
|
|
||||||
int32_t expected_strides[dst_ndims] = { 32, 16 };
|
|
||||||
assert_arrays_match("shape", "%d", dst_ndims, expected_shape, dst_ndarray.shape);
|
|
||||||
assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides);
|
|
||||||
|
|
||||||
assert_values_match("dst_ndarray[0, 0]", "%f", 5.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0, 0 })));
|
|
||||||
assert_values_match("dst_ndarray[0, 1]", "%f", 7.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0, 1 })));
|
|
||||||
assert_values_match("dst_ndarray[1, 0]", "%f", 9.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1, 0 })));
|
|
||||||
assert_values_match("dst_ndarray[1, 1]", "%f", 11.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1, 1 })));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndslice_2() {
|
|
||||||
/*
|
|
||||||
```python
|
|
||||||
ndarray = np.arange(12, dtype=np.float64).reshape((3, 4))
|
|
||||||
# array([[ 0., 1., 2., 3.],
|
|
||||||
# [ 4., 5., 6., 7.],
|
|
||||||
# [ 8., 9., 10., 11.]])
|
|
||||||
|
|
||||||
dst_ndarray = ndarray[2, ::-2]
|
|
||||||
# array([11., 9.])
|
|
||||||
|
|
||||||
assert dst_ndarray.shape == (2,)
|
|
||||||
assert dst_ndarray.strides == (-16,)
|
|
||||||
assert dst_ndarray[0] == 11.0
|
|
||||||
assert dst_ndarray[1] == 9.0
|
|
||||||
|
|
||||||
dst_ndarray[1, 0] == 99 # If you write to `dst_ndarray`
|
|
||||||
assert ndarray[1, 3] == 99 # `ndarray` also updates!!
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
double in_data[12] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 };
|
|
||||||
int32_t in_itemsize = sizeof(double);
|
|
||||||
const int32_t in_ndims = 2;
|
|
||||||
int32_t in_shape[in_ndims] = { 3, 4 };
|
|
||||||
int32_t in_strides[in_ndims] = {};
|
|
||||||
NDArray<int32_t> ndarray = {
|
|
||||||
.data = (uint8_t*) in_data,
|
|
||||||
.itemsize = in_itemsize,
|
|
||||||
.ndims = in_ndims,
|
|
||||||
.shape = in_shape,
|
|
||||||
.strides = in_strides
|
|
||||||
};
|
|
||||||
ndarray.set_strides_by_shape();
|
|
||||||
|
|
||||||
// Destination ndarray
|
|
||||||
// As documented, ndims and shape & strides must be allocated and determined by the caller.
|
|
||||||
const int32_t dst_ndims = 1;
|
|
||||||
int32_t dst_shape[dst_ndims] = {999}; // Empty values
|
|
||||||
int32_t dst_strides[dst_ndims] = {999}; // Empty values
|
|
||||||
NDArray<int32_t> dst_ndarray = {
|
|
||||||
.data = nullptr,
|
|
||||||
.ndims = dst_ndims,
|
|
||||||
.shape = dst_shape,
|
|
||||||
.strides = dst_strides
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the slice in `ndarray[2, ::-2]`
|
|
||||||
int32_t user_slice_1 = 2;
|
|
||||||
UserSlice<int32_t> user_slice_2 = {
|
|
||||||
.start_defined = 0,
|
|
||||||
.stop_defined = 0,
|
|
||||||
.step_defined = 1,
|
|
||||||
.step = -2
|
|
||||||
};
|
|
||||||
|
|
||||||
const int32_t num_ndslices = 2;
|
|
||||||
NDSlice ndslices[num_ndslices] = {
|
|
||||||
{ .type = INPUT_SLICE_TYPE_INDEX, .slice = (uint8_t*) &user_slice_1 },
|
|
||||||
{ .type = INPUT_SLICE_TYPE_SLICE, .slice = (uint8_t*) &user_slice_2 }
|
|
||||||
};
|
|
||||||
|
|
||||||
ndarray.slice(num_ndslices, ndslices, &dst_ndarray);
|
|
||||||
|
|
||||||
int32_t expected_shape[dst_ndims] = { 2 };
|
|
||||||
int32_t expected_strides[dst_ndims] = { -16 };
|
|
||||||
assert_arrays_match("shape", "%d", dst_ndims, expected_shape, dst_ndarray.shape);
|
|
||||||
assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides);
|
|
||||||
|
|
||||||
// [5.0, 3.0]
|
|
||||||
assert_values_match("dst_ndarray[0]", "%f", 11.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0 })));
|
|
||||||
assert_values_match("dst_ndarray[1]", "%f", 9.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1 })));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_can_broadcast_shape() {
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([3], [1, 1, 1, 1, 3]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 3 }, 5, (int32_t[]) { 1, 1, 1, 1, 3 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([3], [3, 1]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 3 }, 2, (int32_t[]) { 3, 1 }));
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([3], [3]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 3 }, 1, (int32_t[]) { 3 }));
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([1], [3]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 1 }, 1, (int32_t[]) { 3 }));
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([1], [1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 1 }, 1, (int32_t[]) { 1 }));
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([256, 256, 3], [256, 1, 3]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(3, (int32_t[]) { 256, 256, 3 }, 3, (int32_t[]) { 256, 1, 3 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([256, 256, 3], [3]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(3, (int32_t[]) { 256, 256, 3 }, 1, (int32_t[]) { 3 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([256, 256, 3], [2]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(3, (int32_t[]) { 256, 256, 3 }, 1, (int32_t[]) { 2 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([256, 256, 3], [1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(3, (int32_t[]) { 256, 256, 3 }, 1, (int32_t[]) { 1 })
|
|
||||||
);
|
|
||||||
|
|
||||||
// In cases when the shapes contain zero(es)
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([0], [1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 0 }, 1, (int32_t[]) { 1 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([0], [2]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(1, (int32_t[]) { 0 }, 1, (int32_t[]) { 2 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([0, 4, 0, 0], [1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(4, (int32_t[]) { 0, 4, 0, 0 }, 1, (int32_t[]) { 1 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([0, 4, 0, 0], [1, 1, 1, 1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(4, (int32_t[]) { 0, 4, 0, 0 }, 4, (int32_t[]) { 1, 1, 1, 1 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([0, 4, 0, 0], [1, 4, 1, 1]) == true",
|
|
||||||
"%d",
|
|
||||||
true,
|
|
||||||
ndarray_util::can_broadcast_shape_to(4, (int32_t[]) { 0, 4, 0, 0 }, 4, (int32_t[]) { 1, 4, 1, 1 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([4, 3], [0, 3]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(2, (int32_t[]) { 4, 3 }, 2, (int32_t[]) { 0, 3 })
|
|
||||||
);
|
|
||||||
assert_values_match(
|
|
||||||
"can_broadcast_shape_to([4, 3], [0, 0]) == false",
|
|
||||||
"%d",
|
|
||||||
false,
|
|
||||||
ndarray_util::can_broadcast_shape_to(2, (int32_t[]) { 4, 3 }, 2, (int32_t[]) { 0, 0 })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_ndarray_broadcast_1() {
|
|
||||||
/*
|
|
||||||
# array = np.array([[19.9, 29.9, 39.9, 49.9]], dtype=np.float64)
|
|
||||||
# >>> [[19.9 29.9 39.9 49.9]]
|
|
||||||
#
|
|
||||||
# array = np.broadcast_to(array, (2, 3, 4))
|
|
||||||
# >>> [[[19.9 29.9 39.9 49.9]
|
|
||||||
# >>> [19.9 29.9 39.9 49.9]
|
|
||||||
# >>> [19.9 29.9 39.9 49.9]]
|
|
||||||
# >>> [[19.9 29.9 39.9 49.9]
|
|
||||||
# >>> [19.9 29.9 39.9 49.9]
|
|
||||||
# >>> [19.9 29.9 39.9 49.9]]]
|
|
||||||
#
|
|
||||||
# assery array.strides == (0, 0, 8)
|
|
||||||
|
|
||||||
*/
|
|
||||||
BEGIN_TEST();
|
|
||||||
|
|
||||||
double in_data[4] = { 19.9, 29.9, 39.9, 49.9 };
|
|
||||||
const int32_t in_ndims = 2;
|
|
||||||
int32_t in_shape[in_ndims] = {1, 4};
|
|
||||||
int32_t in_strides[in_ndims] = {};
|
|
||||||
NDArray<int32_t> ndarray = {
|
|
||||||
.data = (uint8_t*) in_data,
|
|
||||||
.itemsize = sizeof(double),
|
|
||||||
.ndims = in_ndims,
|
|
||||||
.shape = in_shape,
|
|
||||||
.strides = in_strides
|
|
||||||
};
|
|
||||||
ndarray.set_strides_by_shape();
|
|
||||||
|
|
||||||
const int32_t dst_ndims = 3;
|
|
||||||
int32_t dst_shape[dst_ndims] = {2, 3, 4};
|
|
||||||
int32_t dst_strides[dst_ndims] = {};
|
|
||||||
NDArray<int32_t> dst_ndarray = {
|
|
||||||
.ndims = dst_ndims,
|
|
||||||
.shape = dst_shape,
|
|
||||||
.strides = dst_strides
|
|
||||||
};
|
|
||||||
|
|
||||||
ndarray.broadcast_to(&dst_ndarray);
|
|
||||||
|
|
||||||
assert_arrays_match("dst_ndarray->strides", "%d", dst_ndims, (int32_t[]) { 0, 0, 8 }, dst_ndarray.strides);
|
|
||||||
|
|
||||||
assert_values_match("dst_ndarray[0, 0, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 0})));
|
|
||||||
assert_values_match("dst_ndarray[0, 0, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 1})));
|
|
||||||
assert_values_match("dst_ndarray[0, 0, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 2})));
|
|
||||||
assert_values_match("dst_ndarray[0, 0, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 3})));
|
|
||||||
assert_values_match("dst_ndarray[0, 1, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 0})));
|
|
||||||
assert_values_match("dst_ndarray[0, 1, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 1})));
|
|
||||||
assert_values_match("dst_ndarray[0, 1, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 2})));
|
|
||||||
assert_values_match("dst_ndarray[0, 1, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 3})));
|
|
||||||
assert_values_match("dst_ndarray[1, 2, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {1, 2, 3})));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_assign_with() {
|
|
||||||
/*
|
|
||||||
```
|
|
||||||
xs = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]], dtype=np.float64)
|
|
||||||
ys = xs.shape
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
test_calc_size_from_shape_normal();
|
|
||||||
test_calc_size_from_shape_has_zero();
|
|
||||||
test_set_strides_by_shape();
|
|
||||||
test_ndarray_indices_iter_normal();
|
|
||||||
test_ndarray_fill_generic();
|
|
||||||
test_ndarray_set_to_eye();
|
|
||||||
test_slice_1();
|
|
||||||
test_slice_2();
|
|
||||||
test_slice_3();
|
|
||||||
test_slice_4();
|
|
||||||
test_ndslice_1();
|
|
||||||
test_ndslice_2();
|
|
||||||
test_can_broadcast_shape();
|
|
||||||
test_ndarray_broadcast_1();
|
|
||||||
test_assign_with();
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// This is made toggleable since `irrt_test.cpp` itself would include
|
|
||||||
// headers that define the `int_t` family.
|
|
||||||
#ifndef IRRT_DONT_TYPEDEF_INTS
|
|
||||||
typedef _BitInt(8) int8_t;
|
|
||||||
typedef unsigned _BitInt(8) uint8_t;
|
|
||||||
typedef _BitInt(32) int32_t;
|
|
||||||
typedef unsigned _BitInt(32) uint32_t;
|
|
||||||
typedef _BitInt(64) int64_t;
|
|
||||||
typedef unsigned _BitInt(64) uint64_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int32_t SliceIndex;
|
|
|
@ -1,37 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "irrt_typedefs.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
template <typename T>
|
|
||||||
T max(T a, T b) {
|
|
||||||
return a > b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T min(T a, T b) {
|
|
||||||
return a > b ? b : a;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool arrays_match(int len, T *as, T *bs) {
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (as[i] != bs[i]) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void irrt_panic() {
|
|
||||||
// Crash the program for now.
|
|
||||||
// TODO: Don't crash the program
|
|
||||||
// ... or at least produce a good message when doing testing IRRT
|
|
||||||
|
|
||||||
uint8_t* death = nullptr;
|
|
||||||
*death = 0; // TODO: address 0 on hardware might be writable?
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this a macro and allow it to be toggled on/off (e.g., debug vs release)
|
|
||||||
void irrt_assert(bool condition) {
|
|
||||||
if (!condition) irrt_panic();
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,8 @@
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
llvm_intrinsics::call_int_umin, stmt::gen_for_callback_incrementing, CodeGenContext,
|
irrt::{call_ndarray_calc_size, call_ndarray_flatten_index},
|
||||||
CodeGenerator,
|
llvm_intrinsics::call_int_umin,
|
||||||
|
stmt::gen_for_callback_incrementing,
|
||||||
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::types::{ArrayType, BasicType, StructType};
|
use inkwell::types::{ArrayType, BasicType, StructType};
|
||||||
|
@ -10,7 +12,6 @@ use inkwell::{
|
||||||
values::{BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
/// A LLVM type that is used to represent a non-primitive type in NAC3.
|
/// A LLVM type that is used to represent a non-primitive type in NAC3.
|
||||||
pub trait ProxyType<'ctx>: Into<Self::Base> {
|
pub trait ProxyType<'ctx>: Into<Self::Base> {
|
||||||
|
@ -1600,8 +1601,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> {
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
generator: &G,
|
generator: &G,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
todo!()
|
call_ndarray_calc_size(generator, ctx, &self.as_slice_value(ctx, generator), (None, None))
|
||||||
// call_ndarray_calc_size(generator, ctx, &self.as_slice_value(ctx, generator), (None, None))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1675,19 +1675,17 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
|
||||||
indices_elem_ty.get_bit_width()
|
indices_elem_ty.get_bit_width()
|
||||||
);
|
);
|
||||||
|
|
||||||
todo!()
|
let index = call_ndarray_flatten_index(generator, ctx, *self.0, indices);
|
||||||
|
|
||||||
// let index = call_ndarray_flatten_index(generator, ctx, *self.0, indices);
|
unsafe {
|
||||||
|
ctx.builder
|
||||||
// unsafe {
|
.build_in_bounds_gep(
|
||||||
// ctx.builder
|
self.base_ptr(ctx, generator),
|
||||||
// .build_in_bounds_gep(
|
&[index],
|
||||||
// self.base_ptr(ctx, generator),
|
name.unwrap_or_default(),
|
||||||
// &[index],
|
)
|
||||||
// name.unwrap_or_default(),
|
.unwrap()
|
||||||
// )
|
}
|
||||||
// .unwrap()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr_offset<G: CodeGenerator + ?Sized>(
|
fn ptr_offset<G: CodeGenerator + ?Sized>(
|
||||||
|
@ -1763,307 +1761,3 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeMutator<'ctx,
|
||||||
for NDArrayDataProxy<'ctx, '_>
|
for NDArrayDataProxy<'ctx, '_>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct StructField<'ctx> {
|
|
||||||
/// The GEP index of this struct field.
|
|
||||||
pub gep_index: u32,
|
|
||||||
/// Name of this struct field.
|
|
||||||
///
|
|
||||||
/// Used for generating names.
|
|
||||||
pub name: &'static str,
|
|
||||||
/// The type of this struct field.
|
|
||||||
pub ty: BasicTypeEnum<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StructFields<'ctx> {
|
|
||||||
/// Name of the struct.
|
|
||||||
///
|
|
||||||
/// Used for generating names.
|
|
||||||
pub name: &'static str,
|
|
||||||
|
|
||||||
/// All the [`StructField`]s of this struct.
|
|
||||||
///
|
|
||||||
/// **NOTE:** The index position of a [`StructField`]
|
|
||||||
/// matches the element's [`StructField::index`].
|
|
||||||
pub fields: Vec<StructField<'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StructFieldsBuilder<'ctx> {
|
|
||||||
gep_index_counter: u32,
|
|
||||||
/// Name of the struct to be built.
|
|
||||||
name: &'static str,
|
|
||||||
fields: Vec<StructField<'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> StructField<'ctx> {
|
|
||||||
pub fn gep(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
ptr: PointerValue<'ctx>,
|
|
||||||
) -> PointerValue<'ctx> {
|
|
||||||
ctx.builder.build_struct_gep(ptr, self.gep_index, self.name).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
ptr: PointerValue<'ctx>,
|
|
||||||
) -> BasicValueEnum<'ctx> {
|
|
||||||
ctx.builder.build_load(self.gep(ctx, ptr), self.name).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store<V>(&self, ctx: &CodeGenContext<'ctx, '_>, ptr: PointerValue<'ctx>, value: V)
|
|
||||||
where
|
|
||||||
V: BasicValue<'ctx>,
|
|
||||||
{
|
|
||||||
ctx.builder.build_store(ptr, value).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type IsInstanceError = String;
|
|
||||||
type IsInstanceResult = Result<(), IsInstanceError>;
|
|
||||||
|
|
||||||
pub fn check_basic_types_match<'ctx, A, B>(expected: A, got: B) -> IsInstanceResult
|
|
||||||
where
|
|
||||||
A: BasicType<'ctx>,
|
|
||||||
B: BasicType<'ctx>,
|
|
||||||
{
|
|
||||||
let expected = expected.as_basic_type_enum();
|
|
||||||
let got = got.as_basic_type_enum();
|
|
||||||
|
|
||||||
// Put those logic into here,
|
|
||||||
// otherwise there is always a fallback reporting on any kind of mismatch
|
|
||||||
match (expected, got) {
|
|
||||||
(BasicTypeEnum::IntType(expected), BasicTypeEnum::IntType(got)) => {
|
|
||||||
if expected.get_bit_width() != got.get_bit_width() {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected IntType ({expected}-bit(s)), got IntType ({got}-bit(s))"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(expected, got) => {
|
|
||||||
if expected != got {
|
|
||||||
return Err(format!("Expected {expected}, got {got}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> StructFields<'ctx> {
|
|
||||||
pub fn num_fields(&self) -> u32 {
|
|
||||||
self.fields.len() as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_struct_type(&self, ctx: &'ctx Context) -> StructType<'ctx> {
|
|
||||||
let llvm_fields = self.fields.iter().map(|field| field.ty).collect_vec();
|
|
||||||
ctx.struct_type(llvm_fields.as_slice(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_type(&self, scrutinee: StructType<'ctx>) -> IsInstanceResult {
|
|
||||||
// Check scrutinee's number of struct fields
|
|
||||||
if scrutinee.count_fields() != self.num_fields() {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected {expected_count} field(s) in `{struct_name}` type, got {got_count}",
|
|
||||||
struct_name = self.name,
|
|
||||||
expected_count = self.num_fields(),
|
|
||||||
got_count = scrutinee.count_fields(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the scrutinee's field types
|
|
||||||
for field in self.fields.iter() {
|
|
||||||
let expected_field_ty = field.ty;
|
|
||||||
let got_field_ty = scrutinee.get_field_type_at_index(field.gep_index).unwrap();
|
|
||||||
|
|
||||||
if let Err(field_err) = check_basic_types_match(expected_field_ty, got_field_ty) {
|
|
||||||
return Err(format!(
|
|
||||||
"Field GEP index {gep_index} does not match the expected type of ({struct_name}::{field_name}): {field_err}",
|
|
||||||
gep_index = field.gep_index,
|
|
||||||
struct_name = self.name,
|
|
||||||
field_name = field.name,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> StructFieldsBuilder<'ctx> {
|
|
||||||
fn start(name: &'static str) -> Self {
|
|
||||||
StructFieldsBuilder { gep_index_counter: 0, name, fields: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_field(&mut self, name: &'static str, ty: BasicTypeEnum<'ctx>) -> StructField<'ctx> {
|
|
||||||
let index = self.gep_index_counter;
|
|
||||||
self.gep_index_counter += 1;
|
|
||||||
StructField { gep_index: index, name, ty }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> StructFields<'ctx> {
|
|
||||||
StructFields { name: self.name, fields: self.fields }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct NpArrayType<'ctx> {
|
|
||||||
pub size_type: IntType<'ctx>,
|
|
||||||
pub elem_type: BasicTypeEnum<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NpArrayStructFields<'ctx> {
|
|
||||||
pub whole_struct: StructFields<'ctx>,
|
|
||||||
pub data: StructField<'ctx>,
|
|
||||||
pub itemsize: StructField<'ctx>,
|
|
||||||
pub ndims: StructField<'ctx>,
|
|
||||||
pub shape: StructField<'ctx>,
|
|
||||||
pub strides: StructField<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> NpArrayType<'ctx> {
|
|
||||||
pub fn new_opaque_elem(
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
size_type: IntType<'ctx>,
|
|
||||||
) -> NpArrayType<'ctx> {
|
|
||||||
NpArrayType { size_type, elem_type: ctx.ctx.i8_type().as_basic_type_enum() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn struct_type(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructType<'ctx> {
|
|
||||||
self.fields().whole_struct.as_struct_type(ctx.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fields(&self) -> NpArrayStructFields<'ctx> {
|
|
||||||
let mut builder = StructFieldsBuilder::start("NpArray");
|
|
||||||
|
|
||||||
let addrspace = AddressSpace::default();
|
|
||||||
|
|
||||||
let byte_type = self.size_type.get_context().i8_type();
|
|
||||||
|
|
||||||
// Make sure the struct matches PERFECTLY with that defined in `nac3core/irrt`.
|
|
||||||
let data = builder.add_field("data", byte_type.ptr_type(addrspace).into());
|
|
||||||
let itemsize = builder.add_field("itemsize", self.size_type.into());
|
|
||||||
let ndims = builder.add_field("ndims", self.size_type.into());
|
|
||||||
let shape = builder.add_field("shape", self.size_type.ptr_type(addrspace).into());
|
|
||||||
let strides = builder.add_field("strides", self.size_type.ptr_type(addrspace).into());
|
|
||||||
|
|
||||||
NpArrayStructFields { whole_struct: builder.end(), data, itemsize, ndims, shape, strides }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocate an `ndarray` on stack, with the following notes:
|
|
||||||
///
|
|
||||||
/// - `ndarray.ndims` will be initialized to `in_ndims`.
|
|
||||||
/// - `ndarray.itemsize` will be initialized to the size of `self.elem_type.size_of()`.
|
|
||||||
/// - `ndarray.shape` and `ndarray.strides` will be allocated on the stack with number of elements being `in_ndims`,
|
|
||||||
/// all with empty/uninitialized values.
|
|
||||||
pub fn alloca(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
in_ndims: IntValue<'ctx>,
|
|
||||||
name: &str,
|
|
||||||
) -> NpArrayValue<'ctx> {
|
|
||||||
let fields = self.fields();
|
|
||||||
let ptr =
|
|
||||||
ctx.builder.build_alloca(fields.whole_struct.as_struct_type(ctx.ctx), name).unwrap();
|
|
||||||
|
|
||||||
// Allocate `in_dims` number of `size_type` on the stack for `shape` and `strides`
|
|
||||||
let allocated_shape =
|
|
||||||
ctx.builder.build_array_alloca(fields.shape.ty, in_ndims, "allocated_shape").unwrap();
|
|
||||||
let allocated_strides = ctx
|
|
||||||
.builder
|
|
||||||
.build_array_alloca(fields.strides.ty, in_ndims, "allocated_strides")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let value = NpArrayValue { ty: *self, ptr };
|
|
||||||
value.store_ndims(ctx, in_ndims);
|
|
||||||
value.store_itemsize(ctx, self.elem_type.size_of().unwrap());
|
|
||||||
value.store_shape(ctx, allocated_shape);
|
|
||||||
value.store_strides(ctx, allocated_strides);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct NpArrayValue<'ctx> {
|
|
||||||
pub ty: NpArrayType<'ctx>,
|
|
||||||
pub ptr: PointerValue<'ctx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> NpArrayValue<'ctx> {
|
|
||||||
pub fn load_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
|
||||||
let field = self.ty.fields().ndims;
|
|
||||||
field.load(ctx, self.ptr).into_int_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
|
||||||
let field = self.ty.fields().ndims;
|
|
||||||
field.store(ctx, self.ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_itemsize(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
|
||||||
let field = self.ty.fields().itemsize;
|
|
||||||
field.load(ctx, self.ptr).into_int_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_itemsize(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
|
||||||
let field = self.ty.fields().itemsize;
|
|
||||||
field.store(ctx, self.ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_shape(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
|
||||||
let field = self.ty.fields().shape;
|
|
||||||
field.load(ctx, self.ptr).into_pointer_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
|
||||||
let field = self.ty.fields().shape;
|
|
||||||
field.store(ctx, self.ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_strides(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
|
||||||
let field = self.ty.fields().strides;
|
|
||||||
field.load(ctx, self.ptr).into_pointer_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_strides(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
|
||||||
let field = self.ty.fields().strides;
|
|
||||||
field.store(ctx, self.ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: DOCUMENT ME -- NDIMS WOULD NEVER CHANGE!!!!!
|
|
||||||
pub fn shape_slice(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
|
|
||||||
let field = self.ty.fields().shape;
|
|
||||||
field.gep(ctx, self.ptr);
|
|
||||||
|
|
||||||
let ndims = self.load_ndims(ctx);
|
|
||||||
|
|
||||||
TypedArrayLikeAdapter {
|
|
||||||
adapted: ArraySliceValue(self.ptr, ndims, Some(field.name)),
|
|
||||||
downcast_fn: Box::new(|_ctx, x| x.into_int_value()),
|
|
||||||
upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: DOCUMENT ME -- NDIMS WOULD NEVER CHANGE!!!!!
|
|
||||||
pub fn strides_slice(
|
|
||||||
&self,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
|
|
||||||
let field = self.ty.fields().strides;
|
|
||||||
field.gep(ctx, self.ptr);
|
|
||||||
|
|
||||||
let ndims = self.load_ndims(ctx);
|
|
||||||
|
|
||||||
TypedArrayLikeAdapter {
|
|
||||||
adapted: ArraySliceValue(self.ptr, ndims, Some(field.name)),
|
|
||||||
downcast_fn: Box::new(|_ctx, x| x.into_int_value()),
|
|
||||||
upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1362,101 +1362,100 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
||||||
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
{
|
{
|
||||||
todo!()
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
// let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
||||||
|
|
||||||
// let is_ndarray1 = ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
let is_ndarray1 = ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
// let is_ndarray2 = ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
let is_ndarray2 = ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
|
|
||||||
// if is_ndarray1 && is_ndarray2 {
|
if is_ndarray1 && is_ndarray2 {
|
||||||
// let (ndarray_dtype1, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty1);
|
let (ndarray_dtype1, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty1);
|
||||||
// let (ndarray_dtype2, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty2);
|
let (ndarray_dtype2, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty2);
|
||||||
|
|
||||||
// assert!(ctx.unifier.unioned(ndarray_dtype1, ndarray_dtype2));
|
assert!(ctx.unifier.unioned(ndarray_dtype1, ndarray_dtype2));
|
||||||
|
|
||||||
// let left_val =
|
let left_val =
|
||||||
// NDArrayValue::from_ptr_val(left_val.into_pointer_value(), llvm_usize, None);
|
NDArrayValue::from_ptr_val(left_val.into_pointer_value(), llvm_usize, None);
|
||||||
// let right_val =
|
let right_val =
|
||||||
// NDArrayValue::from_ptr_val(right_val.into_pointer_value(), llvm_usize, None);
|
NDArrayValue::from_ptr_val(right_val.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
// let res = if op.base == Operator::MatMult {
|
let res = if op.base == Operator::MatMult {
|
||||||
// // MatMult is the only binop which is not an elementwise op
|
// MatMult is the only binop which is not an elementwise op
|
||||||
// numpy::ndarray_matmul_2d(
|
numpy::ndarray_matmul_2d(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ndarray_dtype1,
|
ndarray_dtype1,
|
||||||
// match op.variant {
|
match op.variant {
|
||||||
// BinopVariant::Normal => None,
|
BinopVariant::Normal => None,
|
||||||
// BinopVariant::AugAssign => Some(left_val),
|
BinopVariant::AugAssign => Some(left_val),
|
||||||
// },
|
},
|
||||||
// left_val,
|
left_val,
|
||||||
// right_val,
|
right_val,
|
||||||
// )?
|
)?
|
||||||
// } else {
|
} else {
|
||||||
// numpy::ndarray_elementwise_binop_impl(
|
numpy::ndarray_elementwise_binop_impl(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ndarray_dtype1,
|
ndarray_dtype1,
|
||||||
// match op.variant {
|
match op.variant {
|
||||||
// BinopVariant::Normal => None,
|
BinopVariant::Normal => None,
|
||||||
// BinopVariant::AugAssign => Some(left_val),
|
BinopVariant::AugAssign => Some(left_val),
|
||||||
// },
|
},
|
||||||
// (left_val.as_base_value().into(), false),
|
(left_val.as_base_value().into(), false),
|
||||||
// (right_val.as_base_value().into(), false),
|
(right_val.as_base_value().into(), false),
|
||||||
// |generator, ctx, (lhs, rhs)| {
|
|generator, ctx, (lhs, rhs)| {
|
||||||
// gen_binop_expr_with_values(
|
gen_binop_expr_with_values(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// (&Some(ndarray_dtype1), lhs),
|
(&Some(ndarray_dtype1), lhs),
|
||||||
// op,
|
op,
|
||||||
// (&Some(ndarray_dtype2), rhs),
|
(&Some(ndarray_dtype2), rhs),
|
||||||
// ctx.current_loc,
|
ctx.current_loc,
|
||||||
// )?
|
)?
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .to_basic_value_enum(
|
.to_basic_value_enum(
|
||||||
// ctx,
|
ctx,
|
||||||
// generator,
|
generator,
|
||||||
// ndarray_dtype1,
|
ndarray_dtype1,
|
||||||
// )
|
)
|
||||||
// },
|
},
|
||||||
// )?
|
)?
|
||||||
// };
|
};
|
||||||
|
|
||||||
// Ok(Some(res.as_base_value().into()))
|
Ok(Some(res.as_base_value().into()))
|
||||||
// } else {
|
} else {
|
||||||
// let (ndarray_dtype, _) =
|
let (ndarray_dtype, _) =
|
||||||
// unpack_ndarray_var_tys(&mut ctx.unifier, if is_ndarray1 { ty1 } else { ty2 });
|
unpack_ndarray_var_tys(&mut ctx.unifier, if is_ndarray1 { ty1 } else { ty2 });
|
||||||
// let ndarray_val = NDArrayValue::from_ptr_val(
|
let ndarray_val = NDArrayValue::from_ptr_val(
|
||||||
// if is_ndarray1 { left_val } else { right_val }.into_pointer_value(),
|
if is_ndarray1 { left_val } else { right_val }.into_pointer_value(),
|
||||||
// llvm_usize,
|
llvm_usize,
|
||||||
// None,
|
None,
|
||||||
// );
|
);
|
||||||
// let res = numpy::ndarray_elementwise_binop_impl(
|
let res = numpy::ndarray_elementwise_binop_impl(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ndarray_dtype,
|
ndarray_dtype,
|
||||||
// match op.variant {
|
match op.variant {
|
||||||
// BinopVariant::Normal => None,
|
BinopVariant::Normal => None,
|
||||||
// BinopVariant::AugAssign => Some(ndarray_val),
|
BinopVariant::AugAssign => Some(ndarray_val),
|
||||||
// },
|
},
|
||||||
// (left_val, !is_ndarray1),
|
(left_val, !is_ndarray1),
|
||||||
// (right_val, !is_ndarray2),
|
(right_val, !is_ndarray2),
|
||||||
// |generator, ctx, (lhs, rhs)| {
|
|generator, ctx, (lhs, rhs)| {
|
||||||
// gen_binop_expr_with_values(
|
gen_binop_expr_with_values(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// (&Some(ndarray_dtype), lhs),
|
(&Some(ndarray_dtype), lhs),
|
||||||
// op,
|
op,
|
||||||
// (&Some(ndarray_dtype), rhs),
|
(&Some(ndarray_dtype), rhs),
|
||||||
// ctx.current_loc,
|
ctx.current_loc,
|
||||||
// )?
|
)?
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .to_basic_value_enum(ctx, generator, ndarray_dtype)
|
.to_basic_value_enum(ctx, generator, ndarray_dtype)
|
||||||
// },
|
},
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// Ok(Some(res.as_base_value().into()))
|
Ok(Some(res.as_base_value().into()))
|
||||||
// }
|
}
|
||||||
} else {
|
} else {
|
||||||
let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap());
|
let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap());
|
||||||
let TypeEnum::TObj { fields, obj_id, .. } = left_ty_enum.as_ref() else {
|
let TypeEnum::TObj { fields, obj_id, .. } = left_ty_enum.as_ref() else {
|
||||||
|
@ -1613,41 +1612,40 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
|
||||||
_ => val.into(),
|
_ => val.into(),
|
||||||
}
|
}
|
||||||
} else if ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) {
|
} else if ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) {
|
||||||
todo!()
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
// let llvm_usize = generator.get_size_type(ctx.ctx);
|
let (ndarray_dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
// let (ndarray_dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
|
||||||
|
|
||||||
// let val = NDArrayValue::from_ptr_val(val.into_pointer_value(), llvm_usize, None);
|
let val = NDArrayValue::from_ptr_val(val.into_pointer_value(), llvm_usize, None);
|
||||||
|
|
||||||
// // ndarray uses `~` rather than `not` to perform elementwise inversion, convert it before
|
// ndarray uses `~` rather than `not` to perform elementwise inversion, convert it before
|
||||||
// // passing it to the elementwise codegen function
|
// passing it to the elementwise codegen function
|
||||||
// let op = if ndarray_dtype.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::Bool.id()) {
|
let op = if ndarray_dtype.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::Bool.id()) {
|
||||||
// if op == ast::Unaryop::Invert {
|
if op == ast::Unaryop::Invert {
|
||||||
// ast::Unaryop::Not
|
ast::Unaryop::Not
|
||||||
// } else {
|
} else {
|
||||||
// unreachable!(
|
unreachable!(
|
||||||
// "ufunc {} not supported for ndarray[bool, N]",
|
"ufunc {} not supported for ndarray[bool, N]",
|
||||||
// op.op_info().method_name,
|
op.op_info().method_name,
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// op
|
op
|
||||||
// };
|
};
|
||||||
|
|
||||||
// let res = numpy::ndarray_elementwise_unaryop_impl(
|
let res = numpy::ndarray_elementwise_unaryop_impl(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ndarray_dtype,
|
ndarray_dtype,
|
||||||
// None,
|
None,
|
||||||
// val,
|
val,
|
||||||
// |generator, ctx, val| {
|
|generator, ctx, val| {
|
||||||
// gen_unaryop_expr_with_values(generator, ctx, op, (&Some(ndarray_dtype), val))?
|
gen_unaryop_expr_with_values(generator, ctx, op, (&Some(ndarray_dtype), val))?
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .to_basic_value_enum(ctx, generator, ndarray_dtype)
|
.to_basic_value_enum(ctx, generator, ndarray_dtype)
|
||||||
// },
|
},
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// res.as_base_value().into()
|
res.as_base_value().into()
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}))
|
}))
|
||||||
|
@ -1690,86 +1688,85 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
||||||
if left_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
if left_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
|| right_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
|| right_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
{
|
{
|
||||||
todo!()
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
// let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
||||||
|
|
||||||
// let (Some(left_ty), lhs) = left else { unreachable!() };
|
let (Some(left_ty), lhs) = left else { unreachable!() };
|
||||||
// let (Some(right_ty), rhs) = comparators[0] else { unreachable!() };
|
let (Some(right_ty), rhs) = comparators[0] else { unreachable!() };
|
||||||
// let op = ops[0];
|
let op = ops[0];
|
||||||
|
|
||||||
// let is_ndarray1 =
|
let is_ndarray1 =
|
||||||
// left_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
left_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
// let is_ndarray2 =
|
let is_ndarray2 =
|
||||||
// right_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
right_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id());
|
||||||
|
|
||||||
// return if is_ndarray1 && is_ndarray2 {
|
return if is_ndarray1 && is_ndarray2 {
|
||||||
// let (ndarray_dtype1, _) = unpack_ndarray_var_tys(&mut ctx.unifier, left_ty);
|
let (ndarray_dtype1, _) = unpack_ndarray_var_tys(&mut ctx.unifier, left_ty);
|
||||||
// let (ndarray_dtype2, _) = unpack_ndarray_var_tys(&mut ctx.unifier, right_ty);
|
let (ndarray_dtype2, _) = unpack_ndarray_var_tys(&mut ctx.unifier, right_ty);
|
||||||
|
|
||||||
// assert!(ctx.unifier.unioned(ndarray_dtype1, ndarray_dtype2));
|
assert!(ctx.unifier.unioned(ndarray_dtype1, ndarray_dtype2));
|
||||||
|
|
||||||
// let left_val =
|
let left_val =
|
||||||
// NDArrayValue::from_ptr_val(lhs.into_pointer_value(), llvm_usize, None);
|
NDArrayValue::from_ptr_val(lhs.into_pointer_value(), llvm_usize, None);
|
||||||
// let res = numpy::ndarray_elementwise_binop_impl(
|
let res = numpy::ndarray_elementwise_binop_impl(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ctx.primitives.bool,
|
ctx.primitives.bool,
|
||||||
// None,
|
None,
|
||||||
// (left_val.as_base_value().into(), false),
|
(left_val.as_base_value().into(), false),
|
||||||
// (rhs, false),
|
(rhs, false),
|
||||||
// |generator, ctx, (lhs, rhs)| {
|
|generator, ctx, (lhs, rhs)| {
|
||||||
// let val = gen_cmpop_expr_with_values(
|
let val = gen_cmpop_expr_with_values(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// (Some(ndarray_dtype1), lhs),
|
(Some(ndarray_dtype1), lhs),
|
||||||
// &[op],
|
&[op],
|
||||||
// &[(Some(ndarray_dtype2), rhs)],
|
&[(Some(ndarray_dtype2), rhs)],
|
||||||
// )?
|
)?
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .to_basic_value_enum(
|
.to_basic_value_enum(
|
||||||
// ctx,
|
ctx,
|
||||||
// generator,
|
generator,
|
||||||
// ctx.primitives.bool,
|
ctx.primitives.bool,
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// Ok(generator.bool_to_i8(ctx, val.into_int_value()).into())
|
Ok(generator.bool_to_i8(ctx, val.into_int_value()).into())
|
||||||
// },
|
},
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// Ok(Some(res.as_base_value().into()))
|
Ok(Some(res.as_base_value().into()))
|
||||||
// } else {
|
} else {
|
||||||
// let (ndarray_dtype, _) = unpack_ndarray_var_tys(
|
let (ndarray_dtype, _) = unpack_ndarray_var_tys(
|
||||||
// &mut ctx.unifier,
|
&mut ctx.unifier,
|
||||||
// if is_ndarray1 { left_ty } else { right_ty },
|
if is_ndarray1 { left_ty } else { right_ty },
|
||||||
// );
|
);
|
||||||
// let res = numpy::ndarray_elementwise_binop_impl(
|
let res = numpy::ndarray_elementwise_binop_impl(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// ctx.primitives.bool,
|
ctx.primitives.bool,
|
||||||
// None,
|
None,
|
||||||
// (lhs, !is_ndarray1),
|
(lhs, !is_ndarray1),
|
||||||
// (rhs, !is_ndarray2),
|
(rhs, !is_ndarray2),
|
||||||
// |generator, ctx, (lhs, rhs)| {
|
|generator, ctx, (lhs, rhs)| {
|
||||||
// let val = gen_cmpop_expr_with_values(
|
let val = gen_cmpop_expr_with_values(
|
||||||
// generator,
|
generator,
|
||||||
// ctx,
|
ctx,
|
||||||
// (Some(ndarray_dtype), lhs),
|
(Some(ndarray_dtype), lhs),
|
||||||
// &[op],
|
&[op],
|
||||||
// &[(Some(ndarray_dtype), rhs)],
|
&[(Some(ndarray_dtype), rhs)],
|
||||||
// )?
|
)?
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .to_basic_value_enum(
|
.to_basic_value_enum(
|
||||||
// ctx,
|
ctx,
|
||||||
// generator,
|
generator,
|
||||||
// ctx.primitives.bool,
|
ctx.primitives.bool,
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// Ok(generator.bool_to_i8(ctx, val.into_int_value()).into())
|
Ok(generator.bool_to_i8(ctx, val.into_int_value()).into())
|
||||||
// },
|
},
|
||||||
// )?;
|
)?;
|
||||||
|
|
||||||
// Ok(Some(res.as_base_value().into()))
|
Ok(Some(res.as_base_value().into()))
|
||||||
// };
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2105,312 +2102,310 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
|
||||||
v: NDArrayValue<'ctx>,
|
v: NDArrayValue<'ctx>,
|
||||||
slice: &Expr<Option<Type>>,
|
slice: &Expr<Option<Type>>,
|
||||||
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
||||||
todo!()
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
// let llvm_i1 = ctx.ctx.bool_type();
|
let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndims) else {
|
||||||
// let llvm_i32 = ctx.ctx.i32_type();
|
unreachable!()
|
||||||
// let llvm_usize = generator.get_size_type(ctx.ctx);
|
};
|
||||||
|
|
||||||
// let TypeEnum::TLiteral { values, .. } = &*ctx.unifier.get_ty_immutable(ndims) else {
|
let ndims = values
|
||||||
// unreachable!()
|
.iter()
|
||||||
// };
|
.map(|ndim| u64::try_from(ndim.clone()).map_err(|()| ndim.clone()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(|val| {
|
||||||
|
format!(
|
||||||
|
"Expected non-negative literal for ndarray.ndims, got {}",
|
||||||
|
i128::try_from(val).unwrap()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
// let ndims = values
|
assert!(!ndims.is_empty());
|
||||||
// .iter()
|
|
||||||
// .map(|ndim| u64::try_from(ndim.clone()).map_err(|()| ndim.clone()))
|
|
||||||
// .collect::<Result<Vec<_>, _>>()
|
|
||||||
// .map_err(|val| {
|
|
||||||
// format!(
|
|
||||||
// "Expected non-negative literal for ndarray.ndims, got {}",
|
|
||||||
// i128::try_from(val).unwrap()
|
|
||||||
// )
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// assert!(!ndims.is_empty());
|
// The number of dimensions subscripted by the index expression.
|
||||||
|
// Slicing a ndarray will yield the same number of dimensions, whereas indexing into a
|
||||||
|
// dimension will remove a dimension.
|
||||||
|
let subscripted_dims = match &slice.node {
|
||||||
|
ExprKind::Tuple { elts, .. } => elts.iter().fold(0, |acc, value_subexpr| {
|
||||||
|
if let ExprKind::Slice { .. } = &value_subexpr.node {
|
||||||
|
acc
|
||||||
|
} else {
|
||||||
|
acc + 1
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
// // The number of dimensions subscripted by the index expression.
|
ExprKind::Slice { .. } => 0,
|
||||||
// // Slicing a ndarray will yield the same number of dimensions, whereas indexing into a
|
_ => 1,
|
||||||
// // dimension will remove a dimension.
|
};
|
||||||
// let subscripted_dims = match &slice.node {
|
|
||||||
// ExprKind::Tuple { elts, .. } => elts.iter().fold(0, |acc, value_subexpr| {
|
|
||||||
// if let ExprKind::Slice { .. } = &value_subexpr.node {
|
|
||||||
// acc
|
|
||||||
// } else {
|
|
||||||
// acc + 1
|
|
||||||
// }
|
|
||||||
// }),
|
|
||||||
|
|
||||||
// ExprKind::Slice { .. } => 0,
|
let ndarray_ndims_ty = ctx.unifier.get_fresh_literal(
|
||||||
// _ => 1,
|
ndims.iter().map(|v| SymbolValue::U64(v - subscripted_dims)).collect(),
|
||||||
// };
|
None,
|
||||||
|
);
|
||||||
|
let ndarray_ty =
|
||||||
|
make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(ty), Some(ndarray_ndims_ty));
|
||||||
|
let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type();
|
||||||
|
let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type();
|
||||||
|
let llvm_ndarray_data_t = ctx.get_llvm_type(generator, ty).as_basic_type_enum();
|
||||||
|
|
||||||
// let ndarray_ndims_ty = ctx.unifier.get_fresh_literal(
|
// Check that len is non-zero
|
||||||
// ndims.iter().map(|v| SymbolValue::U64(v - subscripted_dims)).collect(),
|
let len = v.load_ndims(ctx);
|
||||||
// None,
|
ctx.make_assert(
|
||||||
// );
|
generator,
|
||||||
// let ndarray_ty =
|
ctx.builder.build_int_compare(IntPredicate::SGT, len, llvm_usize.const_zero(), "").unwrap(),
|
||||||
// make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(ty), Some(ndarray_ndims_ty));
|
"0:IndexError",
|
||||||
// let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type();
|
"too many indices for array: array is {0}-dimensional but 1 were indexed",
|
||||||
// let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type();
|
[Some(len), None, None],
|
||||||
// let llvm_ndarray_data_t = ctx.get_llvm_type(generator, ty).as_basic_type_enum();
|
slice.location,
|
||||||
|
);
|
||||||
|
|
||||||
// // Check that len is non-zero
|
// Normalizes a possibly-negative index to its corresponding positive index
|
||||||
// let len = v.load_ndims(ctx);
|
let normalize_index = |generator: &mut G,
|
||||||
// ctx.make_assert(
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
// generator,
|
index: IntValue<'ctx>,
|
||||||
// ctx.builder.build_int_compare(IntPredicate::SGT, len, llvm_usize.const_zero(), "").unwrap(),
|
dim: u64| {
|
||||||
// "0:IndexError",
|
gen_if_else_expr_callback(
|
||||||
// "too many indices for array: array is {0}-dimensional but 1 were indexed",
|
generator,
|
||||||
// [Some(len), None, None],
|
ctx,
|
||||||
// slice.location,
|
|_, ctx| {
|
||||||
// );
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::SGE, index, index.get_type().const_zero(), "")
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|_, _| Ok(Some(index)),
|
||||||
|
|generator, ctx| {
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
// // Normalizes a possibly-negative index to its corresponding positive index
|
let len = unsafe {
|
||||||
// let normalize_index = |generator: &mut G,
|
v.dim_sizes().get_typed_unchecked(
|
||||||
// ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx,
|
||||||
// index: IntValue<'ctx>,
|
generator,
|
||||||
// dim: u64| {
|
&llvm_usize.const_int(dim, true),
|
||||||
// gen_if_else_expr_callback(
|
None,
|
||||||
// generator,
|
)
|
||||||
// ctx,
|
};
|
||||||
// |_, ctx| {
|
|
||||||
// Ok(ctx
|
|
||||||
// .builder
|
|
||||||
// .build_int_compare(IntPredicate::SGE, index, index.get_type().const_zero(), "")
|
|
||||||
// .unwrap())
|
|
||||||
// },
|
|
||||||
// |_, _| Ok(Some(index)),
|
|
||||||
// |generator, ctx| {
|
|
||||||
// let llvm_i32 = ctx.ctx.i32_type();
|
|
||||||
|
|
||||||
// let len = unsafe {
|
let index = ctx
|
||||||
// v.dim_sizes().get_typed_unchecked(
|
.builder
|
||||||
// ctx,
|
.build_int_add(
|
||||||
// generator,
|
len,
|
||||||
// &llvm_usize.const_int(dim, true),
|
ctx.builder.build_int_s_extend(index, llvm_usize, "").unwrap(),
|
||||||
// None,
|
"",
|
||||||
// )
|
)
|
||||||
// };
|
.unwrap();
|
||||||
|
|
||||||
// let index = ctx
|
Ok(Some(ctx.builder.build_int_truncate(index, llvm_i32, "").unwrap()))
|
||||||
// .builder
|
},
|
||||||
// .build_int_add(
|
)
|
||||||
// len,
|
.map(|v| v.map(BasicValueEnum::into_int_value))
|
||||||
// ctx.builder.build_int_s_extend(index, llvm_usize, "").unwrap(),
|
};
|
||||||
// "",
|
|
||||||
// )
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
// Ok(Some(ctx.builder.build_int_truncate(index, llvm_i32, "").unwrap()))
|
// Converts a slice expression into a slice-range tuple
|
||||||
// },
|
let expr_to_slice = |generator: &mut G,
|
||||||
// )
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
// .map(|v| v.map(BasicValueEnum::into_int_value))
|
node: &ExprKind<Option<Type>>,
|
||||||
// };
|
dim: u64| {
|
||||||
|
match node {
|
||||||
|
ExprKind::Constant { value: Constant::Int(v), .. } => {
|
||||||
|
let Some(index) =
|
||||||
|
normalize_index(generator, ctx, llvm_i32.const_int(*v as u64, true), dim)?
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
// // Converts a slice expression into a slice-range tuple
|
Ok(Some((index, index, llvm_i32.const_int(1, true))))
|
||||||
// let expr_to_slice = |generator: &mut G,
|
}
|
||||||
// ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
// node: &ExprKind<Option<Type>>,
|
|
||||||
// dim: u64| {
|
|
||||||
// match node {
|
|
||||||
// ExprKind::Constant { value: Constant::Int(v), .. } => {
|
|
||||||
// let Some(index) =
|
|
||||||
// normalize_index(generator, ctx, llvm_i32.const_int(*v as u64, true), dim)?
|
|
||||||
// else {
|
|
||||||
// return Ok(None);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Ok(Some((index, index, llvm_i32.const_int(1, true))))
|
ExprKind::Slice { lower, upper, step } => {
|
||||||
// }
|
let dim_sz = unsafe {
|
||||||
|
v.dim_sizes().get_typed_unchecked(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&llvm_usize.const_int(dim, false),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
// ExprKind::Slice { lower, upper, step } => {
|
handle_slice_indices(lower, upper, step, ctx, generator, dim_sz)
|
||||||
// let dim_sz = unsafe {
|
}
|
||||||
// v.dim_sizes().get_typed_unchecked(
|
|
||||||
// ctx,
|
|
||||||
// generator,
|
|
||||||
// &llvm_usize.const_int(dim, false),
|
|
||||||
// None,
|
|
||||||
// )
|
|
||||||
// };
|
|
||||||
|
|
||||||
// handle_slice_indices(lower, upper, step, ctx, generator, dim_sz)
|
_ => {
|
||||||
// }
|
let Some(index) = generator.gen_expr(ctx, slice)? else { return Ok(None) };
|
||||||
|
let index = index
|
||||||
|
.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
||||||
|
.into_int_value();
|
||||||
|
let Some(index) = normalize_index(generator, ctx, index, dim)? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
// _ => {
|
Ok(Some((index, index, llvm_i32.const_int(1, true))))
|
||||||
// let Some(index) = generator.gen_expr(ctx, slice)? else { return Ok(None) };
|
}
|
||||||
// let index = index
|
}
|
||||||
// .to_basic_value_enum(ctx, generator, slice.custom.unwrap())?
|
};
|
||||||
// .into_int_value();
|
|
||||||
// let Some(index) = normalize_index(generator, ctx, index, dim)? else {
|
|
||||||
// return Ok(None);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Ok(Some((index, index, llvm_i32.const_int(1, true))))
|
let make_indices_arr = |generator: &mut G,
|
||||||
// }
|
ctx: &mut CodeGenContext<'ctx, '_>|
|
||||||
// }
|
-> Result<_, String> {
|
||||||
// };
|
Ok(if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||||
|
let llvm_int_ty = ctx.get_llvm_type(generator, elts[0].custom.unwrap());
|
||||||
|
let index_addr = generator.gen_array_var_alloc(
|
||||||
|
ctx,
|
||||||
|
llvm_int_ty,
|
||||||
|
llvm_usize.const_int(elts.len() as u64, false),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
// let make_indices_arr = |generator: &mut G,
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
// ctx: &mut CodeGenContext<'ctx, '_>|
|
let Some(index) = generator.gen_expr(ctx, elt)? else {
|
||||||
// -> Result<_, String> {
|
return Ok(None);
|
||||||
// Ok(if let ExprKind::Tuple { elts, .. } = &slice.node {
|
};
|
||||||
// let llvm_int_ty = ctx.get_llvm_type(generator, elts[0].custom.unwrap());
|
|
||||||
// let index_addr = generator.gen_array_var_alloc(
|
|
||||||
// ctx,
|
|
||||||
// llvm_int_ty,
|
|
||||||
// llvm_usize.const_int(elts.len() as u64, false),
|
|
||||||
// None,
|
|
||||||
// )?;
|
|
||||||
|
|
||||||
// for (i, elt) in elts.iter().enumerate() {
|
let index = index
|
||||||
// let Some(index) = generator.gen_expr(ctx, elt)? else {
|
.to_basic_value_enum(ctx, generator, elt.custom.unwrap())?
|
||||||
// return Ok(None);
|
.into_int_value();
|
||||||
// };
|
let Some(index) = normalize_index(generator, ctx, index, 0)? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
// let index = index
|
let store_ptr = unsafe {
|
||||||
// .to_basic_value_enum(ctx, generator, elt.custom.unwrap())?
|
index_addr.ptr_offset_unchecked(
|
||||||
// .into_int_value();
|
ctx,
|
||||||
// let Some(index) = normalize_index(generator, ctx, index, 0)? else {
|
generator,
|
||||||
// return Ok(None);
|
&llvm_usize.const_int(i as u64, false),
|
||||||
// };
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
ctx.builder.build_store(store_ptr, index).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// let store_ptr = unsafe {
|
Some(index_addr)
|
||||||
// index_addr.ptr_offset_unchecked(
|
} else if let Some(index) = generator.gen_expr(ctx, slice)? {
|
||||||
// ctx,
|
let llvm_int_ty = ctx.get_llvm_type(generator, slice.custom.unwrap());
|
||||||
// generator,
|
let index_addr = generator.gen_array_var_alloc(
|
||||||
// &llvm_usize.const_int(i as u64, false),
|
ctx,
|
||||||
// None,
|
llvm_int_ty,
|
||||||
// )
|
llvm_usize.const_int(1u64, false),
|
||||||
// };
|
None,
|
||||||
// ctx.builder.build_store(store_ptr, index).unwrap();
|
)?;
|
||||||
// }
|
|
||||||
|
|
||||||
// Some(index_addr)
|
let index =
|
||||||
// } else if let Some(index) = generator.gen_expr(ctx, slice)? {
|
index.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value();
|
||||||
// let llvm_int_ty = ctx.get_llvm_type(generator, slice.custom.unwrap());
|
let Some(index) = normalize_index(generator, ctx, index, 0)? else { return Ok(None) };
|
||||||
// let index_addr = generator.gen_array_var_alloc(
|
|
||||||
// ctx,
|
|
||||||
// llvm_int_ty,
|
|
||||||
// llvm_usize.const_int(1u64, false),
|
|
||||||
// None,
|
|
||||||
// )?;
|
|
||||||
|
|
||||||
// let index =
|
let store_ptr = unsafe {
|
||||||
// index.to_basic_value_enum(ctx, generator, slice.custom.unwrap())?.into_int_value();
|
index_addr.ptr_offset_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
|
||||||
// let Some(index) = normalize_index(generator, ctx, index, 0)? else { return Ok(None) };
|
};
|
||||||
|
ctx.builder.build_store(store_ptr, index).unwrap();
|
||||||
|
|
||||||
// let store_ptr = unsafe {
|
Some(index_addr)
|
||||||
// index_addr.ptr_offset_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
|
} else {
|
||||||
// };
|
None
|
||||||
// ctx.builder.build_store(store_ptr, index).unwrap();
|
})
|
||||||
|
};
|
||||||
|
|
||||||
// Some(index_addr)
|
Ok(Some(if ndims.len() == 1 && ndims[0] - subscripted_dims == 0 {
|
||||||
// } else {
|
let Some(index_addr) = make_indices_arr(generator, ctx)? else { return Ok(None) };
|
||||||
// None
|
|
||||||
// })
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Ok(Some(if ndims.len() == 1 && ndims[0] - subscripted_dims == 0 {
|
v.data().get(ctx, generator, &index_addr, None).into()
|
||||||
// let Some(index_addr) = make_indices_arr(generator, ctx)? else { return Ok(None) };
|
} else {
|
||||||
|
match &slice.node {
|
||||||
|
ExprKind::Tuple { elts, .. } => {
|
||||||
|
let slices = elts
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(dim, elt)| expr_to_slice(generator, ctx, &elt.node, dim as u64))
|
||||||
|
.take_while_inclusive(|slice| slice.as_ref().is_ok_and(Option::is_some))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
if slices.len() < elts.len() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
// v.data().get(ctx, generator, &index_addr, None).into()
|
let slices = slices.into_iter().map(Option::unwrap).collect_vec();
|
||||||
// } else {
|
|
||||||
// match &slice.node {
|
|
||||||
// ExprKind::Tuple { elts, .. } => {
|
|
||||||
// let slices = elts
|
|
||||||
// .iter()
|
|
||||||
// .enumerate()
|
|
||||||
// .map(|(dim, elt)| expr_to_slice(generator, ctx, &elt.node, dim as u64))
|
|
||||||
// .take_while_inclusive(|slice| slice.as_ref().is_ok_and(Option::is_some))
|
|
||||||
// .collect::<Result<Vec<_>, _>>()?;
|
|
||||||
// if slices.len() < elts.len() {
|
|
||||||
// return Ok(None);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let slices = slices.into_iter().map(Option::unwrap).collect_vec();
|
numpy::ndarray_sliced_copy(generator, ctx, ty, v, &slices)?.as_base_value().into()
|
||||||
|
}
|
||||||
|
|
||||||
// numpy::ndarray_sliced_copy(generator, ctx, ty, v, &slices)?.as_base_value().into()
|
ExprKind::Slice { .. } => {
|
||||||
// }
|
let Some(slice) = expr_to_slice(generator, ctx, &slice.node, 0)? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
// ExprKind::Slice { .. } => {
|
numpy::ndarray_sliced_copy(generator, ctx, ty, v, &[slice])?.as_base_value().into()
|
||||||
// let Some(slice) = expr_to_slice(generator, ctx, &slice.node, 0)? else {
|
}
|
||||||
// return Ok(None);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// numpy::ndarray_sliced_copy(generator, ctx, ty, v, &[slice])?.as_base_value().into()
|
_ => {
|
||||||
// }
|
// Accessing an element from a multi-dimensional `ndarray`
|
||||||
|
|
||||||
// _ => {
|
let Some(index_addr) = make_indices_arr(generator, ctx)? else { return Ok(None) };
|
||||||
// // Accessing an element from a multi-dimensional `ndarray`
|
|
||||||
|
|
||||||
// let Some(index_addr) = make_indices_arr(generator, ctx)? else { return Ok(None) };
|
// Create a new array, remove the top dimension from the dimension-size-list, and copy the
|
||||||
|
// elements over
|
||||||
|
let subscripted_ndarray =
|
||||||
|
generator.gen_var_alloc(ctx, llvm_ndarray_t.into(), None)?;
|
||||||
|
let ndarray = NDArrayValue::from_ptr_val(subscripted_ndarray, llvm_usize, None);
|
||||||
|
|
||||||
// // Create a new array, remove the top dimension from the dimension-size-list, and copy the
|
let num_dims = v.load_ndims(ctx);
|
||||||
// // elements over
|
ndarray.store_ndims(
|
||||||
// let subscripted_ndarray =
|
ctx,
|
||||||
// generator.gen_var_alloc(ctx, llvm_ndarray_t.into(), None)?;
|
generator,
|
||||||
// let ndarray = NDArrayValue::from_ptr_val(subscripted_ndarray, llvm_usize, None);
|
ctx.builder
|
||||||
|
.build_int_sub(num_dims, llvm_usize.const_int(1, false), "")
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
// let num_dims = v.load_ndims(ctx);
|
let ndarray_num_dims = ndarray.load_ndims(ctx);
|
||||||
// ndarray.store_ndims(
|
ndarray.create_dim_sizes(ctx, llvm_usize, ndarray_num_dims);
|
||||||
// ctx,
|
|
||||||
// generator,
|
|
||||||
// ctx.builder
|
|
||||||
// .build_int_sub(num_dims, llvm_usize.const_int(1, false), "")
|
|
||||||
// .unwrap(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let ndarray_num_dims = ndarray.load_ndims(ctx);
|
let ndarray_num_dims = ndarray.load_ndims(ctx);
|
||||||
// ndarray.create_dim_sizes(ctx, llvm_usize, ndarray_num_dims);
|
let v_dims_src_ptr = unsafe {
|
||||||
|
v.dim_sizes().ptr_offset_unchecked(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&llvm_usize.const_int(1, false),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
call_memcpy_generic(
|
||||||
|
ctx,
|
||||||
|
ndarray.dim_sizes().base_ptr(ctx, generator),
|
||||||
|
v_dims_src_ptr,
|
||||||
|
ctx.builder
|
||||||
|
.build_int_mul(ndarray_num_dims, llvm_usize.size_of(), "")
|
||||||
|
.map(Into::into)
|
||||||
|
.unwrap(),
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
// let ndarray_num_dims = ndarray.load_ndims(ctx);
|
let ndarray_num_elems = call_ndarray_calc_size(
|
||||||
// let v_dims_src_ptr = unsafe {
|
generator,
|
||||||
// v.dim_sizes().ptr_offset_unchecked(
|
ctx,
|
||||||
// ctx,
|
&ndarray.dim_sizes().as_slice_value(ctx, generator),
|
||||||
// generator,
|
(None, None),
|
||||||
// &llvm_usize.const_int(1, false),
|
);
|
||||||
// None,
|
ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems);
|
||||||
// )
|
|
||||||
// };
|
|
||||||
// call_memcpy_generic(
|
|
||||||
// ctx,
|
|
||||||
// ndarray.dim_sizes().base_ptr(ctx, generator),
|
|
||||||
// v_dims_src_ptr,
|
|
||||||
// ctx.builder
|
|
||||||
// .build_int_mul(ndarray_num_dims, llvm_usize.size_of(), "")
|
|
||||||
// .map(Into::into)
|
|
||||||
// .unwrap(),
|
|
||||||
// llvm_i1.const_zero(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let ndarray_num_elems = call_ndarray_calc_size(
|
let v_data_src_ptr = v.data().ptr_offset(ctx, generator, &index_addr, None);
|
||||||
// generator,
|
call_memcpy_generic(
|
||||||
// ctx,
|
ctx,
|
||||||
// &ndarray.dim_sizes().as_slice_value(ctx, generator),
|
ndarray.data().base_ptr(ctx, generator),
|
||||||
// (None, None),
|
v_data_src_ptr,
|
||||||
// );
|
ctx.builder
|
||||||
// ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems);
|
.build_int_mul(
|
||||||
|
ndarray_num_elems,
|
||||||
|
llvm_ndarray_data_t.size_of().unwrap(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.map(Into::into)
|
||||||
|
.unwrap(),
|
||||||
|
llvm_i1.const_zero(),
|
||||||
|
);
|
||||||
|
|
||||||
// let v_data_src_ptr = v.data().ptr_offset(ctx, generator, &index_addr, None);
|
ndarray.as_base_value().into()
|
||||||
// call_memcpy_generic(
|
}
|
||||||
// ctx,
|
}
|
||||||
// ndarray.data().base_ptr(ctx, generator),
|
}))
|
||||||
// v_data_src_ptr,
|
|
||||||
// ctx.builder
|
|
||||||
// .build_int_mul(
|
|
||||||
// ndarray_num_elems,
|
|
||||||
// llvm_ndarray_data_t.size_of().unwrap(),
|
|
||||||
// "",
|
|
||||||
// )
|
|
||||||
// .map(Into::into)
|
|
||||||
// .unwrap(),
|
|
||||||
// llvm_i1.const_zero(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// ndarray.as_base_value().into()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`CodeGenerator::gen_expr`].
|
/// See [`CodeGenerator::gen_expr`].
|
||||||
|
|
|
@ -4,97 +4,514 @@ use itertools::Either;
|
||||||
|
|
||||||
use crate::codegen::CodeGenContext;
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
/// Macro to generate extern function
|
/// Invokes the [`tan`](https://en.cppreference.com/w/c/numeric/math/tan) function.
|
||||||
/// Both function return type and function parameter type are `FloatValue`
|
pub fn call_tan<'ctx>(
|
||||||
///
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
/// Arguments:
|
arg: FloatValue<'ctx>,
|
||||||
/// * `unary/binary`: Whether the extern function requires one (unary) or two (binary) operands
|
|
||||||
/// * `$fn_name:ident`: The identifier of the rust function to be generated
|
|
||||||
/// * `$extern_fn:literal`: Name of underlying extern function
|
|
||||||
///
|
|
||||||
/// Optional Arguments:
|
|
||||||
/// * `$(,$attributes:literal)*)`: Attributes linked with the extern function
|
|
||||||
/// The default attributes are "mustprogress", "nofree", "nounwind", "willreturn", and "writeonly"
|
|
||||||
/// These will be used unless other attributes are specified
|
|
||||||
/// * `$(,$args:ident)*`: Operands of the extern function
|
|
||||||
/// The data type of these operands will be set to `FloatValue`
|
|
||||||
///
|
|
||||||
macro_rules! generate_extern_fn {
|
|
||||||
("unary", $fn_name:ident, $extern_fn:literal) => {
|
|
||||||
generate_extern_fn!($fn_name, $extern_fn, arg, "mustprogress", "nofree", "nounwind", "willreturn", "writeonly");
|
|
||||||
};
|
|
||||||
("unary", $fn_name:ident, $extern_fn:literal $(,$attributes:literal)*) => {
|
|
||||||
generate_extern_fn!($fn_name, $extern_fn, arg $(,$attributes)*);
|
|
||||||
};
|
|
||||||
("binary", $fn_name:ident, $extern_fn:literal) => {
|
|
||||||
generate_extern_fn!($fn_name, $extern_fn, arg1, arg2, "mustprogress", "nofree", "nounwind", "willreturn", "writeonly");
|
|
||||||
};
|
|
||||||
("binary", $fn_name:ident, $extern_fn:literal $(,$attributes:literal)*) => {
|
|
||||||
generate_extern_fn!($fn_name, $extern_fn, arg1, arg2 $(,$attributes)*);
|
|
||||||
};
|
|
||||||
($fn_name:ident, $extern_fn:literal $(,$args:ident)* $(,$attributes:literal)*) => {
|
|
||||||
#[doc = concat!("Invokes the [`", stringify!($extern_fn), "`](https://en.cppreference.com/w/c/numeric/math/", stringify!($llvm_name), ") function." )]
|
|
||||||
pub fn $fn_name<'ctx>(
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>
|
|
||||||
$(,$args: FloatValue<'ctx>)*,
|
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> FloatValue<'ctx> {
|
) -> FloatValue<'ctx> {
|
||||||
const FN_NAME: &str = $extern_fn;
|
const FN_NAME: &str = "tan";
|
||||||
|
|
||||||
let llvm_f64 = ctx.ctx.f64_type();
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
$(debug_assert_eq!($args.get_type(), llvm_f64);)*
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
let fn_type = llvm_f64.fn_type(&[$($args.get_type().into()),*], false);
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
for attr in [$($attributes),*] {
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
func.add_attribute(
|
func.add_attribute(
|
||||||
AttributeLoc::Function,
|
AttributeLoc::Function,
|
||||||
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
func
|
func
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_call(extern_fn, &[$($args.into()),*], name.unwrap_or_default())
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
.map(CallSiteValue::try_as_basic_value)
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
.map(Either::unwrap_left)
|
.map(Either::unwrap_left)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
/// Invokes the [`asin`](https://en.cppreference.com/w/c/numeric/math/asin) function.
|
||||||
|
pub fn call_asin<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "asin";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_extern_fn!("unary", call_tan, "tan");
|
func
|
||||||
generate_extern_fn!("unary", call_asin, "asin");
|
});
|
||||||
generate_extern_fn!("unary", call_acos, "acos");
|
|
||||||
generate_extern_fn!("unary", call_atan, "atan");
|
|
||||||
generate_extern_fn!("unary", call_sinh, "sinh");
|
|
||||||
generate_extern_fn!("unary", call_cosh, "cosh");
|
|
||||||
generate_extern_fn!("unary", call_tanh, "tanh");
|
|
||||||
generate_extern_fn!("unary", call_asinh, "asinh");
|
|
||||||
generate_extern_fn!("unary", call_acosh, "acosh");
|
|
||||||
generate_extern_fn!("unary", call_atanh, "atanh");
|
|
||||||
generate_extern_fn!("unary", call_expm1, "expm1");
|
|
||||||
generate_extern_fn!(
|
|
||||||
"unary",
|
|
||||||
call_cbrt,
|
|
||||||
"cbrt",
|
|
||||||
"mustprogress",
|
|
||||||
"nofree",
|
|
||||||
"nosync",
|
|
||||||
"nounwind",
|
|
||||||
"readonly",
|
|
||||||
"willreturn"
|
|
||||||
);
|
|
||||||
generate_extern_fn!("unary", call_erf, "erf", "nounwind");
|
|
||||||
generate_extern_fn!("unary", call_erfc, "erfc", "nounwind");
|
|
||||||
generate_extern_fn!("unary", call_j1, "j1", "nounwind");
|
|
||||||
|
|
||||||
generate_extern_fn!("binary", call_atan2, "atan2");
|
ctx.builder
|
||||||
generate_extern_fn!("binary", call_hypot, "hypot", "nounwind");
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
generate_extern_fn!("binary", call_nextafter, "nextafter", "nounwind");
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`acos`](https://en.cppreference.com/w/c/numeric/math/acos) function.
|
||||||
|
pub fn call_acos<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "acos";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`atan`](https://en.cppreference.com/w/c/numeric/math/atan) function.
|
||||||
|
pub fn call_atan<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "atan";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`sinh`](https://en.cppreference.com/w/c/numeric/math/sinh) function.
|
||||||
|
pub fn call_sinh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "sinh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`cosh`](https://en.cppreference.com/w/c/numeric/math/cosh) function.
|
||||||
|
pub fn call_cosh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "cosh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`tanh`](https://en.cppreference.com/w/c/numeric/math/tanh) function.
|
||||||
|
pub fn call_tanh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "tanh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`asinh`](https://en.cppreference.com/w/c/numeric/math/asinh) function.
|
||||||
|
pub fn call_asinh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "asinh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`acosh`](https://en.cppreference.com/w/c/numeric/math/acosh) function.
|
||||||
|
pub fn call_acosh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "acosh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`atanh`](https://en.cppreference.com/w/c/numeric/math/atanh) function.
|
||||||
|
pub fn call_atanh<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "atanh";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`expm1`](https://en.cppreference.com/w/c/numeric/math/expm1) function.
|
||||||
|
pub fn call_expm1<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "expm1";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`cbrt`](https://en.cppreference.com/w/c/numeric/math/cbrt) function.
|
||||||
|
pub fn call_cbrt<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "cbrt";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nosync", "nounwind", "readonly", "willreturn"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`erf`](https://en.cppreference.com/w/c/numeric/math/erf) function.
|
||||||
|
pub fn call_erf<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "erf";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`erfc`](https://en.cppreference.com/w/c/numeric/math/erfc) function.
|
||||||
|
pub fn call_erfc<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "erfc";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`j1`](https://www.gnu.org/software/libc/manual/html_node/Special-Functions.html#index-j1)
|
||||||
|
/// function.
|
||||||
|
pub fn call_j1<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
arg: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "j1";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(arg.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[arg.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`atan2`](https://en.cppreference.com/w/c/numeric/math/atan2) function.
|
||||||
|
pub fn call_atan2<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
y: FloatValue<'ctx>,
|
||||||
|
x: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "atan2";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(y.get_type(), llvm_f64);
|
||||||
|
debug_assert_eq!(x.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[y.into(), x.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
|
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
|
||||||
pub fn call_ldexp<'ctx>(
|
pub fn call_ldexp<'ctx>(
|
||||||
|
@ -130,3 +547,67 @@ pub fn call_ldexp<'ctx>(
|
||||||
.map(Either::unwrap_left)
|
.map(Either::unwrap_left)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`hypot`](https://en.cppreference.com/w/c/numeric/math/hypot) function.
|
||||||
|
pub fn call_hypot<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
x: FloatValue<'ctx>,
|
||||||
|
y: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "hypot";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(x.get_type(), llvm_f64);
|
||||||
|
debug_assert_eq!(y.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[x.into(), y.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`nextafter`](https://en.cppreference.com/w/c/numeric/math/nextafter) function.
|
||||||
|
pub fn call_nextafter<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
from: FloatValue<'ctx>,
|
||||||
|
to: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "nextafter";
|
||||||
|
|
||||||
|
let llvm_f64 = ctx.ctx.f64_type();
|
||||||
|
debug_assert_eq!(from.get_type(), llvm_f64);
|
||||||
|
debug_assert_eq!(to.get_type(), llvm_f64);
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_f64.into()], false);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, &[from.into(), to.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
#ifndef IRRT_DONT_TYPEDEF_INTS
|
|
||||||
typedef _BitInt(8) int8_t;
|
typedef _BitInt(8) int8_t;
|
||||||
typedef unsigned _BitInt(8) uint8_t;
|
typedef unsigned _BitInt(8) uint8_t;
|
||||||
typedef _BitInt(32) int32_t;
|
typedef _BitInt(32) int32_t;
|
||||||
typedef unsigned _BitInt(32) uint32_t;
|
typedef unsigned _BitInt(32) uint32_t;
|
||||||
typedef _BitInt(64) int64_t;
|
typedef _BitInt(64) int64_t;
|
||||||
typedef unsigned _BitInt(64) uint64_t;
|
typedef unsigned _BitInt(64) uint64_t;
|
||||||
#endif
|
|
||||||
|
|
||||||
// NDArray indices are always `uint32_t`.
|
// NDArray indices are always `uint32_t`.
|
||||||
typedef uint32_t NDIndex;
|
typedef uint32_t NDIndex;
|
||||||
// The type of an index or a value describing the length of a range/slice is
|
// The type of an index or a value describing the length of a range/slice is always `int32_t`.
|
||||||
// always `int32_t`.
|
|
||||||
typedef int32_t SliceIndex;
|
typedef int32_t SliceIndex;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -138,20 +135,6 @@ static void __nac3_ndarray_calc_broadcast_idx_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename SizeT>
|
|
||||||
static void __nac3_ndarray_strides_from_shape_impl(
|
|
||||||
SizeT ndims,
|
|
||||||
SizeT *shape,
|
|
||||||
SizeT *dst_strides
|
|
||||||
) {
|
|
||||||
SizeT stride_product = 1;
|
|
||||||
for (SizeT i = 0; i < ndims; i++) {
|
|
||||||
int dim_i = ndims - i - 1;
|
|
||||||
dst_strides[dim_i] = stride_product;
|
|
||||||
stride_product *= shape[dim_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#define DEF_nac3_int_exp_(T) \
|
#define DEF_nac3_int_exp_(T) \
|
||||||
T __nac3_int_exp_##T(T base, T exp) {\
|
T __nac3_int_exp_##T(T base, T exp) {\
|
||||||
|
@ -426,12 +409,4 @@ extern "C" {
|
||||||
) {
|
) {
|
||||||
__nac3_ndarray_calc_broadcast_idx_impl(src_dims, src_ndims, in_idx, out_idx);
|
__nac3_ndarray_calc_broadcast_idx_impl(src_dims, src_ndims, in_idx, out_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __nac3_ndarray_strides_from_shape(uint32_t ndims, uint32_t* shape, uint32_t* dst_strides) {
|
|
||||||
__nac3_ndarray_strides_from_shape_impl(ndims, shape, dst_strides);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __nac3_ndarray_strides_from_shape64(uint64_t ndims, uint64_t* shape, uint64_t* dst_strides) {
|
|
||||||
__nac3_ndarray_strides_from_shape_impl(ndims, shape, dst_strides);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
use crate::{typecheck::typedef::Type, util::SizeVariant};
|
use crate::typecheck::typedef::Type;
|
||||||
|
|
||||||
mod test;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
classes::{
|
classes::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, NpArrayType,
|
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue,
|
||||||
NpArrayValue, TypedArrayLikeAdapter, UntypedArrayLikeAccessor,
|
TypedArrayLikeAdapter, UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
llvm_intrinsics, CodeGenContext, CodeGenerator,
|
llvm_intrinsics, CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
|
@ -16,8 +14,8 @@ use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
memory_buffer::MemoryBuffer,
|
memory_buffer::MemoryBuffer,
|
||||||
module::Module,
|
module::Module,
|
||||||
types::{BasicType, BasicTypeEnum, FunctionType, IntType, PointerType},
|
types::{BasicTypeEnum, IntType},
|
||||||
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue},
|
values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
@ -929,63 +927,3 @@ pub fn call_ndarray_calc_broadcast_index<
|
||||||
Box::new(|_, v| v.into()),
|
Box::new(|_, v| v.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size_variant<'ctx>(ty: IntType<'ctx>) -> SizeVariant {
|
|
||||||
match ty.get_bit_width() {
|
|
||||||
32 => SizeVariant::Bits32,
|
|
||||||
64 => SizeVariant::Bits64,
|
|
||||||
_ => unreachable!("Unsupported int type bit width {}", ty.get_bit_width()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_size_type_dependent_function<'ctx, BuildFuncTypeFn>(
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
size_type: IntType<'ctx>,
|
|
||||||
base_name: &str,
|
|
||||||
build_func_type: BuildFuncTypeFn,
|
|
||||||
) -> FunctionValue<'ctx>
|
|
||||||
where
|
|
||||||
BuildFuncTypeFn: Fn() -> FunctionType<'ctx>,
|
|
||||||
{
|
|
||||||
let mut fn_name = base_name.to_owned();
|
|
||||||
match get_size_variant(size_type) {
|
|
||||||
SizeVariant::Bits32 => {
|
|
||||||
// The original fn_name is the correct function name
|
|
||||||
}
|
|
||||||
SizeVariant::Bits64 => {
|
|
||||||
// Append "64" at the end, this is the naming convention for 64-bit
|
|
||||||
fn_name.push_str("64");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get (or declare then get if does not exist) the corresponding function
|
|
||||||
ctx.module.get_function(&fn_name).unwrap_or_else(|| {
|
|
||||||
let fn_type = build_func_type();
|
|
||||||
ctx.module.add_function(&fn_name, fn_type, None)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ndarray_struct_ptr<'ctx>(ctx: &'ctx Context, size_type: IntType<'ctx>) -> PointerType<'ctx> {
|
|
||||||
let i8_type = ctx.i8_type();
|
|
||||||
|
|
||||||
let ndarray_ty = NpArrayType { size_type, elem_type: i8_type.as_basic_type_enum() };
|
|
||||||
let struct_ty = ndarray_ty.fields().whole_struct.as_struct_type(ctx);
|
|
||||||
struct_ty.ptr_type(AddressSpace::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_nac3_ndarray_size<'ctx>(
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
ndarray: NpArrayValue<'ctx>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
let size_type = ndarray.ty.size_type;
|
|
||||||
let function = get_size_type_dependent_function(ctx, size_type, "__nac3_ndarray_size", || {
|
|
||||||
size_type.fn_type(&[get_ndarray_struct_ptr(ctx.ctx, size_type).into()], false)
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.builder
|
|
||||||
.build_call(function, &[ndarray.ptr.into()], "size")
|
|
||||||
.unwrap()
|
|
||||||
.try_as_basic_value()
|
|
||||||
.unwrap_left()
|
|
||||||
.into_int_value()
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::{path::Path, process::Command};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn run_irrt_test() {
|
|
||||||
assert!(
|
|
||||||
cfg!(feature = "test"),
|
|
||||||
"Please do `cargo test -F test` to compile `irrt_test.out` and run test"
|
|
||||||
);
|
|
||||||
|
|
||||||
let irrt_test_out_path = Path::new(concat!(env!("OUT_DIR"), "/irrt_test.out"));
|
|
||||||
let output = Command::new(irrt_test_out_path.to_str().unwrap()).output().unwrap();
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
eprintln!("irrt_test failed with status {}:", output.status);
|
|
||||||
eprintln!("====== stdout ======");
|
|
||||||
eprintln!("{}", String::from_utf8(output.stdout).unwrap());
|
|
||||||
eprintln!("====== stderr ======");
|
|
||||||
eprintln!("{}", String::from_utf8(output.stderr).unwrap());
|
|
||||||
eprintln!("====================");
|
|
||||||
|
|
||||||
panic!("irrt_test failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -86,6 +86,135 @@ pub fn call_stackrestore<'ctx>(ctx: &CodeGenContext<'ctx, '_>, ptr: PointerValue
|
||||||
ctx.builder.build_call(intrinsic_fn, &[ptr.into()], "").unwrap();
|
ctx.builder.build_call(intrinsic_fn, &[ptr.into()], "").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.abs`](https://llvm.org/docs/LangRef.html#llvm-abs-intrinsic) intrinsic.
|
||||||
|
///
|
||||||
|
/// * `src` - The value for which the absolute value is to be returned.
|
||||||
|
/// * `is_int_min_poison` - Whether `poison` is to be returned if `src` is `INT_MIN`.
|
||||||
|
pub fn call_int_abs<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
src: IntValue<'ctx>,
|
||||||
|
is_int_min_poison: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.abs";
|
||||||
|
|
||||||
|
debug_assert_eq!(is_int_min_poison.get_type().get_bit_width(), 1);
|
||||||
|
debug_assert!(is_int_min_poison.is_const());
|
||||||
|
|
||||||
|
let llvm_src_t = src.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_src_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[src.into(), is_int_min_poison.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.smax`](https://llvm.org/docs/LangRef.html#llvm-smax-intrinsic) intrinsic.
|
||||||
|
pub fn call_int_smax<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
a: IntValue<'ctx>,
|
||||||
|
b: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.smax";
|
||||||
|
|
||||||
|
debug_assert_eq!(a.get_type().get_bit_width(), b.get_type().get_bit_width());
|
||||||
|
|
||||||
|
let llvm_int_t = a.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_int_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[a.into(), b.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.smin`](https://llvm.org/docs/LangRef.html#llvm-smin-intrinsic) intrinsic.
|
||||||
|
pub fn call_int_smin<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
a: IntValue<'ctx>,
|
||||||
|
b: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.smin";
|
||||||
|
|
||||||
|
debug_assert_eq!(a.get_type().get_bit_width(), b.get_type().get_bit_width());
|
||||||
|
|
||||||
|
let llvm_int_t = a.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_int_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[a.into(), b.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.umax`](https://llvm.org/docs/LangRef.html#llvm-umax-intrinsic) intrinsic.
|
||||||
|
pub fn call_int_umax<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
a: IntValue<'ctx>,
|
||||||
|
b: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.umax";
|
||||||
|
|
||||||
|
debug_assert_eq!(a.get_type().get_bit_width(), b.get_type().get_bit_width());
|
||||||
|
|
||||||
|
let llvm_int_t = a.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_int_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[a.into(), b.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.umin`](https://llvm.org/docs/LangRef.html#llvm-umin-intrinsic) intrinsic.
|
||||||
|
pub fn call_int_umin<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
a: IntValue<'ctx>,
|
||||||
|
b: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.umin";
|
||||||
|
|
||||||
|
debug_assert_eq!(a.get_type().get_bit_width(), b.get_type().get_bit_width());
|
||||||
|
|
||||||
|
let llvm_int_t = a.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_int_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[a.into(), b.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Invokes the [`llvm.memcpy`](https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic) intrinsic.
|
/// Invokes the [`llvm.memcpy`](https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic) intrinsic.
|
||||||
///
|
///
|
||||||
/// * `dest` - The pointer to the destination. Must be a pointer to an integer type.
|
/// * `dest` - The pointer to the destination. Must be a pointer to an integer type.
|
||||||
|
@ -165,122 +294,28 @@ pub fn call_memcpy_generic<'ctx>(
|
||||||
call_memcpy(ctx, dest, src, len, is_volatile);
|
call_memcpy(ctx, dest, src, len, is_volatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro to find and generate build call for llvm intrinsic (body of llvm intrinsic function)
|
/// Invokes the [`llvm.sqrt`](https://llvm.org/docs/LangRef.html#llvm-sqrt-intrinsic) intrinsic.
|
||||||
///
|
pub fn call_float_sqrt<'ctx>(
|
||||||
/// Arguments:
|
|
||||||
/// * `$ctx:ident`: Reference to the current Code Generation Context
|
|
||||||
/// * `$name:ident`: Optional name to be assigned to the llvm build call (Option<&str>)
|
|
||||||
/// * `$llvm_name:literal`: Name of underlying llvm intrinsic function
|
|
||||||
/// * `$map_fn:ident`: Mapping function to be applied on `BasicValue` (`BasicValue` -> Function Return Type)
|
|
||||||
/// Use `BasicValueEnum::into_int_value` for Integer return type and `BasicValueEnum::into_float_value` for Float return type
|
|
||||||
/// * `$llvm_ty:ident`: Type of first operand
|
|
||||||
/// * `,($val:ident)*`: Comma separated list of operands
|
|
||||||
macro_rules! generate_llvm_intrinsic_fn_body {
|
|
||||||
($ctx:ident, $name:ident, $llvm_name:literal, $map_fn:expr, $llvm_ty:ident $(,$val:ident)*) => {{
|
|
||||||
const FN_NAME: &str = concat!("llvm.", $llvm_name);
|
|
||||||
let intrinsic_fn = Intrinsic::find(FN_NAME).and_then(|intrinsic| intrinsic.get_declaration(&$ctx.module, &[$llvm_ty.into()])).unwrap();
|
|
||||||
$ctx.builder.build_call(intrinsic_fn, &[$($val.into()),*], $name.unwrap_or_default()).map(CallSiteValue::try_as_basic_value).map(|v| v.map_left($map_fn)).map(Either::unwrap_left).unwrap()
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Macro to generate the llvm intrinsic function using [`generate_llvm_intrinsic_fn_body`].
|
|
||||||
///
|
|
||||||
/// Arguments:
|
|
||||||
/// * `float/int`: Indicates the return and argument type of the function
|
|
||||||
/// * `$fn_name:ident`: The identifier of the rust function to be generated
|
|
||||||
/// * `$llvm_name:literal`: Name of underlying llvm intrinsic function
|
|
||||||
/// Omit "llvm." prefix from the function name i.e. use "ceil" instead of "llvm.ceil"
|
|
||||||
/// * `$val:ident`: The operand for unary operations
|
|
||||||
/// * `$val1:ident`, `$val2:ident`: The operands for binary operations
|
|
||||||
macro_rules! generate_llvm_intrinsic_fn {
|
|
||||||
("float", $fn_name:ident, $llvm_name:literal, $val:ident) => {
|
|
||||||
#[doc = concat!("Invokes the [`", stringify!($llvm_name), "`](https://llvm.org/docs/LangRef.html#llvm-", stringify!($llvm_name), "-intrinsic) intrinsic." )]
|
|
||||||
pub fn $fn_name<'ctx> (
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
$val: FloatValue<'ctx>,
|
val: FloatValue<'ctx>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> FloatValue<'ctx> {
|
) -> FloatValue<'ctx> {
|
||||||
let llvm_ty = $val.get_type();
|
const FN_NAME: &str = "llvm.sqrt";
|
||||||
generate_llvm_intrinsic_fn_body!(ctx, name, $llvm_name, BasicValueEnum::into_float_value, llvm_ty, $val)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
("float", $fn_name:ident, $llvm_name:literal, $val1:ident, $val2:ident) => {
|
|
||||||
#[doc = concat!("Invokes the [`", stringify!($llvm_name), "`](https://llvm.org/docs/LangRef.html#llvm-", stringify!($llvm_name), "-intrinsic) intrinsic." )]
|
|
||||||
pub fn $fn_name<'ctx> (
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
$val1: FloatValue<'ctx>,
|
|
||||||
$val2: FloatValue<'ctx>,
|
|
||||||
name: Option<&str>,
|
|
||||||
) -> FloatValue<'ctx> {
|
|
||||||
debug_assert_eq!($val1.get_type(), $val2.get_type());
|
|
||||||
let llvm_ty = $val1.get_type();
|
|
||||||
generate_llvm_intrinsic_fn_body!(ctx, name, $llvm_name, BasicValueEnum::into_float_value, llvm_ty, $val1, $val2)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
("int", $fn_name:ident, $llvm_name:literal, $val1:ident, $val2:ident) => {
|
|
||||||
#[doc = concat!("Invokes the [`", stringify!($llvm_name), "`](https://llvm.org/docs/LangRef.html#llvm-", stringify!($llvm_name), "-intrinsic) intrinsic." )]
|
|
||||||
pub fn $fn_name<'ctx> (
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
$val1: IntValue<'ctx>,
|
|
||||||
$val2: IntValue<'ctx>,
|
|
||||||
name: Option<&str>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
debug_assert_eq!($val1.get_type().get_bit_width(), $val2.get_type().get_bit_width());
|
|
||||||
let llvm_ty = $val1.get_type();
|
|
||||||
generate_llvm_intrinsic_fn_body!(ctx, name, $llvm_name, BasicValueEnum::into_int_value, llvm_ty, $val1, $val2)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invokes the [`llvm.abs`](https://llvm.org/docs/LangRef.html#llvm-abs-intrinsic) intrinsic.
|
let llvm_float_t = val.get_type();
|
||||||
///
|
|
||||||
/// * `src` - The value for which the absolute value is to be returned.
|
|
||||||
/// * `is_int_min_poison` - Whether `poison` is to be returned if `src` is `INT_MIN`.
|
|
||||||
pub fn call_int_abs<'ctx>(
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
src: IntValue<'ctx>,
|
|
||||||
is_int_min_poison: IntValue<'ctx>,
|
|
||||||
name: Option<&str>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
debug_assert_eq!(is_int_min_poison.get_type().get_bit_width(), 1);
|
|
||||||
debug_assert!(is_int_min_poison.is_const());
|
|
||||||
|
|
||||||
let src_type = src.get_type();
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
generate_llvm_intrinsic_fn_body!(
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
ctx,
|
.unwrap();
|
||||||
name,
|
|
||||||
"abs",
|
ctx.builder
|
||||||
BasicValueEnum::into_int_value,
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
src_type,
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
src,
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
is_int_min_poison
|
.map(Either::unwrap_left)
|
||||||
)
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_llvm_intrinsic_fn!("int", call_int_smax, "smax", a, b);
|
|
||||||
generate_llvm_intrinsic_fn!("int", call_int_smin, "smin", a, b);
|
|
||||||
generate_llvm_intrinsic_fn!("int", call_int_umax, "umax", a, b);
|
|
||||||
generate_llvm_intrinsic_fn!("int", call_int_umin, "umin", a, b);
|
|
||||||
generate_llvm_intrinsic_fn!("int", call_expect, "expect", val, expected_val);
|
|
||||||
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_sqrt, "sqrt", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_sin, "sin", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_cos, "cos", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_pow, "pow", val, power);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_exp, "exp", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_exp2, "exp2", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_log, "log", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_log10, "log10", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_log2, "log2", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_fabs, "fabs", src);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_minnum, "minnum", val, power);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_maxnum, "maxnum", val, power);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_copysign, "copysign", mag, sgn);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_floor, "floor", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_ceil, "ceil", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_round, "round", val);
|
|
||||||
generate_llvm_intrinsic_fn!("float", call_float_rint, "rint", val);
|
|
||||||
|
|
||||||
/// Invokes the [`llvm.powi`](https://llvm.org/docs/LangRef.html#llvm-powi-intrinsic) intrinsic.
|
/// Invokes the [`llvm.powi`](https://llvm.org/docs/LangRef.html#llvm-powi-intrinsic) intrinsic.
|
||||||
pub fn call_float_powi<'ctx>(
|
pub fn call_float_powi<'ctx>(
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
@ -306,3 +341,392 @@ pub fn call_float_powi<'ctx>(
|
||||||
.map(Either::unwrap_left)
|
.map(Either::unwrap_left)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.sin`](https://llvm.org/docs/LangRef.html#llvm-sin-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_sin<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.sin";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.cos`](https://llvm.org/docs/LangRef.html#llvm-cos-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_cos<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.cos";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.pow`](https://llvm.org/docs/LangRef.html#llvm-pow-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_pow<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
power: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.pow";
|
||||||
|
|
||||||
|
debug_assert_eq!(val.get_type(), power.get_type());
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into(), power.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.exp`](https://llvm.org/docs/LangRef.html#llvm-exp-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_exp<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.exp";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.exp2`](https://llvm.org/docs/LangRef.html#llvm-exp2-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_exp2<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.exp2";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.log`](https://llvm.org/docs/LangRef.html#llvm-log-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_log<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.log";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.log10`](https://llvm.org/docs/LangRef.html#llvm-log10-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_log10<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.log10";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.log2`](https://llvm.org/docs/LangRef.html#llvm-log2-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_log2<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.log2";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.fabs`](https://llvm.org/docs/LangRef.html#llvm-fabs-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_fabs<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
src: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.fabs";
|
||||||
|
|
||||||
|
let llvm_src_t = src.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_src_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[src.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.minnum`](https://llvm.org/docs/LangRef.html#llvm-minnum-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_minnum<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val1: FloatValue<'ctx>,
|
||||||
|
val2: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.minnum";
|
||||||
|
|
||||||
|
debug_assert_eq!(val1.get_type(), val2.get_type());
|
||||||
|
|
||||||
|
let llvm_float_t = val1.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val1.into(), val2.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.maxnum`](https://llvm.org/docs/LangRef.html#llvm-maxnum-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_maxnum<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val1: FloatValue<'ctx>,
|
||||||
|
val2: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.maxnum";
|
||||||
|
|
||||||
|
debug_assert_eq!(val1.get_type(), val2.get_type());
|
||||||
|
|
||||||
|
let llvm_float_t = val1.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val1.into(), val2.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.copysign`](https://llvm.org/docs/LangRef.html#llvm-copysign-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_copysign<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
mag: FloatValue<'ctx>,
|
||||||
|
sgn: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.copysign";
|
||||||
|
|
||||||
|
debug_assert_eq!(mag.get_type(), sgn.get_type());
|
||||||
|
|
||||||
|
let llvm_float_t = mag.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[mag.into(), sgn.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.floor`](https://llvm.org/docs/LangRef.html#llvm-floor-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_floor<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.floor";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.ceil`](https://llvm.org/docs/LangRef.html#llvm-ceil-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_ceil<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.ceil";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.round`](https://llvm.org/docs/LangRef.html#llvm-round-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_round<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.round";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.rint`](https://llvm.org/docs/LangRef.html#llvm-rint-intrinsic) intrinsic.
|
||||||
|
pub fn call_float_rint<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: FloatValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> FloatValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.rint";
|
||||||
|
|
||||||
|
let llvm_float_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_float_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the [`llvm.expect`](https://llvm.org/docs/LangRef.html#llvm-expect-intrinsic) intrinsic.
|
||||||
|
pub fn call_expect<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
val: IntValue<'ctx>,
|
||||||
|
expected_val: IntValue<'ctx>,
|
||||||
|
name: Option<&str>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "llvm.expect";
|
||||||
|
|
||||||
|
debug_assert_eq!(val.get_type().get_bit_width(), expected_val.get_type().get_bit_width());
|
||||||
|
|
||||||
|
let llvm_int_t = val.get_type();
|
||||||
|
|
||||||
|
let intrinsic_fn = Intrinsic::find(FN_NAME)
|
||||||
|
.and_then(|intrinsic| intrinsic.get_declaration(&ctx.module, &[llvm_int_t.into()]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(intrinsic_fn, &[val.into(), expected_val.into()], name.unwrap_or_default())
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||||
|
.map(Either::unwrap_left)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,4 +23,3 @@ pub mod codegen;
|
||||||
pub mod symbol_resolver;
|
pub mod symbol_resolver;
|
||||||
pub mod toplevel;
|
pub mod toplevel;
|
||||||
pub mod typecheck;
|
pub mod typecheck;
|
||||||
pub mod util;
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
use crate::util::SizeVariant;
|
|
||||||
use helper::{debug_assert_prim_is_allowed, make_exception_fields, PrimDefDetails};
|
use helper::{debug_assert_prim_is_allowed, make_exception_fields, PrimDefDetails};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
|
@ -279,12 +278,21 @@ pub fn get_builtins(unifier: &mut Unifier, primitives: &PrimitiveStore) -> Built
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_variant_to_int_type(variant: SizeVariant, primitives: &PrimitiveStore) -> Type {
|
/// A helper enum used by [`BuiltinBuilder`]
|
||||||
match variant {
|
#[derive(Clone, Copy)]
|
||||||
|
enum SizeVariant {
|
||||||
|
Bits32,
|
||||||
|
Bits64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeVariant {
|
||||||
|
fn of_int(self, primitives: &PrimitiveStore) -> Type {
|
||||||
|
match self {
|
||||||
SizeVariant::Bits32 => primitives.int32,
|
SizeVariant::Bits32 => primitives.int32,
|
||||||
SizeVariant::Bits64 => primitives.int64,
|
SizeVariant::Bits64 => primitives.int64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct BuiltinBuilder<'a> {
|
struct BuiltinBuilder<'a> {
|
||||||
unifier: &'a mut Unifier,
|
unifier: &'a mut Unifier,
|
||||||
|
@ -953,9 +961,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, fun, args, generator| {
|
|ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_copy(ctx, &obj, fun, &args, generator)
|
||||||
// gen_ndarray_copy(ctx, &obj, fun, &args, generator)
|
.map(|val| Some(val.as_basic_value_enum()))
|
||||||
// .map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -971,9 +978,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, fun, args, generator| {
|
|ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_fill(ctx, &obj, fun, &args, generator)?;
|
||||||
// gen_ndarray_fill(ctx, &obj, fun, &args, generator)?;
|
Ok(None)
|
||||||
// Ok(None)
|
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -1053,7 +1059,7 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// The size variant of the function determines the size of the returned int.
|
// The size variant of the function determines the size of the returned int.
|
||||||
let int_sized = size_variant_to_int_type(size_variant, self.primitives);
|
let int_sized = size_variant.of_int(self.primitives);
|
||||||
|
|
||||||
let ndarray_int_sized =
|
let ndarray_int_sized =
|
||||||
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
|
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
|
||||||
|
@ -1078,7 +1084,7 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
|
|
||||||
let ret_elem_ty = size_variant_to_int_type(size_variant, &ctx.primitives);
|
let ret_elem_ty = size_variant.of_int(&ctx.primitives);
|
||||||
Ok(Some(builtin_fns::call_round(generator, ctx, (arg_ty, arg), ret_elem_ty)?))
|
Ok(Some(builtin_fns::call_round(generator, ctx, (arg_ty, arg), ret_elem_ty)?))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -1119,7 +1125,7 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.ty));
|
make_ndarray_ty(self.unifier, self.primitives, Some(float), Some(common_ndim.ty));
|
||||||
|
|
||||||
// The size variant of the function determines the type of int returned
|
// The size variant of the function determines the type of int returned
|
||||||
let int_sized = size_variant_to_int_type(size_variant, self.primitives);
|
let int_sized = size_variant.of_int(self.primitives);
|
||||||
let ndarray_int_sized =
|
let ndarray_int_sized =
|
||||||
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
|
make_ndarray_ty(self.unifier, self.primitives, Some(int_sized), Some(common_ndim.ty));
|
||||||
|
|
||||||
|
@ -1142,7 +1148,7 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
let arg_ty = fun.0.args[0].ty;
|
let arg_ty = fun.0.args[0].ty;
|
||||||
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
let arg = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
|
|
||||||
let ret_elem_ty = size_variant_to_int_type(size_variant, &ctx.primitives);
|
let ret_elem_ty = size_variant.of_int(&ctx.primitives);
|
||||||
let func = match kind {
|
let func = match kind {
|
||||||
Kind::Ceil => builtin_fns::call_ceil,
|
Kind::Ceil => builtin_fns::call_ceil,
|
||||||
Kind::Floor => builtin_fns::call_floor,
|
Kind::Floor => builtin_fns::call_floor,
|
||||||
|
@ -1193,14 +1199,13 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
self.ndarray_float,
|
self.ndarray_float,
|
||||||
&[(self.ndarray_factory_fn_shape_arg_tvar.ty, "shape")],
|
&[(self.ndarray_factory_fn_shape_arg_tvar.ty, "shape")],
|
||||||
Box::new(move |ctx, obj, fun, args, generator| {
|
Box::new(move |ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
let func = match prim {
|
||||||
// let func = match prim {
|
PrimDef::FunNpNDArray | PrimDef::FunNpEmpty => gen_ndarray_empty,
|
||||||
// PrimDef::FunNpNDArray | PrimDef::FunNpEmpty => gen_ndarray_empty,
|
PrimDef::FunNpZeros => gen_ndarray_zeros,
|
||||||
// PrimDef::FunNpZeros => gen_ndarray_zeros,
|
PrimDef::FunNpOnes => gen_ndarray_ones,
|
||||||
// PrimDef::FunNpOnes => gen_ndarray_ones,
|
_ => unreachable!(),
|
||||||
// _ => unreachable!(),
|
};
|
||||||
// };
|
func(ctx, &obj, fun, &args, generator).map(|val| Some(val.as_basic_value_enum()))
|
||||||
// func(ctx, &obj, fun, &args, generator).map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1246,9 +1251,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, fun, args, generator| {
|
|ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_array(ctx, &obj, fun, &args, generator)
|
||||||
// gen_ndarray_array(ctx, &obj, fun, &args, generator)
|
.map(|val| Some(val.as_basic_value_enum()))
|
||||||
// .map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -1266,9 +1270,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
// type variable
|
// type variable
|
||||||
&[(self.list_int32, "shape"), (tv.ty, "fill_value")],
|
&[(self.list_int32, "shape"), (tv.ty, "fill_value")],
|
||||||
Box::new(move |ctx, obj, fun, args, generator| {
|
Box::new(move |ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_full(ctx, &obj, fun, &args, generator)
|
||||||
// gen_ndarray_full(ctx, &obj, fun, &args, generator)
|
.map(|val| Some(val.as_basic_value_enum()))
|
||||||
// .map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1300,9 +1303,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
resolver: None,
|
resolver: None,
|
||||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||||
|ctx, obj, fun, args, generator| {
|
|ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_eye(ctx, &obj, fun, &args, generator)
|
||||||
// gen_ndarray_eye(ctx, &obj, fun, &args, generator)
|
.map(|val| Some(val.as_basic_value_enum()))
|
||||||
// .map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
|
@ -1315,9 +1317,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||||
self.ndarray_float_2d,
|
self.ndarray_float_2d,
|
||||||
&[(int32, "n")],
|
&[(int32, "n")],
|
||||||
Box::new(|ctx, obj, fun, args, generator| {
|
Box::new(|ctx, obj, fun, args, generator| {
|
||||||
todo!()
|
gen_ndarray_identity(ctx, &obj, fun, &args, generator)
|
||||||
// gen_ndarray_identity(ctx, &obj, fun, &args, generator)
|
.map(|val| Some(val.as_basic_value_enum()))
|
||||||
// .map(|val| Some(val.as_basic_value_enum()))
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -361,13 +361,7 @@ impl TopLevelComposer {
|
||||||
});
|
});
|
||||||
let range = unifier.add_ty(TypeEnum::TObj {
|
let range = unifier.add_ty(TypeEnum::TObj {
|
||||||
obj_id: PrimDef::Range.id(),
|
obj_id: PrimDef::Range.id(),
|
||||||
fields: [
|
fields: HashMap::new(),
|
||||||
("start".into(), (int32, true)),
|
|
||||||
("stop".into(), (int32, true)),
|
|
||||||
("step".into(), (int32, true)),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
params: VarMap::new(),
|
params: VarMap::new(),
|
||||||
});
|
});
|
||||||
let str = unifier.add_ty(TypeEnum::TObj {
|
let str = unifier.add_ty(TypeEnum::TObj {
|
||||||
|
|
|
@ -4,12 +4,13 @@ use std::iter::once;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc};
|
||||||
|
|
||||||
|
use super::typedef::OperatorInfo;
|
||||||
use super::{
|
use super::{
|
||||||
magic_methods::*,
|
magic_methods::*,
|
||||||
type_error::{TypeError, TypeErrorKind},
|
type_error::TypeError,
|
||||||
typedef::{
|
typedef::{
|
||||||
into_var_map, iter_type_vars, Call, CallId, FunSignature, FuncArg, OperatorInfo,
|
into_var_map, iter_type_vars, Call, CallId, FunSignature, FuncArg, RecordField, Type,
|
||||||
RecordField, RecordKey, Type, TypeEnum, TypeVar, Unifier, VarMap,
|
TypeEnum, TypeVar, Unifier, VarMap,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -113,14 +114,6 @@ fn report_error<T>(msg: &str, location: Location) -> Result<T, HashSet<String>>
|
||||||
Err(HashSet::from([format!("{msg} at {location}")]))
|
Err(HashSet::from([format!("{msg} at {location}")]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_type_error<T>(
|
|
||||||
kind: TypeErrorKind,
|
|
||||||
loc: Option<Location>,
|
|
||||||
unifier: &Unifier,
|
|
||||||
) -> Result<T, HashSet<String>> {
|
|
||||||
Err(HashSet::from([TypeError::new(kind, loc).to_display(unifier).to_string()]))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Fold<()> for Inferencer<'a> {
|
impl<'a> Fold<()> for Inferencer<'a> {
|
||||||
type TargetU = Option<Type>;
|
type TargetU = Option<Type>;
|
||||||
type Error = HashSet<String>;
|
type Error = HashSet<String>;
|
||||||
|
@ -1666,11 +1659,9 @@ impl<'a> Inferencer<'a> {
|
||||||
// just a fast path
|
// just a fast path
|
||||||
match (fields.get(&attr), ctx == ExprContext::Store) {
|
match (fields.get(&attr), ctx == ExprContext::Store) {
|
||||||
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
||||||
(Some((ty, false)), true) => report_type_error(
|
(Some((_, false)), true) => {
|
||||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
report_error(&format!("Field `{attr}` is immutable"), value.location)
|
||||||
Some(value.location),
|
}
|
||||||
self.unifier,
|
|
||||||
),
|
|
||||||
(None, mutable) => {
|
(None, mutable) => {
|
||||||
// Check whether it is a class attribute
|
// Check whether it is a class attribute
|
||||||
let defs = self.top_level.definitions.read();
|
let defs = self.top_level.definitions.read();
|
||||||
|
@ -1692,11 +1683,13 @@ impl<'a> Inferencer<'a> {
|
||||||
&format!("Class Attribute `{attr}` is immutable"),
|
&format!("Class Attribute `{attr}` is immutable"),
|
||||||
value.location,
|
value.location,
|
||||||
),
|
),
|
||||||
None => report_type_error(
|
None => {
|
||||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
let t = self.unifier.stringify(ty);
|
||||||
Some(value.location),
|
report_error(
|
||||||
self.unifier,
|
&format!("`{t}::{attr}` field/method does not exist"),
|
||||||
),
|
value.location,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,10 @@ void output_float64(double x) {
|
||||||
|
|
||||||
void output_range(int32_t range[3]) {
|
void output_range(int32_t range[3]) {
|
||||||
printf("range(");
|
printf("range(");
|
||||||
printf("%d, %d", range[0], range[1]);
|
if (range[0] != 0) {
|
||||||
|
printf("%d, ", range[0]);
|
||||||
|
}
|
||||||
|
printf("%d", range[1]);
|
||||||
if (range[2] != 1) {
|
if (range[2] != 1) {
|
||||||
printf(", %d", range[2]);
|
printf(", %d", range[2]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,6 @@ def patch(module):
|
||||||
"output_uint32",
|
"output_uint32",
|
||||||
"output_uint64",
|
"output_uint64",
|
||||||
"output_strln",
|
"output_strln",
|
||||||
"output_range",
|
|
||||||
}:
|
}:
|
||||||
return print
|
return print
|
||||||
elif name == "dbg_stack_address":
|
elif name == "dbg_stack_address":
|
||||||
|
|
|
@ -81,7 +81,6 @@ in rec {
|
||||||
''
|
''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
ln -s ${llvm-nac3}/bin/clang.exe $out/bin/clang-irrt.exe
|
ln -s ${llvm-nac3}/bin/clang.exe $out/bin/clang-irrt.exe
|
||||||
ln -s ${llvm-nac3}/bin/clang.exe $out/bin/clang-irrt-test.exe
|
|
||||||
ln -s ${llvm-nac3}/bin/llvm-as.exe $out/bin/llvm-as-irrt.exe
|
ln -s ${llvm-nac3}/bin/llvm-as.exe $out/bin/llvm-as-irrt.exe
|
||||||
'';
|
'';
|
||||||
nac3artiq = pkgs.rustPlatform.buildRustPackage {
|
nac3artiq = pkgs.rustPlatform.buildRustPackage {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
{ pkgs } : [
|
{ pkgs } : [
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "1v8zkfcbf1ga2ndpd1j0dwv5s1rassxs2b5pjhcsmqwjcvczba1m";
|
sha256 = "0ksz7xz1lbwsmdr9sa1444k0dlfkbd8k11pq7w08ir7r1wjy6fid";
|
||||||
name = "mingw-w64-clang-x86_64-libunwind-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libunwind-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "0mfd8wrmgx12j5gf354j7pk1l3lg9ykxvq75xdk3jipsr6hbn846";
|
sha256 = "0r8skyjqv4cpkqif0niakx4hdpkscil1zf6mzj34pqna0j5gdnq2";
|
||||||
name = "mingw-w64-clang-x86_64-libc++-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libc++-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -31,9 +31,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.2-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "0phb9hwqksk1rg29yhwlc7si78zav19c2kac0i841pc7mc2n9gzx";
|
sha256 = "14p4xxaxjjy6j1ingji82xhai1mc1gls5ali6z40fbb2ylxkaggs";
|
||||||
name = "mingw-w64-clang-x86_64-xz-5.6.2-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-xz-5.6.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -43,81 +43,81 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1imipb0dz4w6x4n9arn22imyzzcwdlf2cqxvn7irqq7w9by6fy0b";
|
sha256 = "177b3rmsknqq6hf0zqwva71s3avh20ca7vzznp2ls2z5qm8vhhlp";
|
||||||
name = "mingw-w64-clang-x86_64-libxml2-2.12.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libxml2-2.12.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zstd-1.5.6-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zstd-1.5.5-1-any.pkg.tar.zst";
|
||||||
sha256 = "02cp5ci8w50k7xn38mpkwnr8sn898v18wcc07y8f9sfla7vcyfix";
|
sha256 = "07739wmwgxf0d6db4p8w302a6jwcm01aafr1s8jvcl5k1h5a1m2m";
|
||||||
name = "mingw-w64-clang-x86_64-zstd-1.5.6-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-zstd-1.5.5-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "0rpbgvvinsqflhd3nhfxk0g0yy8j80zzw5yx6573ak0m78a9fa06";
|
sha256 = "0ibiy01v16naik9pj32ch7a9pkbw4yrn3gyq7p0y6kcc63fkjazy";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-libs-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-llvm-libs-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "185g5h8q3x3rav9lp2njln58ny2idh2067fd02j3nsbik6glshpf";
|
sha256 = "1hcfz6nb6svmmcqzfrdi96az2x7mzj0cispdv2ssbgn7nkf19pi0";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-llvm-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "089hji3yd7wsd03v9mdfgc99l5k1dql8kg7p3hy13vrbgfsabxhc";
|
sha256 = "1k17d18g7rmq2ph4kq1mf84vs8133jzf52nkv6syh39ypjga67wa";
|
||||||
name = "mingw-w64-clang-x86_64-clang-libs-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-clang-libs-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "1dwcxnv1k5ljim5ys4h1c3jlrdpi0054z094ynav7if65i8zjj4a";
|
sha256 = "1w2j0vs888haz9shjr1l8dc4j957sk1p0377zzipkbqnzqwjf1z8";
|
||||||
name = "mingw-w64-clang-x86_64-compiler-rt-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-compiler-rt-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
sha256 = "1h3cdcajz29iq7vja908kkijz1vb9xn0f7w1lw1ima0q0zhinv4q";
|
sha256 = "18csfwlk2h9pr4411crx1b41qjzn5jgbssm3h109nzwbdizkp62h";
|
||||||
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-headers-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
sha256 = "15kamyi3b0j6f5zxin4i2jgzjc7lzvwl4z5cz3dx0i8hg91aq0n7";
|
sha256 = "03l1zkrxgxxssp430xcv2gch1d03rbnbk1c0vgiqxigcs8lljh2g";
|
||||||
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-crt-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "1vpij5d06m4kjy3qv8bizwlkl21gcv6fv0r2f1j9bclgm6k3144x";
|
sha256 = "1ai4gl7ybpk9n10jmbpf3zzfa893m1krj5qhf44ajln0jabdfnbn";
|
||||||
name = "mingw-w64-clang-x86_64-lld-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-lld-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
sha256 = "0qdvgs1rmjjhn9klf9kpw7l0ydz36rr5fasn4q9gpby2lgl11bkb";
|
sha256 = "1svhjzwhvl4ldl439jhgfy47g05y2af1cjqvydgijn1dd4g8y8vq";
|
||||||
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libwinpthread-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
sha256 = "0rh2mn078cifcmr4as4k57jxjln5lbnsmpx47h9d0s5d2i8sf2rc";
|
sha256 = "0jxdhkl256vnr13xf1x3fyjrdf764zg70xcs3gki3rg109f0a6xk";
|
||||||
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-winpthreads-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "1qny934nv4g75k9gb5sf31v24bgafkg6qw7r35xv3in491w6annq";
|
sha256 = "0ahfic7vdfv96k5v7fdkgk1agk28l833xjn2igrmbvqg96ak0w6n";
|
||||||
name = "mingw-w64-clang-x86_64-clang-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-clang-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.29.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.27.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "01xg1h1a8kda0kq2921w25ybvm1ms7lfdzday0hv93f3myq7briq";
|
sha256 = "06y3sgqv6a0gr3dsbzs36jrj8adklssgjqi2ms5clsyq6ay4f91r";
|
||||||
name = "mingw-w64-clang-x86_64-c-ares-1.29.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-c-ares-1.27.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -127,9 +127,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "13nz49li39z1zgfx1q9jg4vrmyrmqb6qdq0nqshidaqc6zr16k3g";
|
sha256 = "16myvbg33q5s7jl30w5qd8n8f1r05335ms8r61234vn52n32l2c4";
|
||||||
name = "mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libunistring-1.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -151,9 +151,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-p11-kit-0.25.5-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-p11-kit-0.25.3-2-any.pkg.tar.zst";
|
||||||
sha256 = "00yz6cmr1ldlrskv811n345xcia88mj7w4fyx4m9z5848jxgsabd";
|
sha256 = "1jrwkc4lvw5hm5rqmi5gqh7mfkbqfa5gi81zjij0krnl0gaxw3c8";
|
||||||
name = "mingw-w64-clang-x86_64-p11-kit-0.25.5-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-p11-kit-0.25.3-2-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -163,9 +163,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.3.1-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.2.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "0ywhwm4kw3qjzv0872qwabnsq2rzbmqjb9m69q3fykjl0m9gigsa";
|
sha256 = "0ix2r4ll09m2z5vz2k94gmwfs0pp3ipvjdimwzx7v6xhcs2l25lz";
|
||||||
name = "mingw-w64-clang-x86_64-openssl-3.3.1-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-openssl-3.2.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -175,33 +175,27 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp2-1.61.0-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp2-1.60.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "07bkk98126gy4k6lb9rrqqnzjfz9j2rsr5dzr2djmzdkw0h4dr95";
|
sha256 = "0wxw8266hf4qd2m4zpgb1wvlrnaksmcrs0kh5y9zpf2y5sy8f2bq";
|
||||||
name = "mingw-w64-clang-x86_64-nghttp2-1.61.0-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-nghttp2-1.60.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp3-1.4.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.6.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "007w2252nzn274j4wjc1vf56xyzzh5vg3blj1hil7mlmffgvc923";
|
sha256 = "1racc7cyzj22kink9w8m8jv73ji5hfg6r6d1ka9dqmvcbx04r8p0";
|
||||||
name = "mingw-w64-clang-x86_64-nghttp3-1.4.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-curl-8.6.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.8.0-10-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.76.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "024z5b1achkf448gxqy1i3gcw371x54kfl6igv08b5wb3rrw35a4";
|
sha256 = "0ny3bvwvn5wmqrxzhdfw34akr0kj0m7rg9lg3w5yibqz2mkqhk11";
|
||||||
name = "mingw-w64-clang-x86_64-curl-8.8.0-10-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-rust-1.76.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.79.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-pkgconf-1~2.1.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "0i7s88hj8m4920xifkj7i4b4sq8cqq7p5cypp3jqx3dc44pwm19a";
|
sha256 = "00kxqg9ds4q74lxrzjh8z0858smqbi1j9r06s0zjadsql0ln98cq";
|
||||||
name = "mingw-w64-clang-x86_64-rust-1.79.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-pkgconf-12.1.1-1-any.pkg.tar.zst";
|
||||||
})
|
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-pkgconf-1~2.2.0-1-any.pkg.tar.zst";
|
|
||||||
sha256 = "1y44ijg3y8p80f1yn9972nshrnyrd06a9sh984ajhxg8bi8s5xyl";
|
|
||||||
name = "mingw-w64-clang-x86_64-pkgconf-12.2.0-1-any.pkg.tar.zst";
|
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -247,9 +241,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libarchive-3.7.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libarchive-3.7.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "1ykw6imllgxv6lsgwxx1miqjr4l1iryqkrj286jcbfrb8ghpzhv5";
|
sha256 = "1p84yh6yzkdpmr02vyvgz16x5gycckah25jkdc2py09l7iw96bmw";
|
||||||
name = "mingw-w64-clang-x86_64-libarchive-3.7.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libarchive-3.7.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -259,9 +253,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ninja-1.12.1-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ninja-1.11.1-3-any.pkg.tar.zst";
|
||||||
sha256 = "1vj9qaa43v316daz8k4ricmz3f33nhjpj7r0vn979nwmy7hzs7jx";
|
sha256 = "13wjfmyfr952n3ydpldjlwx1nla5xpyvr96ng8pfbyw4z900v5ms";
|
||||||
name = "mingw-w64-clang-x86_64-ninja-1.12.1-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-ninja-1.11.1-3-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -271,9 +265,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.30.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.29.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "07b7132hwhiqrf0l2lgw3g4zw9i2lln3kqc9kg2qijvkapbkmwqb";
|
sha256 = "0l79lf6zihn0k8hz93qnjnq259y45yq19235g9c444jc2w093si1";
|
||||||
name = "mingw-w64-clang-x86_64-cmake-3.30.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-cmake-3.29.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -307,15 +301,15 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-sqlite3-3.46.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-sqlite3-3.45.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "0q676i2z5nr4c71jnd4z5qz9xa1xryl0cpi84w74yvd0p4qiz7y2";
|
sha256 = "1icvw3f08cgi94p0177i46v72wgpsxw95p6kd0sm2w3vj0qlqbcw";
|
||||||
name = "mingw-w64-clang-x86_64-sqlite3-3.46.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-sqlite3-3.45.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tk-8.6.13-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tk-8.6.12-2-any.pkg.tar.zst";
|
||||||
sha256 = "12f6lqx1sglczcnz2ns6sxw9cxwm1klxajqzcrbnfwln1nllz2nd";
|
sha256 = "0pi74q91vl6vw8vvmmwnvrgai3b1aanp0zhca5qsmv8ljh2wdgzx";
|
||||||
name = "mingw-w64-clang-x86_64-tk-8.6.13-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-tk-8.6.12-2-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -325,21 +319,21 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.11.9-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.11.8-1-any.pkg.tar.zst";
|
||||||
sha256 = "0ah1idjqxg7jc07a1gz9z766rjjd0f0c6ri4hpcsimsrbj1zjd3c";
|
sha256 = "0djpf4k8s25nys6nrm2x2v134lcgzhhbjs37ihkg0b3sxmmc3b0p";
|
||||||
name = "mingw-w64-clang-x86_64-python-3.11.9-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-python-3.11.8-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-18.1.8-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openmp-18.1.2-1-any.pkg.tar.zst";
|
||||||
sha256 = "0cy2v0l4af24j34mzj5q5nlzcqhackfajlfj1rpf6mb3rbz23qw9";
|
sha256 = "1v9wm3ja3a7a7yna2bpqky481qf244wc98kfdl7l03k7rkvvydpl";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-openmp-18.1.8-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-openmp-18.1.2-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.27-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.26-1-any.pkg.tar.zst";
|
||||||
sha256 = "06ygz1wa488wqvmxbn74b0fyan4wf3lb6kbwfampgikd1gijww2k";
|
sha256 = "0kdr72y5lc9dl9s1bjrw8g21qmv2iwd1xvn1r21170i277wsmqiv";
|
||||||
name = "mingw-w64-clang-x86_64-openblas-0.3.27-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-openblas-0.3.26-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
|
@ -349,8 +343,8 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-70.2.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-69.1.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "1q4r9bg2hn3jmshvq81xm5zvy9wn35yf0z2ayksrkwph1zzdkvkm";
|
sha256 = "1mc56anasj0v92nlg84m3pa7dbqgjakxw0b4ibqlrr9cq0xzsg4b";
|
||||||
name = "mingw-w64-clang-x86_64-python-setuptools-70.2.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-python-setuptools-69.1.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue