forked from M-Labs/nac3
Compare commits
10 Commits
ndarray-st
...
ndarray-st
Author | SHA1 | Date |
---|---|---|
lyken | 87d2a4ed59 | |
lyken | 9aae290727 | |
lyken | d18c769cdc | |
lyken | f41f06aec7 | |
lyken | 1303265785 | |
lyken | e9cf6ce1e5 | |
lyken | bc91ab9b13 | |
lyken | 1e06a3d199 | |
lyken | 87511ac749 | |
Sebastien Bourdeauducq | d658d9b00e |
|
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.104"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
|
||||
checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.8"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
|
||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -139,9 +139,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.8"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
|
||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -158,7 +158,7 @@ dependencies = [
|
|||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -421,7 +421,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -749,7 +749,7 @@ dependencies = [
|
|||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -850,7 +850,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -863,7 +863,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"pyo3-build-config",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1029,22 +1029,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1134,7 +1134,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1150,9 +1150,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.68"
|
||||
version = "2.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1161,9 +1161,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.14"
|
||||
version = "0.12.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
|
||||
checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
|
@ -1218,7 +1218,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1398,9 +1398,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
|
@ -1414,51 +1414,51 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
|
@ -1486,5 +1486,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.68",
|
||||
"syn 2.0.70",
|
||||
]
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
clang-irrt --target=wasm32 -x c++ -fno-discard-value-names -fno-exceptions -fno-rtti -O0 -emit-llvm -S -Wall -Wextra nac3core/irrt/irrt.cpp
|
||||
clang -x c++ -fno-discard-value-names -fno-exceptions -fno-rtti -O0 -emit-llvm -S -Wall -Wextra nac3core/irrt/irrt_test.cpp
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1718530797,
|
||||
"narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=",
|
||||
"lastModified": 1720418205,
|
||||
"narHash": "sha256-cPJoFPXU44GlhWg4pUk9oUPqurPlCFZ11ZQPk21GTPU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b60ebf54c15553b393d144357375ea956f89e9a9",
|
||||
"rev": "655a58a72a6601292512670343087c2d75d859c1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
'';
|
||||
installPhase =
|
||||
''
|
||||
u PYTHON_SITEPACKAGES=$out/${pkgs.python3Packages.python.sitePackages}
|
||||
PYTHON_SITEPACKAGES=$out/${pkgs.python3Packages.python.sitePackages}
|
||||
mkdir -p $PYTHON_SITEPACKAGES
|
||||
cp target/x86_64-unknown-linux-gnu/release/libnac3artiq.so $PYTHON_SITEPACKAGES/nac3artiq.so
|
||||
|
||||
|
|
|
@ -106,7 +106,6 @@ fn compile_irrt_test(irrt_dir: &Path, out_dir: &Path) {
|
|||
"-o",
|
||||
exe_path.to_str().unwrap(),
|
||||
];
|
||||
println!("{:?}", flags);
|
||||
|
||||
Command::new("clang-irrt-test")
|
||||
.args(flags)
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
#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
|
||||
|
||||
// NDArray indices are always `uint32_t`.
|
||||
typedef uint32_t NDIndex;
|
||||
// The type of an index or a value describing the length of a range/slice is
|
||||
// always `int32_t`.
|
||||
typedef int32_t SliceIndex;
|
||||
|
||||
template <typename T>
|
||||
static T max(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T min(T a, T b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
// 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>
|
||||
static 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;
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
static SizeT __nac3_ndarray_calc_size_impl(
|
||||
const SizeT *list_data,
|
||||
SizeT list_len,
|
||||
SizeT begin_idx,
|
||||
SizeT end_idx
|
||||
) {
|
||||
__builtin_assume(end_idx <= list_len);
|
||||
|
||||
SizeT num_elems = 1;
|
||||
for (SizeT i = begin_idx; i < end_idx; ++i) {
|
||||
SizeT val = list_data[i];
|
||||
__builtin_assume(val > 0);
|
||||
num_elems *= val;
|
||||
}
|
||||
return num_elems;
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
static void __nac3_ndarray_calc_nd_indices_impl(
|
||||
SizeT index,
|
||||
const SizeT *dims,
|
||||
SizeT num_dims,
|
||||
NDIndex *idxs
|
||||
) {
|
||||
SizeT stride = 1;
|
||||
for (SizeT dim = 0; dim < num_dims; dim++) {
|
||||
SizeT i = num_dims - dim - 1;
|
||||
__builtin_assume(dims[i] > 0);
|
||||
idxs[i] = (index / stride) % dims[i];
|
||||
stride *= dims[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
static SizeT __nac3_ndarray_flatten_index_impl(
|
||||
const SizeT *dims,
|
||||
SizeT num_dims,
|
||||
const NDIndex *indices,
|
||||
SizeT num_indices
|
||||
) {
|
||||
SizeT idx = 0;
|
||||
SizeT stride = 1;
|
||||
for (SizeT i = 0; i < num_dims; ++i) {
|
||||
SizeT ri = num_dims - i - 1;
|
||||
if (ri < num_indices) {
|
||||
idx += stride * indices[ri];
|
||||
}
|
||||
|
||||
__builtin_assume(dims[i] > 0);
|
||||
stride *= dims[ri];
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
static void __nac3_ndarray_calc_broadcast_impl(
|
||||
const SizeT *lhs_dims,
|
||||
SizeT lhs_ndims,
|
||||
const SizeT *rhs_dims,
|
||||
SizeT rhs_ndims,
|
||||
SizeT *out_dims
|
||||
) {
|
||||
SizeT max_ndims = lhs_ndims > rhs_ndims ? lhs_ndims : rhs_ndims;
|
||||
|
||||
for (SizeT i = 0; i < max_ndims; ++i) {
|
||||
const SizeT *lhs_dim_sz = i < lhs_ndims ? &lhs_dims[lhs_ndims - i - 1] : nullptr;
|
||||
const SizeT *rhs_dim_sz = i < rhs_ndims ? &rhs_dims[rhs_ndims - i - 1] : nullptr;
|
||||
SizeT *out_dim = &out_dims[max_ndims - i - 1];
|
||||
|
||||
if (lhs_dim_sz == nullptr) {
|
||||
*out_dim = *rhs_dim_sz;
|
||||
} else if (rhs_dim_sz == nullptr) {
|
||||
*out_dim = *lhs_dim_sz;
|
||||
} else if (*lhs_dim_sz == 1) {
|
||||
*out_dim = *rhs_dim_sz;
|
||||
} else if (*rhs_dim_sz == 1) {
|
||||
*out_dim = *lhs_dim_sz;
|
||||
} else if (*lhs_dim_sz == *rhs_dim_sz) {
|
||||
*out_dim = *lhs_dim_sz;
|
||||
} else {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SizeT>
|
||||
static void __nac3_ndarray_calc_broadcast_idx_impl(
|
||||
const SizeT *src_dims,
|
||||
SizeT src_ndims,
|
||||
const NDIndex *in_idx,
|
||||
NDIndex *out_idx
|
||||
) {
|
||||
for (SizeT i = 0; i < src_ndims; ++i) {
|
||||
SizeT src_i = src_ndims - i - 1;
|
||||
out_idx[src_i] = src_dims[src_i] == 1 ? 0 : in_idx[src_i];
|
||||
}
|
||||
}
|
||||
|
||||
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" {
|
||||
#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);
|
||||
}
|
||||
|
||||
uint32_t __nac3_ndarray_calc_size(
|
||||
const uint32_t *list_data,
|
||||
uint32_t list_len,
|
||||
uint32_t begin_idx,
|
||||
uint32_t end_idx
|
||||
) {
|
||||
return __nac3_ndarray_calc_size_impl(list_data, list_len, begin_idx, end_idx);
|
||||
}
|
||||
|
||||
uint64_t __nac3_ndarray_calc_size64(
|
||||
const uint64_t *list_data,
|
||||
uint64_t list_len,
|
||||
uint64_t begin_idx,
|
||||
uint64_t end_idx
|
||||
) {
|
||||
return __nac3_ndarray_calc_size_impl(list_data, list_len, begin_idx, end_idx);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_nd_indices(
|
||||
uint32_t index,
|
||||
const uint32_t* dims,
|
||||
uint32_t num_dims,
|
||||
NDIndex* idxs
|
||||
) {
|
||||
__nac3_ndarray_calc_nd_indices_impl(index, dims, num_dims, idxs);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_nd_indices64(
|
||||
uint64_t index,
|
||||
const uint64_t* dims,
|
||||
uint64_t num_dims,
|
||||
NDIndex* idxs
|
||||
) {
|
||||
__nac3_ndarray_calc_nd_indices_impl(index, dims, num_dims, idxs);
|
||||
}
|
||||
|
||||
uint32_t __nac3_ndarray_flatten_index(
|
||||
const uint32_t* dims,
|
||||
uint32_t num_dims,
|
||||
const NDIndex* indices,
|
||||
uint32_t num_indices
|
||||
) {
|
||||
return __nac3_ndarray_flatten_index_impl(dims, num_dims, indices, num_indices);
|
||||
}
|
||||
|
||||
uint64_t __nac3_ndarray_flatten_index64(
|
||||
const uint64_t* dims,
|
||||
uint64_t num_dims,
|
||||
const NDIndex* indices,
|
||||
uint64_t num_indices
|
||||
) {
|
||||
return __nac3_ndarray_flatten_index_impl(dims, num_dims, indices, num_indices);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_broadcast(
|
||||
const uint32_t *lhs_dims,
|
||||
uint32_t lhs_ndims,
|
||||
const uint32_t *rhs_dims,
|
||||
uint32_t rhs_ndims,
|
||||
uint32_t *out_dims
|
||||
) {
|
||||
return __nac3_ndarray_calc_broadcast_impl(lhs_dims, lhs_ndims, rhs_dims, rhs_ndims, out_dims);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_broadcast64(
|
||||
const uint64_t *lhs_dims,
|
||||
uint64_t lhs_ndims,
|
||||
const uint64_t *rhs_dims,
|
||||
uint64_t rhs_ndims,
|
||||
uint64_t *out_dims
|
||||
) {
|
||||
return __nac3_ndarray_calc_broadcast_impl(lhs_dims, lhs_ndims, rhs_dims, rhs_ndims, out_dims);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_broadcast_idx(
|
||||
const uint32_t *src_dims,
|
||||
uint32_t src_ndims,
|
||||
const NDIndex *in_idx,
|
||||
NDIndex *out_idx
|
||||
) {
|
||||
__nac3_ndarray_calc_broadcast_idx_impl(src_dims, src_ndims, in_idx, out_idx);
|
||||
}
|
||||
|
||||
void __nac3_ndarray_calc_broadcast_idx64(
|
||||
const uint64_t *src_dims,
|
||||
uint64_t src_ndims,
|
||||
const NDIndex *in_idx,
|
||||
NDIndex *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);
|
||||
}
|
||||
}
|
|
@ -12,22 +12,23 @@
|
|||
|
||||
// The type of an index or a value describing the length of a range/slice is
|
||||
// always `int32_t`.
|
||||
typedef int32_t SliceIndex;
|
||||
|
||||
// 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>
|
||||
static 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;
|
||||
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" {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "irrt_utils.hpp"
|
||||
#include "irrt_typedefs.hpp"
|
||||
#include "irrt_basic.hpp"
|
||||
#include "irrt_slice.hpp"
|
||||
#include "irrt_numpy_ndarray.hpp"
|
||||
|
||||
/*
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "irrt_utils.hpp"
|
||||
#include "irrt_typedefs.hpp"
|
||||
#include "irrt_slice.hpp"
|
||||
|
||||
/*
|
||||
NDArray-related implementations.
|
||||
|
@ -11,170 +12,435 @@
|
|||
using NDIndex = uint32_t;
|
||||
|
||||
namespace {
|
||||
namespace ndarray_util {
|
||||
// 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 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;
|
||||
stride_product *= shape[dim_i];
|
||||
}
|
||||
}
|
||||
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];
|
||||
|
||||
// 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>
|
||||
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;
|
||||
indices[dim_i] = nth % dim;
|
||||
nth /= dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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, uint8_t* pvalue) {
|
||||
__builtin_memcpy(pelement, pvalue, itemsize);
|
||||
}
|
||||
|
||||
uint8_t* get_pelement(SizeT *indices) {
|
||||
uint8_t* element = data;
|
||||
for (SizeT dim_i = 0; dim_i < ndims; dim_i++)
|
||||
element += indices[dim_i] * strides[dim_i] * itemsize;
|
||||
return element;
|
||||
}
|
||||
|
||||
// Is the given `indices` valid/in-bounds?
|
||||
bool in_bounds(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;
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fill the ndarray with a value
|
||||
void fill_generic(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();
|
||||
// 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;
|
||||
}
|
||||
|
||||
for (SizeT i = 0; i < this->size(); i++, iter.next()) {
|
||||
uint8_t* pelement = get_pelement(iter.indices);
|
||||
set_value_at_pelement(pelement, pvalue);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the strides of the ndarray with `ndarray_util::set_strides_by_shape`
|
||||
void set_strides_by_shape() {
|
||||
ndarray_util::set_strides_by_shape(ndims, strides, shape);
|
||||
typedef uint8_t NDSliceType;
|
||||
extern "C" {
|
||||
const NDSliceType INPUT_SLICE_TYPE_INDEX = 0;
|
||||
const NDSliceType INPUT_SLICE_TYPE_SLICE = 1;
|
||||
}
|
||||
|
||||
// https://numpy.org/doc/stable/reference/generated/numpy.eye.html
|
||||
void set_to_eye(SizeT k, uint8_t* zero_pvalue, uint8_t* one_pvalue) {
|
||||
__builtin_assume(ndims == 2);
|
||||
struct NDSlice {
|
||||
// A poor-man's `std::variant<int, UserRange>`
|
||||
NDSliceType type;
|
||||
|
||||
// TODO: Better implementation
|
||||
/*
|
||||
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;
|
||||
};
|
||||
|
||||
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 };
|
||||
namespace ndarray_util {
|
||||
template<typename SizeT>
|
||||
SizeT deduce_ndims_after_slicing(SizeT ndims, SizeT num_slices, const NDSlice *slices) {
|
||||
irrt_assert(num_slices <= ndims);
|
||||
|
||||
if (!in_bounds(indices)) continue;
|
||||
|
||||
uint8_t* pelement = get_pelement(indices);
|
||||
set_value_at_pelement(pelement, one_pvalue);
|
||||
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" {
|
||||
|
@ -193,4 +459,8 @@ extern "C" {
|
|||
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);
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
#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,31 +1,25 @@
|
|||
// 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` has it all
|
||||
// Set `IRRT_DONT_TYPEDEF_INTS` because `cstdint` defines them
|
||||
#define IRRT_DONT_TYPEDEF_INTS
|
||||
#include "irrt_everything.hpp"
|
||||
|
||||
namespace {
|
||||
static void test_fail() {
|
||||
void test_fail() {
|
||||
printf("[!] Test failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void __begin_test(const char* function_name, const char* file, int line) {
|
||||
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>
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void debug_print_array(const char* format, int len, T* as) {
|
||||
printf("[");
|
||||
|
@ -39,10 +33,11 @@ void debug_print_array(const char* format, int len, T* as) {
|
|||
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("expected %s: ", label);
|
||||
printf(">>>>>>> %s\n", label);
|
||||
printf(" Expecting = ");
|
||||
debug_print_array(format, len, expected);
|
||||
printf("\n");
|
||||
printf("got %s: ", label);
|
||||
printf(" Got = ");
|
||||
debug_print_array(format, len, got);
|
||||
printf("\n");
|
||||
test_fail();
|
||||
|
@ -52,22 +47,89 @@ void assert_arrays_match(const char* label, const char* format, int len, T* expe
|
|||
template <typename T>
|
||||
void assert_values_match(const char* label, const char* format, T expected, T got) {
|
||||
if (expected != got) {
|
||||
printf("expected %s: ", label);
|
||||
printf(">>>>>>> %s\n", label);
|
||||
printf(" Expecting = ");
|
||||
printf(format, expected);
|
||||
printf("\n");
|
||||
printf("got %s: ", label);
|
||||
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 };
|
||||
debug_print_array("%d", 4, shape);
|
||||
assert_values_match("size", "%d", 210, ndarray_util::calc_size_from_shape<int32_t>(4, shape));
|
||||
}
|
||||
|
||||
|
@ -85,9 +147,14 @@ void test_set_strides_by_shape() {
|
|||
|
||||
int32_t shape[4] = { 99, 3, 5, 7 };
|
||||
int32_t strides[4] = { 0 };
|
||||
ndarray_util::set_strides_by_shape(4, strides, shape);
|
||||
ndarray_util::set_strides_by_shape((int32_t) sizeof(int32_t), 4, strides, shape);
|
||||
|
||||
int32_t expected_strides[4] = { 105, 35, 7, 1 };
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -98,7 +165,7 @@ void test_ndarray_indices_iter_normal() {
|
|||
int32_t shape[3] = { 1, 2, 3 };
|
||||
int32_t indices[3] = { 0, 0, 0 };
|
||||
auto iter = NDArrayIndicesIter<int32_t> {
|
||||
.ndims = 3u,
|
||||
.ndims = 3,
|
||||
.shape = shape,
|
||||
.indices = indices
|
||||
};
|
||||
|
@ -148,6 +215,9 @@ void test_ndarray_fill_generic() {
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -176,6 +246,396 @@ void test_ndarray_set_to_eye() {
|
|||
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() {
|
||||
|
@ -185,5 +645,14 @@ int main() {
|
|||
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;
|
||||
}
|
|
@ -9,4 +9,6 @@ typedef _BitInt(32) int32_t;
|
|||
typedef unsigned _BitInt(32) uint32_t;
|
||||
typedef _BitInt(64) int64_t;
|
||||
typedef unsigned _BitInt(64) uint64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef int32_t SliceIndex;
|
|
@ -1,11 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
template <typename T>
|
||||
static T max(T a, T b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
#include "irrt_typedefs.hpp"
|
||||
|
||||
template <typename T>
|
||||
static T min(T a, T b) {
|
||||
return a > b ? b : a;
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -702,54 +702,53 @@ pub fn call_numpy_min<'ctx, G: CodeGenerator + ?Sized>(
|
|||
BasicValueEnum::PointerValue(n)
|
||||
if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||
{
|
||||
todo!()
|
||||
// let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
||||
// let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
||||
let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||
|
||||
// let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||
// let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
|
||||
// if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||
// let n_sz_eqz = ctx
|
||||
// .builder
|
||||
// .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
|
||||
// .unwrap();
|
||||
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
|
||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||
let n_sz_eqz = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
|
||||
.unwrap();
|
||||
|
||||
// ctx.make_assert(
|
||||
// generator,
|
||||
// n_sz_eqz,
|
||||
// "0:ValueError",
|
||||
// "zero-size array to reduction operation minimum which has no identity",
|
||||
// [None, None, None],
|
||||
// ctx.current_loc,
|
||||
// );
|
||||
// }
|
||||
ctx.make_assert(
|
||||
generator,
|
||||
n_sz_eqz,
|
||||
"0:ValueError",
|
||||
"zero-size array to reduction operation minimum which has no identity",
|
||||
[None, None, None],
|
||||
ctx.current_loc,
|
||||
);
|
||||
}
|
||||
|
||||
// let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
|
||||
// unsafe {
|
||||
// let identity =
|
||||
// n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
|
||||
// ctx.builder.build_store(accumulator_addr, identity).unwrap();
|
||||
// }
|
||||
let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
|
||||
unsafe {
|
||||
let identity =
|
||||
n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
|
||||
ctx.builder.build_store(accumulator_addr, identity).unwrap();
|
||||
}
|
||||
|
||||
// gen_for_callback_incrementing(
|
||||
// generator,
|
||||
// ctx,
|
||||
// llvm_usize.const_int(1, false),
|
||||
// (n_sz, false),
|
||||
// |generator, ctx, _, idx| {
|
||||
// let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||
gen_for_callback_incrementing(
|
||||
generator,
|
||||
ctx,
|
||||
llvm_usize.const_int(1, false),
|
||||
(n_sz, false),
|
||||
|generator, ctx, _, idx| {
|
||||
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||
|
||||
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
// let result = call_min(ctx, (elem_ty, accumulator), (elem_ty, elem));
|
||||
// ctx.builder.build_store(accumulator_addr, result).unwrap();
|
||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
let result = call_min(ctx, (elem_ty, accumulator), (elem_ty, elem));
|
||||
ctx.builder.build_store(accumulator_addr, result).unwrap();
|
||||
|
||||
// Ok(())
|
||||
// },
|
||||
// llvm_usize.const_int(1, false),
|
||||
// )?;
|
||||
Ok(())
|
||||
},
|
||||
llvm_usize.const_int(1, false),
|
||||
)?;
|
||||
|
||||
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
// accumulator
|
||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
accumulator
|
||||
}
|
||||
|
||||
_ => unsupported_type(ctx, FN_NAME, &[a_ty]),
|
||||
|
@ -921,54 +920,53 @@ pub fn call_numpy_max<'ctx, G: CodeGenerator + ?Sized>(
|
|||
BasicValueEnum::PointerValue(n)
|
||||
if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||
{
|
||||
todo!()
|
||||
// let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
||||
// let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
||||
let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||
|
||||
// let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||
// let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
|
||||
// if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||
// let n_sz_eqz = ctx
|
||||
// .builder
|
||||
// .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
|
||||
// .unwrap();
|
||||
let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
|
||||
let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
|
||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||
let n_sz_eqz = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
|
||||
.unwrap();
|
||||
|
||||
// ctx.make_assert(
|
||||
// generator,
|
||||
// n_sz_eqz,
|
||||
// "0:ValueError",
|
||||
// "zero-size array to reduction operation minimum which has no identity",
|
||||
// [None, None, None],
|
||||
// ctx.current_loc,
|
||||
// );
|
||||
// }
|
||||
ctx.make_assert(
|
||||
generator,
|
||||
n_sz_eqz,
|
||||
"0:ValueError",
|
||||
"zero-size array to reduction operation minimum which has no identity",
|
||||
[None, None, None],
|
||||
ctx.current_loc,
|
||||
);
|
||||
}
|
||||
|
||||
// let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
|
||||
// unsafe {
|
||||
// let identity =
|
||||
// n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
|
||||
// ctx.builder.build_store(accumulator_addr, identity).unwrap();
|
||||
// }
|
||||
let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
|
||||
unsafe {
|
||||
let identity =
|
||||
n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
|
||||
ctx.builder.build_store(accumulator_addr, identity).unwrap();
|
||||
}
|
||||
|
||||
// gen_for_callback_incrementing(
|
||||
// generator,
|
||||
// ctx,
|
||||
// llvm_usize.const_int(1, false),
|
||||
// (n_sz, false),
|
||||
// |generator, ctx, _, idx| {
|
||||
// let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||
gen_for_callback_incrementing(
|
||||
generator,
|
||||
ctx,
|
||||
llvm_usize.const_int(1, false),
|
||||
(n_sz, false),
|
||||
|generator, ctx, _, idx| {
|
||||
let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
|
||||
|
||||
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
// let result = call_max(ctx, (elem_ty, accumulator), (elem_ty, elem));
|
||||
// ctx.builder.build_store(accumulator_addr, result).unwrap();
|
||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
let result = call_max(ctx, (elem_ty, accumulator), (elem_ty, elem));
|
||||
ctx.builder.build_store(accumulator_addr, result).unwrap();
|
||||
|
||||
// Ok(())
|
||||
// },
|
||||
// llvm_usize.const_int(1, false),
|
||||
// )?;
|
||||
Ok(())
|
||||
},
|
||||
llvm_usize.const_int(1, false),
|
||||
)?;
|
||||
|
||||
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
// accumulator
|
||||
let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
|
||||
accumulator
|
||||
}
|
||||
|
||||
_ => unsupported_type(ctx, FN_NAME, &[a_ty]),
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
use crate::{
|
||||
codegen::classes::{NDArrayType, NpArrayType},
|
||||
typecheck::typedef::Type,
|
||||
util::SizeVariant,
|
||||
};
|
||||
use crate::{typecheck::typedef::Type, util::SizeVariant};
|
||||
|
||||
mod test;
|
||||
|
||||
use super::{
|
||||
classes::{
|
||||
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, NpArrayValue,
|
||||
TypedArrayLikeAdapter, UntypedArrayLikeAccessor,
|
||||
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, NpArrayType,
|
||||
NpArrayValue, TypedArrayLikeAdapter, UntypedArrayLikeAccessor,
|
||||
},
|
||||
llvm_intrinsics, CodeGenContext, CodeGenerator,
|
||||
};
|
||||
|
@ -21,7 +17,7 @@ use inkwell::{
|
|||
memory_buffer::MemoryBuffer,
|
||||
module::Module,
|
||||
types::{BasicType, BasicTypeEnum, FunctionType, IntType, PointerType},
|
||||
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, PointerValue},
|
||||
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue},
|
||||
AddressSpace, IntPredicate,
|
||||
};
|
||||
use itertools::Either;
|
||||
|
@ -569,6 +565,371 @@ pub fn call_j0<'ctx>(ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>) -> Flo
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
/// Generates a call to `__nac3_ndarray_calc_size`. Returns an [`IntValue`] representing the
|
||||
/// calculated total size.
|
||||
///
|
||||
/// * `dims` - An [`ArrayLikeIndexer`] containing the size of each dimension.
|
||||
/// * `range` - The dimension index to begin and end (exclusively) calculating the dimensions for,
|
||||
/// or [`None`] if starting from the first dimension and ending at the last dimension respectively.
|
||||
pub fn call_ndarray_calc_size<'ctx, G, Dims>(
|
||||
generator: &G,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
dims: &Dims,
|
||||
(begin, end): (Option<IntValue<'ctx>>, Option<IntValue<'ctx>>),
|
||||
) -> IntValue<'ctx>
|
||||
where
|
||||
G: CodeGenerator + ?Sized,
|
||||
Dims: ArrayLikeIndexer<'ctx>,
|
||||
{
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||
|
||||
let ndarray_calc_size_fn_name = match llvm_usize.get_bit_width() {
|
||||
32 => "__nac3_ndarray_calc_size",
|
||||
64 => "__nac3_ndarray_calc_size64",
|
||||
bw => unreachable!("Unsupported size type bit width: {}", bw),
|
||||
};
|
||||
let ndarray_calc_size_fn_t = llvm_usize.fn_type(
|
||||
&[llvm_pusize.into(), llvm_usize.into(), llvm_usize.into(), llvm_usize.into()],
|
||||
false,
|
||||
);
|
||||
let ndarray_calc_size_fn =
|
||||
ctx.module.get_function(ndarray_calc_size_fn_name).unwrap_or_else(|| {
|
||||
ctx.module.add_function(ndarray_calc_size_fn_name, ndarray_calc_size_fn_t, None)
|
||||
});
|
||||
|
||||
let begin = begin.unwrap_or_else(|| llvm_usize.const_zero());
|
||||
let end = end.unwrap_or_else(|| dims.size(ctx, generator));
|
||||
ctx.builder
|
||||
.build_call(
|
||||
ndarray_calc_size_fn,
|
||||
&[
|
||||
dims.base_ptr(ctx, generator).into(),
|
||||
dims.size(ctx, generator).into(),
|
||||
begin.into(),
|
||||
end.into(),
|
||||
],
|
||||
"",
|
||||
)
|
||||
.map(CallSiteValue::try_as_basic_value)
|
||||
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||
.map(Either::unwrap_left)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Generates a call to `__nac3_ndarray_calc_nd_indices`. Returns a [`TypeArrayLikeAdpater`]
|
||||
/// containing `i32` indices of the flattened index.
|
||||
///
|
||||
/// * `index` - The index to compute the multidimensional index for.
|
||||
/// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an
|
||||
/// `NDArray`.
|
||||
pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
index: IntValue<'ctx>,
|
||||
ndarray: NDArrayValue<'ctx>,
|
||||
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
|
||||
let llvm_void = ctx.ctx.void_type();
|
||||
let llvm_i32 = ctx.ctx.i32_type();
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
|
||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||
|
||||
let ndarray_calc_nd_indices_fn_name = match llvm_usize.get_bit_width() {
|
||||
32 => "__nac3_ndarray_calc_nd_indices",
|
||||
64 => "__nac3_ndarray_calc_nd_indices64",
|
||||
bw => unreachable!("Unsupported size type bit width: {}", bw),
|
||||
};
|
||||
let ndarray_calc_nd_indices_fn =
|
||||
ctx.module.get_function(ndarray_calc_nd_indices_fn_name).unwrap_or_else(|| {
|
||||
let fn_type = llvm_void.fn_type(
|
||||
&[llvm_usize.into(), llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into()],
|
||||
false,
|
||||
);
|
||||
|
||||
ctx.module.add_function(ndarray_calc_nd_indices_fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
let ndarray_num_dims = ndarray.load_ndims(ctx);
|
||||
let ndarray_dims = ndarray.dim_sizes();
|
||||
|
||||
let indices = ctx.builder.build_array_alloca(llvm_i32, ndarray_num_dims, "").unwrap();
|
||||
|
||||
ctx.builder
|
||||
.build_call(
|
||||
ndarray_calc_nd_indices_fn,
|
||||
&[
|
||||
index.into(),
|
||||
ndarray_dims.base_ptr(ctx, generator).into(),
|
||||
ndarray_num_dims.into(),
|
||||
indices.into(),
|
||||
],
|
||||
"",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
TypedArrayLikeAdapter::from(
|
||||
ArraySliceValue::from_ptr_val(indices, ndarray_num_dims, None),
|
||||
Box::new(|_, v| v.into_int_value()),
|
||||
Box::new(|_, v| v.into()),
|
||||
)
|
||||
}
|
||||
|
||||
fn call_ndarray_flatten_index_impl<'ctx, G, Indices>(
|
||||
generator: &G,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
ndarray: NDArrayValue<'ctx>,
|
||||
indices: &Indices,
|
||||
) -> IntValue<'ctx>
|
||||
where
|
||||
G: CodeGenerator + ?Sized,
|
||||
Indices: ArrayLikeIndexer<'ctx>,
|
||||
{
|
||||
let llvm_i32 = ctx.ctx.i32_type();
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
|
||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||
|
||||
debug_assert_eq!(
|
||||
IntType::try_from(indices.element_type(ctx, generator))
|
||||
.map(IntType::get_bit_width)
|
||||
.unwrap_or_default(),
|
||||
llvm_i32.get_bit_width(),
|
||||
"Expected i32 value for argument `indices` to `call_ndarray_flatten_index_impl`"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
indices.size(ctx, generator).get_type().get_bit_width(),
|
||||
llvm_usize.get_bit_width(),
|
||||
"Expected usize integer value for argument `indices_size` to `call_ndarray_flatten_index_impl`"
|
||||
);
|
||||
|
||||
let ndarray_flatten_index_fn_name = match llvm_usize.get_bit_width() {
|
||||
32 => "__nac3_ndarray_flatten_index",
|
||||
64 => "__nac3_ndarray_flatten_index64",
|
||||
bw => unreachable!("Unsupported size type bit width: {}", bw),
|
||||
};
|
||||
let ndarray_flatten_index_fn =
|
||||
ctx.module.get_function(ndarray_flatten_index_fn_name).unwrap_or_else(|| {
|
||||
let fn_type = llvm_usize.fn_type(
|
||||
&[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_usize.into()],
|
||||
false,
|
||||
);
|
||||
|
||||
ctx.module.add_function(ndarray_flatten_index_fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
let ndarray_num_dims = ndarray.load_ndims(ctx);
|
||||
let ndarray_dims = ndarray.dim_sizes();
|
||||
|
||||
let index = ctx
|
||||
.builder
|
||||
.build_call(
|
||||
ndarray_flatten_index_fn,
|
||||
&[
|
||||
ndarray_dims.base_ptr(ctx, generator).into(),
|
||||
ndarray_num_dims.into(),
|
||||
indices.base_ptr(ctx, generator).into(),
|
||||
indices.size(ctx, generator).into(),
|
||||
],
|
||||
"",
|
||||
)
|
||||
.map(CallSiteValue::try_as_basic_value)
|
||||
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||
.map(Either::unwrap_left)
|
||||
.unwrap();
|
||||
|
||||
index
|
||||
}
|
||||
|
||||
/// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the
|
||||
/// multidimensional index.
|
||||
///
|
||||
/// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an
|
||||
/// `NDArray`.
|
||||
/// * `indices` - The multidimensional index to compute the flattened index for.
|
||||
pub fn call_ndarray_flatten_index<'ctx, G, Index>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
ndarray: NDArrayValue<'ctx>,
|
||||
indices: &Index,
|
||||
) -> IntValue<'ctx>
|
||||
where
|
||||
G: CodeGenerator + ?Sized,
|
||||
Index: ArrayLikeIndexer<'ctx>,
|
||||
{
|
||||
call_ndarray_flatten_index_impl(generator, ctx, ndarray, indices)
|
||||
}
|
||||
|
||||
/// Generates a call to `__nac3_ndarray_calc_broadcast`. Returns a tuple containing the number of
|
||||
/// dimension and size of each dimension of the resultant `ndarray`.
|
||||
pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
lhs: NDArrayValue<'ctx>,
|
||||
rhs: NDArrayValue<'ctx>,
|
||||
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||
|
||||
let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() {
|
||||
32 => "__nac3_ndarray_calc_broadcast",
|
||||
64 => "__nac3_ndarray_calc_broadcast64",
|
||||
bw => unreachable!("Unsupported size type bit width: {}", bw),
|
||||
};
|
||||
let ndarray_calc_broadcast_fn =
|
||||
ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| {
|
||||
let fn_type = llvm_usize.fn_type(
|
||||
&[
|
||||
llvm_pusize.into(),
|
||||
llvm_usize.into(),
|
||||
llvm_pusize.into(),
|
||||
llvm_usize.into(),
|
||||
llvm_pusize.into(),
|
||||
],
|
||||
false,
|
||||
);
|
||||
|
||||
ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
let lhs_ndims = lhs.load_ndims(ctx);
|
||||
let rhs_ndims = rhs.load_ndims(ctx);
|
||||
let min_ndims = llvm_intrinsics::call_int_umin(ctx, lhs_ndims, rhs_ndims, None);
|
||||
|
||||
gen_for_callback_incrementing(
|
||||
generator,
|
||||
ctx,
|
||||
llvm_usize.const_zero(),
|
||||
(min_ndims, false),
|
||||
|generator, ctx, _, idx| {
|
||||
let idx = ctx.builder.build_int_sub(min_ndims, idx, "").unwrap();
|
||||
let (lhs_dim_sz, rhs_dim_sz) = unsafe {
|
||||
(
|
||||
lhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None),
|
||||
rhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None),
|
||||
)
|
||||
};
|
||||
|
||||
let llvm_usize_const_one = llvm_usize.const_int(1, false);
|
||||
let lhs_eqz = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::EQ, lhs_dim_sz, llvm_usize_const_one, "")
|
||||
.unwrap();
|
||||
let rhs_eqz = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::EQ, rhs_dim_sz, llvm_usize_const_one, "")
|
||||
.unwrap();
|
||||
let lhs_or_rhs_eqz = ctx.builder.build_or(lhs_eqz, rhs_eqz, "").unwrap();
|
||||
|
||||
let lhs_eq_rhs = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::EQ, lhs_dim_sz, rhs_dim_sz, "")
|
||||
.unwrap();
|
||||
|
||||
let is_compatible = ctx.builder.build_or(lhs_or_rhs_eqz, lhs_eq_rhs, "").unwrap();
|
||||
|
||||
ctx.make_assert(
|
||||
generator,
|
||||
is_compatible,
|
||||
"0:ValueError",
|
||||
"operands could not be broadcast together",
|
||||
[None, None, None],
|
||||
ctx.current_loc,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
llvm_usize.const_int(1, false),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let max_ndims = llvm_intrinsics::call_int_umax(ctx, lhs_ndims, rhs_ndims, None);
|
||||
let lhs_dims = lhs.dim_sizes().base_ptr(ctx, generator);
|
||||
let lhs_ndims = lhs.load_ndims(ctx);
|
||||
let rhs_dims = rhs.dim_sizes().base_ptr(ctx, generator);
|
||||
let rhs_ndims = rhs.load_ndims(ctx);
|
||||
let out_dims = ctx.builder.build_array_alloca(llvm_usize, max_ndims, "").unwrap();
|
||||
let out_dims = ArraySliceValue::from_ptr_val(out_dims, max_ndims, None);
|
||||
|
||||
ctx.builder
|
||||
.build_call(
|
||||
ndarray_calc_broadcast_fn,
|
||||
&[
|
||||
lhs_dims.into(),
|
||||
lhs_ndims.into(),
|
||||
rhs_dims.into(),
|
||||
rhs_ndims.into(),
|
||||
out_dims.base_ptr(ctx, generator).into(),
|
||||
],
|
||||
"",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
TypedArrayLikeAdapter::from(
|
||||
out_dims,
|
||||
Box::new(|_, v| v.into_int_value()),
|
||||
Box::new(|_, v| v.into()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates a call to `__nac3_ndarray_calc_broadcast_idx`. Returns an [`ArrayAllocaValue`]
|
||||
/// containing the indices used for accessing `array` corresponding to the index of the broadcasted
|
||||
/// array `broadcast_idx`.
|
||||
pub fn call_ndarray_calc_broadcast_index<
|
||||
'ctx,
|
||||
G: CodeGenerator + ?Sized,
|
||||
BroadcastIdx: UntypedArrayLikeAccessor<'ctx>,
|
||||
>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
array: NDArrayValue<'ctx>,
|
||||
broadcast_idx: &BroadcastIdx,
|
||||
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
|
||||
let llvm_i32 = ctx.ctx.i32_type();
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
|
||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||
|
||||
let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() {
|
||||
32 => "__nac3_ndarray_calc_broadcast_idx",
|
||||
64 => "__nac3_ndarray_calc_broadcast_idx64",
|
||||
bw => unreachable!("Unsupported size type bit width: {}", bw),
|
||||
};
|
||||
let ndarray_calc_broadcast_fn =
|
||||
ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| {
|
||||
let fn_type = llvm_usize.fn_type(
|
||||
&[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_pi32.into()],
|
||||
false,
|
||||
);
|
||||
|
||||
ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None)
|
||||
});
|
||||
|
||||
let broadcast_size = broadcast_idx.size(ctx, generator);
|
||||
let out_idx = ctx.builder.build_array_alloca(llvm_i32, broadcast_size, "").unwrap();
|
||||
|
||||
let array_dims = array.dim_sizes().base_ptr(ctx, generator);
|
||||
let array_ndims = array.load_ndims(ctx);
|
||||
let broadcast_idx_ptr = unsafe {
|
||||
broadcast_idx.ptr_offset_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
|
||||
};
|
||||
|
||||
ctx.builder
|
||||
.build_call(
|
||||
ndarray_calc_broadcast_fn,
|
||||
&[array_dims.into(), array_ndims.into(), broadcast_idx_ptr.into(), out_idx.into()],
|
||||
"",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
TypedArrayLikeAdapter::from(
|
||||
ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None),
|
||||
Box::new(|_, v| v.into_int_value()),
|
||||
Box::new(|_, v| v.into()),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_size_variant<'ctx>(ty: IntType<'ctx>) -> SizeVariant {
|
||||
match ty.get_bit_width() {
|
||||
32 => SizeVariant::Bits32,
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
use crate::{
|
||||
codegen::{
|
||||
classes::{
|
||||
check_basic_types_match, ArrayLikeIndexer, ArrayLikeValue, ListType, ListValue,
|
||||
NDArrayType, NDArrayValue, NpArrayType, NpArrayValue, ProxyType, ProxyValue,
|
||||
TypedArrayLikeAccessor, TypedArrayLikeAdapter, TypedArrayLikeMutator,
|
||||
UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
||||
ArrayLikeIndexer, ArrayLikeValue, ListType, ListValue, NDArrayType, NDArrayValue,
|
||||
ProxyType, ProxyValue, TypedArrayLikeAccessor, TypedArrayLikeAdapter,
|
||||
TypedArrayLikeMutator, UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
||||
},
|
||||
expr::gen_binop_expr_with_values,
|
||||
irrt::calculate_len_for_slice_range,
|
||||
irrt::{
|
||||
calculate_len_for_slice_range, call_ndarray_calc_broadcast,
|
||||
call_ndarray_calc_broadcast_index, call_ndarray_calc_nd_indices,
|
||||
call_ndarray_calc_size,
|
||||
},
|
||||
llvm_intrinsics::{self, call_memcpy_generic},
|
||||
stmt::{gen_for_callback_incrementing, gen_for_range_callback, gen_if_else_expr_callback},
|
||||
CodeGenContext, CodeGenerator,
|
||||
|
@ -23,140 +26,14 @@ use crate::{
|
|||
typedef::{FunSignature, Type, TypeEnum},
|
||||
},
|
||||
};
|
||||
use inkwell::types::{AnyTypeEnum, BasicTypeEnum, PointerType};
|
||||
use inkwell::{
|
||||
types::BasicType,
|
||||
values::{BasicValueEnum, IntValue, PointerValue},
|
||||
AddressSpace, IntPredicate, OptimizationLevel,
|
||||
};
|
||||
use inkwell::{
|
||||
types::{AnyTypeEnum, BasicTypeEnum, IntType, PointerType},
|
||||
values::BasicValue,
|
||||
};
|
||||
use nac3parser::ast::{Operator, StrRef};
|
||||
|
||||
fn memory_copy_slice<'ctx, G, T, Dst, Src>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
dst: Dst,
|
||||
src: Src,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
G: CodeGenerator + ?Sized,
|
||||
Dst: TypedArrayLikeMutator<'ctx, T>,
|
||||
Src: TypedArrayLikeAccessor<'ctx, T>,
|
||||
{
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
// Check `src.size` == `dst.size`, otherwise throw an Exception
|
||||
let size_ok = ctx
|
||||
.builder
|
||||
.build_int_compare(IntPredicate::EQ, src.size(ctx, generator), dst.size(ctx, generator), "")
|
||||
.unwrap();
|
||||
ctx.make_assert(
|
||||
generator,
|
||||
size_ok,
|
||||
"0:ValueError",
|
||||
"copy slice mismatched",
|
||||
[None, None, None],
|
||||
ctx.current_loc,
|
||||
);
|
||||
|
||||
// Copy data
|
||||
let len = dst.size(ctx, generator);
|
||||
gen_for_callback_incrementing(
|
||||
generator,
|
||||
ctx,
|
||||
llvm_usize.const_zero(),
|
||||
(len, false),
|
||||
|generator, ctx, _, idx| {
|
||||
let value = src.get_typed(ctx, generator, &idx, None);
|
||||
dst.set_typed(ctx, generator, &idx, value);
|
||||
Ok(())
|
||||
},
|
||||
llvm_usize.const_int(1, false),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn allocate_ndarray<'ctx, G>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
elem_type: BasicTypeEnum<'ctx>,
|
||||
in_ndims: IntValue<'ctx>,
|
||||
name: &'static str,
|
||||
) -> NpArrayValue<'ctx>
|
||||
where
|
||||
G: CodeGenerator + ?Sized,
|
||||
{
|
||||
let size_type = generator.get_size_type(ctx.ctx);
|
||||
let ndarray_ty = NpArrayType { elem_type, size_type };
|
||||
ndarray_ty.alloca(ctx, in_ndims, name)
|
||||
}
|
||||
|
||||
fn user_shape_set<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
in_shape: BasicValueEnum<'ctx>,
|
||||
in_shape_ty: Type,
|
||||
dst_shape: TypedArrayLikeAdapter<'ctx, IntValue<'ctx>>,
|
||||
) -> Result<(), String> {
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
// Check `in_shape_ty` to determine what to do determining on the user's input
|
||||
match &*ctx.unifier.get_ty(in_shape_ty) {
|
||||
TypeEnum::TObj { obj_id, .. }
|
||||
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
||||
{
|
||||
// 1. A list of ints; e.g., `np.empty([600, 800, 3])`
|
||||
|
||||
// NOTE: If there are no logic errors, the list's element type MUST BE int32.
|
||||
|
||||
// List has to be a pointer
|
||||
let BasicValueEnum::PointerValue(shape_list_ptr) = in_shape else { unreachable!() };
|
||||
|
||||
let shape_list = ListValue::from_ptr_val(shape_list_ptr, llvm_usize, None);
|
||||
memory_copy_slice(
|
||||
generator,
|
||||
ctx,
|
||||
dst_shape,
|
||||
TypedArrayLikeAdapter::from(
|
||||
shape_list.data(),
|
||||
Box::new(|_ctx, value| value.into_int_value()),
|
||||
Box::new(|_ctx, value| value.as_basic_value_enum()),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
TypeEnum::TTuple { ty, .. } => {
|
||||
// 2. A tuple of ints; e.g., `np.empty((600, 800, 3))`
|
||||
|
||||
// Tuple has to be a struct
|
||||
// Read [`codegen::expr::gen_expr`] to see how `nac3core` translates a Python tuple into LLVM.
|
||||
let BasicValueEnum::StructValue(shape_tuple) = in_shape else { unreachable!() };
|
||||
|
||||
let ndims = ty.len();
|
||||
for dim_i in 0..ndims {
|
||||
let dim = ctx
|
||||
.builder
|
||||
.build_extract_value(shape_tuple, dim_i as u32, format!("dim{dim_i}").as_str())
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let idx = llvm_usize.const_int(dim_i as u64, false);
|
||||
dst_shape.set_typed(ctx, generator, &idx, dim);
|
||||
}
|
||||
}
|
||||
TypeEnum::TObj { obj_id, .. }
|
||||
if *obj_id == ctx.primitives.int32.obj_id(&ctx.unifier).unwrap() =>
|
||||
{
|
||||
// 3. A scalar `int32`; e.g., `np.empty(3)`, this is functionally equivalent to `np.empty([3])`
|
||||
let shape_int = in_shape.into_int_value();
|
||||
dst_shape.set_typed(ctx, generator, &llvm_usize.const_zero(), shape_int);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// /// Creates an uninitialized `NDArray` instance.
|
||||
// fn create_ndarray_uninitialized<'ctx, G: CodeGenerator + ?Sized>(
|
||||
// generator: &mut G,
|
||||
|
|
|
@ -23,4 +23,4 @@ pub mod codegen;
|
|||
pub mod symbol_resolver;
|
||||
pub mod toplevel;
|
||||
pub mod typecheck;
|
||||
pub mod util;
|
||||
pub mod util;
|
|
@ -34,7 +34,6 @@ pub mod numpy;
|
|||
pub mod type_annotation;
|
||||
use composer::*;
|
||||
use type_annotation::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SizeVariant {
|
||||
Bits32,
|
||||
Bits64,
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
{ pkgs } : [
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "0ksz7xz1lbwsmdr9sa1444k0dlfkbd8k11pq7w08ir7r1wjy6fid";
|
||||
name = "mingw-w64-clang-x86_64-libunwind-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "1v8zkfcbf1ga2ndpd1j0dwv5s1rassxs2b5pjhcsmqwjcvczba1m";
|
||||
name = "mingw-w64-clang-x86_64-libunwind-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "0r8skyjqv4cpkqif0niakx4hdpkscil1zf6mzj34pqna0j5gdnq2";
|
||||
name = "mingw-w64-clang-x86_64-libc++-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "0mfd8wrmgx12j5gf354j7pk1l3lg9ykxvq75xdk3jipsr6hbn846";
|
||||
name = "mingw-w64-clang-x86_64-libc++-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -31,9 +31,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.1-1-any.pkg.tar.zst";
|
||||
sha256 = "14p4xxaxjjy6j1ingji82xhai1mc1gls5ali6z40fbb2ylxkaggs";
|
||||
name = "mingw-w64-clang-x86_64-xz-5.6.1-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.2-2-any.pkg.tar.zst";
|
||||
sha256 = "0phb9hwqksk1rg29yhwlc7si78zav19c2kac0i841pc7mc2n9gzx";
|
||||
name = "mingw-w64-clang-x86_64-xz-5.6.2-2-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -43,81 +43,81 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.6-1-any.pkg.tar.zst";
|
||||
sha256 = "177b3rmsknqq6hf0zqwva71s3avh20ca7vzznp2ls2z5qm8vhhlp";
|
||||
name = "mingw-w64-clang-x86_64-libxml2-2.12.6-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.8-1-any.pkg.tar.zst";
|
||||
sha256 = "1imipb0dz4w6x4n9arn22imyzzcwdlf2cqxvn7irqq7w9by6fy0b";
|
||||
name = "mingw-w64-clang-x86_64-libxml2-2.12.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zstd-1.5.5-1-any.pkg.tar.zst";
|
||||
sha256 = "07739wmwgxf0d6db4p8w302a6jwcm01aafr1s8jvcl5k1h5a1m2m";
|
||||
name = "mingw-w64-clang-x86_64-zstd-1.5.5-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zstd-1.5.6-2-any.pkg.tar.zst";
|
||||
sha256 = "02cp5ci8w50k7xn38mpkwnr8sn898v18wcc07y8f9sfla7vcyfix";
|
||||
name = "mingw-w64-clang-x86_64-zstd-1.5.6-2-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "0ibiy01v16naik9pj32ch7a9pkbw4yrn3gyq7p0y6kcc63fkjazy";
|
||||
name = "mingw-w64-clang-x86_64-llvm-libs-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "0rpbgvvinsqflhd3nhfxk0g0yy8j80zzw5yx6573ak0m78a9fa06";
|
||||
name = "mingw-w64-clang-x86_64-llvm-libs-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1hcfz6nb6svmmcqzfrdi96az2x7mzj0cispdv2ssbgn7nkf19pi0";
|
||||
name = "mingw-w64-clang-x86_64-llvm-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "185g5h8q3x3rav9lp2njln58ny2idh2067fd02j3nsbik6glshpf";
|
||||
name = "mingw-w64-clang-x86_64-llvm-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1k17d18g7rmq2ph4kq1mf84vs8133jzf52nkv6syh39ypjga67wa";
|
||||
name = "mingw-w64-clang-x86_64-clang-libs-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "089hji3yd7wsd03v9mdfgc99l5k1dql8kg7p3hy13vrbgfsabxhc";
|
||||
name = "mingw-w64-clang-x86_64-clang-libs-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1w2j0vs888haz9shjr1l8dc4j957sk1p0377zzipkbqnzqwjf1z8";
|
||||
name = "mingw-w64-clang-x86_64-compiler-rt-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "1dwcxnv1k5ljim5ys4h1c3jlrdpi0054z094ynav7if65i8zjj4a";
|
||||
name = "mingw-w64-clang-x86_64-compiler-rt-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
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 = "18csfwlk2h9pr4411crx1b41qjzn5jgbssm3h109nzwbdizkp62h";
|
||||
name = "mingw-w64-clang-x86_64-headers-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
sha256 = "1h3cdcajz29iq7vja908kkijz1vb9xn0f7w1lw1ima0q0zhinv4q";
|
||||
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
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 = "03l1zkrxgxxssp430xcv2gch1d03rbnbk1c0vgiqxigcs8lljh2g";
|
||||
name = "mingw-w64-clang-x86_64-crt-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
sha256 = "15kamyi3b0j6f5zxin4i2jgzjc7lzvwl4z5cz3dx0i8hg91aq0n7";
|
||||
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1ai4gl7ybpk9n10jmbpf3zzfa893m1krj5qhf44ajln0jabdfnbn";
|
||||
name = "mingw-w64-clang-x86_64-lld-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "1vpij5d06m4kjy3qv8bizwlkl21gcv6fv0r2f1j9bclgm6k3144x";
|
||||
name = "mingw-w64-clang-x86_64-lld-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
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 = "1svhjzwhvl4ldl439jhgfy47g05y2af1cjqvydgijn1dd4g8y8vq";
|
||||
name = "mingw-w64-clang-x86_64-libwinpthread-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
sha256 = "0qdvgs1rmjjhn9klf9kpw7l0ydz36rr5fasn4q9gpby2lgl11bkb";
|
||||
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
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 = "0jxdhkl256vnr13xf1x3fyjrdf764zg70xcs3gki3rg109f0a6xk";
|
||||
name = "mingw-w64-clang-x86_64-winpthreads-git-11.0.0.r655.gdbfdf8025-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
sha256 = "0rh2mn078cifcmr4as4k57jxjln5lbnsmpx47h9d0s5d2i8sf2rc";
|
||||
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r81.g90abf784a-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "0ahfic7vdfv96k5v7fdkgk1agk28l833xjn2igrmbvqg96ak0w6n";
|
||||
name = "mingw-w64-clang-x86_64-clang-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "1qny934nv4g75k9gb5sf31v24bgafkg6qw7r35xv3in491w6annq";
|
||||
name = "mingw-w64-clang-x86_64-clang-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.27.0-1-any.pkg.tar.zst";
|
||||
sha256 = "06y3sgqv6a0gr3dsbzs36jrj8adklssgjqi2ms5clsyq6ay4f91r";
|
||||
name = "mingw-w64-clang-x86_64-c-ares-1.27.0-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.29.0-1-any.pkg.tar.zst";
|
||||
sha256 = "01xg1h1a8kda0kq2921w25ybvm1ms7lfdzday0hv93f3myq7briq";
|
||||
name = "mingw-w64-clang-x86_64-c-ares-1.29.0-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -127,9 +127,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.1-1-any.pkg.tar.zst";
|
||||
sha256 = "16myvbg33q5s7jl30w5qd8n8f1r05335ms8r61234vn52n32l2c4";
|
||||
name = "mingw-w64-clang-x86_64-libunistring-1.1-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "13nz49li39z1zgfx1q9jg4vrmyrmqb6qdq0nqshidaqc6zr16k3g";
|
||||
name = "mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -151,9 +151,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-p11-kit-0.25.3-2-any.pkg.tar.zst";
|
||||
sha256 = "1jrwkc4lvw5hm5rqmi5gqh7mfkbqfa5gi81zjij0krnl0gaxw3c8";
|
||||
name = "mingw-w64-clang-x86_64-p11-kit-0.25.3-2-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-p11-kit-0.25.5-1-any.pkg.tar.zst";
|
||||
sha256 = "00yz6cmr1ldlrskv811n345xcia88mj7w4fyx4m9z5848jxgsabd";
|
||||
name = "mingw-w64-clang-x86_64-p11-kit-0.25.5-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -163,9 +163,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.2.1-1-any.pkg.tar.zst";
|
||||
sha256 = "0ix2r4ll09m2z5vz2k94gmwfs0pp3ipvjdimwzx7v6xhcs2l25lz";
|
||||
name = "mingw-w64-clang-x86_64-openssl-3.2.1-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.3.1-1-any.pkg.tar.zst";
|
||||
sha256 = "0ywhwm4kw3qjzv0872qwabnsq2rzbmqjb9m69q3fykjl0m9gigsa";
|
||||
name = "mingw-w64-clang-x86_64-openssl-3.3.1-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -175,27 +175,33 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp2-1.60.0-1-any.pkg.tar.zst";
|
||||
sha256 = "0wxw8266hf4qd2m4zpgb1wvlrnaksmcrs0kh5y9zpf2y5sy8f2bq";
|
||||
name = "mingw-w64-clang-x86_64-nghttp2-1.60.0-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp2-1.61.0-2-any.pkg.tar.zst";
|
||||
sha256 = "07bkk98126gy4k6lb9rrqqnzjfz9j2rsr5dzr2djmzdkw0h4dr95";
|
||||
name = "mingw-w64-clang-x86_64-nghttp2-1.61.0-2-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.6.0-1-any.pkg.tar.zst";
|
||||
sha256 = "1racc7cyzj22kink9w8m8jv73ji5hfg6r6d1ka9dqmvcbx04r8p0";
|
||||
name = "mingw-w64-clang-x86_64-curl-8.6.0-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp3-1.4.0-1-any.pkg.tar.zst";
|
||||
sha256 = "007w2252nzn274j4wjc1vf56xyzzh5vg3blj1hil7mlmffgvc923";
|
||||
name = "mingw-w64-clang-x86_64-nghttp3-1.4.0-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.76.0-1-any.pkg.tar.zst";
|
||||
sha256 = "0ny3bvwvn5wmqrxzhdfw34akr0kj0m7rg9lg3w5yibqz2mkqhk11";
|
||||
name = "mingw-w64-clang-x86_64-rust-1.76.0-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.8.0-10-any.pkg.tar.zst";
|
||||
sha256 = "024z5b1achkf448gxqy1i3gcw371x54kfl6igv08b5wb3rrw35a4";
|
||||
name = "mingw-w64-clang-x86_64-curl-8.8.0-10-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-pkgconf-1~2.1.1-1-any.pkg.tar.zst";
|
||||
sha256 = "00kxqg9ds4q74lxrzjh8z0858smqbi1j9r06s0zjadsql0ln98cq";
|
||||
name = "mingw-w64-clang-x86_64-pkgconf-12.1.1-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.79.0-1-any.pkg.tar.zst";
|
||||
sha256 = "0i7s88hj8m4920xifkj7i4b4sq8cqq7p5cypp3jqx3dc44pwm19a";
|
||||
name = "mingw-w64-clang-x86_64-rust-1.79.0-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 {
|
||||
|
@ -241,9 +247,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libarchive-3.7.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1p84yh6yzkdpmr02vyvgz16x5gycckah25jkdc2py09l7iw96bmw";
|
||||
name = "mingw-w64-clang-x86_64-libarchive-3.7.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libarchive-3.7.4-1-any.pkg.tar.zst";
|
||||
sha256 = "1ykw6imllgxv6lsgwxx1miqjr4l1iryqkrj286jcbfrb8ghpzhv5";
|
||||
name = "mingw-w64-clang-x86_64-libarchive-3.7.4-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -253,9 +259,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ninja-1.11.1-3-any.pkg.tar.zst";
|
||||
sha256 = "13wjfmyfr952n3ydpldjlwx1nla5xpyvr96ng8pfbyw4z900v5ms";
|
||||
name = "mingw-w64-clang-x86_64-ninja-1.11.1-3-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ninja-1.12.1-1-any.pkg.tar.zst";
|
||||
sha256 = "1vj9qaa43v316daz8k4ricmz3f33nhjpj7r0vn979nwmy7hzs7jx";
|
||||
name = "mingw-w64-clang-x86_64-ninja-1.12.1-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -265,9 +271,9 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.29.0-1-any.pkg.tar.zst";
|
||||
sha256 = "0l79lf6zihn0k8hz93qnjnq259y45yq19235g9c444jc2w093si1";
|
||||
name = "mingw-w64-clang-x86_64-cmake-3.29.0-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.30.0-1-any.pkg.tar.zst";
|
||||
sha256 = "07b7132hwhiqrf0l2lgw3g4zw9i2lln3kqc9kg2qijvkapbkmwqb";
|
||||
name = "mingw-w64-clang-x86_64-cmake-3.30.0-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -301,15 +307,15 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-sqlite3-3.45.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1icvw3f08cgi94p0177i46v72wgpsxw95p6kd0sm2w3vj0qlqbcw";
|
||||
name = "mingw-w64-clang-x86_64-sqlite3-3.45.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-sqlite3-3.46.0-1-any.pkg.tar.zst";
|
||||
sha256 = "0q676i2z5nr4c71jnd4z5qz9xa1xryl0cpi84w74yvd0p4qiz7y2";
|
||||
name = "mingw-w64-clang-x86_64-sqlite3-3.46.0-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tk-8.6.12-2-any.pkg.tar.zst";
|
||||
sha256 = "0pi74q91vl6vw8vvmmwnvrgai3b1aanp0zhca5qsmv8ljh2wdgzx";
|
||||
name = "mingw-w64-clang-x86_64-tk-8.6.12-2-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tk-8.6.13-1-any.pkg.tar.zst";
|
||||
sha256 = "12f6lqx1sglczcnz2ns6sxw9cxwm1klxajqzcrbnfwln1nllz2nd";
|
||||
name = "mingw-w64-clang-x86_64-tk-8.6.13-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -319,21 +325,21 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.11.8-1-any.pkg.tar.zst";
|
||||
sha256 = "0djpf4k8s25nys6nrm2x2v134lcgzhhbjs37ihkg0b3sxmmc3b0p";
|
||||
name = "mingw-w64-clang-x86_64-python-3.11.8-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.11.9-1-any.pkg.tar.zst";
|
||||
sha256 = "0ah1idjqxg7jc07a1gz9z766rjjd0f0c6ri4hpcsimsrbj1zjd3c";
|
||||
name = "mingw-w64-clang-x86_64-python-3.11.9-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openmp-18.1.2-1-any.pkg.tar.zst";
|
||||
sha256 = "1v9wm3ja3a7a7yna2bpqky481qf244wc98kfdl7l03k7rkvvydpl";
|
||||
name = "mingw-w64-clang-x86_64-openmp-18.1.2-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-18.1.8-1-any.pkg.tar.zst";
|
||||
sha256 = "0cy2v0l4af24j34mzj5q5nlzcqhackfajlfj1rpf6mb3rbz23qw9";
|
||||
name = "mingw-w64-clang-x86_64-llvm-openmp-18.1.8-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.26-1-any.pkg.tar.zst";
|
||||
sha256 = "0kdr72y5lc9dl9s1bjrw8g21qmv2iwd1xvn1r21170i277wsmqiv";
|
||||
name = "mingw-w64-clang-x86_64-openblas-0.3.26-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.27-1-any.pkg.tar.zst";
|
||||
sha256 = "06ygz1wa488wqvmxbn74b0fyan4wf3lb6kbwfampgikd1gijww2k";
|
||||
name = "mingw-w64-clang-x86_64-openblas-0.3.27-1-any.pkg.tar.zst";
|
||||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
|
@ -343,8 +349,8 @@
|
|||
})
|
||||
|
||||
(pkgs.fetchurl {
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-69.1.1-1-any.pkg.tar.zst";
|
||||
sha256 = "1mc56anasj0v92nlg84m3pa7dbqgjakxw0b4ibqlrr9cq0xzsg4b";
|
||||
name = "mingw-w64-clang-x86_64-python-setuptools-69.1.1-1-any.pkg.tar.zst";
|
||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-70.2.0-1-any.pkg.tar.zst";
|
||||
sha256 = "1q4r9bg2hn3jmshvq81xm5zvy9wn35yf0z2ayksrkwph1zzdkvkm";
|
||||
name = "mingw-w64-clang-x86_64-python-setuptools-70.2.0-1-any.pkg.tar.zst";
|
||||
})
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue