forked from M-Labs/nac3
Compare commits
1 Commits
ndarray-st
...
misc/impl-
Author | SHA1 | Date |
---|---|---|
David Mak | a9ca91c387 |
|
@ -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",
|
||||||
|
@ -158,7 +158,7 @@ dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -421,7 +421,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -749,7 +749,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]]
|
||||||
|
@ -850,7 +850,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -863,7 +863,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1029,22 +1029,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]]
|
||||||
|
@ -1134,7 +1134,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1150,9 +1150,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 +1161,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 +1218,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.70",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1398,9 +1398,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc",
|
||||||
|
@ -1414,51 +1414,51 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnullvm"
|
name = "windows_i686_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yaml-rust"
|
name = "yaml-rust"
|
||||||
|
@ -1486,5 +1486,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";
|
||||||
|
|
|
@ -47,6 +47,7 @@ use parking_lot::{Mutex, RwLock};
|
||||||
|
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::irrt::load_irrt,
|
codegen::irrt::load_irrt,
|
||||||
|
codegen::tracert::TraceRuntimeConfig,
|
||||||
codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry},
|
codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{
|
toplevel::{
|
||||||
|
@ -635,8 +636,13 @@ impl Nac3 {
|
||||||
|
|
||||||
let membuffer = membuffers.clone();
|
let membuffer = membuffers.clone();
|
||||||
py.allow_threads(|| {
|
py.allow_threads(|| {
|
||||||
let (registry, handles) =
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
WorkerRegistry::create_workers(threads, top_level.clone(), &self.llvm_options, &f);
|
threads,
|
||||||
|
top_level.clone(),
|
||||||
|
&self.llvm_options,
|
||||||
|
&TraceRuntimeConfig::default(),
|
||||||
|
&f,
|
||||||
|
);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
[features]
|
|
||||||
test = []
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nac3core"
|
name = "nac3core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
tracing = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
|
@ -28,4 +28,5 @@ indoc = "2.0"
|
||||||
insta = "=1.11.0"
|
insta = "=1.11.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
itertools = "0.13"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use regex::Regex;
|
use std::ffi::OsStr;
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
@ -7,18 +7,24 @@ use std::{
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
use itertools::Itertools;
|
||||||
let irrt_cpp_path = irrt_dir.join("irrt.cpp");
|
use regex::Regex;
|
||||||
|
|
||||||
|
/// Extracts the extension-less filename from a [`Path`].
|
||||||
|
fn path_to_extless_filename(path: &Path) -> &str {
|
||||||
|
path.file_name().map(Path::new).and_then(Path::file_stem).and_then(OsStr::to_str).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compiles a source C file into LLVM bitcode.
|
||||||
|
fn compile_file_to_ir(path: &Path, filename_without_ext: &str) {
|
||||||
/*
|
/*
|
||||||
* HACK: Sadly, clang doesn't let us emit generic LLVM bitcode.
|
* HACK: Sadly, clang doesn't let us emit generic LLVM bitcode.
|
||||||
* Compiling for WASM32 and filtering the output with regex is the closest we can get.
|
* Compiling for WASM32 and filtering the output with regex is the closest we can get.
|
||||||
*/
|
*/
|
||||||
let flags: &[&str] = &[
|
let flags: &[&str] = &[
|
||||||
"--target=wasm32",
|
"--target=wasm32",
|
||||||
irrt_cpp_path.to_str().unwrap(),
|
path.to_str().unwrap(),
|
||||||
"-x",
|
"-x", "c++",
|
||||||
"c++",
|
|
||||||
"-fno-discard-value-names",
|
"-fno-discard-value-names",
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
@ -31,14 +37,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={}", path.to_str().unwrap());
|
||||||
|
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)
|
||||||
|
@ -49,16 +54,11 @@ fn compile_irrt(irrt_dir: &Path, out_dir: &Path) {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// https://github.com/rust-lang/regex/issues/244
|
let output = std::str::from_utf8(&output.stdout).unwrap();
|
||||||
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
|
for f in regex_filter.captures_iter(output) {
|
||||||
// (?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) {
|
|
||||||
assert_eq!(f.len(), 1);
|
assert_eq!(f.len(), 1);
|
||||||
filtered_output.push_str(&f[0]);
|
filtered_output.push_str(&f[0]);
|
||||||
filtered_output.push('\n');
|
filtered_output.push('\n');
|
||||||
|
@ -70,65 +70,32 @@ 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(format!("{filename_without_ext}.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(format!("{filename_without_ext}-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(format!("{filename_without_ext}.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() {
|
fn main() {
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
const IRRT_SOURCE_PATHS: &[&str] =
|
||||||
let out_dir = Path::new(&out_dir);
|
&["src/codegen/irrt/irrt.cpp", "src/codegen/tracert/tracert.cpp"];
|
||||||
|
|
||||||
let irrt_dir = Path::new("./irrt");
|
assert!(IRRT_SOURCE_PATHS.iter().map(Path::new).map(path_to_extless_filename).all_unique());
|
||||||
|
|
||||||
compile_irrt(irrt_dir, out_dir);
|
for path in IRRT_SOURCE_PATHS {
|
||||||
|
let path = Path::new(path);
|
||||||
|
|
||||||
// https://github.com/rust-lang/cargo/issues/2549
|
compile_file_to_ir(path, path_to_extless_filename(path))
|
||||||
// `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`].
|
||||||
|
|
|
@ -1,100 +1,519 @@
|
||||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||||
use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue};
|
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FloatValue, IntValue};
|
||||||
use itertools::Either;
|
use inkwell::AddressSpace;
|
||||||
|
use itertools::{Either, Itertools};
|
||||||
|
use std::iter::once;
|
||||||
|
|
||||||
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 +549,113 @@ 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the `printf` function.
|
||||||
|
pub fn call_printf<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
format: &str,
|
||||||
|
args: &[BasicValueEnum<'ctx>],
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
const FN_NAME: &str = "printf";
|
||||||
|
|
||||||
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
|
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||||
|
let fn_type = llvm_i32.fn_type(&[llvm_pi8.into()], true);
|
||||||
|
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||||
|
for attr in ["nofree", "nounwind"] {
|
||||||
|
func.add_attribute(
|
||||||
|
AttributeLoc::Function,
|
||||||
|
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
func
|
||||||
|
});
|
||||||
|
|
||||||
|
let pformat = ctx
|
||||||
|
.builder
|
||||||
|
.build_global_string_ptr(&format!("{format}\0"), "")
|
||||||
|
.map(|v| v.as_basic_value_enum())
|
||||||
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fn_args = once(&pformat.as_basic_value_enum())
|
||||||
|
.chain(args)
|
||||||
|
.copied()
|
||||||
|
.map(BasicValueEnum::into)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_call(extern_fn, fn_args.as_slice(), "")
|
||||||
|
.map(CallSiteValue::try_as_basic_value)
|
||||||
|
.map(|v| v.map_left(BasicValueEnum::into_int_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()
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::classes::{ListType, NDArrayType, ProxyType, RangeType},
|
codegen::classes::{ListType, NDArrayType, ProxyType, RangeType},
|
||||||
|
codegen::tracert::{TraceRuntimeConfig, TraceRuntimeState},
|
||||||
symbol_resolver::{StaticValue, SymbolResolver},
|
symbol_resolver::{StaticValue, SymbolResolver},
|
||||||
toplevel::{helper::PrimDef, numpy::unpack_ndarray_var_tys, TopLevelContext, TopLevelDef},
|
toplevel::{helper::PrimDef, numpy::unpack_ndarray_var_tys, TopLevelContext, TopLevelDef},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
|
@ -43,6 +44,7 @@ pub mod irrt;
|
||||||
pub mod llvm_intrinsics;
|
pub mod llvm_intrinsics;
|
||||||
pub mod numpy;
|
pub mod numpy;
|
||||||
pub mod stmt;
|
pub mod stmt;
|
||||||
|
pub mod tracert;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
@ -189,6 +191,8 @@ pub struct CodeGenContext<'ctx, 'a> {
|
||||||
/// See [`need_sret`].
|
/// See [`need_sret`].
|
||||||
pub need_sret: bool,
|
pub need_sret: bool,
|
||||||
|
|
||||||
|
pub tracert_state: Option<TraceRuntimeState>,
|
||||||
|
|
||||||
/// The current source location.
|
/// The current source location.
|
||||||
pub current_loc: Location,
|
pub current_loc: Location,
|
||||||
}
|
}
|
||||||
|
@ -236,6 +240,8 @@ pub struct WorkerRegistry {
|
||||||
|
|
||||||
/// LLVM-related options for code generation.
|
/// LLVM-related options for code generation.
|
||||||
pub llvm_options: CodeGenLLVMOptions,
|
pub llvm_options: CodeGenLLVMOptions,
|
||||||
|
|
||||||
|
tracert_config: TraceRuntimeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerRegistry {
|
impl WorkerRegistry {
|
||||||
|
@ -245,6 +251,7 @@ impl WorkerRegistry {
|
||||||
generators: Vec<Box<G>>,
|
generators: Vec<Box<G>>,
|
||||||
top_level_ctx: Arc<TopLevelContext>,
|
top_level_ctx: Arc<TopLevelContext>,
|
||||||
llvm_options: &CodeGenLLVMOptions,
|
llvm_options: &CodeGenLLVMOptions,
|
||||||
|
tracert_config: &TraceRuntimeConfig,
|
||||||
f: &Arc<WithCall>,
|
f: &Arc<WithCall>,
|
||||||
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
||||||
let (sender, receiver) = unbounded();
|
let (sender, receiver) = unbounded();
|
||||||
|
@ -266,6 +273,7 @@ impl WorkerRegistry {
|
||||||
wait_condvar,
|
wait_condvar,
|
||||||
top_level_ctx,
|
top_level_ctx,
|
||||||
llvm_options: llvm_options.clone(),
|
llvm_options: llvm_options.clone(),
|
||||||
|
tracert_config: tracert_config.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
|
@ -895,6 +903,13 @@ pub fn gen_func_impl<
|
||||||
unifier,
|
unifier,
|
||||||
static_value_store,
|
static_value_store,
|
||||||
need_sret: has_sret,
|
need_sret: has_sret,
|
||||||
|
tracert_state: if cfg!(feature = "tracing")
|
||||||
|
|| registry.tracert_config.enabled_tags.is_empty()
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(TraceRuntimeState::create(registry.tracert_config.clone()))
|
||||||
|
},
|
||||||
current_loc: Location::default(),
|
current_loc: Location::default(),
|
||||||
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
|
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
classes::{ListType, NDArrayType, ProxyType, RangeType},
|
classes::{ListType, NDArrayType, ProxyType, RangeType},
|
||||||
concrete_type::ConcreteTypeStore,
|
concrete_type::ConcreteTypeStore,
|
||||||
|
tracert::TraceRuntimeConfig,
|
||||||
CodeGenContext, CodeGenLLVMOptions, CodeGenTargetMachineOptions, CodeGenTask,
|
CodeGenContext, CodeGenLLVMOptions, CodeGenTargetMachineOptions, CodeGenTask,
|
||||||
CodeGenerator, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
CodeGenerator, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
||||||
},
|
},
|
||||||
|
@ -228,7 +229,13 @@ fn test_primitives() {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: CodeGenTargetMachineOptions::from_host_triple(),
|
target: CodeGenTargetMachineOptions::from_host_triple(),
|
||||||
};
|
};
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
|
threads,
|
||||||
|
top_level,
|
||||||
|
&llvm_options,
|
||||||
|
&TraceRuntimeConfig::default(),
|
||||||
|
&f,
|
||||||
|
);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
}
|
}
|
||||||
|
@ -413,7 +420,13 @@ fn test_simple_call() {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: CodeGenTargetMachineOptions::from_host_triple(),
|
target: CodeGenTargetMachineOptions::from_host_triple(),
|
||||||
};
|
};
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
let (registry, handles) = WorkerRegistry::create_workers(
|
||||||
|
threads,
|
||||||
|
top_level,
|
||||||
|
&llvm_options,
|
||||||
|
&TraceRuntimeConfig::default(),
|
||||||
|
&f,
|
||||||
|
);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
use std::panic::Location;
|
||||||
|
|
||||||
|
use inkwell::context::Context;
|
||||||
|
use inkwell::memory_buffer::MemoryBuffer;
|
||||||
|
use inkwell::module::Module;
|
||||||
|
use inkwell::values::BasicValueEnum;
|
||||||
|
use inkwell::AtomicOrdering;
|
||||||
|
|
||||||
|
use crate::codegen::{extern_fns, CodeGenContext};
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Eq, PartialEq)]
|
||||||
|
pub struct TraceRuntimeConfig {
|
||||||
|
pub enabled_tags: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Clone, PartialEq)]
|
||||||
|
pub struct TraceRuntimeState {
|
||||||
|
config: TraceRuntimeConfig,
|
||||||
|
indent: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TraceRuntimeState {
|
||||||
|
#[must_use]
|
||||||
|
pub fn create(config: TraceRuntimeConfig) -> TraceRuntimeState {
|
||||||
|
TraceRuntimeState { config, indent: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn load_tracert<'ctx>(ctx: &'ctx Context, config: &TraceRuntimeConfig) -> Option<Module<'ctx>> {
|
||||||
|
if cfg!(feature = "tracing") && !config.enabled_tags.is_empty() {
|
||||||
|
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
||||||
|
include_bytes!(concat!(env!("OUT_DIR"), "/tracert.bc")),
|
||||||
|
"tracert_bitcode_buffer",
|
||||||
|
);
|
||||||
|
let module = Module::parse_bitcode_from_buffer(&bitcode_buf, ctx).unwrap();
|
||||||
|
|
||||||
|
return Some(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Might need to redesign how trace logging should be done
|
||||||
|
|
||||||
|
pub fn trace_log<'ctx>(
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
tag: &'static str,
|
||||||
|
format: &'static str,
|
||||||
|
args: &[BasicValueEnum<'ctx>],
|
||||||
|
) {
|
||||||
|
if ctx.tracert_state.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add indentation
|
||||||
|
let str = format!("[TRACING] {tag} - {format}\n\0");
|
||||||
|
extern_fns::call_printf(ctx, &str, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn trace_log_with_location<'ctx>(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
tag: &'static str,
|
||||||
|
format: &str,
|
||||||
|
args: &[BasicValueEnum<'ctx>],
|
||||||
|
) {
|
||||||
|
if ctx.tracert_state.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add indentation
|
||||||
|
let caller_loc = Location::caller();
|
||||||
|
let str = format!(
|
||||||
|
"[TRACING] {}:{}:{}: {tag} - {format}\n\0",
|
||||||
|
caller_loc.file(),
|
||||||
|
caller_loc.line(),
|
||||||
|
caller_loc.column()
|
||||||
|
);
|
||||||
|
extern_fns::call_printf(ctx, &str, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_push_level(ctx: &mut CodeGenContext<'_, '_>) {
|
||||||
|
let Some(tracert_state) = &mut ctx.tracert_state else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(tracert_state.indent < usize::MAX);
|
||||||
|
if tracert_state.indent < usize::MAX {
|
||||||
|
tracert_state.indent = tracert_state.indent.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_pop_level(ctx: &mut CodeGenContext<'_, '_>) {
|
||||||
|
let Some(tracert_state) = &mut ctx.tracert_state else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(tracert_state.indent > 0);
|
||||||
|
if tracert_state.indent > 0 {
|
||||||
|
tracert_state.indent = tracert_state.indent.saturating_sub(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mfence(ctx: &mut CodeGenContext<'_, '_>) {
|
||||||
|
if ctx.tracert_state.is_some() {
|
||||||
|
ctx.builder.build_fence(AtomicOrdering::SequentiallyConsistent, 0, "").unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
extern "C" {
|
||||||
|
// stdio.h
|
||||||
|
int printf(const char *format, ...);
|
||||||
|
} // extern "C"
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["M-Labs"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
tracing = ["nac3core/tracing"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
|
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +70,7 @@ struct cslice {
|
||||||
usize len;
|
usize len;
|
||||||
};
|
};
|
||||||
|
|
||||||
void output_int32_list(struct cslice *slice) {
|
void output_int32_list(const struct cslice *slice) {
|
||||||
const int32_t *data = (int32_t *) slice->data;
|
const int32_t *data = (int32_t *) slice->data;
|
||||||
|
|
||||||
putchar('[');
|
putchar('[');
|
||||||
|
@ -82,7 +85,7 @@ void output_int32_list(struct cslice *slice) {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_str(struct cslice *slice) {
|
void output_str(const struct cslice *slice) {
|
||||||
const char *data = (const char *) slice->data;
|
const char *data = (const char *) slice->data;
|
||||||
|
|
||||||
for (usize i = 0; i < slice->len; ++i) {
|
for (usize i = 0; i < slice->len; ++i) {
|
||||||
|
@ -90,12 +93,12 @@ void output_str(struct cslice *slice) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_strln(struct cslice *slice) {
|
void output_strln(const struct cslice *slice) {
|
||||||
output_str(slice);
|
output_str(slice);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t dbg_stack_address(__attribute__((unused)) struct cslice *slice) {
|
uint64_t dbg_stack_address(__attribute__((unused)) const struct cslice *slice) {
|
||||||
int i;
|
int i;
|
||||||
void *ptr = (void *) &i;
|
void *ptr = (void *) &i;
|
||||||
return (uintptr_t) ptr;
|
return (uintptr_t) ptr;
|
||||||
|
@ -107,8 +110,34 @@ uint32_t __nac3_personality(uint32_t state, uint32_t exception_object, uint32_t
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct exception {
|
||||||
|
uint32_t name;
|
||||||
|
struct cslice file;
|
||||||
|
uint32_t line;
|
||||||
|
uint32_t col;
|
||||||
|
struct cslice func;
|
||||||
|
struct cslice message;
|
||||||
|
uint64_t param0;
|
||||||
|
uint64_t param1;
|
||||||
|
uint64_t param2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void output_exception(const struct exception *ex) {
|
||||||
|
fputs("exception { location: ", stdout);
|
||||||
|
output_str(&ex->file);
|
||||||
|
printf(":%u:%u, func: ", ex->line, ex->col);
|
||||||
|
output_str(&ex->func);
|
||||||
|
fputs(", message: ", stdout);
|
||||||
|
output_str(&ex->message);
|
||||||
|
printf(", params: [%lu, %lu, %lu] }\n", ex->param0, ex->param1, ex->param2);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t __nac3_raise(uint32_t state, uint32_t exception_object, uint32_t context) {
|
uint32_t __nac3_raise(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||||
printf("__nac3_raise(state: %u, exception_object: %u, context: %u)\n", state, exception_object, context);
|
printf("__nac3_raise(state: %#10x, exception_object: %#10x, context: %#10x)\n", state, exception_object, context);
|
||||||
|
|
||||||
|
struct exception *ex = (struct exception *)((0x7ffffffful << 16) | state);
|
||||||
|
output_exception(ex);
|
||||||
|
|
||||||
exit(101);
|
exit(101);
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -20,8 +20,11 @@ use std::{collections::HashMap, fs, path::Path, sync::Arc};
|
||||||
|
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions,
|
concrete_type::ConcreteTypeStore,
|
||||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
irrt::load_irrt,
|
||||||
|
tracert::{load_tracert, TraceRuntimeConfig},
|
||||||
|
CodeGenLLVMOptions, CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator,
|
||||||
|
WithCall, WorkerRegistry,
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
toplevel::{
|
toplevel::{
|
||||||
|
@ -76,6 +79,9 @@ struct CommandLineArgs {
|
||||||
/// Additional target features to enable/disable, specified using the `+`/`-` prefixes.
|
/// Additional target features to enable/disable, specified using the `+`/`-` prefixes.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
target_features: Option<String>,
|
target_features: Option<String>,
|
||||||
|
|
||||||
|
#[arg(long)]
|
||||||
|
trace: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_typevar_definition(
|
fn handle_typevar_definition(
|
||||||
|
@ -242,8 +248,16 @@ fn main() {
|
||||||
const SIZE_T: u32 = usize::BITS;
|
const SIZE_T: u32 = usize::BITS;
|
||||||
|
|
||||||
let cli = CommandLineArgs::parse();
|
let cli = CommandLineArgs::parse();
|
||||||
let CommandLineArgs { file_name, threads, opt_level, emit_llvm, triple, mcpu, target_features } =
|
let CommandLineArgs {
|
||||||
cli;
|
file_name,
|
||||||
|
threads,
|
||||||
|
opt_level,
|
||||||
|
emit_llvm,
|
||||||
|
triple,
|
||||||
|
mcpu,
|
||||||
|
target_features,
|
||||||
|
trace,
|
||||||
|
} = cli;
|
||||||
|
|
||||||
Target::initialize_all(&InitializationConfig::default());
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
|
|
||||||
|
@ -272,6 +286,7 @@ fn main() {
|
||||||
// The default behavior for -O<n> where n>3 defaults to O3 for both Clang and GCC
|
// The default behavior for -O<n> where n>3 defaults to O3 for both Clang and GCC
|
||||||
_ => OptimizationLevel::Aggressive,
|
_ => OptimizationLevel::Aggressive,
|
||||||
};
|
};
|
||||||
|
let tracert_config = TraceRuntimeConfig { enabled_tags: trace };
|
||||||
|
|
||||||
let program = match fs::read_to_string(file_name.clone()) {
|
let program = match fs::read_to_string(file_name.clone()) {
|
||||||
Ok(program) => program,
|
Ok(program) => program,
|
||||||
|
@ -405,7 +420,8 @@ fn main() {
|
||||||
let threads = (0..threads)
|
let threads = (0..threads)
|
||||||
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), SIZE_T)))
|
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), SIZE_T)))
|
||||||
.collect();
|
.collect();
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
let (registry, handles) =
|
||||||
|
WorkerRegistry::create_workers(threads, top_level, &llvm_options, &tracert_config, &f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
|
|
||||||
|
@ -436,6 +452,14 @@ fn main() {
|
||||||
}
|
}
|
||||||
main.link_in_module(irrt).unwrap();
|
main.link_in_module(irrt).unwrap();
|
||||||
|
|
||||||
|
if let Some(tracert) = load_tracert(&context, &tracert_config) {
|
||||||
|
if emit_llvm {
|
||||||
|
tracert.write_bitcode_to_path(Path::new("tracert.bc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
main.link_in_module(tracert).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let mut function_iter = main.get_first_function();
|
let mut function_iter = main.get_first_function();
|
||||||
while let Some(func) = function_iter {
|
while let Some(func) = function_iter {
|
||||||
if func.count_basic_blocks() > 0 && func.get_name().to_str().unwrap() != "run" {
|
if func.count_basic_blocks() > 0 && func.get_name().to_str().unwrap() != "run" {
|
||||||
|
|
|
@ -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