forked from M-Labs/nac3
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
c32c68b0b0 | |||
d394b24304 | |||
68da9b0ecf | |||
eec62c3bbb | |||
b521bc0c82 | |||
96e98947cc | |||
87a637b448 | |||
bdeeced122 | |||
37df08b803 | |||
05fd1a5199 | |||
f817d3347b | |||
2d275949b8 | |||
2783834cb1 | |||
879b063968 | |||
14e80dfab7 | |||
5fdbc34b43 | |||
32f24261f2 | |||
ce40a46f8a | |||
f15a64cc1b | |||
7fac801936 | |||
febfd1241d | |||
4bd5349381 | |||
c15062ab4c | |||
933804e270 | |||
1cfaa1a779 | |||
18e8e5269f | |||
357970a793 | |||
762a2447c3 | |||
8e614d83de | |||
bd66fe48d8 | |||
c59fd286ff | |||
f8530e0ef6 | |||
3ebd4ba5d1 | |||
d1dcfa19ff |
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
255
Cargo.lock
generated
255
Cargo.lock
generated
@ -1,6 +1,6 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
@ -65,11 +65,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.6"
|
version = "3.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
"once_cell",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -105,9 +106,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
@ -126,9 +127,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.7"
|
version = "1.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
@ -141,9 +142,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.23"
|
version = "4.5.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -151,9 +152,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.23"
|
version = "4.5.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -163,14 +164,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.18"
|
version = "4.5.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -199,9 +200,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.16"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -333,9 +334,15 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
version = "0.4.2"
|
version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fxhash"
|
name = "fxhash"
|
||||||
@ -373,7 +380,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.13.3+wasi-0.2.2",
|
||||||
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -388,20 +407,14 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.14.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@ -436,9 +449,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.7.0"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
@ -472,7 +485,7 @@ checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -497,9 +510,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.13.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
@ -521,9 +534,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop"
|
name = "lalrpop"
|
||||||
version = "0.22.0"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06093b57658c723a21da679530e061a8c25340fa5a6f98e313b542268c7e2a1f"
|
checksum = "7047a26de42016abf8f181b46b398aef0b77ad46711df41847f6ed869a2a1d5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ascii-canvas",
|
"ascii-canvas",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
@ -543,9 +556,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop-util"
|
name = "lalrpop-util"
|
||||||
version = "0.22.0"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "feee752d43abd0f4807a921958ab4131f692a44d4d599733d4419c5d586176ce"
|
checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
@ -581,9 +594,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.14"
|
version = "0.4.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "llvm-sys"
|
name = "llvm-sys"
|
||||||
@ -610,9 +623,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
@ -655,7 +668,7 @@ name = "nac3core"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"indexmap 2.7.0",
|
"indexmap 2.7.1",
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"insta",
|
"insta",
|
||||||
@ -663,7 +676,6 @@ dependencies = [
|
|||||||
"nac3core_derive",
|
"nac3core_derive",
|
||||||
"nac3parser",
|
"nac3parser",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rayon",
|
|
||||||
"regex",
|
"regex",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
@ -678,7 +690,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
"trybuild",
|
"trybuild",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -751,55 +763,55 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.6.5"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"indexmap 2.7.0",
|
"indexmap 2.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros",
|
"phf_macros",
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_codegen"
|
name = "phf_codegen"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
|
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator",
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_generator"
|
name = "phf_generator"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.3",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_macros"
|
name = "phf_macros"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator",
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.3",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -808,16 +820,16 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
|
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher",
|
"siphasher 0.3.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher",
|
"siphasher 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -873,9 +885,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -927,7 +939,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -940,7 +952,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -979,27 +991,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1049,9 +1041,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.42"
|
version = "0.38.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
@ -1068,9 +1060,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
@ -1089,9 +1081,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.24"
|
version = "1.0.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
@ -1110,14 +1102,14 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.134"
|
version = "1.0.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1164,9 +1156,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "similar"
|
name = "similar"
|
||||||
version = "2.6.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
|
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
@ -1174,6 +1166,12 @@ version = "0.3.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
@ -1182,12 +1180,11 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string-interner"
|
name = "string-interner"
|
||||||
version = "0.17.0"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e"
|
checksum = "1a3275464d7a9f2d4cac57c89c2ef96a8524dba2864c8d6f82e3980baf136f9b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"hashbrown 0.15.2",
|
||||||
"hashbrown 0.14.5",
|
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1226,7 +1223,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1242,9 +1239,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.94"
|
version = "2.0.96"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
|
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1265,13 +1262,13 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.15.0"
|
version = "3.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom",
|
"getrandom 0.3.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@ -1326,7 +1323,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1356,7 +1353,7 @@ version = "0.22.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.7.0",
|
"indexmap 2.7.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@ -1365,9 +1362,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trybuild"
|
name = "trybuild"
|
||||||
version = "1.0.101"
|
version = "1.0.103"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4"
|
checksum = "b812699e0c4f813b872b373a4471717d9eb550da14b311058a4d9cf4173cbca6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dissimilar",
|
"dissimilar",
|
||||||
"glob",
|
"glob",
|
||||||
@ -1439,9 +1436,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
@ -1511,6 +1508,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.13.3+wasi-0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@ -1604,13 +1610,22 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.22"
|
version = "0.6.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
|
checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yaml-rust"
|
name = "yaml-rust"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@ -1638,5 +1653,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.94",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1735834308,
|
"lastModified": 1738680400,
|
||||||
"narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=",
|
"narHash": "sha256-ooLh+XW8jfa+91F1nhf9OF7qhuA/y1ChLx6lXDNeY5U=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "6df24922a1400241dae323af55f30e4318a6ca65",
|
"rev": "799ba5bffed04ced7067a91798353d360788b30d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
12
flake.nix
12
flake.nix
@ -41,7 +41,7 @@
|
|||||||
lockFile = ./Cargo.lock;
|
lockFile = ./Cargo.lock;
|
||||||
};
|
};
|
||||||
passthru.cargoLock = cargoLock;
|
passthru.cargoLock = cargoLock;
|
||||||
nativeBuildInputs = [ pkgs.python3 (pkgs.wrapClangMulti pkgs.llvmPackages_14.clang) llvm-tools-irrt pkgs.llvmPackages_14.llvm.out llvm-nac3 ];
|
nativeBuildInputs = [ pkgs.python3 (pkgs.wrapClangMulti pkgs.llvmPackages_14.clang) llvm-tools-irrt pkgs.llvmPackages_14.llvm.out pkgs.llvmPackages_14.bintools llvm-nac3 ];
|
||||||
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
||||||
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ps.scipy ])) ];
|
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ps.scipy ])) ];
|
||||||
checkPhase =
|
checkPhase =
|
||||||
@ -85,7 +85,7 @@
|
|||||||
name = "nac3artiq-instrumented";
|
name = "nac3artiq-instrumented";
|
||||||
src = self;
|
src = self;
|
||||||
inherit (nac3artiq) cargoLock;
|
inherit (nac3artiq) cargoLock;
|
||||||
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt llvm-nac3-instrumented ];
|
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_14.bintools llvm-nac3-instrumented ];
|
||||||
buildInputs = [ pkgs.python3 llvm-nac3-instrumented ];
|
buildInputs = [ pkgs.python3 llvm-nac3-instrumented ];
|
||||||
cargoBuildFlags = [ "--package" "nac3artiq" "--features" "init-llvm-profile" ];
|
cargoBuildFlags = [ "--package" "nac3artiq" "--features" "init-llvm-profile" ];
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
@ -120,6 +120,7 @@
|
|||||||
buildInputs = [
|
buildInputs = [
|
||||||
(python3-mimalloc.withPackages(ps: [ ps.numpy ps.scipy ps.jsonschema ps.lmdb ps.platformdirs nac3artiq-instrumented ]))
|
(python3-mimalloc.withPackages(ps: [ ps.numpy ps.scipy ps.jsonschema ps.lmdb ps.platformdirs nac3artiq-instrumented ]))
|
||||||
pkgs.llvmPackages_14.llvm.out
|
pkgs.llvmPackages_14.llvm.out
|
||||||
|
pkgs.llvmPackages_14.bintools
|
||||||
];
|
];
|
||||||
phases = [ "buildPhase" "installPhase" ];
|
phases = [ "buildPhase" "installPhase" ];
|
||||||
buildPhase =
|
buildPhase =
|
||||||
@ -147,7 +148,7 @@
|
|||||||
name = "nac3artiq-pgo";
|
name = "nac3artiq-pgo";
|
||||||
src = self;
|
src = self;
|
||||||
inherit (nac3artiq) cargoLock;
|
inherit (nac3artiq) cargoLock;
|
||||||
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt llvm-nac3-pgo ];
|
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_14.bintools llvm-nac3-pgo ];
|
||||||
buildInputs = [ pkgs.python3 llvm-nac3-pgo ];
|
buildInputs = [ pkgs.python3 llvm-nac3-pgo ];
|
||||||
cargoBuildFlags = [ "--package" "nac3artiq" ];
|
cargoBuildFlags = [ "--package" "nac3artiq" ];
|
||||||
cargoTestFlags = [ "--package" "nac3ast" "--package" "nac3parser" "--package" "nac3core" "--package" "nac3artiq" ];
|
cargoTestFlags = [ "--package" "nac3ast" "--package" "nac3parser" "--package" "nac3core" "--package" "nac3artiq" ];
|
||||||
@ -168,7 +169,7 @@
|
|||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
# build dependencies
|
# build dependencies
|
||||||
packages.x86_64-linux.llvm-nac3
|
packages.x86_64-linux.llvm-nac3
|
||||||
(pkgs.wrapClangMulti llvmPackages_14.clang) llvmPackages_14.llvm.out # for running nac3standalone demos
|
(pkgs.wrapClangMulti llvmPackages_14.clang) llvmPackages_14.llvm.out llvmPackages_14.bintools # for running nac3standalone demos
|
||||||
packages.x86_64-linux.llvm-tools-irrt
|
packages.x86_64-linux.llvm-tools-irrt
|
||||||
cargo
|
cargo
|
||||||
rustc
|
rustc
|
||||||
@ -180,12 +181,9 @@
|
|||||||
clippy
|
clippy
|
||||||
pre-commit
|
pre-commit
|
||||||
rustfmt
|
rustfmt
|
||||||
rust-analyzer
|
|
||||||
];
|
];
|
||||||
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
|
|
||||||
shellHook =
|
shellHook =
|
||||||
''
|
''
|
||||||
export PYTHONPATH=/home/abdul/nac3/pyo3:$PYTHONPATH
|
|
||||||
export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a
|
export DEMO_LINALG_STUB=${packages.x86_64-linux.demo-linalg-stub}/lib/liblinalg.a
|
||||||
export DEMO_LINALG_STUB32=${packages.x86_64-linux.demo-linalg-stub32}/lib/liblinalg.a
|
export DEMO_LINALG_STUB32=${packages.x86_64-linux.demo-linalg-stub32}/lib/liblinalg.a
|
||||||
'';
|
'';
|
||||||
|
@ -9,10 +9,10 @@ name = "nac3artiq"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.14"
|
||||||
pyo3 = { version = "0.21", features = ["extension-module", "gil-refs"] }
|
pyo3 = { version = "0.21", features = ["extension-module", "gil-refs"] }
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
tempfile = "3.13"
|
tempfile = "3.16"
|
||||||
nac3core = { path = "../nac3core" }
|
nac3core = { path = "../nac3core" }
|
||||||
nac3ld = { path = "../nac3ld" }
|
nac3ld = { path = "../nac3ld" }
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from min_artiq import *
|
from min_artiq import *
|
||||||
|
|
||||||
attr1: Kernel[str] = "ss"
|
|
||||||
|
|
||||||
@nac3
|
@nac3
|
||||||
class Demo:
|
class Demo:
|
||||||
@ -15,8 +14,6 @@ class Demo:
|
|||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
global attr1
|
|
||||||
# attr1 = "2"
|
|
||||||
self.core.reset()
|
self.core.reset()
|
||||||
while True:
|
while True:
|
||||||
with parallel:
|
with parallel:
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
class EmbeddingMap:
|
|
||||||
def __init__(self):
|
|
||||||
self.object_inverse_map = {}
|
|
||||||
self.object_map = {}
|
|
||||||
self.string_map = {}
|
|
||||||
self.string_reverse_map = {}
|
|
||||||
self.function_map = {}
|
|
||||||
self.attributes_writeback = []
|
|
||||||
|
|
||||||
def store_function(self, key, fun):
|
|
||||||
self.function_map[key] = fun
|
|
||||||
return key
|
|
||||||
|
|
||||||
def store_object(self, obj):
|
|
||||||
obj_id = id(obj)
|
|
||||||
if obj_id in self.object_inverse_map:
|
|
||||||
return self.object_inverse_map[obj_id]
|
|
||||||
key = len(self.object_map) + 1
|
|
||||||
self.object_map[key] = obj
|
|
||||||
self.object_inverse_map[obj_id] = key
|
|
||||||
return key
|
|
||||||
|
|
||||||
def store_str(self, s):
|
|
||||||
if s in self.string_reverse_map:
|
|
||||||
return self.string_reverse_map[s]
|
|
||||||
key = len(self.string_map)
|
|
||||||
self.string_map[key] = s
|
|
||||||
self.string_reverse_map[s] = key
|
|
||||||
return key
|
|
||||||
|
|
||||||
def retrieve_function(self, key):
|
|
||||||
return self.function_map[key]
|
|
||||||
|
|
||||||
def retrieve_object(self, key):
|
|
||||||
return self.object_map[key]
|
|
||||||
|
|
||||||
def retrieve_str(self, key):
|
|
||||||
return self.string_map[key]
|
|
||||||
|
|
@ -6,7 +6,6 @@ from typing import Generic, TypeVar
|
|||||||
from math import floor, ceil
|
from math import floor, ceil
|
||||||
|
|
||||||
import nac3artiq
|
import nac3artiq
|
||||||
from embedding_map import EmbeddingMap
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -193,6 +192,46 @@ def print_int64(x: int64):
|
|||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddingMap:
|
||||||
|
def __init__(self):
|
||||||
|
self.object_inverse_map = {}
|
||||||
|
self.object_map = {}
|
||||||
|
self.string_map = {}
|
||||||
|
self.string_reverse_map = {}
|
||||||
|
self.function_map = {}
|
||||||
|
self.attributes_writeback = []
|
||||||
|
|
||||||
|
def store_function(self, key, fun):
|
||||||
|
self.function_map[key] = fun
|
||||||
|
return key
|
||||||
|
|
||||||
|
def store_object(self, obj):
|
||||||
|
obj_id = id(obj)
|
||||||
|
if obj_id in self.object_inverse_map:
|
||||||
|
return self.object_inverse_map[obj_id]
|
||||||
|
key = len(self.object_map) + 1
|
||||||
|
self.object_map[key] = obj
|
||||||
|
self.object_inverse_map[obj_id] = key
|
||||||
|
return key
|
||||||
|
|
||||||
|
def store_str(self, s):
|
||||||
|
if s in self.string_reverse_map:
|
||||||
|
return self.string_reverse_map[s]
|
||||||
|
key = len(self.string_map)
|
||||||
|
self.string_map[key] = s
|
||||||
|
self.string_reverse_map[s] = key
|
||||||
|
return key
|
||||||
|
|
||||||
|
def retrieve_function(self, key):
|
||||||
|
return self.function_map[key]
|
||||||
|
|
||||||
|
def retrieve_object(self, key):
|
||||||
|
return self.object_map[key]
|
||||||
|
|
||||||
|
def retrieve_str(self, key):
|
||||||
|
return self.string_map[key]
|
||||||
|
|
||||||
|
|
||||||
@nac3
|
@nac3
|
||||||
class Core:
|
class Core:
|
||||||
ref_period: KernelInvariant[float]
|
ref_period: KernelInvariant[float]
|
||||||
|
26
nac3artiq/demo/module.py
Normal file
26
nac3artiq/demo/module.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from min_artiq import *
|
||||||
|
from numpy import int32
|
||||||
|
|
||||||
|
# Global Variable Definition
|
||||||
|
X: Kernel[int32] = 1
|
||||||
|
|
||||||
|
# TopLevelFunction Defintion
|
||||||
|
@kernel
|
||||||
|
def display_X():
|
||||||
|
print_int32(X)
|
||||||
|
|
||||||
|
# TopLevel Class Definition
|
||||||
|
@nac3
|
||||||
|
class A:
|
||||||
|
@kernel
|
||||||
|
def __init__(self):
|
||||||
|
self.set_x(1)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_x(self, new_val: int32):
|
||||||
|
global X
|
||||||
|
X = new_val
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def get_X(self) -> int32:
|
||||||
|
return X
|
26
nac3artiq/demo/module_support.py
Normal file
26
nac3artiq/demo/module_support.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from min_artiq import *
|
||||||
|
import module as module_definition
|
||||||
|
|
||||||
|
@nac3
|
||||||
|
class TestModuleSupport:
|
||||||
|
core: KernelInvariant[Core]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.core = Core()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def run(self):
|
||||||
|
# Accessing classes
|
||||||
|
obj = module_definition.A()
|
||||||
|
obj.get_X()
|
||||||
|
obj.set_x(2)
|
||||||
|
|
||||||
|
# Calling functions
|
||||||
|
module_definition.display_X()
|
||||||
|
|
||||||
|
# Updating global variables
|
||||||
|
module_definition.X = 9
|
||||||
|
module_definition.display_X()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
TestModuleSupport().run()
|
1
nac3artiq/demo/nac3artiq.so
Symbolic link
1
nac3artiq/demo/nac3artiq.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../target/release/libnac3artiq.so
|
@ -1,24 +0,0 @@
|
|||||||
from min_artiq import *
|
|
||||||
from numpy import int32
|
|
||||||
|
|
||||||
|
|
||||||
@nac3
|
|
||||||
class Demo:
|
|
||||||
core: KernelInvariant[Core]
|
|
||||||
attr1: KernelInvariant[str]
|
|
||||||
attr2: KernelInvariant[int32]
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.core = Core()
|
|
||||||
self.attr2 = 32
|
|
||||||
self.attr1 = "SAMPLE"
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def run(self):
|
|
||||||
print_int32(self.attr2)
|
|
||||||
self.attr1
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
Demo().run()
|
|
@ -1,40 +0,0 @@
|
|||||||
from min_artiq import *
|
|
||||||
from numpy import int32
|
|
||||||
|
|
||||||
|
|
||||||
@nac3
|
|
||||||
class Demo:
|
|
||||||
attr1: KernelInvariant[int32] = 2
|
|
||||||
attr2: int32 = 4
|
|
||||||
attr3: Kernel[int32]
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def __init__(self):
|
|
||||||
self.attr3 = 8
|
|
||||||
|
|
||||||
|
|
||||||
@nac3
|
|
||||||
class NAC3Devices:
|
|
||||||
core: KernelInvariant[Core]
|
|
||||||
attr4: KernelInvariant[int32] = 16
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.core = Core()
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def run(self):
|
|
||||||
Demo.attr1 # Supported
|
|
||||||
# Demo.attr2 # Field not accessible on Kernel
|
|
||||||
# Demo.attr3 # Only attributes can be accessed in this way
|
|
||||||
# Demo.attr1 = 2 # Attributes are immutable
|
|
||||||
|
|
||||||
self.attr4 # Attributes can be accessed within class
|
|
||||||
|
|
||||||
obj = Demo()
|
|
||||||
obj.attr1 # Attributes can be accessed by class objects
|
|
||||||
|
|
||||||
NAC3Devices.attr4 # Attributes accessible for classes without __init__
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
NAC3Devices().run()
|
|
@ -8,7 +8,8 @@ use std::{
|
|||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
types::{PyDict, PyList}, PyObject, PyResult, Python
|
types::{PyDict, PyList},
|
||||||
|
PyObject, PyResult, Python,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
use super::{symbol_resolver::InnerResolver, timeline::TimeFns};
|
||||||
@ -18,9 +19,9 @@ use nac3core::{
|
|||||||
llvm_intrinsics::{call_int_smax, call_memcpy, call_stackrestore, call_stacksave},
|
llvm_intrinsics::{call_int_smax, call_memcpy, call_stackrestore, call_stacksave},
|
||||||
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
|
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
|
||||||
type_aligned_alloca,
|
type_aligned_alloca,
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, ProxyValue,
|
||||||
UntypedArrayLikeAccessor,
|
UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
@ -28,6 +29,7 @@ use nac3core::{
|
|||||||
inkwell::{
|
inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
module::Linkage,
|
module::Linkage,
|
||||||
|
targets::TargetMachine,
|
||||||
types::{BasicType, IntType},
|
types::{BasicType, IntType},
|
||||||
values::{BasicValueEnum, IntValue, PointerValue, StructValue},
|
values::{BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
@ -37,7 +39,7 @@ use nac3core::{
|
|||||||
toplevel::{
|
toplevel::{
|
||||||
helper::{extract_ndims, PrimDef},
|
helper::{extract_ndims, PrimDef},
|
||||||
numpy::unpack_ndarray_var_tys,
|
numpy::unpack_ndarray_var_tys,
|
||||||
DefinitionId, GenCall, TopLevelDef,
|
DefinitionId, GenCall,
|
||||||
},
|
},
|
||||||
typecheck::typedef::{iter_type_vars, FunSignature, FuncArg, Type, TypeEnum, VarMap},
|
typecheck::typedef::{iter_type_vars, FunSignature, FuncArg, Type, TypeEnum, VarMap},
|
||||||
};
|
};
|
||||||
@ -86,13 +88,13 @@ pub struct ArtiqCodeGenerator<'a> {
|
|||||||
impl<'a> ArtiqCodeGenerator<'a> {
|
impl<'a> ArtiqCodeGenerator<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: String,
|
name: String,
|
||||||
size_t: u32,
|
size_t: IntType<'_>,
|
||||||
timeline: &'a (dyn TimeFns + Sync),
|
timeline: &'a (dyn TimeFns + Sync),
|
||||||
) -> ArtiqCodeGenerator<'a> {
|
) -> ArtiqCodeGenerator<'a> {
|
||||||
assert!(size_t == 32 || size_t == 64);
|
assert!(matches!(size_t.get_bit_width(), 32 | 64));
|
||||||
ArtiqCodeGenerator {
|
ArtiqCodeGenerator {
|
||||||
name,
|
name,
|
||||||
size_t,
|
size_t: size_t.get_bit_width(),
|
||||||
name_counter: 0,
|
name_counter: 0,
|
||||||
start: None,
|
start: None,
|
||||||
end: None,
|
end: None,
|
||||||
@ -101,6 +103,17 @@ impl<'a> ArtiqCodeGenerator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_target_machine(
|
||||||
|
name: String,
|
||||||
|
ctx: &Context,
|
||||||
|
target_machine: &TargetMachine,
|
||||||
|
timeline: &'a (dyn TimeFns + Sync),
|
||||||
|
) -> ArtiqCodeGenerator<'a> {
|
||||||
|
let llvm_usize = ctx.ptr_sized_int_type(&target_machine.get_target_data(), None);
|
||||||
|
Self::new(name, llvm_usize, timeline)
|
||||||
|
}
|
||||||
|
|
||||||
/// If the generator is currently in a direct-`parallel` block context, emits IR that resets the
|
/// If the generator is currently in a direct-`parallel` block context, emits IR that resets the
|
||||||
/// position of the timeline to the initial timeline position before entering the `parallel`
|
/// position of the timeline to the initial timeline position before entering the `parallel`
|
||||||
/// block.
|
/// block.
|
||||||
@ -458,13 +471,13 @@ fn format_rpc_arg<'ctx>(
|
|||||||
// libproto_artiq: NDArray = [data[..], dim_sz[..]]
|
// libproto_artiq: NDArray = [data[..], dim_sz[..]]
|
||||||
|
|
||||||
let llvm_i1 = ctx.ctx.bool_type();
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let (elem_ty, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty);
|
let (elem_ty, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty);
|
||||||
let ndims = extract_ndims(&ctx.unifier, ndims);
|
let ndims = extract_ndims(&ctx.unifier, ndims);
|
||||||
let dtype = ctx.get_llvm_type(generator, elem_ty);
|
let dtype = ctx.get_llvm_type(generator, elem_ty);
|
||||||
let ndarray = NDArrayType::new(generator, ctx.ctx, dtype, ndims)
|
let ndarray = NDArrayType::new(ctx, dtype, ndims)
|
||||||
.map_value(arg.into_pointer_value(), None);
|
.map_pointer_value(arg.into_pointer_value(), None);
|
||||||
|
|
||||||
let ndims = llvm_usize.const_int(ndims, false);
|
let ndims = llvm_usize.const_int(ndims, false);
|
||||||
|
|
||||||
@ -543,7 +556,7 @@ fn format_rpc_ret<'ctx>(
|
|||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let llvm_i8_8 = ctx.ctx.struct_type(&[llvm_i8.array_type(8).into()], false);
|
let llvm_i8_8 = ctx.ctx.struct_type(&[llvm_i8.array_type(8).into()], false);
|
||||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
let rpc_recv = ctx.module.get_function("rpc_recv").unwrap_or_else(|| {
|
let rpc_recv = ctx.module.get_function("rpc_recv").unwrap_or_else(|| {
|
||||||
@ -596,7 +609,7 @@ fn format_rpc_ret<'ctx>(
|
|||||||
let (dtype, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ret_ty);
|
let (dtype, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ret_ty);
|
||||||
let dtype_llvm = ctx.get_llvm_type(generator, dtype);
|
let dtype_llvm = ctx.get_llvm_type(generator, dtype);
|
||||||
let ndims = extract_ndims(&ctx.unifier, ndims);
|
let ndims = extract_ndims(&ctx.unifier, ndims);
|
||||||
let ndarray = NDArrayType::new(generator, ctx.ctx, dtype_llvm, ndims)
|
let ndarray = NDArrayType::new(ctx, dtype_llvm, ndims)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
|
|
||||||
// NOTE: Current content of `ndarray`:
|
// NOTE: Current content of `ndarray`:
|
||||||
@ -684,7 +697,7 @@ fn format_rpc_ret<'ctx>(
|
|||||||
|
|
||||||
// debug_assert(nelems * sizeof(T) >= ndarray_nbytes)
|
// debug_assert(nelems * sizeof(T) >= ndarray_nbytes)
|
||||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||||
let num_elements = ndarray.size(generator, ctx);
|
let num_elements = ndarray.size(ctx);
|
||||||
|
|
||||||
let expected_ndarray_nbytes =
|
let expected_ndarray_nbytes =
|
||||||
ctx.builder.build_int_mul(num_elements, itemsize, "").unwrap();
|
ctx.builder.build_int_mul(num_elements, itemsize, "").unwrap();
|
||||||
@ -748,7 +761,7 @@ fn format_rpc_ret<'ctx>(
|
|||||||
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
ctx.builder.build_unconditional_branch(head_bb).unwrap();
|
||||||
|
|
||||||
ctx.builder.position_at_end(tail_bb);
|
ctx.builder.position_at_end(tail_bb);
|
||||||
ndarray.as_base_value().into()
|
ndarray.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@ -796,7 +809,7 @@ fn rpc_codegen_callback_fn<'ctx>(
|
|||||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
let int8 = ctx.ctx.i8_type();
|
let int8 = ctx.ctx.i8_type();
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let size_type = generator.get_size_type(ctx.ctx);
|
let size_type = ctx.get_size_type();
|
||||||
let ptr_type = int8.ptr_type(AddressSpace::default());
|
let ptr_type = int8.ptr_type(AddressSpace::default());
|
||||||
let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false);
|
let tag_ptr_type = ctx.ctx.struct_type(&[ptr_type.into(), size_type.into()], false);
|
||||||
|
|
||||||
@ -981,8 +994,7 @@ pub fn attributes_writeback<'ctx>(
|
|||||||
values.push((ty, obj.to_basic_value_enum(ctx, generator, ty).unwrap()));
|
values.push((ty, obj.to_basic_value_enum(ctx, generator, ty).unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now the global variables are just values so completely useless (14.0 stored as a float object in globals)
|
for val in (*globals).values() {
|
||||||
for (gloabl_id, val) in &*globals {
|
|
||||||
let val = val.as_ref(py);
|
let val = val.as_ref(py);
|
||||||
let ty = inner_resolver.get_obj_type(
|
let ty = inner_resolver.get_obj_type(
|
||||||
py,
|
py,
|
||||||
@ -995,33 +1007,6 @@ pub fn attributes_writeback<'ctx>(
|
|||||||
return Ok(Err(ty));
|
return Ok(Err(ty));
|
||||||
}
|
}
|
||||||
let ty = ty.unwrap();
|
let ty = ty.unwrap();
|
||||||
|
|
||||||
if let Some(def_id) = inner_resolver.pyid_to_def.read().get(gloabl_id) {
|
|
||||||
if let TopLevelDef::Variable { name, simple_name, .. } = &*top_levels[def_id.0].read() {
|
|
||||||
// println!("[+] Varaible with type: {:?}\n{:?}\n", ctx.unifier.stringify(*ty), ctx.unifier.get_ty(*ty));
|
|
||||||
println!("Sending Value of {:?}", val.to_string());
|
|
||||||
if gen_rpc_tag(ctx, ty, &mut scratch_buffer).is_ok() {
|
|
||||||
// let Some(val) = ctx.module.get_global(simple_name.to_string().as_str()) else {continue;};
|
|
||||||
// let val = val.as_pointer_value();
|
|
||||||
let pydict = PyDict::new(py);
|
|
||||||
pydict.set_item("global", val)?;
|
|
||||||
pydict.set_item("name", name)?;
|
|
||||||
host_attributes.append(pydict)?;
|
|
||||||
|
|
||||||
values.push((
|
|
||||||
ty,
|
|
||||||
// ctx.build_gep_and_load(
|
|
||||||
// val,
|
|
||||||
// &[zero, int32.const_int(0, false)],
|
|
||||||
// None,
|
|
||||||
// ),
|
|
||||||
inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match &*ctx.unifier.get_ty(ty) {
|
match &*ctx.unifier.get_ty(ty) {
|
||||||
TypeEnum::TObj { fields, obj_id, .. }
|
TypeEnum::TObj { fields, obj_id, .. }
|
||||||
if *obj_id != ctx.primitives.option.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id != ctx.primitives.option.obj_id(&ctx.unifier).unwrap() =>
|
||||||
@ -1030,15 +1015,6 @@ pub fn attributes_writeback<'ctx>(
|
|||||||
// for non-primitive attributes, they should be in another global
|
// for non-primitive attributes, they should be in another global
|
||||||
let mut attributes = Vec::new();
|
let mut attributes = Vec::new();
|
||||||
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
|
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
|
||||||
|
|
||||||
if !obj.is_pointer_value() && gen_rpc_tag(ctx, ty, &mut scratch_buffer).is_ok() {
|
|
||||||
println!("[-] Other function skipped");
|
|
||||||
// values.push((ty, obj));
|
|
||||||
// let pydict = PyDict::new(py);
|
|
||||||
// pydict.set_item("global", val)?;
|
|
||||||
// host_attributes.append(pydict)?;
|
|
||||||
// continue;
|
|
||||||
}
|
|
||||||
for (name, (field_ty, is_mutable)) in fields {
|
for (name, (field_ty, is_mutable)) in fields {
|
||||||
if !is_mutable {
|
if !is_mutable {
|
||||||
continue;
|
continue;
|
||||||
@ -1076,6 +1052,34 @@ pub fn attributes_writeback<'ctx>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TypeEnum::TModule { attributes, .. } => {
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
let obj = inner_resolver.get_obj_value(py, val, ctx, generator, ty)?.unwrap();
|
||||||
|
|
||||||
|
for (name, (field_ty, is_method)) in attributes {
|
||||||
|
if *is_method {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if gen_rpc_tag(ctx, *field_ty, &mut scratch_buffer).is_ok() {
|
||||||
|
fields.push(name.to_string());
|
||||||
|
let (index, _) = ctx.get_attr_index(ty, *name);
|
||||||
|
values.push((
|
||||||
|
*field_ty,
|
||||||
|
ctx.build_gep_and_load(
|
||||||
|
obj.into_pointer_value(),
|
||||||
|
&[zero, int32.const_int(index as u64, false)],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !fields.is_empty() {
|
||||||
|
let pydict = PyDict::new(py);
|
||||||
|
pydict.set_item("obj", val)?;
|
||||||
|
pydict.set_item("fields", fields)?;
|
||||||
|
host_attributes.append(pydict)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1191,7 +1195,7 @@ fn polymorphic_print<'ctx>(
|
|||||||
|
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let llvm_i64 = ctx.ctx.i64_type();
|
let llvm_i64 = ctx.ctx.i64_type();
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let suffix = suffix.unwrap_or_default();
|
let suffix = suffix.unwrap_or_default();
|
||||||
|
|
||||||
@ -1379,7 +1383,7 @@ fn polymorphic_print<'ctx>(
|
|||||||
|
|
||||||
let (dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
let (dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ty)
|
||||||
.map_value(value.into_pointer_value(), None);
|
.map_pointer_value(value.into_pointer_value(), None);
|
||||||
|
|
||||||
let num_0 = llvm_usize.const_zero();
|
let num_0 = llvm_usize.const_zero();
|
||||||
|
|
||||||
@ -1427,7 +1431,7 @@ fn polymorphic_print<'ctx>(
|
|||||||
fmt.push_str("range(");
|
fmt.push_str("range(");
|
||||||
flush(ctx, generator, &mut fmt, &mut args);
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
let val = RangeValue::from_pointer_value(value.into_pointer_value(), None);
|
let val = RangeType::new(ctx).map_pointer_value(value.into_pointer_value(), None);
|
||||||
|
|
||||||
let (start, stop, step) = destructure_range(ctx, val);
|
let (start, stop, step) = destructure_range(ctx, val);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ use nac3core::{
|
|||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
},
|
},
|
||||||
nac3parser::{
|
nac3parser::{
|
||||||
ast::{Constant, ExprKind, Located, Stmt, StmtKind, StrRef},
|
ast::{self, Constant, ExprKind, Located, Stmt, StmtKind, StrRef},
|
||||||
parser::parse_program,
|
parser::parse_program,
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::SymbolResolver,
|
||||||
@ -78,14 +78,62 @@ enum Isa {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Isa {
|
impl Isa {
|
||||||
/// Returns the number of bits in `size_t` for the [`Isa`].
|
/// Returns the [`TargetTriple`] used for compiling to this ISA.
|
||||||
fn get_size_type(self) -> u32 {
|
pub fn get_llvm_target_triple(self) -> TargetTriple {
|
||||||
if self == Isa::Host {
|
match self {
|
||||||
64u32
|
Isa::Host => TargetMachine::get_default_triple(),
|
||||||
} else {
|
Isa::RiscV32G | Isa::RiscV32IMA => TargetTriple::create("riscv32-unknown-linux"),
|
||||||
32u32
|
Isa::CortexA9 => TargetTriple::create("armv7-unknown-linux-gnueabihf"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`String`] representing the target CPU used for compiling to this ISA.
|
||||||
|
pub fn get_llvm_target_cpu(self) -> String {
|
||||||
|
match self {
|
||||||
|
Isa::Host => TargetMachine::get_host_cpu_name().to_string(),
|
||||||
|
Isa::RiscV32G | Isa::RiscV32IMA => "generic-rv32".to_string(),
|
||||||
|
Isa::CortexA9 => "cortex-a9".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`String`] representing the target features used for compiling to this ISA.
|
||||||
|
pub fn get_llvm_target_features(self) -> String {
|
||||||
|
match self {
|
||||||
|
Isa::Host => TargetMachine::get_host_cpu_features().to_string(),
|
||||||
|
Isa::RiscV32G => "+a,+m,+f,+d".to_string(),
|
||||||
|
Isa::RiscV32IMA => "+a,+m".to_string(),
|
||||||
|
Isa::CortexA9 => "+dsp,+fp16,+neon,+vfp3,+long-calls".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an instance of [`CodeGenTargetMachineOptions`] representing the target machine
|
||||||
|
/// options used for compiling to this ISA.
|
||||||
|
pub fn get_llvm_target_options(self) -> CodeGenTargetMachineOptions {
|
||||||
|
CodeGenTargetMachineOptions {
|
||||||
|
triple: self.get_llvm_target_triple().as_str().to_string_lossy().into_owned(),
|
||||||
|
cpu: self.get_llvm_target_cpu(),
|
||||||
|
features: self.get_llvm_target_features(),
|
||||||
|
reloc_mode: RelocMode::PIC,
|
||||||
|
..CodeGenTargetMachineOptions::from_host()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an instance of [`TargetMachine`] used in compiling and linking of a program of this
|
||||||
|
/// ISA.
|
||||||
|
pub fn create_llvm_target_machine(self, opt_level: OptimizationLevel) -> TargetMachine {
|
||||||
|
self.get_llvm_target_options()
|
||||||
|
.create_target_machine(opt_level)
|
||||||
|
.expect("couldn't create target machine")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of bits in `size_t` for this ISA.
|
||||||
|
fn get_size_type(self, ctx: &Context) -> u32 {
|
||||||
|
ctx.ptr_sized_int_type(
|
||||||
|
&self.create_llvm_target_machine(OptimizationLevel::Default).get_target_data(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.get_bit_width()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -111,6 +159,7 @@ pub struct PrimitivePythonId {
|
|||||||
generic_alias: (u64, u64),
|
generic_alias: (u64, u64),
|
||||||
virtual_id: u64,
|
virtual_id: u64,
|
||||||
option: u64,
|
option: u64,
|
||||||
|
module: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TopLevelComponent = (Stmt, String, PyObject);
|
type TopLevelComponent = (Stmt, String, PyObject);
|
||||||
@ -228,17 +277,10 @@ impl Nac3 {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Allow global declaration with Kernel[X] to pass across
|
// Allow global variable declaration with `Kernel` type annotation
|
||||||
// These are kept in sync between kernel and host
|
|
||||||
// KernelInvariants are constants, and hence not included here
|
|
||||||
StmtKind::AnnAssign { ref annotation, .. } => {
|
StmtKind::AnnAssign { ref annotation, .. } => {
|
||||||
match &annotation.node {
|
matches!(&annotation.node, ExprKind::Subscript { value, .. } if matches!(&value.node, ExprKind::Name {id, ..} if id == &"Kernel".into()))
|
||||||
ExprKind::Subscript { value, .. }
|
}
|
||||||
if matches!(&value.node, ExprKind::Name { id, .. }
|
|
||||||
if id.to_string().as_str() == "Kernel") => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -389,7 +431,7 @@ impl Nac3 {
|
|||||||
py: Python,
|
py: Python,
|
||||||
link_fn: &dyn Fn(&Module) -> PyResult<T>,
|
link_fn: &dyn Fn(&Module) -> PyResult<T>,
|
||||||
) -> PyResult<T> {
|
) -> PyResult<T> {
|
||||||
let size_t = self.isa.get_size_type();
|
let size_t = self.isa.get_size_type(&Context::create());
|
||||||
let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new(
|
let (mut composer, mut builtins_def, mut builtins_ty) = TopLevelComposer::new(
|
||||||
self.builtins.clone(),
|
self.builtins.clone(),
|
||||||
Self::get_lateinit_builtins(),
|
Self::get_lateinit_builtins(),
|
||||||
@ -432,12 +474,14 @@ impl Nac3 {
|
|||||||
];
|
];
|
||||||
add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names);
|
add_exceptions(&mut composer, &mut builtins_def, &mut builtins_ty, &exception_names);
|
||||||
|
|
||||||
|
// Stores a mapping from module id to attributes
|
||||||
let mut module_to_resolver_cache: HashMap<u64, _> = HashMap::new();
|
let mut module_to_resolver_cache: HashMap<u64, _> = HashMap::new();
|
||||||
|
|
||||||
let mut rpc_ids = vec![];
|
let mut rpc_ids = vec![];
|
||||||
for (stmt, path, module) in &self.top_levels {
|
for (stmt, path, module) in &self.top_levels {
|
||||||
let py_module: &PyAny = module.extract(py)?;
|
let py_module: &PyAny = module.extract(py)?;
|
||||||
let module_id: u64 = id_fn.call1((py_module,))?.extract()?;
|
let module_id: u64 = id_fn.call1((py_module,))?.extract()?;
|
||||||
|
let module_name: String = py_module.getattr("__name__")?.extract()?;
|
||||||
let helper = helper.clone();
|
let helper = helper.clone();
|
||||||
let class_obj;
|
let class_obj;
|
||||||
if let StmtKind::ClassDef { name, .. } = &stmt.node {
|
if let StmtKind::ClassDef { name, .. } = &stmt.node {
|
||||||
@ -452,7 +496,7 @@ impl Nac3 {
|
|||||||
} else {
|
} else {
|
||||||
class_obj = None;
|
class_obj = None;
|
||||||
}
|
}
|
||||||
let (name_to_pyid, resolver) =
|
let (name_to_pyid, resolver, _, _) =
|
||||||
module_to_resolver_cache.get(&module_id).cloned().unwrap_or_else(|| {
|
module_to_resolver_cache.get(&module_id).cloned().unwrap_or_else(|| {
|
||||||
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
|
||||||
let members: &PyDict =
|
let members: &PyDict =
|
||||||
@ -481,9 +525,17 @@ impl Nac3 {
|
|||||||
})))
|
})))
|
||||||
as Arc<dyn SymbolResolver + Send + Sync>;
|
as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
let name_to_pyid = Rc::new(name_to_pyid);
|
let name_to_pyid = Rc::new(name_to_pyid);
|
||||||
module_to_resolver_cache
|
let module_location = ast::Location::new(1, 1, stmt.location.file);
|
||||||
.insert(module_id, (name_to_pyid.clone(), resolver.clone()));
|
module_to_resolver_cache.insert(
|
||||||
(name_to_pyid, resolver)
|
module_id,
|
||||||
|
(
|
||||||
|
name_to_pyid.clone(),
|
||||||
|
resolver.clone(),
|
||||||
|
module_name.clone(),
|
||||||
|
Some(module_location),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
(name_to_pyid, resolver, module_name, Some(module_location))
|
||||||
});
|
});
|
||||||
|
|
||||||
let (name, def_id, ty) = composer
|
let (name, def_id, ty) = composer
|
||||||
@ -555,15 +607,24 @@ impl Nac3 {
|
|||||||
pyid_to_ty.insert(id, ty);
|
pyid_to_ty.insert(id, ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let StmtKind::AnnAssign { target, .. } = &stmt.node {
|
}
|
||||||
let ExprKind::Name { id: name, .. } = target.node else { unreachable!() };
|
|
||||||
|
|
||||||
global_value_ids
|
|
||||||
.write()
|
|
||||||
// .insert(id, py_module.getattr(name.to_string().as_str()).unwrap().into());
|
|
||||||
.insert(id, module.as_ref(py).into());
|
|
||||||
|
|
||||||
}
|
// Adding top level module definitions
|
||||||
|
for (module_id, (module_name_to_pyid, module_resolver, module_name, module_location)) in
|
||||||
|
module_to_resolver_cache
|
||||||
|
{
|
||||||
|
let def_id = composer
|
||||||
|
.register_top_level_module(
|
||||||
|
&module_name,
|
||||||
|
&module_name_to_pyid,
|
||||||
|
module_resolver,
|
||||||
|
module_location,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
CompileError::new_err(format!("compilation failed\n----------\n{e}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.pyid_to_def.write().insert(module_id, def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let id_fun = PyModule::import(py, "builtins")?.getattr("id")?;
|
let id_fun = PyModule::import(py, "builtins")?.getattr("id")?;
|
||||||
@ -685,6 +746,9 @@ impl Nac3 {
|
|||||||
"Unsupported @rpc annotation on global variable",
|
"Unsupported @rpc annotation on global variable",
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
TopLevelDef::Module { .. } => {
|
||||||
|
unreachable!("Type module cannot be decorated with @rpc")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,14 +787,18 @@ impl Nac3 {
|
|||||||
let buffer = buffer.as_slice().into();
|
let buffer = buffer.as_slice().into();
|
||||||
membuffer.lock().push(buffer);
|
membuffer.lock().push(buffer);
|
||||||
})));
|
})));
|
||||||
let size_t = context
|
|
||||||
.ptr_sized_int_type(&self.get_llvm_target_machine().get_target_data(), None)
|
|
||||||
.get_bit_width();
|
|
||||||
let num_threads = if is_multithreaded() { 4 } else { 1 };
|
let num_threads = if is_multithreaded() { 4 } else { 1 };
|
||||||
let thread_names: Vec<String> = (0..num_threads).map(|_| "main".to_string()).collect();
|
let thread_names: Vec<String> = (0..num_threads).map(|_| "main".to_string()).collect();
|
||||||
let threads: Vec<_> = thread_names
|
let threads: Vec<_> = thread_names
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Box::new(ArtiqCodeGenerator::new(s.to_string(), size_t, self.time_fns)))
|
.map(|s| {
|
||||||
|
Box::new(ArtiqCodeGenerator::with_target_machine(
|
||||||
|
s.to_string(),
|
||||||
|
&context,
|
||||||
|
&self.get_llvm_target_machine(),
|
||||||
|
self.time_fns,
|
||||||
|
))
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let membuffer = membuffers.clone();
|
let membuffer = membuffers.clone();
|
||||||
@ -739,8 +807,13 @@ impl Nac3 {
|
|||||||
let (registry, handles) =
|
let (registry, handles) =
|
||||||
WorkerRegistry::create_workers(threads, top_level.clone(), &self.llvm_options, &f);
|
WorkerRegistry::create_workers(threads, top_level.clone(), &self.llvm_options, &f);
|
||||||
|
|
||||||
let mut generator = ArtiqCodeGenerator::new("main".to_string(), size_t, self.time_fns);
|
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
|
let mut generator = ArtiqCodeGenerator::with_target_machine(
|
||||||
|
"main".to_string(),
|
||||||
|
&context,
|
||||||
|
&self.get_llvm_target_machine(),
|
||||||
|
self.time_fns,
|
||||||
|
);
|
||||||
let module = context.create_module("main");
|
let module = context.create_module("main");
|
||||||
let target_machine = self.llvm_options.create_target_machine().unwrap();
|
let target_machine = self.llvm_options.create_target_machine().unwrap();
|
||||||
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
|
module.set_data_layout(&target_machine.get_target_data().get_data_layout());
|
||||||
@ -859,52 +932,10 @@ impl Nac3 {
|
|||||||
link_fn(&main)
|
link_fn(&main)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`TargetTriple`] used for compiling to [isa].
|
|
||||||
fn get_llvm_target_triple(isa: Isa) -> TargetTriple {
|
|
||||||
match isa {
|
|
||||||
Isa::Host => TargetMachine::get_default_triple(),
|
|
||||||
Isa::RiscV32G | Isa::RiscV32IMA => TargetTriple::create("riscv32-unknown-linux"),
|
|
||||||
Isa::CortexA9 => TargetTriple::create("armv7-unknown-linux-gnueabihf"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`String`] representing the target CPU used for compiling to [isa].
|
|
||||||
fn get_llvm_target_cpu(isa: Isa) -> String {
|
|
||||||
match isa {
|
|
||||||
Isa::Host => TargetMachine::get_host_cpu_name().to_string(),
|
|
||||||
Isa::RiscV32G | Isa::RiscV32IMA => "generic-rv32".to_string(),
|
|
||||||
Isa::CortexA9 => "cortex-a9".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`String`] representing the target features used for compiling to [isa].
|
|
||||||
fn get_llvm_target_features(isa: Isa) -> String {
|
|
||||||
match isa {
|
|
||||||
Isa::Host => TargetMachine::get_host_cpu_features().to_string(),
|
|
||||||
Isa::RiscV32G => "+a,+m,+f,+d".to_string(),
|
|
||||||
Isa::RiscV32IMA => "+a,+m".to_string(),
|
|
||||||
Isa::CortexA9 => "+dsp,+fp16,+neon,+vfp3,+long-calls".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`CodeGenTargetMachineOptions`] representing the target machine
|
|
||||||
/// options used for compiling to [isa].
|
|
||||||
fn get_llvm_target_options(isa: Isa) -> CodeGenTargetMachineOptions {
|
|
||||||
CodeGenTargetMachineOptions {
|
|
||||||
triple: Nac3::get_llvm_target_triple(isa).as_str().to_string_lossy().into_owned(),
|
|
||||||
cpu: Nac3::get_llvm_target_cpu(isa),
|
|
||||||
features: Nac3::get_llvm_target_features(isa),
|
|
||||||
reloc_mode: RelocMode::PIC,
|
|
||||||
..CodeGenTargetMachineOptions::from_host()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`TargetMachine`] used in compiling and linking of a program to the
|
/// Returns an instance of [`TargetMachine`] used in compiling and linking of a program to the
|
||||||
/// target [isa].
|
/// target [ISA][isa].
|
||||||
fn get_llvm_target_machine(&self) -> TargetMachine {
|
fn get_llvm_target_machine(&self) -> TargetMachine {
|
||||||
Nac3::get_llvm_target_options(self.isa)
|
self.isa.create_llvm_target_machine(self.llvm_options.opt_level)
|
||||||
.create_target_machine(self.llvm_options.opt_level)
|
|
||||||
.expect("couldn't create target machine")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1012,7 +1043,8 @@ impl Nac3 {
|
|||||||
Isa::RiscV32IMA => &timeline::NOW_PINNING_TIME_FNS,
|
Isa::RiscV32IMA => &timeline::NOW_PINNING_TIME_FNS,
|
||||||
Isa::CortexA9 | Isa::Host => &timeline::EXTERN_TIME_FNS,
|
Isa::CortexA9 | Isa::Host => &timeline::EXTERN_TIME_FNS,
|
||||||
};
|
};
|
||||||
let (primitive, _) = TopLevelComposer::make_primitives(isa.get_size_type());
|
let (primitive, _) =
|
||||||
|
TopLevelComposer::make_primitives(isa.get_size_type(&Context::create()));
|
||||||
let builtins = vec![
|
let builtins = vec![
|
||||||
(
|
(
|
||||||
"now_mu".into(),
|
"now_mu".into(),
|
||||||
@ -1100,6 +1132,7 @@ impl Nac3 {
|
|||||||
tuple: get_attr_id(builtins_mod, "tuple"),
|
tuple: get_attr_id(builtins_mod, "tuple"),
|
||||||
exception: get_attr_id(builtins_mod, "Exception"),
|
exception: get_attr_id(builtins_mod, "Exception"),
|
||||||
option: get_id(artiq_builtins.get_item("Option").ok().flatten().unwrap()),
|
option: get_id(artiq_builtins.get_item("Option").ok().flatten().unwrap()),
|
||||||
|
module: get_attr_id(types_mod, "ModuleType"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
|
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
|
||||||
@ -1161,7 +1194,7 @@ impl Nac3 {
|
|||||||
deferred_eval_store: DeferredEvaluationStore::new(),
|
deferred_eval_store: DeferredEvaluationStore::new(),
|
||||||
llvm_options: CodeGenLLVMOptions {
|
llvm_options: CodeGenLLVMOptions {
|
||||||
opt_level: OptimizationLevel::Default,
|
opt_level: OptimizationLevel::Default,
|
||||||
target: Nac3::get_llvm_target_options(isa),
|
target: isa.get_llvm_target_options(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use pyo3::{
|
|||||||
use super::PrimitivePythonId;
|
use super::PrimitivePythonId;
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
types::{ndarray::NDArrayType, ProxyType},
|
types::{ndarray::NDArrayType, structure::StructProxyType, ProxyType},
|
||||||
values::ndarray::make_contiguous_strides,
|
values::ndarray::make_contiguous_strides,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
@ -674,6 +674,48 @@ impl InnerResolver {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// check if obj is module
|
||||||
|
if self.helper.id_fn.call1(py, (ty.clone(),))?.extract::<u64>(py)?
|
||||||
|
== self.primitive_ids.module
|
||||||
|
&& self.pyid_to_def.read().contains_key(&py_obj_id)
|
||||||
|
{
|
||||||
|
let def_id = self.pyid_to_def.read()[&py_obj_id];
|
||||||
|
let def = defs[def_id.0].read();
|
||||||
|
let TopLevelDef::Module { name: module_name, module_id, attributes, methods, .. } =
|
||||||
|
&*def
|
||||||
|
else {
|
||||||
|
unreachable!("must be a module here");
|
||||||
|
};
|
||||||
|
// Construct the module return type
|
||||||
|
let mut module_attributes = HashMap::new();
|
||||||
|
for (name, _) in attributes {
|
||||||
|
let attribute_obj = obj.getattr(name.to_string().as_str())?;
|
||||||
|
let attribute_ty =
|
||||||
|
self.get_obj_type(py, attribute_obj, unifier, defs, primitives)?;
|
||||||
|
if let Ok(attribute_ty) = attribute_ty {
|
||||||
|
module_attributes.insert(*name, (attribute_ty, false));
|
||||||
|
} else {
|
||||||
|
return Ok(Err(format!("Unable to resolve {module_name}.{name}")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for name in methods.keys() {
|
||||||
|
let method_obj = obj.getattr(name.to_string().as_str())?;
|
||||||
|
let method_ty = self.get_obj_type(py, method_obj, unifier, defs, primitives)?;
|
||||||
|
if let Ok(method_ty) = method_ty {
|
||||||
|
module_attributes.insert(*name, (method_ty, true));
|
||||||
|
} else {
|
||||||
|
return Ok(Err(format!("Unable to resolve {module_name}.{name}")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let module_ty =
|
||||||
|
TypeEnum::TModule { module_id: *module_id, attributes: module_attributes };
|
||||||
|
|
||||||
|
let ty = unifier.add_ty(module_ty);
|
||||||
|
return Ok(Ok(ty));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ty) = constructor_ty {
|
if let Some(ty) = constructor_ty {
|
||||||
self.pyid_to_type.write().insert(py_obj_id, ty);
|
self.pyid_to_type.write().insert(py_obj_id, ty);
|
||||||
return Ok(Ok(ty));
|
return Ok(Ok(ty));
|
||||||
@ -1007,7 +1049,7 @@ impl InnerResolver {
|
|||||||
}
|
}
|
||||||
_ => unreachable!("must be list"),
|
_ => unreachable!("must be list"),
|
||||||
};
|
};
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = ctx.get_size_type();
|
||||||
let ty = if len == 0
|
let ty = if len == 0
|
||||||
&& matches!(&*ctx.unifier.get_ty_immutable(elem_ty), TypeEnum::TVar { .. })
|
&& matches!(&*ctx.unifier.get_ty_immutable(elem_ty), TypeEnum::TVar { .. })
|
||||||
{
|
{
|
||||||
@ -1096,7 +1138,7 @@ impl InnerResolver {
|
|||||||
|
|
||||||
let llvm_i8 = ctx.ctx.i8_type();
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty);
|
let llvm_ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty);
|
||||||
let dtype = llvm_ndarray.element_type();
|
let dtype = llvm_ndarray.element_type();
|
||||||
|
|
||||||
@ -1104,7 +1146,7 @@ impl InnerResolver {
|
|||||||
if self.global_value_ids.read().contains_key(&id) {
|
if self.global_value_ids.read().contains_key(&id) {
|
||||||
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
|
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
|
||||||
ctx.module.add_global(
|
ctx.module.add_global(
|
||||||
llvm_ndarray.as_base_type().get_element_type().into_struct_type(),
|
llvm_ndarray.as_abi_type().get_element_type().into_struct_type(),
|
||||||
Some(AddressSpace::default()),
|
Some(AddressSpace::default()),
|
||||||
&id_str,
|
&id_str,
|
||||||
)
|
)
|
||||||
@ -1273,20 +1315,16 @@ impl InnerResolver {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let ndarray = llvm_ndarray
|
let ndarray = llvm_ndarray.get_struct_type().const_named_struct(&[
|
||||||
.as_base_type()
|
ndarray_itemsize.into(),
|
||||||
.get_element_type()
|
ndarray_ndims.into(),
|
||||||
.into_struct_type()
|
ndarray_shape.into(),
|
||||||
.const_named_struct(&[
|
ndarray_strides.into(),
|
||||||
ndarray_itemsize.into(),
|
ndarray_data.into(),
|
||||||
ndarray_ndims.into(),
|
]);
|
||||||
ndarray_shape.into(),
|
|
||||||
ndarray_strides.into(),
|
|
||||||
ndarray_data.into(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let ndarray_global = ctx.module.add_global(
|
let ndarray_global = ctx.module.add_global(
|
||||||
llvm_ndarray.as_base_type().get_element_type().into_struct_type(),
|
llvm_ndarray.as_abi_type().get_element_type().into_struct_type(),
|
||||||
Some(AddressSpace::default()),
|
Some(AddressSpace::default()),
|
||||||
&id_str,
|
&id_str,
|
||||||
);
|
);
|
||||||
@ -1373,6 +1411,77 @@ impl InnerResolver {
|
|||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if ty_id == self.primitive_ids.module {
|
||||||
|
let id_str = id.to_string();
|
||||||
|
|
||||||
|
if let Some(global) = ctx.module.get_global(&id_str) {
|
||||||
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let top_level_defs = ctx.top_level.definitions.read();
|
||||||
|
let ty = self
|
||||||
|
.get_obj_type(py, obj, &mut ctx.unifier, &top_level_defs, &ctx.primitives)?
|
||||||
|
.unwrap();
|
||||||
|
let ty = ctx
|
||||||
|
.get_llvm_type(generator, ty)
|
||||||
|
.into_pointer_type()
|
||||||
|
.get_element_type()
|
||||||
|
.into_struct_type();
|
||||||
|
|
||||||
|
{
|
||||||
|
if self.global_value_ids.read().contains_key(&id) {
|
||||||
|
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
|
||||||
|
ctx.module.add_global(ty, Some(AddressSpace::default()), &id_str)
|
||||||
|
});
|
||||||
|
return Ok(Some(global.as_pointer_value().into()));
|
||||||
|
}
|
||||||
|
self.global_value_ids.write().insert(id, obj.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let fields = {
|
||||||
|
let definition =
|
||||||
|
top_level_defs.get(self.pyid_to_def.read().get(&id).unwrap().0).unwrap().read();
|
||||||
|
let TopLevelDef::Module { attributes, .. } = &*definition else { unreachable!() };
|
||||||
|
attributes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|f| {
|
||||||
|
let definition = top_level_defs.get(f.1 .0).unwrap().read();
|
||||||
|
if let TopLevelDef::Variable { ty, .. } = &*definition {
|
||||||
|
Some((f.0, *ty))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
let values: Result<Option<Vec<_>>, _> = fields
|
||||||
|
.iter()
|
||||||
|
.map(|(name, ty)| {
|
||||||
|
self.get_obj_value(
|
||||||
|
py,
|
||||||
|
obj.getattr(name.to_string().as_str())?,
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
*ty,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
super::CompileError::new_err(format!("Error getting field {name}: {e}"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let values = values?;
|
||||||
|
|
||||||
|
if let Some(values) = values {
|
||||||
|
let val = ty.const_named_struct(&values);
|
||||||
|
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
|
||||||
|
ctx.module.add_global(ty, Some(AddressSpace::default()), &id_str)
|
||||||
|
});
|
||||||
|
global.set_initializer(&val);
|
||||||
|
Ok(Some(global.as_pointer_value().into()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let id_str = id.to_string();
|
let id_str = id.to_string();
|
||||||
|
|
||||||
@ -1558,35 +1667,45 @@ impl SymbolResolver for Resolver {
|
|||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
) -> Option<ValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
if let Some(global_value) = self
|
if let Some(def_id) = self.0.id_to_def.read().get(&id) {
|
||||||
.0
|
let top_levels = ctx.top_level.definitions.read();
|
||||||
.name_to_pyid
|
if matches!(&*top_levels[def_id.0].read(), TopLevelDef::Variable { .. }) {
|
||||||
.get(&id)
|
let module_val = &self.0.module;
|
||||||
.and_then(|pyid| self.0.global_value_ids.read().get(pyid).cloned())
|
let ret = Python::with_gil(|py| -> PyResult<Result<BasicValueEnum, String>> {
|
||||||
{
|
let module_val = module_val.as_ref(py);
|
||||||
let val = ctx.module.get_global(id.to_string().as_str()).unwrap_or_else(|| {
|
|
||||||
let v = Python::with_gil(|py| -> PyResult<SymbolValue> {
|
let ty = self.0.get_obj_type(
|
||||||
Ok(self
|
py,
|
||||||
.0
|
module_val,
|
||||||
.get_default_param_obj_value(py, global_value.as_ref(py))
|
&mut ctx.unifier,
|
||||||
.unwrap()
|
&top_levels,
|
||||||
.unwrap())
|
&ctx.primitives,
|
||||||
|
)?;
|
||||||
|
if let Err(ty) = ty {
|
||||||
|
return Ok(Err(ty));
|
||||||
|
}
|
||||||
|
let ty = ty.unwrap();
|
||||||
|
let obj = self.0.get_obj_value(py, module_val, ctx, generator, ty)?.unwrap();
|
||||||
|
let (idx, _) = ctx.get_attr_index(ty, id);
|
||||||
|
let ret = unsafe {
|
||||||
|
ctx.builder.build_gep(
|
||||||
|
obj.into_pointer_value(),
|
||||||
|
&[
|
||||||
|
ctx.ctx.i32_type().const_zero(),
|
||||||
|
ctx.ctx.i32_type().const_int(idx as u64, false),
|
||||||
|
],
|
||||||
|
id.to_string().as_str(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
Ok(Ok(ret.as_basic_value_enum()))
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
if ret.is_err() {
|
||||||
let ty = v.get_type(&ctx.primitives, &mut ctx.unifier);
|
return None;
|
||||||
|
}
|
||||||
let init_val = ctx.gen_symbol_val(generator, &v, ty);
|
return Some(ret.unwrap().into());
|
||||||
let llvm_ty = init_val.get_type();
|
}
|
||||||
|
|
||||||
println!("Adding {id}");
|
|
||||||
let global = ctx.module.add_global(llvm_ty, None, &id.to_string());
|
|
||||||
global.set_linkage(Linkage::LinkOnceAny);
|
|
||||||
global.set_initializer(&init_val);
|
|
||||||
|
|
||||||
global
|
|
||||||
});
|
|
||||||
return Some(val.as_basic_value_enum().into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sym_value = {
|
let sym_value = {
|
||||||
|
@ -11,5 +11,5 @@ fold = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
string-interner = "0.17"
|
string-interner = "0.18"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
|
@ -10,11 +10,10 @@ derive = ["dep:nac3core_derive"]
|
|||||||
no-escape-analysis = []
|
no-escape-analysis = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.13"
|
itertools = "0.14"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
indexmap = "2.6"
|
indexmap = "2.7"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
rayon = "1.10"
|
|
||||||
nac3core_derive = { path = "nac3core_derive", optional = true }
|
nac3core_derive = { path = "nac3core_derive", optional = true }
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
strum = "0.26"
|
strum = "0.26"
|
||||||
@ -31,4 +30,4 @@ indoc = "2.0"
|
|||||||
insta = "=1.11.0"
|
insta = "=1.11.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = "1.10"
|
regex = "1.11"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::BasicTypeEnum,
|
types::BasicTypeEnum,
|
||||||
values::{BasicValue, BasicValueEnum, IntValue},
|
values::{BasicValueEnum, IntValue},
|
||||||
FloatPredicate, IntPredicate, OptimizationLevel,
|
FloatPredicate, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -11,10 +11,10 @@ use super::{
|
|||||||
irrt::calculate_len_for_slice_range,
|
irrt::calculate_len_for_slice_range,
|
||||||
llvm_intrinsics,
|
llvm_intrinsics,
|
||||||
macros::codegen_unreachable,
|
macros::codegen_unreachable,
|
||||||
types::{ndarray::NDArrayType, ListType, TupleType},
|
types::{ndarray::NDArrayType, ListType, RangeType, TupleType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayOut, NDArrayValue, ScalarOrNDArray},
|
ndarray::{NDArrayOut, NDArrayValue, ScalarOrNDArray},
|
||||||
ProxyValue, RangeValue, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
ProxyValue, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -47,14 +47,14 @@ pub fn call_len<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let range_ty = ctx.primitives.range;
|
let range_ty = ctx.primitives.range;
|
||||||
|
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
||||||
let arg = RangeValue::from_pointer_value(arg.into_pointer_value(), Some("range"));
|
let arg = RangeType::new(ctx).map_pointer_value(arg.into_pointer_value(), Some("range"));
|
||||||
let (start, end, step) = destructure_range(ctx, arg);
|
let (start, end, step) = destructure_range(ctx, arg);
|
||||||
calculate_len_for_slice_range(generator, ctx, start, end, step)
|
calculate_len_for_slice_range(generator, ctx, start, end, step)
|
||||||
} else {
|
} else {
|
||||||
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
match &*ctx.unifier.get_ty_immutable(arg_ty) {
|
||||||
TypeEnum::TTuple { .. } => {
|
TypeEnum::TTuple { .. } => {
|
||||||
let tuple = TupleType::from_unifier_type(generator, ctx, arg_ty)
|
let tuple = TupleType::from_unifier_type(generator, ctx, arg_ty)
|
||||||
.map_value(arg.into_struct_value(), None);
|
.map_struct_value(arg.into_struct_value(), None);
|
||||||
llvm_i32.const_int(tuple.get_type().num_elements().into(), false)
|
llvm_i32.const_int(tuple.get_type().num_elements().into(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,9 +62,9 @@ pub fn call_len<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, arg_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, arg_ty)
|
||||||
.map_value(arg.into_pointer_value(), None);
|
.map_pointer_value(arg.into_pointer_value(), None);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_truncate_or_bit_cast(ndarray.len(generator, ctx), llvm_i32, "len")
|
.build_int_truncate_or_bit_cast(ndarray.len(ctx), llvm_i32, "len")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ pub fn call_len<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let list = ListType::from_unifier_type(generator, ctx, arg_ty)
|
let list = ListType::from_unifier_type(generator, ctx, arg_ty)
|
||||||
.map_value(arg.into_pointer_value(), None);
|
.map_pointer_value(arg.into_pointer_value(), None);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_truncate_or_bit_cast(list.load_size(ctx, None), llvm_i32, "len")
|
.build_int_truncate_or_bit_cast(list.load_size(ctx, None), llvm_i32, "len")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -126,7 +126,8 @@ pub fn call_int32<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -137,7 +138,7 @@ pub fn call_int32<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, "int32", &[n_ty]),
|
_ => unsupported_type(ctx, "int32", &[n_ty]),
|
||||||
@ -186,7 +187,8 @@ pub fn call_int64<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -197,7 +199,7 @@ pub fn call_int64<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, "int64", &[n_ty]),
|
_ => unsupported_type(ctx, "int64", &[n_ty]),
|
||||||
@ -262,7 +264,8 @@ pub fn call_uint32<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -273,7 +276,7 @@ pub fn call_uint32<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, "uint32", &[n_ty]),
|
_ => unsupported_type(ctx, "uint32", &[n_ty]),
|
||||||
@ -327,7 +330,8 @@ pub fn call_uint64<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -338,7 +342,7 @@ pub fn call_uint64<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, "uint64", &[n_ty]),
|
_ => unsupported_type(ctx, "uint64", &[n_ty]),
|
||||||
@ -391,7 +395,8 @@ pub fn call_float<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -402,7 +407,7 @@ pub fn call_float<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, "float", &[n_ty]),
|
_ => unsupported_type(ctx, "float", &[n_ty]),
|
||||||
@ -435,7 +440,8 @@ pub fn call_round<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -448,7 +454,7 @@ pub fn call_round<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
||||||
@ -474,7 +480,8 @@ pub fn call_numpy_round<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -485,7 +492,7 @@ pub fn call_numpy_round<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
||||||
@ -536,7 +543,8 @@ pub fn call_bool<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -550,7 +558,7 @@ pub fn call_bool<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
||||||
@ -587,7 +595,8 @@ pub fn call_floor<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -600,7 +609,7 @@ pub fn call_floor<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
||||||
@ -637,7 +646,8 @@ pub fn call_ceil<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
if n_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
|
||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, n_ty);
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, n_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, n_ty).map_pointer_value(n, None);
|
||||||
|
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.map(
|
.map(
|
||||||
@ -650,7 +660,7 @@ pub fn call_ceil<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[n_ty]),
|
||||||
@ -752,26 +762,22 @@ pub fn call_numpy_minimum<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
debug_assert!(ctx.unifier.unioned(x1_dtype, x2_dtype));
|
debug_assert!(ctx.unifier.unioned(x1_dtype, x2_dtype));
|
||||||
let llvm_common_dtype = x1.get_type().element_type();
|
let llvm_common_dtype = x1.get_type().element_type();
|
||||||
|
|
||||||
let result = NDArrayType::new_broadcast(
|
let result =
|
||||||
generator,
|
NDArrayType::new_broadcast(ctx, llvm_common_dtype, &[x1.get_type(), x2.get_type()])
|
||||||
ctx.ctx,
|
.broadcast_starmap(
|
||||||
llvm_common_dtype,
|
generator,
|
||||||
&[x1.get_type(), x2.get_type()],
|
ctx,
|
||||||
)
|
&[x1, x2],
|
||||||
.broadcast_starmap(
|
NDArrayOut::NewNDArray { dtype: llvm_common_dtype },
|
||||||
generator,
|
|_, ctx, scalars| {
|
||||||
ctx,
|
let x1_scalar = scalars[0];
|
||||||
&[x1, x2],
|
let x2_scalar = scalars[1];
|
||||||
NDArrayOut::NewNDArray { dtype: llvm_common_dtype },
|
Ok(call_min(ctx, (x1_dtype, x1_scalar), (x2_dtype, x2_scalar)))
|
||||||
|_, ctx, scalars| {
|
},
|
||||||
let x1_scalar = scalars[0];
|
)
|
||||||
let x2_scalar = scalars[1];
|
.unwrap();
|
||||||
Ok(call_min(ctx, (x1_dtype, x1_scalar), (x2_dtype, x2_scalar)))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
|
||||||
@ -835,7 +841,7 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
debug_assert!(["np_argmin", "np_argmax", "np_max", "np_min"].iter().any(|f| *f == fn_name));
|
debug_assert!(["np_argmin", "np_argmax", "np_max", "np_min"].iter().any(|f| *f == fn_name));
|
||||||
|
|
||||||
let llvm_int64 = ctx.ctx.i64_type();
|
let llvm_int64 = ctx.ctx.i64_type();
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
Ok(match a {
|
Ok(match a {
|
||||||
BasicValueEnum::IntValue(_) | BasicValueEnum::FloatValue(_) => {
|
BasicValueEnum::IntValue(_) | BasicValueEnum::FloatValue(_) => {
|
||||||
@ -862,7 +868,8 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
{
|
{
|
||||||
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
|
||||||
|
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, a_ty).map_value(n, None);
|
let ndarray =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, a_ty).map_pointer_value(n, None);
|
||||||
let llvm_dtype = ndarray.get_type().element_type();
|
let llvm_dtype = ndarray.get_type().element_type();
|
||||||
|
|
||||||
let zero = llvm_usize.const_zero();
|
let zero = llvm_usize.const_zero();
|
||||||
@ -870,7 +877,7 @@ pub fn call_numpy_max_min<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
|
||||||
let size_nez = ctx
|
let size_nez = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_compare(IntPredicate::NE, ndarray.size(generator, ctx), zero, "")
|
.build_int_compare(IntPredicate::NE, ndarray.size(ctx), zero, "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
ctx.make_assert(
|
ctx.make_assert(
|
||||||
@ -1015,26 +1022,22 @@ pub fn call_numpy_maximum<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
debug_assert!(ctx.unifier.unioned(x1_dtype, x2_dtype));
|
debug_assert!(ctx.unifier.unioned(x1_dtype, x2_dtype));
|
||||||
let llvm_common_dtype = x1.get_type().element_type();
|
let llvm_common_dtype = x1.get_type().element_type();
|
||||||
|
|
||||||
let result = NDArrayType::new_broadcast(
|
let result =
|
||||||
generator,
|
NDArrayType::new_broadcast(ctx, llvm_common_dtype, &[x1.get_type(), x2.get_type()])
|
||||||
ctx.ctx,
|
.broadcast_starmap(
|
||||||
llvm_common_dtype,
|
generator,
|
||||||
&[x1.get_type(), x2.get_type()],
|
ctx,
|
||||||
)
|
&[x1, x2],
|
||||||
.broadcast_starmap(
|
NDArrayOut::NewNDArray { dtype: llvm_common_dtype },
|
||||||
generator,
|
|_, ctx, scalars| {
|
||||||
ctx,
|
let x1_scalar = scalars[0];
|
||||||
&[x1, x2],
|
let x2_scalar = scalars[1];
|
||||||
NDArrayOut::NewNDArray { dtype: llvm_common_dtype },
|
Ok(call_max(ctx, (x1_dtype, x1_scalar), (x2_dtype, x2_scalar)))
|
||||||
|_, ctx, scalars| {
|
},
|
||||||
let x1_scalar = scalars[0];
|
)
|
||||||
let x2_scalar = scalars[1];
|
.unwrap();
|
||||||
Ok(call_max(ctx, (x1_dtype, x1_scalar), (x2_dtype, x2_scalar)))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
result.as_base_value().into()
|
result.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
|
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
|
||||||
@ -1646,13 +1649,13 @@ pub fn call_np_linalg_cholesky<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2)
|
let out = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
out.copy_shape_from_ndarray(generator, ctx, x1);
|
out.copy_shape_from_ndarray(generator, ctx, x1);
|
||||||
unsafe { out.create_data(generator, ctx) };
|
unsafe { out.create_data(generator, ctx) };
|
||||||
@ -1661,11 +1664,11 @@ pub fn call_np_linalg_cholesky<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_np_linalg_cholesky(
|
extern_fns::call_np_linalg_cholesky(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
out_c.as_base_value().into(),
|
out_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
Ok(out.as_base_value().into())
|
Ok(out.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_qr` linalg function
|
/// Invokes the `np_linalg_qr` linalg function
|
||||||
@ -1676,11 +1679,11 @@ pub fn call_np_linalg_qr<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "np_linalg_qr";
|
const FN_NAME: &str = "np_linalg_qr";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
@ -1694,7 +1697,7 @@ pub fn call_np_linalg_qr<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
};
|
};
|
||||||
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
||||||
|
|
||||||
let out_ndarray_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2);
|
let out_ndarray_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2);
|
||||||
let q = out_ndarray_ty.construct_dyn_shape(generator, ctx, &[d0, dk], None);
|
let q = out_ndarray_ty.construct_dyn_shape(generator, ctx, &[d0, dk], None);
|
||||||
unsafe { q.create_data(generator, ctx) };
|
unsafe { q.create_data(generator, ctx) };
|
||||||
|
|
||||||
@ -1707,17 +1710,20 @@ pub fn call_np_linalg_qr<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
extern_fns::call_np_linalg_qr(
|
extern_fns::call_np_linalg_qr(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
q_c.as_base_value().into(),
|
q_c.as_abi_value(ctx).into(),
|
||||||
r_c.as_base_value().into(),
|
r_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let q = q.as_base_value().as_basic_value_enum();
|
let q = q.as_abi_value(ctx);
|
||||||
let r = r.as_base_value().as_basic_value_enum();
|
let r = r.as_abi_value(ctx);
|
||||||
let tuple = TupleType::new(generator, ctx.ctx, &[q.get_type(), r.get_type()])
|
let tuple = TupleType::new(ctx, &[q.get_type(), r.get_type()]).construct_from_objects(
|
||||||
.construct_from_objects(ctx, [q, r], None);
|
ctx,
|
||||||
Ok(tuple.as_base_value().into())
|
[q.into(), r.into()],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
Ok(tuple.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_svd` linalg function
|
/// Invokes the `np_linalg_svd` linalg function
|
||||||
@ -1728,11 +1734,11 @@ pub fn call_np_linalg_svd<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "np_linalg_svd";
|
const FN_NAME: &str = "np_linalg_svd";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
@ -1746,8 +1752,8 @@ pub fn call_np_linalg_svd<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
};
|
};
|
||||||
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
||||||
|
|
||||||
let out_ndarray1_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 1);
|
let out_ndarray1_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 1);
|
||||||
let out_ndarray2_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2);
|
let out_ndarray2_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2);
|
||||||
|
|
||||||
let u = out_ndarray2_ty.construct_dyn_shape(generator, ctx, &[d0, d0], None);
|
let u = out_ndarray2_ty.construct_dyn_shape(generator, ctx, &[d0, d0], None);
|
||||||
unsafe { u.create_data(generator, ctx) };
|
unsafe { u.create_data(generator, ctx) };
|
||||||
@ -1765,19 +1771,19 @@ pub fn call_np_linalg_svd<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
extern_fns::call_np_linalg_svd(
|
extern_fns::call_np_linalg_svd(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
u_c.as_base_value().into(),
|
u_c.as_abi_value(ctx).into(),
|
||||||
s_c.as_base_value().into(),
|
s_c.as_abi_value(ctx).into(),
|
||||||
vh_c.as_base_value().into(),
|
vh_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let u = u.as_base_value().as_basic_value_enum();
|
let u = u.as_abi_value(ctx);
|
||||||
let s = s.as_base_value().as_basic_value_enum();
|
let s = s.as_abi_value(ctx);
|
||||||
let vh = vh.as_base_value().as_basic_value_enum();
|
let vh = vh.as_abi_value(ctx);
|
||||||
let tuple = TupleType::new(generator, ctx.ctx, &[u.get_type(), s.get_type(), vh.get_type()])
|
let tuple = TupleType::new(ctx, &[u.get_type(), s.get_type(), vh.get_type()])
|
||||||
.construct_from_objects(ctx, [u, s, vh], None);
|
.construct_from_objects(ctx, [u.into(), s.into(), vh.into()], None);
|
||||||
Ok(tuple.as_base_value().into())
|
Ok(tuple.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_inv` linalg function
|
/// Invokes the `np_linalg_inv` linalg function
|
||||||
@ -1790,13 +1796,13 @@ pub fn call_np_linalg_inv<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2)
|
let out = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
out.copy_shape_from_ndarray(generator, ctx, x1);
|
out.copy_shape_from_ndarray(generator, ctx, x1);
|
||||||
unsafe { out.create_data(generator, ctx) };
|
unsafe { out.create_data(generator, ctx) };
|
||||||
@ -1805,12 +1811,12 @@ pub fn call_np_linalg_inv<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_np_linalg_inv(
|
extern_fns::call_np_linalg_inv(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
out_c.as_base_value().into(),
|
out_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(out.as_base_value().into())
|
Ok(out.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_pinv` linalg function
|
/// Invokes the `np_linalg_pinv` linalg function
|
||||||
@ -1821,11 +1827,11 @@ pub fn call_np_linalg_pinv<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "np_linalg_pinv";
|
const FN_NAME: &str = "np_linalg_pinv";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
@ -1838,20 +1844,24 @@ pub fn call_np_linalg_pinv<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
x1_shape.get_typed_unchecked(ctx, generator, &llvm_usize.const_int(1, false), None)
|
x1_shape.get_typed_unchecked(ctx, generator, &llvm_usize.const_int(1, false), None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let out = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2)
|
let out = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2).construct_dyn_shape(
|
||||||
.construct_dyn_shape(generator, ctx, &[d0, d1], None);
|
generator,
|
||||||
|
ctx,
|
||||||
|
&[d0, d1],
|
||||||
|
None,
|
||||||
|
);
|
||||||
unsafe { out.create_data(generator, ctx) };
|
unsafe { out.create_data(generator, ctx) };
|
||||||
|
|
||||||
let x1_c = x1.make_contiguous_ndarray(generator, ctx);
|
let x1_c = x1.make_contiguous_ndarray(generator, ctx);
|
||||||
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
let out_c = out.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_np_linalg_pinv(
|
extern_fns::call_np_linalg_pinv(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
out_c.as_base_value().into(),
|
out_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(out.as_base_value().into())
|
Ok(out.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `sp_linalg_lu` linalg function
|
/// Invokes the `sp_linalg_lu` linalg function
|
||||||
@ -1862,11 +1872,11 @@ pub fn call_sp_linalg_lu<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "sp_linalg_lu";
|
const FN_NAME: &str = "sp_linalg_lu";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
@ -1880,7 +1890,7 @@ pub fn call_sp_linalg_lu<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
};
|
};
|
||||||
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
let dk = llvm_intrinsics::call_int_smin(ctx, d0, d1, None);
|
||||||
|
|
||||||
let out_ndarray_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2);
|
let out_ndarray_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2);
|
||||||
|
|
||||||
let l = out_ndarray_ty.construct_dyn_shape(generator, ctx, &[d0, dk], None);
|
let l = out_ndarray_ty.construct_dyn_shape(generator, ctx, &[d0, dk], None);
|
||||||
unsafe { l.create_data(generator, ctx) };
|
unsafe { l.create_data(generator, ctx) };
|
||||||
@ -1893,17 +1903,20 @@ pub fn call_sp_linalg_lu<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let u_c = u.make_contiguous_ndarray(generator, ctx);
|
let u_c = u.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_sp_linalg_lu(
|
extern_fns::call_sp_linalg_lu(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
l_c.as_base_value().into(),
|
l_c.as_abi_value(ctx).into(),
|
||||||
u_c.as_base_value().into(),
|
u_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let l = l.as_base_value().as_basic_value_enum();
|
let l = l.as_abi_value(ctx);
|
||||||
let u = u.as_base_value().as_basic_value_enum();
|
let u = u.as_abi_value(ctx);
|
||||||
let tuple = TupleType::new(generator, ctx.ctx, &[l.get_type(), u.get_type()])
|
let tuple = TupleType::new(ctx, &[l.get_type(), u.get_type()]).construct_from_objects(
|
||||||
.construct_from_objects(ctx, [l, u], None);
|
ctx,
|
||||||
Ok(tuple.as_base_value().into())
|
[l.into(), u.into()],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
Ok(tuple.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_matrix_power` linalg function
|
/// Invokes the `np_linalg_matrix_power` linalg function
|
||||||
@ -1915,7 +1928,7 @@ pub fn call_np_linalg_matrix_power<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "np_linalg_matrix_power";
|
const FN_NAME: &str = "np_linalg_matrix_power";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else {
|
let BasicValueEnum::PointerValue(x1) = x1 else {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
||||||
@ -1936,11 +1949,11 @@ pub fn call_np_linalg_matrix_power<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
||||||
};
|
};
|
||||||
|
|
||||||
let x2 = NDArrayType::new_unsized(generator, ctx.ctx, ctx.ctx.f64_type().into())
|
let x2 = NDArrayType::new_unsized(ctx, ctx.ctx.f64_type().into())
|
||||||
.construct_unsized(generator, ctx, &x2, None); // x2.shape == []
|
.construct_unsized(generator, ctx, &x2, None); // x2.shape == []
|
||||||
let x2 = x2.atleast_nd(generator, ctx, 1); // x2.shape == [1]
|
let x2 = x2.atleast_nd(generator, ctx, 1); // x2.shape == [1]
|
||||||
|
|
||||||
let out = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2)
|
let out = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
out.copy_shape_from_ndarray(generator, ctx, x1);
|
out.copy_shape_from_ndarray(generator, ctx, x1);
|
||||||
unsafe { out.create_data(generator, ctx) };
|
unsafe { out.create_data(generator, ctx) };
|
||||||
@ -1951,13 +1964,13 @@ pub fn call_np_linalg_matrix_power<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
extern_fns::call_np_linalg_matrix_power(
|
extern_fns::call_np_linalg_matrix_power(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
x2_c.as_base_value().into(),
|
x2_c.as_abi_value(ctx).into(),
|
||||||
out_c.as_base_value().into(),
|
out_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(out.as_base_value().into())
|
Ok(out.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_linalg_det` linalg function
|
/// Invokes the `np_linalg_det` linalg function
|
||||||
@ -1968,27 +1981,31 @@ pub fn call_np_linalg_det<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
const FN_NAME: &str = "np_linalg_matrix_power";
|
const FN_NAME: &str = "np_linalg_matrix_power";
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The output is a float64, but we are using an ndarray (shape == [1]) for uniformity in function call.
|
// The output is a float64, but we are using an ndarray (shape == [1]) for uniformity in function call.
|
||||||
let det = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 1)
|
let det = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 1).construct_const_shape(
|
||||||
.construct_const_shape(generator, ctx, &[1], None);
|
generator,
|
||||||
|
ctx,
|
||||||
|
&[1],
|
||||||
|
None,
|
||||||
|
);
|
||||||
unsafe { det.create_data(generator, ctx) };
|
unsafe { det.create_data(generator, ctx) };
|
||||||
|
|
||||||
let x1_c = x1.make_contiguous_ndarray(generator, ctx);
|
let x1_c = x1.make_contiguous_ndarray(generator, ctx);
|
||||||
let out_c = det.make_contiguous_ndarray(generator, ctx);
|
let out_c = det.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_np_linalg_det(
|
extern_fns::call_np_linalg_det(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
out_c.as_base_value().into(),
|
out_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2007,14 +2024,14 @@ pub fn call_sp_linalg_schur<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
assert_eq!(x1.get_type().ndims(), 2);
|
assert_eq!(x1.get_type().ndims(), 2);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_ndarray_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2);
|
let out_ndarray_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2);
|
||||||
|
|
||||||
let t = out_ndarray_ty.construct_uninitialized(generator, ctx, None);
|
let t = out_ndarray_ty.construct_uninitialized(generator, ctx, None);
|
||||||
t.copy_shape_from_ndarray(generator, ctx, x1);
|
t.copy_shape_from_ndarray(generator, ctx, x1);
|
||||||
@ -2029,17 +2046,20 @@ pub fn call_sp_linalg_schur<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let z_c = z.make_contiguous_ndarray(generator, ctx);
|
let z_c = z.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_sp_linalg_schur(
|
extern_fns::call_sp_linalg_schur(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
t_c.as_base_value().into(),
|
t_c.as_abi_value(ctx).into(),
|
||||||
z_c.as_base_value().into(),
|
z_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let t = t.as_base_value().as_basic_value_enum();
|
let t = t.as_abi_value(ctx);
|
||||||
let z = z.as_base_value().as_basic_value_enum();
|
let z = z.as_abi_value(ctx);
|
||||||
let tuple = TupleType::new(generator, ctx.ctx, &[t.get_type(), z.get_type()])
|
let tuple = TupleType::new(ctx, &[t.get_type(), z.get_type()]).construct_from_objects(
|
||||||
.construct_from_objects(ctx, [t, z], None);
|
ctx,
|
||||||
Ok(tuple.as_base_value().into())
|
[t.into(), z.into()],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
Ok(tuple.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `sp_linalg_hessenberg` linalg function
|
/// Invokes the `sp_linalg_hessenberg` linalg function
|
||||||
@ -2052,14 +2072,14 @@ pub fn call_sp_linalg_hessenberg<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
let BasicValueEnum::PointerValue(x1) = x1 else { unsupported_type(ctx, FN_NAME, &[x1_ty]) };
|
||||||
|
|
||||||
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(x1, None);
|
let x1 = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(x1, None);
|
||||||
assert_eq!(x1.get_type().ndims(), 2);
|
assert_eq!(x1.get_type().ndims(), 2);
|
||||||
|
|
||||||
if !x1.get_type().element_type().is_float_type() {
|
if !x1.get_type().element_type().is_float_type() {
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_ndarray_ty = NDArrayType::new(generator, ctx.ctx, ctx.ctx.f64_type().into(), 2);
|
let out_ndarray_ty = NDArrayType::new(ctx, ctx.ctx.f64_type().into(), 2);
|
||||||
|
|
||||||
let h = out_ndarray_ty.construct_uninitialized(generator, ctx, None);
|
let h = out_ndarray_ty.construct_uninitialized(generator, ctx, None);
|
||||||
h.copy_shape_from_ndarray(generator, ctx, x1);
|
h.copy_shape_from_ndarray(generator, ctx, x1);
|
||||||
@ -2074,15 +2094,18 @@ pub fn call_sp_linalg_hessenberg<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let q_c = q.make_contiguous_ndarray(generator, ctx);
|
let q_c = q.make_contiguous_ndarray(generator, ctx);
|
||||||
extern_fns::call_sp_linalg_hessenberg(
|
extern_fns::call_sp_linalg_hessenberg(
|
||||||
ctx,
|
ctx,
|
||||||
x1_c.as_base_value().into(),
|
x1_c.as_abi_value(ctx).into(),
|
||||||
h_c.as_base_value().into(),
|
h_c.as_abi_value(ctx).into(),
|
||||||
q_c.as_base_value().into(),
|
q_c.as_abi_value(ctx).into(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let h = h.as_base_value().as_basic_value_enum();
|
let h = h.as_abi_value(ctx);
|
||||||
let q = q.as_base_value().as_basic_value_enum();
|
let q = q.as_abi_value(ctx);
|
||||||
let tuple = TupleType::new(generator, ctx.ctx, &[h.get_type(), q.get_type()])
|
let tuple = TupleType::new(ctx, &[h.get_type(), q.get_type()]).construct_from_objects(
|
||||||
.construct_from_objects(ctx, [h, q], None);
|
ctx,
|
||||||
Ok(tuple.as_base_value().into())
|
[h.into(), q.into()],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
Ok(tuple.as_abi_value(ctx).into())
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,10 @@ pub enum ConcreteTypeEnum {
|
|||||||
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
||||||
params: IndexMap<TypeVarId, ConcreteType>,
|
params: IndexMap<TypeVarId, ConcreteType>,
|
||||||
},
|
},
|
||||||
|
TModule {
|
||||||
|
module_id: DefinitionId,
|
||||||
|
methods: HashMap<StrRef, (ConcreteType, bool)>,
|
||||||
|
},
|
||||||
TVirtual {
|
TVirtual {
|
||||||
ty: ConcreteType,
|
ty: ConcreteType,
|
||||||
},
|
},
|
||||||
@ -205,6 +209,19 @@ impl ConcreteTypeStore {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
|
TypeEnum::TModule { module_id, attributes } => ConcreteTypeEnum::TModule {
|
||||||
|
module_id: *module_id,
|
||||||
|
methods: attributes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(name, ty)| match &*unifier.get_ty(ty.0) {
|
||||||
|
TypeEnum::TFunc(..) | TypeEnum::TObj { .. } => None,
|
||||||
|
_ => Some((
|
||||||
|
*name,
|
||||||
|
(self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
||||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
||||||
},
|
},
|
||||||
@ -284,6 +301,15 @@ impl ConcreteTypeStore {
|
|||||||
TypeVar { id, ty }
|
TypeVar { id, ty }
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
ConcreteTypeEnum::TModule { module_id, methods } => TypeEnum::TModule {
|
||||||
|
module_id: *module_id,
|
||||||
|
attributes: methods
|
||||||
|
.iter()
|
||||||
|
.map(|(name, cty)| {
|
||||||
|
(*name, (self.to_unifier_type(unifier, primitives, cty.0, cache), cty.1))
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
},
|
||||||
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(FunSignature {
|
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(FunSignature {
|
||||||
args: args
|
args: args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -32,7 +32,7 @@ use super::{
|
|||||||
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
|
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
|
||||||
gen_var,
|
gen_var,
|
||||||
},
|
},
|
||||||
types::{ndarray::NDArrayType, ListType},
|
types::{ndarray::NDArrayType, ListType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
||||||
@ -61,8 +61,13 @@ pub fn get_subst_key(
|
|||||||
) -> String {
|
) -> String {
|
||||||
let mut vars = obj
|
let mut vars = obj
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) else { unreachable!() };
|
if let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) {
|
||||||
params.clone()
|
params.clone()
|
||||||
|
} else if let TypeEnum::TModule { .. } = &*unifier.get_ty(ty) {
|
||||||
|
indexmap::IndexMap::new()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
vars.extend(fun_vars);
|
vars.extend(fun_vars);
|
||||||
@ -120,6 +125,7 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
|||||||
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> (usize, Option<Constant>) {
|
pub fn get_attr_index(&mut self, ty: Type, attr: StrRef) -> (usize, Option<Constant>) {
|
||||||
let obj_id = match &*self.unifier.get_ty(ty) {
|
let obj_id = match &*self.unifier.get_ty(ty) {
|
||||||
TypeEnum::TObj { obj_id, .. } => *obj_id,
|
TypeEnum::TObj { obj_id, .. } => *obj_id,
|
||||||
|
TypeEnum::TModule { module_id, .. } => *module_id,
|
||||||
// we cannot have other types, virtual type should be handled by function calls
|
// we cannot have other types, virtual type should be handled by function calls
|
||||||
_ => codegen_unreachable!(self),
|
_ => codegen_unreachable!(self),
|
||||||
};
|
};
|
||||||
@ -131,6 +137,8 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
|||||||
let attribute_index = attributes.iter().find_position(|x| x.0 == attr).unwrap();
|
let attribute_index = attributes.iter().find_position(|x| x.0 == attr).unwrap();
|
||||||
(attribute_index.0, Some(attribute_index.1 .2.clone()))
|
(attribute_index.0, Some(attribute_index.1 .2.clone()))
|
||||||
}
|
}
|
||||||
|
} else if let TopLevelDef::Module { attributes, .. } = &*def.read() {
|
||||||
|
(attributes.iter().find_position(|x| x.0 == attr).unwrap().0, None)
|
||||||
} else {
|
} else {
|
||||||
codegen_unreachable!(self)
|
codegen_unreachable!(self)
|
||||||
};
|
};
|
||||||
@ -165,7 +173,7 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
|||||||
.build_global_string_ptr(v, "const")
|
.build_global_string_ptr(v, "const")
|
||||||
.map(|v| v.as_pointer_value().into())
|
.map(|v| v.as_pointer_value().into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let size = generator.get_size_type(self.ctx).const_int(v.len() as u64, false);
|
let size = self.get_size_type().const_int(v.len() as u64, false);
|
||||||
let ty = self.get_llvm_type(generator, self.primitives.str).into_struct_type();
|
let ty = self.get_llvm_type(generator, self.primitives.str).into_struct_type();
|
||||||
ty.const_named_struct(&[str_ptr, size.into()]).into()
|
ty.const_named_struct(&[str_ptr, size.into()]).into()
|
||||||
}
|
}
|
||||||
@ -318,7 +326,7 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
|||||||
.build_global_string_ptr(v, "const")
|
.build_global_string_ptr(v, "const")
|
||||||
.map(|v| v.as_pointer_value().into())
|
.map(|v| v.as_pointer_value().into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let size = generator.get_size_type(self.ctx).const_int(v.len() as u64, false);
|
let size = self.get_size_type().const_int(v.len() as u64, false);
|
||||||
let ty = self.get_llvm_type(generator, self.primitives.str);
|
let ty = self.get_llvm_type(generator, self.primitives.str);
|
||||||
let val =
|
let val =
|
||||||
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
||||||
@ -820,7 +828,7 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
|||||||
fun: (&FunSignature, DefinitionId),
|
fun: (&FunSignature, DefinitionId),
|
||||||
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let definition = ctx.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
let definition = ctx.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
||||||
let id;
|
let id;
|
||||||
@ -979,7 +987,7 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
|||||||
TopLevelDef::Class { .. } => {
|
TopLevelDef::Class { .. } => {
|
||||||
return Ok(Some(generator.gen_constructor(ctx, fun.0, &def, params)?))
|
return Ok(Some(generator.gen_constructor(ctx, fun.0, &def, params)?))
|
||||||
}
|
}
|
||||||
TopLevelDef::Variable { .. } => unreachable!(),
|
TopLevelDef::Variable { .. } | TopLevelDef::Module { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.or_else(|_: String| {
|
.or_else(|_: String| {
|
||||||
@ -1020,7 +1028,7 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
let is_vararg = args.iter().any(|arg| arg.is_vararg);
|
let is_vararg = args.iter().any(|arg| arg.is_vararg);
|
||||||
if is_vararg {
|
if is_vararg {
|
||||||
params.push(generator.get_size_type(ctx.ctx).into());
|
params.push(ctx.get_size_type().into());
|
||||||
}
|
}
|
||||||
let fun_ty = match ret_type {
|
let fun_ty = match ret_type {
|
||||||
Some(ret_type) if !has_sret => ret_type.fn_type(¶ms, is_vararg),
|
Some(ret_type) if !has_sret => ret_type.fn_type(¶ms, is_vararg),
|
||||||
@ -1128,7 +1136,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = ctx.get_size_type();
|
||||||
let zero_size_t = size_t.const_zero();
|
let zero_size_t = size_t.const_zero();
|
||||||
let zero_32 = int32.const_zero();
|
let zero_32 = int32.const_zero();
|
||||||
|
|
||||||
@ -1143,7 +1151,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let iter_val =
|
let iter_val =
|
||||||
RangeValue::from_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
RangeType::new(ctx).map_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
||||||
let (start, stop, step) = destructure_range(ctx, iter_val);
|
let (start, stop, step) = destructure_range(ctx, iter_val);
|
||||||
let diff = ctx.builder.build_int_sub(stop, start, "diff").unwrap();
|
let diff = ctx.builder.build_int_sub(stop, start, "diff").unwrap();
|
||||||
// add 1 to the length as the value is rounded to zero
|
// add 1 to the length as the value is rounded to zero
|
||||||
@ -1167,7 +1175,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
"listcomp.alloc_size",
|
"listcomp.alloc_size",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
list = ListType::new(generator, ctx.ctx, elem_ty).construct(
|
list = ListType::new(ctx, &elem_ty).construct(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
list_alloc_size.into_int_value(),
|
list_alloc_size.into_int_value(),
|
||||||
@ -1218,12 +1226,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
Some("length"),
|
Some("length"),
|
||||||
)
|
)
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
list = ListType::new(generator, ctx.ctx, elem_ty).construct(
|
list = ListType::new(ctx, &elem_ty).construct(generator, ctx, length, Some("listcomp"));
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
length,
|
|
||||||
Some("listcomp"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?;
|
||||||
// counter = -1
|
// counter = -1
|
||||||
@ -1258,15 +1261,13 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Emits the content of `cont_bb`
|
// Emits the content of `cont_bb`
|
||||||
let emit_cont_bb =
|
let emit_cont_bb = |ctx: &CodeGenContext<'ctx, '_>, list: ListValue<'ctx>| {
|
||||||
|ctx: &CodeGenContext<'ctx, '_>, generator: &dyn CodeGenerator, list: ListValue<'ctx>| {
|
ctx.builder.position_at_end(cont_bb);
|
||||||
ctx.builder.position_at_end(cont_bb);
|
list.store_size(
|
||||||
list.store_size(
|
ctx,
|
||||||
ctx,
|
ctx.builder.build_load(index, "index").map(BasicValueEnum::into_int_value).unwrap(),
|
||||||
generator,
|
);
|
||||||
ctx.builder.build_load(index, "index").map(BasicValueEnum::into_int_value).unwrap(),
|
};
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
for cond in ifs {
|
for cond in ifs {
|
||||||
let result = if let Some(v) = generator.gen_expr(ctx, cond)? {
|
let result = if let Some(v) = generator.gen_expr(ctx, cond)? {
|
||||||
@ -1274,7 +1275,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
// Bail if the predicate is an ellipsis - Emit cont_bb contents in case the
|
// Bail if the predicate is an ellipsis - Emit cont_bb contents in case the
|
||||||
// no element matches the predicate
|
// no element matches the predicate
|
||||||
emit_cont_bb(ctx, generator, list);
|
emit_cont_bb(ctx, list);
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
@ -1287,7 +1288,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
|
|
||||||
let Some(elem) = generator.gen_expr(ctx, elt)? else {
|
let Some(elem) = generator.gen_expr(ctx, elt)? else {
|
||||||
// Similarly, bail if the generator expression is an ellipsis, but keep cont_bb contents
|
// Similarly, bail if the generator expression is an ellipsis, but keep cont_bb contents
|
||||||
emit_cont_bb(ctx, generator, list);
|
emit_cont_bb(ctx, list);
|
||||||
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
@ -1304,9 +1305,9 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
ctx.builder.build_unconditional_branch(test_bb).unwrap();
|
ctx.builder.build_unconditional_branch(test_bb).unwrap();
|
||||||
|
|
||||||
emit_cont_bb(ctx, generator, list);
|
emit_cont_bb(ctx, list);
|
||||||
|
|
||||||
Ok(Some(list.as_base_value().into()))
|
Ok(Some(list.as_abi_value(ctx).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for a binary operator expression using the [`Type`] and
|
/// Generates LLVM IR for a binary operator expression using the [`Type`] and
|
||||||
@ -1350,7 +1351,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
||||||
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|
||||||
{
|
{
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
if op.variant == BinopVariant::AugAssign {
|
if op.variant == BinopVariant::AugAssign {
|
||||||
todo!("Augmented assignment operators not implemented for lists")
|
todo!("Augmented assignment operators not implemented for lists")
|
||||||
@ -1388,8 +1389,8 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
.build_int_add(lhs.load_size(ctx, None), rhs.load_size(ctx, None), "")
|
.build_int_add(lhs.load_size(ctx, None), rhs.load_size(ctx, None), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let new_list = ListType::new(generator, ctx.ctx, llvm_elem_ty)
|
let new_list =
|
||||||
.construct(generator, ctx, size, None);
|
ListType::new(ctx, &llvm_elem_ty).construct(generator, ctx, size, None);
|
||||||
|
|
||||||
let lhs_size = ctx
|
let lhs_size = ctx
|
||||||
.builder
|
.builder
|
||||||
@ -1436,7 +1437,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
ctx.ctx.bool_type().const_zero(),
|
ctx.ctx.bool_type().const_zero(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Some(new_list.as_base_value().into()))
|
Ok(Some(new_list.as_abi_value(ctx).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator::Mult => {
|
Operator::Mult => {
|
||||||
@ -1476,7 +1477,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
let elem_llvm_ty = ctx.get_llvm_type(generator, elem_ty);
|
let elem_llvm_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
let sizeof_elem = elem_llvm_ty.size_of().unwrap();
|
let sizeof_elem = elem_llvm_ty.size_of().unwrap();
|
||||||
|
|
||||||
let new_list = ListType::new(generator, ctx.ctx, elem_llvm_ty).construct(
|
let new_list = ListType::new(ctx, &elem_llvm_ty).construct(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
ctx.builder.build_int_mul(list_val.load_size(ctx, None), int_val, "").unwrap(),
|
ctx.builder.build_int_mul(list_val.load_size(ctx, None), int_val, "").unwrap(),
|
||||||
@ -1523,7 +1524,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
llvm_usize.const_int(1, false),
|
llvm_usize.const_int(1, false),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Some(new_list.as_base_value().into()))
|
Ok(Some(new_list.as_abi_value(ctx).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => todo!("Operator not supported"),
|
_ => todo!("Operator not supported"),
|
||||||
@ -1578,8 +1579,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
let right = right.to_ndarray(generator, ctx);
|
let right = right.to_ndarray(generator, ctx);
|
||||||
|
|
||||||
let result = NDArrayType::new_broadcast(
|
let result = NDArrayType::new_broadcast(
|
||||||
generator,
|
ctx,
|
||||||
ctx.ctx,
|
|
||||||
llvm_common_dtype,
|
llvm_common_dtype,
|
||||||
&[left.get_type(), right.get_type()],
|
&[left.get_type(), right.get_type()],
|
||||||
)
|
)
|
||||||
@ -1601,7 +1601,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(Some(result.as_base_value().into()))
|
Ok(Some(result.as_abi_value(ctx).into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap());
|
let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap());
|
||||||
@ -1767,7 +1767,7 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
let (ndarray_dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
let (ndarray_dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
|
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ty)
|
||||||
.map_value(val.into_pointer_value(), None);
|
.map_pointer_value(val.into_pointer_value(), None);
|
||||||
|
|
||||||
// ndarray uses `~` rather than `not` to perform elementwise inversion, convert it before
|
// ndarray uses `~` rather than `not` to perform elementwise inversion, convert it before
|
||||||
// passing it to the elementwise codegen function
|
// passing it to the elementwise codegen function
|
||||||
@ -1796,7 +1796,7 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
mapped_ndarray.as_base_value().into()
|
mapped_ndarray.as_abi_value(ctx).into()
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}))
|
}))
|
||||||
@ -1852,8 +1852,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
.to_ndarray(generator, ctx);
|
.to_ndarray(generator, ctx);
|
||||||
|
|
||||||
let result_ndarray = NDArrayType::new_broadcast(
|
let result_ndarray = NDArrayType::new_broadcast(
|
||||||
generator,
|
ctx,
|
||||||
ctx.ctx,
|
|
||||||
ctx.ctx.i8_type().into(),
|
ctx.ctx.i8_type().into(),
|
||||||
&[left.get_type(), right.get_type()],
|
&[left.get_type(), right.get_type()],
|
||||||
)
|
)
|
||||||
@ -1884,7 +1883,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
return Ok(Some(result_ndarray.as_base_value().into()));
|
return Ok(Some(result_ndarray.as_abi_value(ctx).into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,7 +1971,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
let rhs = rhs.into_struct_value();
|
let rhs = rhs.into_struct_value();
|
||||||
|
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let plhs = generator.gen_var_alloc(ctx, lhs.get_type().into(), None).unwrap();
|
let plhs = generator.gen_var_alloc(ctx, lhs.get_type().into(), None).unwrap();
|
||||||
ctx.builder.build_store(plhs, lhs).unwrap();
|
ctx.builder.build_store(plhs, lhs).unwrap();
|
||||||
@ -2000,7 +1999,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
&[llvm_usize.const_zero(), llvm_i32.const_int(1, false)],
|
&[llvm_usize.const_zero(), llvm_i32.const_int(1, false)],
|
||||||
None,
|
None,
|
||||||
).into_int_value();
|
).into_int_value();
|
||||||
let result = call_string_eq(generator, ctx, lhs_ptr, lhs_len, rhs_ptr, rhs_len);
|
let result = call_string_eq(ctx, lhs_ptr, lhs_len, rhs_ptr, rhs_len);
|
||||||
if *op == Cmpop::NotEq {
|
if *op == Cmpop::NotEq {
|
||||||
ctx.builder.build_not(result, "").unwrap()
|
ctx.builder.build_not(result, "").unwrap()
|
||||||
} else {
|
} else {
|
||||||
@ -2010,7 +2009,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|ty| ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id()))
|
.any(|ty| ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id()))
|
||||||
{
|
{
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let gen_list_cmpop = |generator: &mut G,
|
let gen_list_cmpop = |generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>|
|
ctx: &mut CodeGenContext<'ctx, '_>|
|
||||||
@ -2131,9 +2130,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
|
|||||||
ctx.ctx.bool_type().const_zero(),
|
ctx.ctx.bool_type().const_zero(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ctx.builder
|
hooks.build_break_branch(&ctx.builder);
|
||||||
.build_unconditional_branch(hooks.exit_bb)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@ -2375,7 +2372,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
) -> Result<Option<ValueEnum<'ctx>>, String> {
|
||||||
ctx.current_loc = expr.location;
|
ctx.current_loc = expr.location;
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let usize = generator.get_size_type(ctx.ctx);
|
let usize = ctx.get_size_type();
|
||||||
let zero = int32.const_int(0, false);
|
let zero = int32.const_int(0, false);
|
||||||
|
|
||||||
let loc = ctx.debug_info.0.create_debug_location(
|
let loc = ctx.debug_info.0.create_debug_location(
|
||||||
@ -2480,20 +2477,11 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
Some(elements[0].get_type())
|
Some(elements[0].get_type())
|
||||||
};
|
};
|
||||||
let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false);
|
let length = ctx.get_size_type().const_int(elements.len() as u64, false);
|
||||||
let arr_str_ptr = if let Some(ty) = ty {
|
let arr_str_ptr = if let Some(ty) = ty {
|
||||||
ListType::new(generator, ctx.ctx, ty).construct(
|
ListType::new(ctx, &ty).construct(generator, ctx, length, Some("list"))
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
length,
|
|
||||||
Some("list"),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
ListType::new_untyped(generator, ctx.ctx).construct_empty(
|
ListType::new_untyped(ctx).construct_empty(generator, ctx, Some("list"))
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
Some("list"),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
let arr_ptr = arr_str_ptr.data();
|
let arr_ptr = arr_str_ptr.data();
|
||||||
for (i, v) in elements.iter().enumerate() {
|
for (i, v) in elements.iter().enumerate() {
|
||||||
@ -2505,7 +2493,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
);
|
);
|
||||||
ctx.builder.build_store(elem_ptr, *v).unwrap();
|
ctx.builder.build_store(elem_ptr, *v).unwrap();
|
||||||
}
|
}
|
||||||
arr_str_ptr.as_base_value().into()
|
arr_str_ptr.as_abi_value(ctx).into()
|
||||||
}
|
}
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
let elements_val = elts
|
let elements_val = elts
|
||||||
@ -2825,6 +2813,10 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
&*ctx.unifier.get_ty(value.custom.unwrap())
|
&*ctx.unifier.get_ty(value.custom.unwrap())
|
||||||
{
|
{
|
||||||
*obj_id
|
*obj_id
|
||||||
|
} else if let TypeEnum::TModule { module_id, .. } =
|
||||||
|
&*ctx.unifier.get_ty(value.custom.unwrap())
|
||||||
|
{
|
||||||
|
*module_id
|
||||||
} else {
|
} else {
|
||||||
codegen_unreachable!(ctx)
|
codegen_unreachable!(ctx)
|
||||||
};
|
};
|
||||||
@ -2835,11 +2827,13 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
} else {
|
} else {
|
||||||
let defs = ctx.top_level.definitions.read();
|
let defs = ctx.top_level.definitions.read();
|
||||||
let obj_def = defs.get(id.0).unwrap().read();
|
let obj_def = defs.get(id.0).unwrap().read();
|
||||||
let TopLevelDef::Class { methods, .. } = &*obj_def else {
|
if let TopLevelDef::Class { methods, .. } = &*obj_def {
|
||||||
|
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
||||||
|
} else if let TopLevelDef::Module { methods, .. } = &*obj_def {
|
||||||
|
*methods.iter().find(|method| method.0 == attr).unwrap().1
|
||||||
|
} else {
|
||||||
codegen_unreachable!(ctx)
|
codegen_unreachable!(ctx)
|
||||||
};
|
}
|
||||||
|
|
||||||
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
|
||||||
};
|
};
|
||||||
// directly generate code for option.unwrap
|
// directly generate code for option.unwrap
|
||||||
// since it needs to return static value to optimize for kernel invariant
|
// since it needs to return static value to optimize for kernel invariant
|
||||||
@ -2972,12 +2966,8 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
step,
|
step,
|
||||||
);
|
);
|
||||||
let res_array_ret = ListType::new(generator, ctx.ctx, ty).construct(
|
let res_array_ret =
|
||||||
generator,
|
ListType::new(ctx, &ty).construct(generator, ctx, length, Some("ret"));
|
||||||
ctx,
|
|
||||||
length,
|
|
||||||
Some("ret"),
|
|
||||||
);
|
|
||||||
let Some(res_ind) = handle_slice_indices(
|
let Some(res_ind) = handle_slice_indices(
|
||||||
&None,
|
&None,
|
||||||
&None,
|
&None,
|
||||||
@ -2998,7 +2988,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
v,
|
v,
|
||||||
(start, end, step),
|
(start, end, step),
|
||||||
);
|
);
|
||||||
res_array_ret.as_base_value().into()
|
res_array_ret.as_abi_value(ctx).into()
|
||||||
} else {
|
} else {
|
||||||
let len = v.load_size(ctx, Some("len"));
|
let len = v.load_size(ctx, Some("len"));
|
||||||
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
|
let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? {
|
||||||
@ -3009,7 +2999,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
};
|
};
|
||||||
let raw_index = ctx
|
let raw_index = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_s_extend(raw_index, generator.get_size_type(ctx.ctx), "sext")
|
.build_int_s_extend(raw_index, ctx.get_size_type(), "sext")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// handle negative index
|
// handle negative index
|
||||||
let is_negative = ctx
|
let is_negative = ctx
|
||||||
@ -3017,7 +3007,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
.build_int_compare(
|
.build_int_compare(
|
||||||
IntPredicate::SLT,
|
IntPredicate::SLT,
|
||||||
raw_index,
|
raw_index,
|
||||||
generator.get_size_type(ctx.ctx).const_zero(),
|
ctx.get_size_type().const_zero(),
|
||||||
"is_neg",
|
"is_neg",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -3053,14 +3043,14 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
|||||||
let ndarray_ty = value.custom.unwrap();
|
let ndarray_ty = value.custom.unwrap();
|
||||||
let ndarray = ndarray.to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
let ndarray = ndarray.to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
||||||
.map_value(ndarray.into_pointer_value(), None);
|
.map_pointer_value(ndarray.into_pointer_value(), None);
|
||||||
|
|
||||||
let indices = RustNDIndex::from_subscript_expr(generator, ctx, slice)?;
|
let indices = RustNDIndex::from_subscript_expr(generator, ctx, slice)?;
|
||||||
let result = ndarray
|
let result = ndarray
|
||||||
.index(generator, ctx, &indices)
|
.index(generator, ctx, &indices)
|
||||||
.split_unsized(generator, ctx)
|
.split_unsized(generator, ctx)
|
||||||
.to_basic_value_enum();
|
.to_basic_value_enum();
|
||||||
return Ok(Some(ValueEnum::Dynamic(result)));
|
return Ok(Some(result.into()));
|
||||||
}
|
}
|
||||||
TypeEnum::TTuple { .. } => {
|
TypeEnum::TTuple { .. } => {
|
||||||
let index: u32 =
|
let index: u32 =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
|
targets::TargetMachine,
|
||||||
types::{BasicTypeEnum, IntType},
|
types::{BasicTypeEnum, IntType},
|
||||||
values::{BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue},
|
||||||
};
|
};
|
||||||
@ -18,6 +19,9 @@ pub trait CodeGenerator {
|
|||||||
fn get_name(&self) -> &str;
|
fn get_name(&self) -> &str;
|
||||||
|
|
||||||
/// Return an instance of [`IntType`] corresponding to the type of `size_t` for this instance.
|
/// Return an instance of [`IntType`] corresponding to the type of `size_t` for this instance.
|
||||||
|
///
|
||||||
|
/// Prefer using [`CodeGenContext::get_size_type`] if [`CodeGenContext`] is available, as it is
|
||||||
|
/// equivalent to this function in a more concise syntax.
|
||||||
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx>;
|
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx>;
|
||||||
|
|
||||||
/// Generate function call and returns the function return value.
|
/// Generate function call and returns the function return value.
|
||||||
@ -270,19 +274,27 @@ pub struct DefaultCodeGenerator {
|
|||||||
|
|
||||||
impl DefaultCodeGenerator {
|
impl DefaultCodeGenerator {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: String, size_t: u32) -> DefaultCodeGenerator {
|
pub fn new(name: String, size_t: IntType<'_>) -> DefaultCodeGenerator {
|
||||||
assert!(matches!(size_t, 32 | 64));
|
assert!(matches!(size_t.get_bit_width(), 32 | 64));
|
||||||
DefaultCodeGenerator { name, size_t }
|
DefaultCodeGenerator { name, size_t: size_t.get_bit_width() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_target_machine(
|
||||||
|
name: String,
|
||||||
|
ctx: &Context,
|
||||||
|
target_machine: &TargetMachine,
|
||||||
|
) -> DefaultCodeGenerator {
|
||||||
|
let llvm_usize = ctx.ptr_sized_int_type(&target_machine.get_target_data(), None);
|
||||||
|
Self::new(name, llvm_usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeGenerator for DefaultCodeGenerator {
|
impl CodeGenerator for DefaultCodeGenerator {
|
||||||
/// Returns the name for this [`CodeGenerator`].
|
|
||||||
fn get_name(&self) -> &str {
|
fn get_name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an LLVM integer type representing `size_t`.
|
|
||||||
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_size_type<'ctx>(&self, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
// it should be unsigned, but we don't really need unsigned and this could save us from
|
// it should be unsigned, but we don't really need unsigned and this could save us from
|
||||||
// having to do a bit cast...
|
// having to do a bit cast...
|
||||||
|
@ -24,7 +24,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
src_arr: ListValue<'ctx>,
|
src_arr: ListValue<'ctx>,
|
||||||
src_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>),
|
src_idx: (IntValue<'ctx>, IntValue<'ctx>, IntValue<'ctx>),
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx.builder.position_at_end(update_bb);
|
ctx.builder.position_at_end(update_bb);
|
||||||
let new_len =
|
let new_len =
|
||||||
ctx.builder.build_int_z_extend_or_bit_cast(new_len, llvm_usize, "new_len").unwrap();
|
ctx.builder.build_int_z_extend_or_bit_cast(new_len, llvm_usize, "new_len").unwrap();
|
||||||
dest_arr.store_size(ctx, generator, new_len);
|
dest_arr.store_size(ctx, new_len);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb).unwrap();
|
ctx.builder.build_unconditional_branch(cont_bb).unwrap();
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
}
|
}
|
||||||
|
@ -68,13 +68,9 @@ pub fn load_irrt<'ctx>(ctx: &'ctx Context, symbol_resolver: &dyn SymbolResolver)
|
|||||||
/// - When [`TypeContext::size_type`] is 32-bits, the function name is `fn_name}`.
|
/// - When [`TypeContext::size_type`] is 32-bits, the function name is `fn_name}`.
|
||||||
/// - When [`TypeContext::size_type`] is 64-bits, the function name is `{fn_name}64`.
|
/// - When [`TypeContext::size_type`] is 64-bits, the function name is `{fn_name}64`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_usize_dependent_function_name<G: CodeGenerator + ?Sized>(
|
pub fn get_usize_dependent_function_name(ctx: &CodeGenContext<'_, '_>, name: &str) -> String {
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'_, '_>,
|
|
||||||
name: &str,
|
|
||||||
) -> String {
|
|
||||||
let mut name = name.to_owned();
|
let mut name = name.to_owned();
|
||||||
match generator.get_size_type(ctx.ctx).get_bit_width() {
|
match ctx.get_size_type().get_bit_width() {
|
||||||
32 => {}
|
32 => {}
|
||||||
64 => name.push_str("64"),
|
64 => name.push_str("64"),
|
||||||
bit_width => {
|
bit_width => {
|
||||||
|
@ -21,7 +21,7 @@ pub fn call_nac3_ndarray_array_set_and_validate_list_shape<'ctx, G: CodeGenerato
|
|||||||
ndims: IntValue<'ctx>,
|
ndims: IntValue<'ctx>,
|
||||||
shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
assert_eq!(list.get_type().element_type().unwrap(), ctx.ctx.i8_type().into());
|
assert_eq!(list.get_type().element_type().unwrap(), ctx.ctx.i8_type().into());
|
||||||
assert_eq!(ndims.get_type(), llvm_usize);
|
assert_eq!(ndims.get_type(), llvm_usize);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -29,17 +29,14 @@ pub fn call_nac3_ndarray_array_set_and_validate_list_shape<'ctx, G: CodeGenerato
|
|||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(
|
let name =
|
||||||
generator,
|
get_usize_dependent_function_name(ctx, "__nac3_ndarray_array_set_and_validate_list_shape");
|
||||||
ctx,
|
|
||||||
"__nac3_ndarray_array_set_and_validate_list_shape",
|
|
||||||
);
|
|
||||||
|
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[list.as_base_value().into(), ndims.into(), shape.base_ptr(ctx, generator).into()],
|
&[list.as_abi_value(ctx).into(), ndims.into(), shape.base_ptr(ctx, generator).into()],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -55,25 +52,20 @@ pub fn call_nac3_ndarray_array_set_and_validate_list_shape<'ctx, G: CodeGenerato
|
|||||||
/// - `ndarray.ndims`: Must be initialized.
|
/// - `ndarray.ndims`: Must be initialized.
|
||||||
/// - `ndarray.shape`: Must be initialized.
|
/// - `ndarray.shape`: Must be initialized.
|
||||||
/// - `ndarray.data`: Must be allocated and contiguous.
|
/// - `ndarray.data`: Must be allocated and contiguous.
|
||||||
pub fn call_nac3_ndarray_array_write_list_to_array<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_array_write_list_to_array<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
list: ListValue<'ctx>,
|
list: ListValue<'ctx>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
assert_eq!(list.get_type().element_type().unwrap(), ctx.ctx.i8_type().into());
|
assert_eq!(list.get_type().element_type().unwrap(), ctx.ctx.i8_type().into());
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_array_write_list_to_array");
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
"__nac3_ndarray_array_write_list_to_array",
|
|
||||||
);
|
|
||||||
|
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[list.as_base_value().into(), ndarray.as_base_value().into()],
|
&[list.as_abi_value(ctx).into(), ndarray.as_abi_value(ctx).into()],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -20,7 +20,7 @@ pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator +
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -28,11 +28,8 @@ pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator +
|
|||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(
|
let name =
|
||||||
generator,
|
get_usize_dependent_function_name(ctx, "__nac3_ndarray_util_assert_shape_no_negative");
|
||||||
ctx,
|
|
||||||
"__nac3_ndarray_util_assert_shape_no_negative",
|
|
||||||
);
|
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
@ -57,7 +54,7 @@ pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator +
|
|||||||
ndarray_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
ndarray_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
output_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
output_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -69,11 +66,8 @@ pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator +
|
|||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(
|
let name =
|
||||||
generator,
|
get_usize_dependent_function_name(ctx, "__nac3_ndarray_util_assert_output_shape_same");
|
||||||
ctx,
|
|
||||||
"__nac3_ndarray_util_assert_output_shape_same",
|
|
||||||
);
|
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
@ -94,21 +88,20 @@ pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator +
|
|||||||
///
|
///
|
||||||
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the number of elements of an
|
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the number of elements of an
|
||||||
/// `ndarray`, corresponding to the value of `ndarray.size`.
|
/// `ndarray`, corresponding to the value of `ndarray.size`.
|
||||||
pub fn call_nac3_ndarray_size<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_size<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_size");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_size");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_usize.into()),
|
Some(llvm_usize.into()),
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into())],
|
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
|
||||||
Some("size"),
|
Some("size"),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -120,21 +113,20 @@ pub fn call_nac3_ndarray_size<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
///
|
///
|
||||||
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the number of bytes consumed by the
|
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the number of bytes consumed by the
|
||||||
/// data of the `ndarray`, corresponding to the value of `ndarray.nbytes`.
|
/// data of the `ndarray`, corresponding to the value of `ndarray.nbytes`.
|
||||||
pub fn call_nac3_ndarray_nbytes<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_nbytes<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_nbytes");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_nbytes");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_usize.into()),
|
Some(llvm_usize.into()),
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into())],
|
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
|
||||||
Some("nbytes"),
|
Some("nbytes"),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -146,21 +138,20 @@ pub fn call_nac3_ndarray_nbytes<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
///
|
///
|
||||||
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the size of the topmost dimension of
|
/// Returns a [`usize`][CodeGenerator::get_size_type] value of the size of the topmost dimension of
|
||||||
/// the `ndarray`, corresponding to the value of `ndarray.__len__`.
|
/// the `ndarray`, corresponding to the value of `ndarray.__len__`.
|
||||||
pub fn call_nac3_ndarray_len<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_len<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_len");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_len");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_usize.into()),
|
Some(llvm_usize.into()),
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into())],
|
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
|
||||||
Some("len"),
|
Some("len"),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -171,21 +162,20 @@ pub fn call_nac3_ndarray_len<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
/// Generates a call to `__nac3_ndarray_is_c_contiguous`.
|
/// Generates a call to `__nac3_ndarray_is_c_contiguous`.
|
||||||
///
|
///
|
||||||
/// Returns an `i1` value indicating whether the `ndarray` is C-contiguous.
|
/// Returns an `i1` value indicating whether the `ndarray` is C-contiguous.
|
||||||
pub fn call_nac3_ndarray_is_c_contiguous<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_is_c_contiguous<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let llvm_i1 = ctx.ctx.bool_type();
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_is_c_contiguous");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_is_c_contiguous");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_i1.into()),
|
Some(llvm_i1.into()),
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into())],
|
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
|
||||||
Some("is_c_contiguous"),
|
Some("is_c_contiguous"),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -196,26 +186,28 @@ pub fn call_nac3_ndarray_is_c_contiguous<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
/// Generates a call to `__nac3_ndarray_get_nth_pelement`.
|
/// Generates a call to `__nac3_ndarray_get_nth_pelement`.
|
||||||
///
|
///
|
||||||
/// Returns a [`PointerValue`] to the `index`-th flattened element of the `ndarray`.
|
/// Returns a [`PointerValue`] to the `index`-th flattened element of the `ndarray`.
|
||||||
pub fn call_nac3_ndarray_get_nth_pelement<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_get_nth_pelement<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
index: IntValue<'ctx>,
|
index: IntValue<'ctx>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let llvm_i8 = ctx.ctx.i8_type();
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
assert_eq!(index.get_type(), llvm_usize);
|
assert_eq!(index.get_type(), llvm_usize);
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_nth_pelement");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_get_nth_pelement");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_pi8.into()),
|
Some(llvm_pi8.into()),
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into()), (llvm_usize.into(), index.into())],
|
&[
|
||||||
|
(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
|
||||||
|
(llvm_usize.into(), index.into()),
|
||||||
|
],
|
||||||
Some("pelement"),
|
Some("pelement"),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -236,24 +228,23 @@ pub fn call_nac3_ndarray_get_pelement_by_indices<'ctx, G: CodeGenerator + ?Sized
|
|||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let llvm_i8 = ctx.ctx.i8_type();
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BasicTypeEnum::try_from(indices.element_type(ctx, generator)).unwrap(),
|
BasicTypeEnum::try_from(indices.element_type(ctx, generator)).unwrap(),
|
||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name =
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_get_pelement_by_indices");
|
||||||
get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_pelement_by_indices");
|
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(llvm_pi8.into()),
|
Some(llvm_pi8.into()),
|
||||||
&[
|
&[
|
||||||
(llvm_ndarray.into(), ndarray.as_base_value().into()),
|
(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
|
||||||
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
|
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
|
||||||
],
|
],
|
||||||
Some("pelement"),
|
Some("pelement"),
|
||||||
@ -266,21 +257,19 @@ pub fn call_nac3_ndarray_get_pelement_by_indices<'ctx, G: CodeGenerator + ?Sized
|
|||||||
/// Generates a call to `__nac3_ndarray_set_strides_by_shape`.
|
/// Generates a call to `__nac3_ndarray_set_strides_by_shape`.
|
||||||
///
|
///
|
||||||
/// Sets `ndarray.strides` assuming that `ndarray.shape` is C-contiguous.
|
/// Sets `ndarray.strides` assuming that `ndarray.shape` is C-contiguous.
|
||||||
pub fn call_nac3_ndarray_set_strides_by_shape<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_set_strides_by_shape<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let llvm_ndarray = ndarray.get_type().as_base_type();
|
let llvm_ndarray = ndarray.get_type();
|
||||||
|
|
||||||
let name =
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_set_strides_by_shape");
|
||||||
get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_set_strides_by_shape");
|
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[(llvm_ndarray.into(), ndarray.as_base_value().into())],
|
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -291,19 +280,18 @@ pub fn call_nac3_ndarray_set_strides_by_shape<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
/// Copies all elements from `src_ndarray` to `dst_ndarray` using their flattened views. The number
|
/// Copies all elements from `src_ndarray` to `dst_ndarray` using their flattened views. The number
|
||||||
/// of elements in `src_ndarray` must be greater than or equal to the number of elements in
|
/// of elements in `src_ndarray` must be greater than or equal to the number of elements in
|
||||||
/// `dst_ndarray`.
|
/// `dst_ndarray`.
|
||||||
pub fn call_nac3_ndarray_copy_data<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_copy_data<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
src_ndarray: NDArrayValue<'ctx>,
|
src_ndarray: NDArrayValue<'ctx>,
|
||||||
dst_ndarray: NDArrayValue<'ctx>,
|
dst_ndarray: NDArrayValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_copy_data");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_copy_data");
|
||||||
|
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[src_ndarray.as_base_value().into(), dst_ndarray.as_base_value().into()],
|
&[src_ndarray.as_abi_value(ctx).into(), dst_ndarray.as_abi_value(ctx).into()],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -20,18 +20,17 @@ use crate::codegen::{
|
|||||||
/// - `dst_ndarray.ndims` must be initialized and matching the length of `dst_ndarray.shape`.
|
/// - `dst_ndarray.ndims` must be initialized and matching the length of `dst_ndarray.shape`.
|
||||||
/// - `dst_ndarray.shape` must be initialized and contains the target broadcast shape.
|
/// - `dst_ndarray.shape` must be initialized and contains the target broadcast shape.
|
||||||
/// - `dst_ndarray.strides` must be allocated and may contain uninitialized values.
|
/// - `dst_ndarray.strides` must be allocated and may contain uninitialized values.
|
||||||
pub fn call_nac3_ndarray_broadcast_to<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_broadcast_to<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
src_ndarray: NDArrayValue<'ctx>,
|
src_ndarray: NDArrayValue<'ctx>,
|
||||||
dst_ndarray: NDArrayValue<'ctx>,
|
dst_ndarray: NDArrayValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_broadcast_to");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_broadcast_to");
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[src_ndarray.as_base_value().into(), dst_ndarray.as_base_value().into()],
|
&[src_ndarray.as_abi_value(ctx).into(), dst_ndarray.as_abi_value(ctx).into()],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -53,19 +52,18 @@ pub fn call_nac3_ndarray_broadcast_shapes<'ctx, G, Shape>(
|
|||||||
Shape: TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>
|
Shape: TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>
|
||||||
+ TypedArrayLikeMutator<'ctx, G, IntValue<'ctx>>,
|
+ TypedArrayLikeMutator<'ctx, G, IntValue<'ctx>>,
|
||||||
{
|
{
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
assert_eq!(num_shape_entries.get_type(), llvm_usize);
|
assert_eq!(num_shape_entries.get_type(), llvm_usize);
|
||||||
assert!(ShapeEntryType::is_type(
|
assert!(ShapeEntryType::is_representable(
|
||||||
generator,
|
shape_entries.base_ptr(ctx, generator).get_type(),
|
||||||
ctx.ctx,
|
llvm_usize,
|
||||||
shape_entries.base_ptr(ctx, generator).get_type()
|
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert_eq!(dst_ndims.get_type(), llvm_usize);
|
assert_eq!(dst_ndims.get_type(), llvm_usize);
|
||||||
assert_eq!(dst_shape.element_type(ctx, generator), llvm_usize.into());
|
assert_eq!(dst_shape.element_type(ctx, generator), llvm_usize.into());
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_broadcast_shapes");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_broadcast_shapes");
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
|
@ -17,7 +17,7 @@ pub fn call_nac3_ndarray_index<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
src_ndarray: NDArrayValue<'ctx>,
|
src_ndarray: NDArrayValue<'ctx>,
|
||||||
dst_ndarray: NDArrayValue<'ctx>,
|
dst_ndarray: NDArrayValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_index");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_index");
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
@ -25,8 +25,8 @@ pub fn call_nac3_ndarray_index<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
&[
|
&[
|
||||||
indices.size(ctx, generator).into(),
|
indices.size(ctx, generator).into(),
|
||||||
indices.base_ptr(ctx, generator).into(),
|
indices.base_ptr(ctx, generator).into(),
|
||||||
src_ndarray.as_base_value().into(),
|
src_ndarray.as_abi_value(ctx).into(),
|
||||||
dst_ndarray.as_base_value().into(),
|
dst_ndarray.as_abi_value(ctx).into(),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -25,7 +25,7 @@ pub fn call_nac3_nditer_initialize<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ndarray: NDArrayValue<'ctx>,
|
ndarray: NDArrayValue<'ctx>,
|
||||||
indices: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
indices: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -33,15 +33,15 @@ pub fn call_nac3_nditer_initialize<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_nditer_initialize");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_nditer_initialize");
|
||||||
|
|
||||||
create_and_call_function(
|
create_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[
|
&[
|
||||||
(iter.get_type().as_base_type().into(), iter.as_base_value().into()),
|
(iter.get_type().as_abi_type().into(), iter.as_abi_value(ctx).into()),
|
||||||
(ndarray.get_type().as_base_type().into(), ndarray.as_base_value().into()),
|
(ndarray.get_type().as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
|
||||||
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
|
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
@ -53,18 +53,17 @@ pub fn call_nac3_nditer_initialize<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
///
|
///
|
||||||
/// Returns an `i1` value indicating whether there are elements left to traverse for the `iter`
|
/// Returns an `i1` value indicating whether there are elements left to traverse for the `iter`
|
||||||
/// object.
|
/// object.
|
||||||
pub fn call_nac3_nditer_has_element<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_nditer_has_element<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
iter: NDIterValue<'ctx>,
|
iter: NDIterValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_nditer_has_element");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_nditer_has_element");
|
||||||
|
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
Some(ctx.ctx.bool_type().into()),
|
Some(ctx.ctx.bool_type().into()),
|
||||||
&[iter.as_base_value().into()],
|
&[iter.as_abi_value(ctx).into()],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -75,12 +74,8 @@ pub fn call_nac3_nditer_has_element<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
/// Generates a call to `__nac3_nditer_next`.
|
/// Generates a call to `__nac3_nditer_next`.
|
||||||
///
|
///
|
||||||
/// Moves `iter` to point to the next element.
|
/// Moves `iter` to point to the next element.
|
||||||
pub fn call_nac3_nditer_next<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_nditer_next<'ctx>(ctx: &CodeGenContext<'ctx, '_>, iter: NDIterValue<'ctx>) {
|
||||||
generator: &G,
|
let name = get_usize_dependent_function_name(ctx, "__nac3_nditer_next");
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
iter: NDIterValue<'ctx>,
|
|
||||||
) {
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_nditer_next");
|
|
||||||
|
|
||||||
infer_and_call_function(ctx, &name, None, &[iter.as_base_value().into()], None, None);
|
infer_and_call_function(ctx, &name, None, &[iter.as_abi_value(ctx).into()], None, None);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub fn call_nac3_ndarray_matmul_calculate_shapes<'ctx, G: CodeGenerator + ?Sized
|
|||||||
new_b_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
new_b_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
dst_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
dst_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BasicTypeEnum::try_from(a_shape.element_type(ctx, generator)).unwrap(),
|
BasicTypeEnum::try_from(a_shape.element_type(ctx, generator)).unwrap(),
|
||||||
@ -43,8 +43,7 @@ pub fn call_nac3_ndarray_matmul_calculate_shapes<'ctx, G: CodeGenerator + ?Sized
|
|||||||
llvm_usize.into()
|
llvm_usize.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
let name =
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_matmul_calculate_shapes");
|
||||||
get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_matmul_calculate_shapes");
|
|
||||||
|
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -18,14 +18,13 @@ pub fn call_nac3_ndarray_reshape_resolve_and_check_new_shape<'ctx, G: CodeGenera
|
|||||||
new_ndims: IntValue<'ctx>,
|
new_ndims: IntValue<'ctx>,
|
||||||
new_shape: ArraySliceValue<'ctx>,
|
new_shape: ArraySliceValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
assert_eq!(size.get_type(), llvm_usize);
|
assert_eq!(size.get_type(), llvm_usize);
|
||||||
assert_eq!(new_ndims.get_type(), llvm_usize);
|
assert_eq!(new_ndims.get_type(), llvm_usize);
|
||||||
assert_eq!(new_shape.element_type(ctx, generator), llvm_usize.into());
|
assert_eq!(new_shape.element_type(ctx, generator), llvm_usize.into());
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(
|
let name = get_usize_dependent_function_name(
|
||||||
generator,
|
|
||||||
ctx,
|
ctx,
|
||||||
"__nac3_ndarray_reshape_resolve_and_check_new_shape",
|
"__nac3_ndarray_reshape_resolve_and_check_new_shape",
|
||||||
);
|
);
|
||||||
|
@ -23,19 +23,19 @@ pub fn call_nac3_ndarray_transpose<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
dst_ndarray: NDArrayValue<'ctx>,
|
dst_ndarray: NDArrayValue<'ctx>,
|
||||||
axes: Option<&impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>>,
|
axes: Option<&impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>>,
|
||||||
) {
|
) {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
assert!(axes.is_none_or(|axes| axes.size(ctx, generator).get_type() == llvm_usize));
|
assert!(axes.is_none_or(|axes| axes.size(ctx, generator).get_type() == llvm_usize));
|
||||||
assert!(axes.is_none_or(|axes| axes.element_type(ctx, generator) == llvm_usize.into()));
|
assert!(axes.is_none_or(|axes| axes.element_type(ctx, generator) == llvm_usize.into()));
|
||||||
|
|
||||||
let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_transpose");
|
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_transpose");
|
||||||
infer_and_call_function(
|
infer_and_call_function(
|
||||||
ctx,
|
ctx,
|
||||||
&name,
|
&name,
|
||||||
None,
|
None,
|
||||||
&[
|
&[
|
||||||
src_ndarray.as_base_value().into(),
|
src_ndarray.as_abi_value(ctx).into(),
|
||||||
dst_ndarray.as_base_value().into(),
|
dst_ndarray.as_abi_value(ctx).into(),
|
||||||
axes.map_or(llvm_usize.const_zero(), |axes| axes.size(ctx, generator)).into(),
|
axes.map_or(llvm_usize.const_zero(), |axes| axes.size(ctx, generator)).into(),
|
||||||
axes.map_or(llvm_usize.ptr_type(AddressSpace::default()).const_null(), |axes| {
|
axes.map_or(llvm_usize.ptr_type(AddressSpace::default()).const_null(), |axes| {
|
||||||
axes.base_ptr(ctx, generator)
|
axes.base_ptr(ctx, generator)
|
||||||
|
@ -2,11 +2,10 @@ use inkwell::values::{BasicValueEnum, CallSiteValue, IntValue, PointerValue};
|
|||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
|
||||||
use super::get_usize_dependent_function_name;
|
use super::get_usize_dependent_function_name;
|
||||||
use crate::codegen::{CodeGenContext, CodeGenerator};
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
/// Generates a call to string equality comparison. Returns an `i1` representing whether the strings are equal.
|
/// Generates a call to string equality comparison. Returns an `i1` representing whether the strings are equal.
|
||||||
pub fn call_string_eq<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_string_eq<'ctx>(
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
str1_ptr: PointerValue<'ctx>,
|
str1_ptr: PointerValue<'ctx>,
|
||||||
str1_len: IntValue<'ctx>,
|
str1_len: IntValue<'ctx>,
|
||||||
@ -15,7 +14,7 @@ pub fn call_string_eq<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let llvm_i1 = ctx.ctx.bool_type();
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
|
||||||
let func_name = get_usize_dependent_function_name(generator, ctx, "nac3_str_eq");
|
let func_name = get_usize_dependent_function_name(ctx, "nac3_str_eq");
|
||||||
|
|
||||||
let func = ctx.module.get_function(&func_name).unwrap_or_else(|| {
|
let func = ctx.module.get_function(&func_name).unwrap_or_else(|| {
|
||||||
ctx.module.add_function(
|
ctx.module.add_function(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
cell::OnceCell,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
@ -19,7 +20,7 @@ use inkwell::{
|
|||||||
module::Module,
|
module::Module,
|
||||||
passes::PassBuilderOptions,
|
passes::PassBuilderOptions,
|
||||||
targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple},
|
targets::{CodeModel, RelocMode, Target, TargetMachine, TargetTriple},
|
||||||
types::{AnyType, BasicType, BasicTypeEnum},
|
types::{AnyType, BasicType, BasicTypeEnum, IntType},
|
||||||
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
values::{BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
@ -226,14 +227,33 @@ pub struct CodeGenContext<'ctx, 'a> {
|
|||||||
|
|
||||||
/// The current source location.
|
/// The current source location.
|
||||||
pub current_loc: Location,
|
pub current_loc: Location,
|
||||||
|
|
||||||
|
/// The cached type of `size_t`.
|
||||||
|
llvm_usize: OnceCell<IntType<'ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeGenContext<'_, '_> {
|
impl<'ctx> CodeGenContext<'ctx, '_> {
|
||||||
/// Whether the [current basic block][Builder::get_insert_block] referenced by `builder`
|
/// Whether the [current basic block][Builder::get_insert_block] referenced by `builder`
|
||||||
/// contains a [terminator statement][BasicBlock::get_terminator].
|
/// contains a [terminator statement][BasicBlock::get_terminator].
|
||||||
pub fn is_terminated(&self) -> bool {
|
pub fn is_terminated(&self) -> bool {
|
||||||
self.builder.get_insert_block().and_then(BasicBlock::get_terminator).is_some()
|
self.builder.get_insert_block().and_then(BasicBlock::get_terminator).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a [`IntType`] representing `size_t` for the compilation target as specified by
|
||||||
|
/// [`self.registry`][WorkerRegistry].
|
||||||
|
pub fn get_size_type(&self) -> IntType<'ctx> {
|
||||||
|
*self.llvm_usize.get_or_init(|| {
|
||||||
|
self.ctx.ptr_sized_int_type(
|
||||||
|
&self
|
||||||
|
.registry
|
||||||
|
.llvm_options
|
||||||
|
.create_target_machine()
|
||||||
|
.map(|tm| tm.get_target_data())
|
||||||
|
.unwrap(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fp = Box<dyn Fn(&Module) + Send + Sync>;
|
type Fp = Box<dyn Fn(&Module) + Send + Sync>;
|
||||||
@ -481,6 +501,38 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
type_cache.get(&unifier.get_representative(ty)).copied().unwrap_or_else(|| {
|
type_cache.get(&unifier.get_representative(ty)).copied().unwrap_or_else(|| {
|
||||||
let ty_enum = unifier.get_ty(ty);
|
let ty_enum = unifier.get_ty(ty);
|
||||||
let result = match &*ty_enum {
|
let result = match &*ty_enum {
|
||||||
|
TModule {module_id, attributes} => {
|
||||||
|
let top_level_defs = top_level.definitions.read();
|
||||||
|
let definition = top_level_defs.get(module_id.0).unwrap();
|
||||||
|
let TopLevelDef::Module { name, attributes: attribute_fields, .. } = &*definition.read() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let ty: BasicTypeEnum<'_> = if let Some(t) = module.get_struct_type(&name.to_string()) {
|
||||||
|
t.ptr_type(AddressSpace::default()).into()
|
||||||
|
} else {
|
||||||
|
let struct_type = ctx.opaque_struct_type(&name.to_string());
|
||||||
|
type_cache.insert(
|
||||||
|
unifier.get_representative(ty),
|
||||||
|
struct_type.ptr_type(AddressSpace::default()).into(),
|
||||||
|
);
|
||||||
|
let module_fields: Vec<BasicTypeEnum<'_>> = attribute_fields.iter()
|
||||||
|
.map(|f| {
|
||||||
|
get_llvm_type(
|
||||||
|
ctx,
|
||||||
|
module,
|
||||||
|
generator,
|
||||||
|
unifier,
|
||||||
|
top_level,
|
||||||
|
type_cache,
|
||||||
|
attributes[&f.0].0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
struct_type.set_body(&module_fields, false);
|
||||||
|
struct_type.ptr_type(AddressSpace::default()).into()
|
||||||
|
};
|
||||||
|
return ty;
|
||||||
|
},
|
||||||
TObj { obj_id, fields, .. } => {
|
TObj { obj_id, fields, .. } => {
|
||||||
// check to avoid treating non-class primitives as classes
|
// check to avoid treating non-class primitives as classes
|
||||||
if PrimDef::contains_id(*obj_id) {
|
if PrimDef::contains_id(*obj_id) {
|
||||||
@ -510,7 +562,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
*params.iter().next().unwrap().1,
|
*params.iter().next().unwrap().1,
|
||||||
);
|
);
|
||||||
|
|
||||||
ListType::new(generator, ctx, element_type).as_base_type().into()
|
ListType::new_with_generator(generator, ctx, element_type).as_abi_type().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
TObj { obj_id, .. } if *obj_id == PrimDef::NDArray.id() => {
|
||||||
@ -520,7 +572,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx, module, generator, unifier, top_level, type_cache, dtype,
|
ctx, module, generator, unifier, top_level, type_cache, dtype,
|
||||||
);
|
);
|
||||||
|
|
||||||
NDArrayType::new(generator, ctx, element_type, ndims).as_base_type().into()
|
NDArrayType::new_with_generator(generator, ctx, element_type, ndims).as_abi_type().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!(
|
_ => unreachable!(
|
||||||
@ -574,7 +626,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
get_llvm_type(ctx, module, generator, unifier, top_level, type_cache, *ty)
|
get_llvm_type(ctx, module, generator, unifier, top_level, type_cache, *ty)
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
TupleType::new(generator, ctx, &fields).as_base_type().into()
|
TupleType::new_with_generator(generator, ctx, &fields).as_abi_type().into()
|
||||||
}
|
}
|
||||||
TVirtual { .. } => unimplemented!(),
|
TVirtual { .. } => unimplemented!(),
|
||||||
_ => unreachable!("{}", ty_enum.get_type_name()),
|
_ => unreachable!("{}", ty_enum.get_type_name()),
|
||||||
@ -748,7 +800,7 @@ pub fn gen_func_impl<
|
|||||||
Some(t) => t.as_basic_type_enum(),
|
Some(t) => t.as_basic_type_enum(),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
(primitives.range, RangeType::new(context).as_base_type().into()),
|
(primitives.range, RangeType::new_with_generator(generator, context).as_abi_type().into()),
|
||||||
(primitives.exception, {
|
(primitives.exception, {
|
||||||
let name = "Exception";
|
let name = "Exception";
|
||||||
if let Some(t) = module.get_struct_type(name) {
|
if let Some(t) = module.get_struct_type(name) {
|
||||||
@ -987,8 +1039,20 @@ pub fn gen_func_impl<
|
|||||||
need_sret: has_sret,
|
need_sret: has_sret,
|
||||||
current_loc: Location::default(),
|
current_loc: Location::default(),
|
||||||
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
|
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
|
||||||
|
llvm_usize: OnceCell::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let target_llvm_usize = context.ptr_sized_int_type(
|
||||||
|
®istry.llvm_options.create_target_machine().map(|tm| tm.get_target_data()).unwrap(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let generator_llvm_usize = generator.get_size_type(context);
|
||||||
|
assert_eq!(
|
||||||
|
generator_llvm_usize,
|
||||||
|
target_llvm_usize,
|
||||||
|
"CodeGenerator (size_t = {generator_llvm_usize}) is not compatible with CodeGen Target (size_t = {target_llvm_usize})",
|
||||||
|
);
|
||||||
|
|
||||||
let loc = code_gen_context.debug_info.0.create_debug_location(
|
let loc = code_gen_context.debug_info.0.create_debug_location(
|
||||||
context,
|
context,
|
||||||
row as u32,
|
row as u32,
|
||||||
@ -1180,7 +1244,7 @@ pub fn type_aligned_alloca<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
let llvm_i8 = ctx.ctx.i8_type();
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let align_ty = align_ty.into();
|
let align_ty = align_ty.into();
|
||||||
|
|
||||||
let size = ctx.builder.build_int_truncate_or_bit_cast(size, llvm_usize, "").unwrap();
|
let size = ctx.builder.build_int_truncate_or_bit_cast(size, llvm_usize, "").unwrap();
|
||||||
|
@ -42,9 +42,9 @@ pub fn gen_ndarray_empty<'ctx>(
|
|||||||
|
|
||||||
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
||||||
|
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, ndims)
|
let ndarray = NDArrayType::new(context, llvm_dtype, ndims)
|
||||||
.construct_numpy_empty(generator, context, &shape, None);
|
.construct_numpy_empty(generator, context, &shape, None);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.zeros`.
|
/// Generates LLVM IR for `ndarray.zeros`.
|
||||||
@ -67,9 +67,9 @@ pub fn gen_ndarray_zeros<'ctx>(
|
|||||||
|
|
||||||
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
||||||
|
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, ndims)
|
let ndarray = NDArrayType::new(context, llvm_dtype, ndims)
|
||||||
.construct_numpy_zeros(generator, context, dtype, &shape, None);
|
.construct_numpy_zeros(generator, context, dtype, &shape, None);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.ones`.
|
/// Generates LLVM IR for `ndarray.ones`.
|
||||||
@ -92,9 +92,9 @@ pub fn gen_ndarray_ones<'ctx>(
|
|||||||
|
|
||||||
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
||||||
|
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, ndims)
|
let ndarray = NDArrayType::new(context, llvm_dtype, ndims)
|
||||||
.construct_numpy_ones(generator, context, dtype, &shape, None);
|
.construct_numpy_ones(generator, context, dtype, &shape, None);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.full`.
|
/// Generates LLVM IR for `ndarray.full`.
|
||||||
@ -120,14 +120,14 @@ pub fn gen_ndarray_full<'ctx>(
|
|||||||
|
|
||||||
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
let shape = parse_numpy_int_sequence(generator, context, (shape_ty, shape_arg));
|
||||||
|
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, ndims).construct_numpy_full(
|
let ndarray = NDArrayType::new(context, llvm_dtype, ndims).construct_numpy_full(
|
||||||
generator,
|
generator,
|
||||||
context,
|
context,
|
||||||
&shape,
|
&shape,
|
||||||
fill_value_arg,
|
fill_value_arg,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_ndarray_array<'ctx>(
|
pub fn gen_ndarray_array<'ctx>(
|
||||||
@ -166,7 +166,7 @@ pub fn gen_ndarray_array<'ctx>(
|
|||||||
.construct_numpy_array(generator, context, (obj_ty, obj_arg), copy, None)
|
.construct_numpy_array(generator, context, (obj_ty, obj_arg), copy, None)
|
||||||
.atleast_nd(generator, context, ndims);
|
.atleast_nd(generator, context, ndims);
|
||||||
|
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.eye`.
|
/// Generates LLVM IR for `ndarray.eye`.
|
||||||
@ -207,7 +207,7 @@ pub fn gen_ndarray_eye<'ctx>(
|
|||||||
|
|
||||||
let (dtype, _) = unpack_ndarray_var_tys(&mut context.unifier, fun.0.ret);
|
let (dtype, _) = unpack_ndarray_var_tys(&mut context.unifier, fun.0.ret);
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(context.ctx);
|
let llvm_usize = context.get_size_type();
|
||||||
let llvm_dtype = context.get_llvm_type(generator, dtype);
|
let llvm_dtype = context.get_llvm_type(generator, dtype);
|
||||||
|
|
||||||
let nrows = context
|
let nrows = context
|
||||||
@ -223,9 +223,9 @@ pub fn gen_ndarray_eye<'ctx>(
|
|||||||
.build_int_s_extend_or_bit_cast(offset_arg.into_int_value(), llvm_usize, "")
|
.build_int_s_extend_or_bit_cast(offset_arg.into_int_value(), llvm_usize, "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, 2)
|
let ndarray = NDArrayType::new(context, llvm_dtype, 2)
|
||||||
.construct_numpy_eye(generator, context, dtype, nrows, ncols, offset, None);
|
.construct_numpy_eye(generator, context, dtype, nrows, ncols, offset, None);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.identity`.
|
/// Generates LLVM IR for `ndarray.identity`.
|
||||||
@ -244,16 +244,16 @@ pub fn gen_ndarray_identity<'ctx>(
|
|||||||
|
|
||||||
let (dtype, _) = unpack_ndarray_var_tys(&mut context.unifier, fun.0.ret);
|
let (dtype, _) = unpack_ndarray_var_tys(&mut context.unifier, fun.0.ret);
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(context.ctx);
|
let llvm_usize = context.get_size_type();
|
||||||
let llvm_dtype = context.get_llvm_type(generator, dtype);
|
let llvm_dtype = context.get_llvm_type(generator, dtype);
|
||||||
|
|
||||||
let n = context
|
let n = context
|
||||||
.builder
|
.builder
|
||||||
.build_int_s_extend_or_bit_cast(n_arg.into_int_value(), llvm_usize, "")
|
.build_int_s_extend_or_bit_cast(n_arg.into_int_value(), llvm_usize, "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ndarray = NDArrayType::new(generator, context.ctx, llvm_dtype, 2)
|
let ndarray = NDArrayType::new(context, llvm_dtype, 2)
|
||||||
.construct_numpy_identity(generator, context, dtype, n, None);
|
.construct_numpy_identity(generator, context, dtype, n, None);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.copy`.
|
/// Generates LLVM IR for `ndarray.copy`.
|
||||||
@ -272,9 +272,9 @@ pub fn gen_ndarray_copy<'ctx>(
|
|||||||
obj.as_ref().unwrap().1.clone().to_basic_value_enum(context, generator, this_ty)?;
|
obj.as_ref().unwrap().1.clone().to_basic_value_enum(context, generator, this_ty)?;
|
||||||
|
|
||||||
let this = NDArrayType::from_unifier_type(generator, context, this_ty)
|
let this = NDArrayType::from_unifier_type(generator, context, this_ty)
|
||||||
.map_value(this_arg.into_pointer_value(), None);
|
.map_pointer_value(this_arg.into_pointer_value(), None);
|
||||||
let ndarray = this.make_copy(generator, context);
|
let ndarray = this.make_copy(generator, context);
|
||||||
Ok(ndarray.as_base_value())
|
Ok(ndarray.as_abi_value(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates LLVM IR for `ndarray.fill`.
|
/// Generates LLVM IR for `ndarray.fill`.
|
||||||
@ -295,7 +295,7 @@ pub fn gen_ndarray_fill<'ctx>(
|
|||||||
let value_arg = args[0].1.clone().to_basic_value_enum(context, generator, value_ty)?;
|
let value_arg = args[0].1.clone().to_basic_value_enum(context, generator, value_ty)?;
|
||||||
|
|
||||||
let this = NDArrayType::from_unifier_type(generator, context, this_ty)
|
let this = NDArrayType::from_unifier_type(generator, context, this_ty)
|
||||||
.map_value(this_arg.into_pointer_value(), None);
|
.map_pointer_value(this_arg.into_pointer_value(), None);
|
||||||
this.fill(generator, context, value_arg);
|
this.fill(generator, context, value_arg);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -316,8 +316,10 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
|
|
||||||
match (x1, x2) {
|
match (x1, x2) {
|
||||||
(BasicValueEnum::PointerValue(n1), BasicValueEnum::PointerValue(n2)) => {
|
(BasicValueEnum::PointerValue(n1), BasicValueEnum::PointerValue(n2)) => {
|
||||||
let a = NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_value(n1, None);
|
let a =
|
||||||
let b = NDArrayType::from_unifier_type(generator, ctx, x2_ty).map_value(n2, None);
|
NDArrayType::from_unifier_type(generator, ctx, x1_ty).map_pointer_value(n1, None);
|
||||||
|
let b =
|
||||||
|
NDArrayType::from_unifier_type(generator, ctx, x2_ty).map_pointer_value(n2, None);
|
||||||
|
|
||||||
// TODO: General `np.dot()` https://numpy.org/doc/stable/reference/generated/numpy.dot.html.
|
// TODO: General `np.dot()` https://numpy.org/doc/stable/reference/generated/numpy.dot.html.
|
||||||
assert_eq!(a.get_type().ndims(), 1);
|
assert_eq!(a.get_type().ndims(), 1);
|
||||||
@ -325,8 +327,8 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let common_dtype = arraylike_flatten_element_type(&mut ctx.unifier, x1_ty);
|
let common_dtype = arraylike_flatten_element_type(&mut ctx.unifier, x1_ty);
|
||||||
|
|
||||||
// Check shapes.
|
// Check shapes.
|
||||||
let a_size = a.size(generator, ctx);
|
let a_size = a.size(ctx);
|
||||||
let b_size = b.size(generator, ctx);
|
let b_size = b.size(ctx);
|
||||||
let same_shape =
|
let same_shape =
|
||||||
ctx.builder.build_int_compare(IntPredicate::EQ, a_size, b_size, "").unwrap();
|
ctx.builder.build_int_compare(IntPredicate::EQ, a_size, b_size, "").unwrap();
|
||||||
ctx.make_assert(
|
ctx.make_assert(
|
||||||
@ -349,13 +351,13 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx,
|
ctx,
|
||||||
Some("np_dot"),
|
Some("np_dot"),
|
||||||
|generator, ctx| {
|
|generator, ctx| {
|
||||||
let a_iter = NDIterType::new(generator, ctx.ctx).construct(generator, ctx, a);
|
let a_iter = NDIterType::new(ctx).construct(generator, ctx, a);
|
||||||
let b_iter = NDIterType::new(generator, ctx.ctx).construct(generator, ctx, b);
|
let b_iter = NDIterType::new(ctx).construct(generator, ctx, b);
|
||||||
Ok((a_iter, b_iter))
|
Ok((a_iter, b_iter))
|
||||||
},
|
},
|
||||||
|generator, ctx, (a_iter, _b_iter)| {
|
|_, ctx, (a_iter, _b_iter)| {
|
||||||
// Only a_iter drives the condition, b_iter should have the same status.
|
// Only a_iter drives the condition, b_iter should have the same status.
|
||||||
Ok(a_iter.has_element(generator, ctx))
|
Ok(a_iter.has_element(ctx))
|
||||||
},
|
},
|
||||||
|_, ctx, _hooks, (a_iter, b_iter)| {
|
|_, ctx, _hooks, (a_iter, b_iter)| {
|
||||||
let a_scalar = a_iter.get_scalar(ctx);
|
let a_scalar = a_iter.get_scalar(ctx);
|
||||||
@ -385,9 +387,9 @@ pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx.builder.build_store(result, new_result).unwrap();
|
ctx.builder.build_store(result, new_result).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|generator, ctx, (a_iter, b_iter)| {
|
|_, ctx, (a_iter, b_iter)| {
|
||||||
a_iter.next(generator, ctx);
|
a_iter.next(ctx);
|
||||||
b_iter.next(generator, ctx);
|
b_iter.next(ctx);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
attributes::{Attribute, AttributeLoc},
|
attributes::{Attribute, AttributeLoc},
|
||||||
basic_block::BasicBlock,
|
basic_block::BasicBlock,
|
||||||
|
builder::Builder,
|
||||||
types::{BasicType, BasicTypeEnum},
|
types::{BasicType, BasicTypeEnum},
|
||||||
values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue},
|
values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue},
|
||||||
IntPredicate,
|
IntPredicate,
|
||||||
@ -16,10 +17,10 @@ use super::{
|
|||||||
gen_in_range_check,
|
gen_in_range_check,
|
||||||
irrt::{handle_slice_indices, list_slice_assignment},
|
irrt::{handle_slice_indices, list_slice_assignment},
|
||||||
macros::codegen_unreachable,
|
macros::codegen_unreachable,
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{RustNDIndex, ScalarOrNDArray},
|
ndarray::{RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -306,7 +307,7 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
// Handle list item assignment
|
// Handle list item assignment
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let target_item_ty = iter_type_vars(list_params).next().unwrap().ty;
|
let target_item_ty = iter_type_vars(list_params).next().unwrap().ty;
|
||||||
|
|
||||||
let target = generator
|
let target = generator
|
||||||
@ -367,10 +368,8 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_basic_value_enum(ctx, generator, key_ty)?
|
.to_basic_value_enum(ctx, generator, key_ty)?
|
||||||
.into_int_value();
|
.into_int_value();
|
||||||
let index = ctx
|
let index =
|
||||||
.builder
|
ctx.builder.build_int_s_extend(index, ctx.get_size_type(), "sext").unwrap();
|
||||||
.build_int_s_extend(index, generator.get_size_type(ctx.ctx), "sext")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// handle negative index
|
// handle negative index
|
||||||
let is_negative = ctx
|
let is_negative = ctx
|
||||||
@ -378,7 +377,7 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
.build_int_compare(
|
.build_int_compare(
|
||||||
IntPredicate::SLT,
|
IntPredicate::SLT,
|
||||||
index,
|
index,
|
||||||
generator.get_size_type(ctx.ctx).const_zero(),
|
ctx.get_size_type().const_zero(),
|
||||||
"is_neg",
|
"is_neg",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -441,7 +440,7 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
// ```
|
// ```
|
||||||
|
|
||||||
let target = NDArrayType::from_unifier_type(generator, ctx, target_ty)
|
let target = NDArrayType::from_unifier_type(generator, ctx, target_ty)
|
||||||
.map_value(target.into_pointer_value(), None);
|
.map_pointer_value(target.into_pointer_value(), None);
|
||||||
let target = target.index(generator, ctx, &key);
|
let target = target.index(generator, ctx, &key);
|
||||||
|
|
||||||
let value = ScalarOrNDArray::from_value(generator, ctx, (value_ty, value))
|
let value = ScalarOrNDArray::from_value(generator, ctx, (value_ty, value))
|
||||||
@ -450,8 +449,7 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
let broadcast_ndims =
|
let broadcast_ndims =
|
||||||
[target.get_type().ndims(), value.get_type().ndims()].into_iter().max().unwrap();
|
[target.get_type().ndims(), value.get_type().ndims()].into_iter().max().unwrap();
|
||||||
let broadcast_result = NDArrayType::new(
|
let broadcast_result = NDArrayType::new(
|
||||||
generator,
|
ctx,
|
||||||
ctx.ctx,
|
|
||||||
value.get_type().element_type(),
|
value.get_type().element_type(),
|
||||||
broadcast_ndims,
|
broadcast_ndims,
|
||||||
)
|
)
|
||||||
@ -460,7 +458,7 @@ pub fn gen_setitem<'ctx, G: CodeGenerator>(
|
|||||||
let target = broadcast_result.ndarrays[0];
|
let target = broadcast_result.ndarrays[0];
|
||||||
let value = broadcast_result.ndarrays[1];
|
let value = broadcast_result.ndarrays[1];
|
||||||
|
|
||||||
target.copy_data_from(generator, ctx, value);
|
target.copy_data_from(ctx, value);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("encountered unknown target type: {}", ctx.unifier.stringify(target_ty));
|
panic!("encountered unknown target type: {}", ctx.unifier.stringify(target_ty));
|
||||||
@ -484,7 +482,7 @@ pub fn gen_for<G: CodeGenerator>(
|
|||||||
let var_assignment = ctx.var_assignment.clone();
|
let var_assignment = ctx.var_assignment.clone();
|
||||||
|
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let size_t = generator.get_size_type(ctx.ctx);
|
let size_t = ctx.get_size_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let current = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
|
let current = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
|
||||||
let body_bb = ctx.ctx.append_basic_block(current, "for.body");
|
let body_bb = ctx.ctx.append_basic_block(current, "for.body");
|
||||||
@ -513,7 +511,7 @@ pub fn gen_for<G: CodeGenerator>(
|
|||||||
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let iter_val =
|
let iter_val =
|
||||||
RangeValue::from_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
RangeType::new(ctx).map_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
||||||
// Internal variable for loop; Cannot be assigned
|
// Internal variable for loop; Cannot be assigned
|
||||||
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
||||||
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
||||||
@ -665,11 +663,25 @@ pub fn gen_for<G: CodeGenerator>(
|
|||||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)]
|
#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)]
|
||||||
pub struct BreakContinueHooks<'ctx> {
|
pub struct BreakContinueHooks<'ctx> {
|
||||||
/// The [exit block][`BasicBlock`] to branch to when `break`-ing out of a loop.
|
/// The [exit block][`BasicBlock`] to branch to when `break`-ing out of a loop.
|
||||||
pub exit_bb: BasicBlock<'ctx>,
|
exit_bb: BasicBlock<'ctx>,
|
||||||
|
|
||||||
/// The [latch basic block][`BasicBlock`] to branch to for `continue`-ing to the next iteration
|
/// The [latch basic block][`BasicBlock`] to branch to for `continue`-ing to the next iteration
|
||||||
/// of the loop.
|
/// of the loop.
|
||||||
pub latch_bb: BasicBlock<'ctx>,
|
latch_bb: BasicBlock<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> BreakContinueHooks<'ctx> {
|
||||||
|
/// Creates a [`br` instruction][Builder::build_unconditional_branch] to the exit
|
||||||
|
/// [`BasicBlock`], as if by calling `break`.
|
||||||
|
pub fn build_break_branch(&self, builder: &Builder<'ctx>) {
|
||||||
|
builder.build_unconditional_branch(self.exit_bb).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`br` instruction][Builder::build_unconditional_branch] to the latch
|
||||||
|
/// [`BasicBlock`], as if by calling `continue`.
|
||||||
|
pub fn build_continue_branch(&self, builder: &Builder<'ctx>) {
|
||||||
|
builder.build_unconditional_branch(self.latch_bb).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a C-style `for` construct using lambdas, similar to the following C code:
|
/// Generates a C-style `for` construct using lambdas, similar to the following C code:
|
||||||
|
@ -97,7 +97,8 @@ fn test_primitives() {
|
|||||||
"};
|
"};
|
||||||
let statements = parse_program(source, FileName::default()).unwrap();
|
let statements = parse_program(source, FileName::default()).unwrap();
|
||||||
|
|
||||||
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0;
|
let context = inkwell::context::Context::create();
|
||||||
|
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
let mut unifier = composer.unifier.clone();
|
let mut unifier = composer.unifier.clone();
|
||||||
let primitives = composer.primitives_ty;
|
let primitives = composer.primitives_ty;
|
||||||
let top_level = Arc::new(composer.make_top_level_context());
|
let top_level = Arc::new(composer.make_top_level_context());
|
||||||
@ -107,7 +108,7 @@ fn test_primitives() {
|
|||||||
Arc::new(Resolver { id_to_type: HashMap::new(), id_to_def: RwLock::new(HashMap::new()) })
|
Arc::new(Resolver { id_to_type: HashMap::new(), id_to_def: RwLock::new(HashMap::new()) })
|
||||||
as Arc<dyn SymbolResolver + Send + Sync>;
|
as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
|
|
||||||
let threads = vec![DefaultCodeGenerator::new("test".into(), 32).into()];
|
let threads = vec![DefaultCodeGenerator::new("test".into(), context.i64_type()).into()];
|
||||||
let signature = FunSignature {
|
let signature = FunSignature {
|
||||||
args: vec![
|
args: vec![
|
||||||
FuncArg {
|
FuncArg {
|
||||||
@ -260,7 +261,8 @@ fn test_simple_call() {
|
|||||||
"};
|
"};
|
||||||
let statements_2 = parse_program(source_2, FileName::default()).unwrap();
|
let statements_2 = parse_program(source_2, FileName::default()).unwrap();
|
||||||
|
|
||||||
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 32).0;
|
let context = inkwell::context::Context::create();
|
||||||
|
let composer = TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
|
||||||
let mut unifier = composer.unifier.clone();
|
let mut unifier = composer.unifier.clone();
|
||||||
let primitives = composer.primitives_ty;
|
let primitives = composer.primitives_ty;
|
||||||
let top_level = Arc::new(composer.make_top_level_context());
|
let top_level = Arc::new(composer.make_top_level_context());
|
||||||
@ -307,7 +309,7 @@ fn test_simple_call() {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
let threads = vec![DefaultCodeGenerator::new("test".into(), 32).into()];
|
let threads = vec![DefaultCodeGenerator::new("test".into(), context.i64_type()).into()];
|
||||||
let mut function_data = FunctionData {
|
let mut function_data = FunctionData {
|
||||||
resolver: resolver.clone(),
|
resolver: resolver.clone(),
|
||||||
bound_variables: Vec::new(),
|
bound_variables: Vec::new(),
|
||||||
@ -439,31 +441,34 @@ fn test_simple_call() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_classes_list_type_new() {
|
fn test_classes_list_type_new() {
|
||||||
let ctx = inkwell::context::Context::create();
|
let ctx = inkwell::context::Context::create();
|
||||||
let generator = DefaultCodeGenerator::new(String::new(), 64);
|
let generator = DefaultCodeGenerator::new(String::new(), ctx.i64_type());
|
||||||
|
|
||||||
let llvm_i32 = ctx.i32_type();
|
let llvm_i32 = ctx.i32_type();
|
||||||
let llvm_usize = generator.get_size_type(&ctx);
|
let llvm_usize = generator.get_size_type(&ctx);
|
||||||
|
|
||||||
let llvm_list = ListType::new(&generator, &ctx, llvm_i32.into());
|
let llvm_list = ListType::new_with_generator(&generator, &ctx, llvm_i32.into());
|
||||||
assert!(ListType::is_representable(llvm_list.as_base_type(), llvm_usize).is_ok());
|
assert!(ListType::is_representable(llvm_list.as_abi_type(), llvm_usize).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_classes_range_type_new() {
|
fn test_classes_range_type_new() {
|
||||||
let ctx = inkwell::context::Context::create();
|
let ctx = inkwell::context::Context::create();
|
||||||
|
let generator = DefaultCodeGenerator::new(String::new(), ctx.i64_type());
|
||||||
|
|
||||||
let llvm_range = RangeType::new(&ctx);
|
let llvm_usize = generator.get_size_type(&ctx);
|
||||||
assert!(RangeType::is_representable(llvm_range.as_base_type()).is_ok());
|
|
||||||
|
let llvm_range = RangeType::new_with_generator(&generator, &ctx);
|
||||||
|
assert!(RangeType::is_representable(llvm_range.as_abi_type(), llvm_usize).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_classes_ndarray_type_new() {
|
fn test_classes_ndarray_type_new() {
|
||||||
let ctx = inkwell::context::Context::create();
|
let ctx = inkwell::context::Context::create();
|
||||||
let generator = DefaultCodeGenerator::new(String::new(), 64);
|
let generator = DefaultCodeGenerator::new(String::new(), ctx.i64_type());
|
||||||
|
|
||||||
let llvm_i32 = ctx.i32_type();
|
let llvm_i32 = ctx.i32_type();
|
||||||
let llvm_usize = generator.get_size_type(&ctx);
|
let llvm_usize = generator.get_size_type(&ctx);
|
||||||
|
|
||||||
let llvm_ndarray = NDArrayType::new(&generator, &ctx, llvm_i32.into(), 2);
|
let llvm_ndarray = NDArrayType::new_with_generator(&generator, &ctx, llvm_i32.into(), 2);
|
||||||
assert!(NDArrayType::is_representable(llvm_ndarray.as_base_type(), llvm_usize).is_ok());
|
assert!(NDArrayType::is_representable(llvm_ndarray.as_abi_type(), llvm_usize).is_ok());
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context},
|
context::Context,
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -13,8 +13,9 @@ use crate::{
|
|||||||
codegen::{
|
codegen::{
|
||||||
types::structure::{
|
types::structure::{
|
||||||
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
||||||
|
StructProxyType,
|
||||||
},
|
},
|
||||||
values::{ListValue, ProxyValue},
|
values::ListValue,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
typecheck::typedef::{iter_type_vars, Type, TypeEnum},
|
typecheck::typedef::{iter_type_vars, Type, TypeEnum},
|
||||||
@ -56,47 +57,12 @@ impl<'ctx> ListStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ListType<'ctx> {
|
impl<'ctx> ListType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `list` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = ListStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"list",
|
|
||||||
&[(fields.items.name(), &|ty| {
|
|
||||||
if ty.is_pointer_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected T* for `list.items`, got {ty}"))
|
|
||||||
}
|
|
||||||
})],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(item: BasicTypeEnum<'ctx>, llvm_usize: IntType<'ctx>) -> ListStructFields<'ctx> {
|
fn fields(item: BasicTypeEnum<'ctx>, llvm_usize: IntType<'ctx>) -> ListStructFields<'ctx> {
|
||||||
ListStructFields::new_typed(item, llvm_usize)
|
ListStructFields::new_typed(item, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`ListType::fields`].
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self, _ctx: &impl AsContextRef<'ctx>) -> ListStructFields<'ctx> {
|
|
||||||
Self::fields(self.item.unwrap_or(self.llvm_usize.into()), self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a `List`.
|
/// Creates an LLVM type corresponding to the expected structure of a `List`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(
|
fn llvm_type(
|
||||||
@ -104,7 +70,7 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
element_type: Option<BasicTypeEnum<'ctx>>,
|
element_type: Option<BasicTypeEnum<'ctx>>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> PointerType<'ctx> {
|
) -> PointerType<'ctx> {
|
||||||
let element_type = element_type.unwrap_or(llvm_usize.into());
|
let element_type = element_type.map_or(llvm_usize.into(), |ty| ty.as_basic_type_enum());
|
||||||
|
|
||||||
let field_tys =
|
let field_tys =
|
||||||
Self::fields(element_type, llvm_usize).into_iter().map(|field| field.1).collect_vec();
|
Self::fields(element_type, llvm_usize).into_iter().map(|field| field.1).collect_vec();
|
||||||
@ -112,26 +78,45 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_impl(
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
element_type: Option<BasicTypeEnum<'ctx>>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
let llvm_list = Self::llvm_type(ctx, element_type, llvm_usize);
|
||||||
|
|
||||||
|
Self { ty: llvm_list, item: element_type, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`ListType`].
|
/// Creates an instance of [`ListType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>, element_type: &impl BasicType<'ctx>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, Some(element_type.as_basic_type_enum()), ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ListType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
generator: &G,
|
generator: &G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
element_type: BasicTypeEnum<'ctx>,
|
element_type: BasicTypeEnum<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx, Some(element_type.as_basic_type_enum()), generator.get_size_type(ctx))
|
||||||
let llvm_list = Self::llvm_type(ctx, Some(element_type), llvm_usize);
|
|
||||||
|
|
||||||
Self { ty: llvm_list, item: Some(element_type), llvm_usize }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`ListType`] with an unknown element type.
|
/// Creates an instance of [`ListType`] with an unknown element type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_untyped<G: CodeGenerator + ?Sized>(generator: &G, ctx: &'ctx Context) -> Self {
|
pub fn new_untyped(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx.ctx, None, ctx.get_size_type())
|
||||||
let llvm_list = Self::llvm_type(ctx, None, llvm_usize);
|
}
|
||||||
|
|
||||||
Self { ty: llvm_list, item: None, llvm_usize }
|
/// Creates an instance of [`ListType`] with an unknown element type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_untyped_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, None, generator.get_size_type(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ListType`] from a [unifier type][Type].
|
/// Creates an [`ListType`] from a [unifier type][Type].
|
||||||
@ -152,24 +137,26 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
_ => panic!("Expected `list` type, but got {}", ctx.unifier.stringify(ty)),
|
_ => panic!("Expected `list` type, but got {}", ctx.unifier.stringify(ty)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_elem_type = if let TypeEnum::TVar { .. } = &*ctx.unifier.get_ty_immutable(ty) {
|
let llvm_elem_type = if let TypeEnum::TVar { .. } = &*ctx.unifier.get_ty_immutable(ty) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(ctx.get_llvm_type(generator, elem_type))
|
Some(ctx.get_llvm_type(generator, elem_type))
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self::new_impl(ctx.ctx, llvm_elem_type, llvm_usize)
|
||||||
ty: Self::llvm_type(ctx.ctx, llvm_elem_type, llvm_usize),
|
}
|
||||||
item: llvm_elem_type,
|
|
||||||
llvm_usize,
|
/// Creates an [`ListType`] from a [`StructType`].
|
||||||
}
|
#[must_use]
|
||||||
|
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ListType`] from a [`PointerType`].
|
/// Creates an [`ListType`] from a [`PointerType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
let ctx = ptr_ty.get_context();
|
let ctx = ptr_ty.get_context();
|
||||||
|
|
||||||
@ -273,7 +260,7 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let plist = self.alloca_var(generator, ctx, name);
|
let plist = self.alloca_var(generator, ctx, name);
|
||||||
plist.store_size(ctx, generator, len);
|
plist.store_size(ctx, len);
|
||||||
|
|
||||||
let item = self.item.unwrap_or(self.llvm_usize.into());
|
let item = self.item.unwrap_or(self.llvm_usize.into());
|
||||||
plist.create_data(ctx, item, None);
|
plist.create_data(ctx, item, None);
|
||||||
@ -300,7 +287,7 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
let plist = self.alloca_var(generator, ctx, name);
|
let plist = self.alloca_var(generator, ctx, name);
|
||||||
|
|
||||||
plist.store_size(ctx, generator, self.llvm_usize.const_zero());
|
plist.store_size(ctx, self.llvm_usize.const_zero());
|
||||||
plist.create_data(ctx, self.item.unwrap_or(self.llvm_usize.into()), None);
|
plist.create_data(ctx, self.item.unwrap_or(self.llvm_usize.into()), None);
|
||||||
|
|
||||||
plist
|
plist
|
||||||
@ -308,9 +295,27 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
|
|
||||||
/// Converts an existing value into a [`ListValue`].
|
/// Converts an existing value into a [`ListValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`ListValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
||||||
@ -318,36 +323,64 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ListValue<'ctx>;
|
type Value = ListValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = ListStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"list",
|
||||||
|
&[(fields.items.name(), &|ty| {
|
||||||
|
if ty.is_pointer_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected T* for `list.items`, got {ty}"))
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for ListType<'ctx> {
|
||||||
|
type StructFields = ListStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.item.unwrap_or(self.llvm_usize.into()), self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<ListType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<ListType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
//! on the stack.
|
//! on the stack.
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
types::{BasicType, IntType},
|
||||||
types::BasicType,
|
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,25 +38,24 @@ pub mod utils;
|
|||||||
|
|
||||||
/// A LLVM type that is used to represent a corresponding type in NAC3.
|
/// A LLVM type that is used to represent a corresponding type in NAC3.
|
||||||
pub trait ProxyType<'ctx>: Into<Self::Base> {
|
pub trait ProxyType<'ctx>: Into<Self::Base> {
|
||||||
/// The LLVM type of which values of this type possess. This is usually a
|
/// The ABI type of which values of this type possess.
|
||||||
/// [LLVM pointer type][PointerType] for any non-primitive types.
|
type ABI: BasicType<'ctx>;
|
||||||
|
|
||||||
|
/// The LLVM type of which values of this type possess.
|
||||||
type Base: BasicType<'ctx>;
|
type Base: BasicType<'ctx>;
|
||||||
|
|
||||||
/// The type of values represented by this type.
|
/// The type of values represented by this type.
|
||||||
type Value: ProxyValue<'ctx, Type = Self>;
|
type Value: ProxyValue<'ctx, Type = Self>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
/// Checks whether `llvm_ty` can be represented by this [`ProxyType`].
|
||||||
generator: &G,
|
fn is_representable(
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String>;
|
) -> Result<(), String>;
|
||||||
|
|
||||||
/// Checks whether `llvm_ty` can be represented by this [`ProxyType`].
|
/// Checks whether the type represented by `ty` expresses the same type represented by this
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
/// [`ProxyType`].
|
||||||
generator: &G,
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String>;
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String>;
|
|
||||||
|
|
||||||
/// Returns the type that should be used in `alloca` IR statements.
|
/// Returns the type that should be used in `alloca` IR statements.
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx>;
|
fn alloca_type(&self) -> impl BasicType<'ctx>;
|
||||||
@ -122,4 +120,10 @@ pub trait ProxyType<'ctx>: Into<Self::Base> {
|
|||||||
|
|
||||||
/// Returns the [base type][Self::Base] of this proxy.
|
/// Returns the [base type][Self::Base] of this proxy.
|
||||||
fn as_base_type(&self) -> Self::Base;
|
fn as_base_type(&self) -> Self::Base;
|
||||||
|
|
||||||
|
/// Returns this proxy as its ABI type, i.e. the expected type representation if a value of this
|
||||||
|
/// [`ProxyType`] is being passed into or returned from a function.
|
||||||
|
///
|
||||||
|
/// See [`CodeGenContext::get_llvm_abi_type`].
|
||||||
|
fn as_abi_type(&self) -> Self::ABI;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
assert!(self.ndims >= ndims_int);
|
assert!(self.ndims >= ndims_int);
|
||||||
assert_eq!(dtype, self.dtype);
|
assert_eq!(dtype, self.dtype);
|
||||||
|
|
||||||
let list_value = list.as_i8_list(generator, ctx);
|
let list_value = list.as_i8_list(ctx);
|
||||||
|
|
||||||
// Validate `list` has a consistent shape.
|
// Validate `list` has a consistent shape.
|
||||||
// Raise an exception if `list` is something abnormal like `[[1, 2], [3]]`.
|
// Raise an exception if `list` is something abnormal like `[[1, 2], [3]]`.
|
||||||
@ -61,15 +61,13 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
generator, ctx, list_value, ndims, &shape,
|
generator, ctx, list_value, ndims, &shape,
|
||||||
);
|
);
|
||||||
|
|
||||||
let ndarray = Self::new(generator, ctx.ctx, dtype, ndims_int)
|
let ndarray =
|
||||||
.construct_uninitialized(generator, ctx, name);
|
Self::new(ctx, dtype, ndims_int).construct_uninitialized(generator, ctx, name);
|
||||||
ndarray.copy_shape_from_array(generator, ctx, shape.base_ptr(ctx, generator));
|
ndarray.copy_shape_from_array(generator, ctx, shape.base_ptr(ctx, generator));
|
||||||
unsafe { ndarray.create_data(generator, ctx) };
|
unsafe { ndarray.create_data(generator, ctx) };
|
||||||
|
|
||||||
// Copy all contents from the list.
|
// Copy all contents from the list.
|
||||||
irrt::ndarray::call_nac3_ndarray_array_write_list_to_array(
|
irrt::ndarray::call_nac3_ndarray_array_write_list_to_array(ctx, list_value, ndarray);
|
||||||
generator, ctx, list_value, ndarray,
|
|
||||||
);
|
|
||||||
|
|
||||||
ndarray
|
ndarray
|
||||||
}
|
}
|
||||||
@ -98,8 +96,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
|
|
||||||
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
|
||||||
|
|
||||||
let ndarray = Self::new(generator, ctx.ctx, dtype, 1)
|
let ndarray = Self::new(ctx, dtype, 1).construct_uninitialized(generator, ctx, name);
|
||||||
.construct_uninitialized(generator, ctx, name);
|
|
||||||
|
|
||||||
// Set data
|
// Set data
|
||||||
let data = ctx
|
let data = ctx
|
||||||
@ -116,7 +113,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set strides, the `data` is contiguous
|
// Set strides, the `data` is contiguous
|
||||||
ndarray.set_strides_contiguous(generator, ctx);
|
ndarray.set_strides_contiguous(ctx);
|
||||||
|
|
||||||
ndarray
|
ndarray
|
||||||
} else {
|
} else {
|
||||||
@ -154,7 +151,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
(list_ty, list),
|
(list_ty, list),
|
||||||
name,
|
name,
|
||||||
);
|
);
|
||||||
Ok(Some(ndarray.as_base_value()))
|
Ok(Some(ndarray.as_abi_value(ctx)))
|
||||||
},
|
},
|
||||||
|generator, ctx| {
|
|generator, ctx| {
|
||||||
let ndarray = self.construct_numpy_array_from_list_copy_none_impl(
|
let ndarray = self.construct_numpy_array_from_list_copy_none_impl(
|
||||||
@ -163,14 +160,14 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
(list_ty, list),
|
(list_ty, list),
|
||||||
name,
|
name,
|
||||||
);
|
);
|
||||||
Ok(Some(ndarray.as_base_value()))
|
Ok(Some(ndarray.as_abi_value(ctx)))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(BasicValueEnum::into_pointer_value)
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
NDArrayType::new(generator, ctx.ctx, dtype, ndims).map_value(ndarray, None)
|
NDArrayType::new(ctx, dtype, ndims).map_pointer_value(ndarray, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of `np_array(<ndarray>, copy=copy)`.
|
/// Implementation of `np_array(<ndarray>, copy=copy)`.
|
||||||
@ -192,18 +189,18 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
|_generator, _ctx| Ok(copy),
|
|_generator, _ctx| Ok(copy),
|
||||||
|generator, ctx| {
|
|generator, ctx| {
|
||||||
let ndarray = ndarray.make_copy(generator, ctx); // Force copy
|
let ndarray = ndarray.make_copy(generator, ctx); // Force copy
|
||||||
Ok(Some(ndarray.as_base_value()))
|
Ok(Some(ndarray.as_abi_value(ctx)))
|
||||||
},
|
},
|
||||||
|_generator, _ctx| {
|
|_generator, ctx| {
|
||||||
// No need to copy. Return `ndarray` itself.
|
// No need to copy. Return `ndarray` itself.
|
||||||
Ok(Some(ndarray.as_base_value()))
|
Ok(Some(ndarray.as_abi_value(ctx)))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(BasicValueEnum::into_pointer_value)
|
.map(BasicValueEnum::into_pointer_value)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
ndarray.get_type().map_value(ndarray_val, name)
|
ndarray.get_type().map_pointer_value(ndarray_val, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new ndarray like
|
/// Create a new ndarray like
|
||||||
@ -225,7 +222,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let list = ListType::from_unifier_type(generator, ctx, object_ty)
|
let list = ListType::from_unifier_type(generator, ctx, object_ty)
|
||||||
.map_value(object.into_pointer_value(), None);
|
.map_pointer_value(object.into_pointer_value(), None);
|
||||||
self.construct_numpy_array_list_impl(generator, ctx, (object_ty, list), copy, name)
|
self.construct_numpy_array_list_impl(generator, ctx, (object_ty, list), copy, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +230,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, object_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, object_ty)
|
||||||
.map_value(object.into_pointer_value(), None);
|
.map_pointer_value(object.into_pointer_value(), None);
|
||||||
self.construct_numpy_array_ndarray_impl(generator, ctx, ndarray, copy, name)
|
self.construct_numpy_array_ndarray_impl(generator, ctx, ndarray, copy, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context},
|
context::{AsContextRef, Context},
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -10,10 +10,10 @@ use nac3core_derive::StructFields;
|
|||||||
|
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
types::{
|
types::{
|
||||||
structure::{check_struct_type_matches_fields, StructField, StructFields},
|
structure::{check_struct_type_matches_fields, StructField, StructFields, StructProxyType},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
},
|
},
|
||||||
values::{ndarray::ShapeEntryValue, ProxyValue},
|
values::ndarray::ShapeEntryValue,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,28 +32,6 @@ pub struct ShapeEntryStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ShapeEntryType<'ctx> {
|
impl<'ctx> ShapeEntryType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a [`ShapeEntryType`], returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ndarray_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ShapeEntry` type, got {llvm_ndarray_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDArray",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -63,13 +41,6 @@ impl<'ctx> ShapeEntryType<'ctx> {
|
|||||||
ShapeEntryStructFields::new(ctx, llvm_usize)
|
ShapeEntryStructFields::new(ctx, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`ShapeEntryStructFields::fields`].
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self, ctx: impl AsContextRef<'ctx>) -> ShapeEntryStructFields<'ctx> {
|
|
||||||
Self::fields(ctx, self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a `ShapeEntry`.
|
/// Creates an LLVM type corresponding to the expected structure of a `ShapeEntry`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
@ -79,19 +50,37 @@ impl<'ctx> ShapeEntryType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`ShapeEntryType`].
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
#[must_use]
|
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(generator: &G, ctx: &'ctx Context) -> Self {
|
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
|
||||||
let llvm_ty = Self::llvm_type(ctx, llvm_usize);
|
let llvm_ty = Self::llvm_type(ctx, llvm_usize);
|
||||||
|
|
||||||
Self { ty: llvm_ty, llvm_usize }
|
Self { ty: llvm_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ShapeEntryType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ShapeEntryType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`ShapeEntryType`] from a [`StructType`] representing an `ShapeEntry`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a [`ShapeEntryType`] from a [`PointerType`] representing an `ShapeEntry`.
|
/// Creates a [`ShapeEntryType`] from a [`PointerType`] representing an `ShapeEntry`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -127,9 +116,27 @@ impl<'ctx> ShapeEntryType<'ctx> {
|
|||||||
|
|
||||||
/// Converts an existing value into a [`ShapeEntryValue`].
|
/// Converts an existing value into a [`ShapeEntryValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`ShapeEntryValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
||||||
@ -137,36 +144,58 @@ impl<'ctx> ShapeEntryType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for ShapeEntryType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for ShapeEntryType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ShapeEntryValue<'ctx>;
|
type Value = ShapeEntryValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ndarray_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ShapeEntry` type, got {llvm_ndarray_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDArray",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for ShapeEntryType<'ctx> {
|
||||||
|
type StructFields = ShapeEntryStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.ty.get_context(), self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<ShapeEntryType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<ShapeEntryType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -13,10 +13,11 @@ use crate::{
|
|||||||
types::{
|
types::{
|
||||||
structure::{
|
structure::{
|
||||||
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
||||||
|
StructProxyType,
|
||||||
},
|
},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
},
|
},
|
||||||
values::{ndarray::ContiguousNDArrayValue, ProxyValue},
|
values::ndarray::ContiguousNDArrayValue,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
toplevel::numpy::unpack_ndarray_var_tys,
|
toplevel::numpy::unpack_ndarray_var_tys,
|
||||||
@ -58,36 +59,6 @@ impl<'ctx> ContiguousNDArrayStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ContiguousNDArrayType<'ctx> {
|
impl<'ctx> ContiguousNDArrayType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndarray` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = ContiguousNDArrayStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"ContiguousNDArray",
|
|
||||||
&[(fields.data.name(), &|ty| {
|
|
||||||
if ty.is_pointer_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected T* for `ContiguousNDArray.data`, got {ty}"))
|
|
||||||
}
|
|
||||||
})],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -97,13 +68,6 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
ContiguousNDArrayStructFields::new_typed(item, llvm_usize)
|
ContiguousNDArrayStructFields::new_typed(item, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`NDArrayType::fields`].
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self) -> ContiguousNDArrayStructFields<'ctx> {
|
|
||||||
Self::fields(self.item, self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of an `NDArray`.
|
/// Creates an LLVM type corresponding to the expected structure of an `NDArray`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(
|
fn llvm_type(
|
||||||
@ -117,17 +81,26 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_impl(ctx: &'ctx Context, item: BasicTypeEnum<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
let llvm_cndarray = Self::llvm_type(ctx, item, llvm_usize);
|
||||||
|
|
||||||
|
Self { ty: llvm_cndarray, item, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`ContiguousNDArrayType`].
|
/// Creates an instance of [`ContiguousNDArrayType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>, item: &impl BasicType<'ctx>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, item.as_basic_type_enum(), ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`ContiguousNDArrayType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
generator: &G,
|
generator: &G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
item: BasicTypeEnum<'ctx>,
|
item: BasicTypeEnum<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx, item, generator.get_size_type(ctx))
|
||||||
let llvm_cndarray = Self::llvm_type(ctx, item, llvm_usize);
|
|
||||||
|
|
||||||
Self { ty: llvm_cndarray, item, llvm_usize }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ContiguousNDArrayType`] from a [unifier type][Type].
|
/// Creates an [`ContiguousNDArrayType`] from a [unifier type][Type].
|
||||||
@ -140,19 +113,28 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
let (dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
let (dtype, _) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
|
|
||||||
let llvm_dtype = ctx.get_llvm_type(generator, dtype);
|
let llvm_dtype = ctx.get_llvm_type(generator, dtype);
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
||||||
|
|
||||||
Self { ty: Self::llvm_type(ctx.ctx, llvm_dtype, llvm_usize), item: llvm_dtype, llvm_usize }
|
Self::new_impl(ctx.ctx, llvm_dtype, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`ContiguousNDArrayType`] from a [`StructType`] representing an `NDArray`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(
|
||||||
|
ty: StructType<'ctx>,
|
||||||
|
item: BasicTypeEnum<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), item, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ContiguousNDArrayType`] from a [`PointerType`] representing an `NDArray`.
|
/// Creates an [`ContiguousNDArrayType`] from a [`PointerType`] representing an `NDArray`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(
|
pub fn from_pointer_type(
|
||||||
ptr_ty: PointerType<'ctx>,
|
ptr_ty: PointerType<'ctx>,
|
||||||
item: BasicTypeEnum<'ctx>,
|
item: BasicTypeEnum<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, item, llvm_usize }
|
Self { ty: ptr_ty, item, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -196,9 +178,28 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
|
|
||||||
/// Converts an existing value into a [`ContiguousNDArrayValue`].
|
/// Converts an existing value into a [`ContiguousNDArrayValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.item,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`ContiguousNDArrayValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
@ -211,36 +212,66 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for ContiguousNDArrayType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for ContiguousNDArrayType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ContiguousNDArrayValue<'ctx>;
|
type Value = ContiguousNDArrayValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = ContiguousNDArrayStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"ContiguousNDArray",
|
||||||
|
&[(fields.data.name(), &|ty| {
|
||||||
|
if ty.is_pointer_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected T* for `ContiguousNDArray.data`, got {ty}"))
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for ContiguousNDArrayType<'ctx> {
|
||||||
|
type StructFields = ContiguousNDArrayStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.item, self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<ContiguousNDArrayType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<ContiguousNDArrayType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context},
|
context::{AsContextRef, Context},
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -10,12 +10,12 @@ use nac3core_derive::StructFields;
|
|||||||
|
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
types::{
|
types::{
|
||||||
structure::{check_struct_type_matches_fields, StructField, StructFields},
|
structure::{check_struct_type_matches_fields, StructField, StructFields, StructProxyType},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
},
|
},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDIndexValue, RustNDIndex},
|
ndarray::{NDIndexValue, RustNDIndex},
|
||||||
ArrayLikeIndexer, ArraySliceValue, ProxyValue,
|
ArrayLikeIndexer, ArraySliceValue,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -35,25 +35,6 @@ pub struct NDIndexStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIndexType<'ctx> {
|
impl<'ctx> NDIndexType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndindex` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = NDIndexStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(fields, llvm_ty, "NDIndex", &[])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
ctx: impl AsContextRef<'ctx>,
|
ctx: impl AsContextRef<'ctx>,
|
||||||
@ -62,11 +43,6 @@ impl<'ctx> NDIndexType<'ctx> {
|
|||||||
NDIndexStructFields::new(ctx, llvm_usize)
|
NDIndexStructFields::new(ctx, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self) -> NDIndexStructFields<'ctx> {
|
|
||||||
Self::fields(self.ty.get_context(), self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
let field_tys =
|
let field_tys =
|
||||||
@ -75,17 +51,33 @@ impl<'ctx> NDIndexType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(generator: &G, ctx: &'ctx Context) -> Self {
|
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
|
||||||
let llvm_ndindex = Self::llvm_type(ctx, llvm_usize);
|
let llvm_ndindex = Self::llvm_type(ctx, llvm_usize);
|
||||||
|
|
||||||
Self { ty: llvm_ndindex, llvm_usize }
|
Self { ty: llvm_ndindex, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -156,9 +148,26 @@ impl<'ctx> NDIndexType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
||||||
@ -166,36 +175,55 @@ impl<'ctx> NDIndexType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for NDIndexType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for NDIndexType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDIndexValue<'ctx>;
|
type Value = NDIndexValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = NDIndexStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(fields, llvm_ty, "NDIndex", &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for NDIndexType<'ctx> {
|
||||||
|
type StructFields = NDIndexStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.ty.get_context(), self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<NDIndexType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<NDIndexType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -46,9 +46,8 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
let out_ndarray = match out {
|
let out_ndarray = match out {
|
||||||
NDArrayOut::NewNDArray { dtype } => {
|
NDArrayOut::NewNDArray { dtype } => {
|
||||||
// Create a new ndarray based on the broadcast shape.
|
// Create a new ndarray based on the broadcast shape.
|
||||||
let result_ndarray =
|
let result_ndarray = NDArrayType::new(ctx, dtype, broadcast_result.ndims)
|
||||||
NDArrayType::new(generator, ctx.ctx, dtype, broadcast_result.ndims)
|
.construct_uninitialized(generator, ctx, None);
|
||||||
.construct_uninitialized(generator, ctx, None);
|
|
||||||
result_ndarray.copy_shape_from_array(
|
result_ndarray.copy_shape_from_array(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
@ -70,7 +69,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Map element-wise and store results into `mapped_ndarray`.
|
// Map element-wise and store results into `mapped_ndarray`.
|
||||||
let nditer = NDIterType::new(generator, ctx.ctx).construct(generator, ctx, out_ndarray);
|
let nditer = NDIterType::new(ctx).construct(generator, ctx, out_ndarray);
|
||||||
gen_for_callback(
|
gen_for_callback(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
@ -80,16 +79,14 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
let other_nditers = broadcast_result
|
let other_nditers = broadcast_result
|
||||||
.ndarrays
|
.ndarrays
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ndarray| {
|
.map(|ndarray| NDIterType::new(ctx).construct(generator, ctx, *ndarray))
|
||||||
NDIterType::new(generator, ctx.ctx).construct(generator, ctx, *ndarray)
|
|
||||||
})
|
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
Ok((nditer, other_nditers))
|
Ok((nditer, other_nditers))
|
||||||
},
|
},
|
||||||
|generator, ctx, (out_nditer, _in_nditers)| {
|
|_, ctx, (out_nditer, _in_nditers)| {
|
||||||
// We can simply use `out_nditer`'s `has_element()`.
|
// We can simply use `out_nditer`'s `has_element()`.
|
||||||
// `in_nditers`' `has_element()`s should return the same value.
|
// `in_nditers`' `has_element()`s should return the same value.
|
||||||
Ok(out_nditer.has_element(generator, ctx))
|
Ok(out_nditer.has_element(ctx))
|
||||||
},
|
},
|
||||||
|generator, ctx, _hooks, (out_nditer, in_nditers)| {
|
|generator, ctx, _hooks, (out_nditer, in_nditers)| {
|
||||||
// Get all the scalars from the broadcasted input ndarrays, pass them to `mapping`,
|
// Get all the scalars from the broadcasted input ndarrays, pass them to `mapping`,
|
||||||
@ -104,10 +101,10 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|generator, ctx, (out_nditer, in_nditers)| {
|
|_, ctx, (out_nditer, in_nditers)| {
|
||||||
// Advance all iterators
|
// Advance all iterators
|
||||||
out_nditer.next(generator, ctx);
|
out_nditer.next(ctx);
|
||||||
in_nditers.iter().for_each(|nditer| nditer.next(generator, ctx));
|
in_nditers.iter().for_each(|nditer| nditer.next(ctx));
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
@ -169,8 +166,7 @@ impl<'ctx> ScalarOrNDArray<'ctx> {
|
|||||||
// Promote all input to ndarrays and map through them.
|
// Promote all input to ndarrays and map through them.
|
||||||
let inputs = inputs.iter().map(|input| input.to_ndarray(generator, ctx)).collect_vec();
|
let inputs = inputs.iter().map(|input| input.to_ndarray(generator, ctx)).collect_vec();
|
||||||
let ndarray = NDArrayType::new_broadcast(
|
let ndarray = NDArrayType::new_broadcast(
|
||||||
generator,
|
ctx,
|
||||||
ctx.ctx,
|
|
||||||
ret_dtype,
|
ret_dtype,
|
||||||
&inputs.iter().map(NDArrayValue::get_type).collect_vec(),
|
&inputs.iter().map(NDArrayValue::get_type).collect_vec(),
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context},
|
context::{AsContextRef, Context},
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{BasicValue, IntValue, PointerValue},
|
values::{BasicValue, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -9,12 +9,12 @@ use itertools::Itertools;
|
|||||||
use nac3core_derive::StructFields;
|
use nac3core_derive::StructFields;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
structure::{check_struct_type_matches_fields, StructField, StructFields},
|
structure::{check_struct_type_matches_fields, StructField, StructFields, StructProxyType},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
values::{ndarray::NDArrayValue, ProxyValue, TypedArrayLikeMutator},
|
values::{ndarray::NDArrayValue, TypedArrayLikeMutator},
|
||||||
{CodeGenContext, CodeGenerator},
|
{CodeGenContext, CodeGenerator},
|
||||||
},
|
},
|
||||||
toplevel::{helper::extract_ndims, numpy::unpack_ndarray_var_tys},
|
toplevel::{helper::extract_ndims, numpy::unpack_ndarray_var_tys},
|
||||||
@ -62,26 +62,6 @@ pub struct NDArrayStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDArrayType<'ctx> {
|
impl<'ctx> NDArrayType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndarray` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ndarray_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
|
||||||
return Err(format!("Expected struct type for `NDArray` type, got {llvm_ndarray_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDArray",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -91,13 +71,6 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
NDArrayStructFields::new(ctx, llvm_usize)
|
NDArrayStructFields::new(ctx, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`NDArrayType::fields`].
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self, ctx: impl AsContextRef<'ctx>) -> NDArrayStructFields<'ctx> {
|
|
||||||
Self::fields(ctx, self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of an `NDArray`.
|
/// Creates an LLVM type corresponding to the expected structure of an `NDArray`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
@ -107,24 +80,56 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`NDArrayType`].
|
fn new_impl(
|
||||||
#[must_use]
|
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
dtype: BasicTypeEnum<'ctx>,
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
ndims: u64,
|
ndims: u64,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
|
||||||
let llvm_ndarray = Self::llvm_type(ctx, llvm_usize);
|
let llvm_ndarray = Self::llvm_type(ctx, llvm_usize);
|
||||||
|
|
||||||
NDArrayType { ty: llvm_ndarray, dtype, ndims, llvm_usize }
|
NDArrayType { ty: llvm_ndarray, dtype, ndims, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDArrayType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>, dtype: BasicTypeEnum<'ctx>, ndims: u64) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, dtype, ndims, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDArrayType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
|
ndims: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, dtype, ndims, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`NDArrayType`] as a result of a broadcast operation over one or more
|
/// Creates an instance of [`NDArrayType`] as a result of a broadcast operation over one or more
|
||||||
/// `ndarray` operands.
|
/// `ndarray` operands.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_broadcast<G: CodeGenerator + ?Sized>(
|
pub fn new_broadcast(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
|
inputs: &[NDArrayType<'ctx>],
|
||||||
|
) -> Self {
|
||||||
|
assert!(!inputs.is_empty());
|
||||||
|
|
||||||
|
Self::new_impl(
|
||||||
|
ctx.ctx,
|
||||||
|
dtype,
|
||||||
|
inputs.iter().map(NDArrayType::ndims).max().unwrap(),
|
||||||
|
ctx.get_size_type(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDArrayType`] as a result of a broadcast operation over one or more
|
||||||
|
/// `ndarray` operands.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_broadcast_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
generator: &G,
|
generator: &G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
dtype: BasicTypeEnum<'ctx>,
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
@ -132,20 +137,28 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
assert!(!inputs.is_empty());
|
assert!(!inputs.is_empty());
|
||||||
|
|
||||||
Self::new(generator, ctx, dtype, inputs.iter().map(NDArrayType::ndims).max().unwrap())
|
Self::new_impl(
|
||||||
|
ctx,
|
||||||
|
dtype,
|
||||||
|
inputs.iter().map(NDArrayType::ndims).max().unwrap(),
|
||||||
|
generator.get_size_type(ctx),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`NDArrayType`] with `ndims` of 0.
|
/// Creates an instance of [`NDArrayType`] with `ndims` of 0.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_unsized<G: CodeGenerator + ?Sized>(
|
pub fn new_unsized(ctx: &CodeGenContext<'ctx, '_>, dtype: BasicTypeEnum<'ctx>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, dtype, 0, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDArrayType`] with `ndims` of 0.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_unsized_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
generator: &G,
|
generator: &G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
dtype: BasicTypeEnum<'ctx>,
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx, dtype, 0, generator.get_size_type(ctx))
|
||||||
let llvm_ndarray = Self::llvm_type(ctx, llvm_usize);
|
|
||||||
|
|
||||||
NDArrayType { ty: llvm_ndarray, dtype, ndims: 0, llvm_usize }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`NDArrayType`] from a [unifier type][Type].
|
/// Creates an [`NDArrayType`] from a [unifier type][Type].
|
||||||
@ -158,26 +171,31 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
let (dtype, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
let (dtype, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, ty);
|
||||||
|
|
||||||
let llvm_dtype = ctx.get_llvm_type(generator, dtype);
|
let llvm_dtype = ctx.get_llvm_type(generator, dtype);
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
|
||||||
let ndims = extract_ndims(&ctx.unifier, ndims);
|
let ndims = extract_ndims(&ctx.unifier, ndims);
|
||||||
|
|
||||||
NDArrayType {
|
Self::new_impl(ctx.ctx, llvm_dtype, ndims, ctx.get_size_type())
|
||||||
ty: Self::llvm_type(ctx.ctx, llvm_usize),
|
}
|
||||||
dtype: llvm_dtype,
|
|
||||||
ndims,
|
/// Creates an [`NDArrayType`] from a [`StructType`] representing an `NDArray`.
|
||||||
llvm_usize,
|
#[must_use]
|
||||||
}
|
pub fn from_struct_type(
|
||||||
|
ty: StructType<'ctx>,
|
||||||
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
|
ndims: u64,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), dtype, ndims, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`NDArrayType`] from a [`PointerType`] representing an `NDArray`.
|
/// Creates an [`NDArrayType`] from a [`PointerType`] representing an `NDArray`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(
|
pub fn from_pointer_type(
|
||||||
ptr_ty: PointerType<'ctx>,
|
ptr_ty: PointerType<'ctx>,
|
||||||
dtype: BasicTypeEnum<'ctx>,
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
ndims: u64,
|
ndims: u64,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
NDArrayType { ty: ptr_ty, dtype, ndims, llvm_usize }
|
NDArrayType { ty: ptr_ty, dtype, ndims, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -259,9 +277,9 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
.builder
|
.builder
|
||||||
.build_int_truncate_or_bit_cast(self.dtype.size_of().unwrap(), self.llvm_usize, "")
|
.build_int_truncate_or_bit_cast(self.dtype.size_of().unwrap(), self.llvm_usize, "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ndarray.store_itemsize(ctx, generator, itemsize);
|
ndarray.store_itemsize(ctx, itemsize);
|
||||||
|
|
||||||
ndarray.store_ndims(ctx, generator, ndims);
|
ndarray.store_ndims(ctx, ndims);
|
||||||
|
|
||||||
ndarray.create_shape(ctx, self.llvm_usize, ndims);
|
ndarray.create_shape(ctx, self.llvm_usize, ndims);
|
||||||
ndarray.create_strides(ctx, self.llvm_usize, ndims);
|
ndarray.create_strides(ctx, self.llvm_usize, ndims);
|
||||||
@ -304,10 +322,10 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
assert_eq!(shape.len() as u64, self.ndims);
|
assert_eq!(shape.len() as u64, self.ndims);
|
||||||
|
|
||||||
let ndarray = Self::new(generator, ctx.ctx, self.dtype, shape.len() as u64)
|
let ndarray = Self::new(ctx, self.dtype, shape.len() as u64)
|
||||||
.construct_uninitialized(generator, ctx, name);
|
.construct_uninitialized(generator, ctx, name);
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
// Write shape
|
// Write shape
|
||||||
let ndarray_shape = ndarray.shape();
|
let ndarray_shape = ndarray.shape();
|
||||||
@ -339,10 +357,10 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
assert_eq!(shape.len() as u64, self.ndims);
|
assert_eq!(shape.len() as u64, self.ndims);
|
||||||
|
|
||||||
let ndarray = Self::new(generator, ctx.ctx, self.dtype, shape.len() as u64)
|
let ndarray = Self::new(ctx, self.dtype, shape.len() as u64)
|
||||||
.construct_uninitialized(generator, ctx, name);
|
.construct_uninitialized(generator, ctx, name);
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
// Write shape
|
// Write shape
|
||||||
let ndarray_shape = ndarray.shape();
|
let ndarray_shape = ndarray.shape();
|
||||||
@ -389,17 +407,37 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
.build_pointer_cast(data, ctx.ctx.i8_type().ptr_type(AddressSpace::default()), "")
|
.build_pointer_cast(data, ctx.ctx.i8_type().ptr_type(AddressSpace::default()), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ndarray = Self::new_unsized(generator, ctx.ctx, value.get_type())
|
let ndarray =
|
||||||
.construct_uninitialized(generator, ctx, name);
|
Self::new_unsized(ctx, value.get_type()).construct_uninitialized(generator, ctx, name);
|
||||||
ctx.builder.build_store(ndarray.ptr_to_data(ctx), data).unwrap();
|
ctx.builder.build_store(ndarray.ptr_to_data(ctx), data).unwrap();
|
||||||
ndarray
|
ndarray
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an existing value into a [`NDArrayValue`].
|
/// Converts an existing value into a [`NDArrayValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.dtype,
|
||||||
|
self.ndims,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`NDArrayValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
@ -413,36 +451,56 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDArrayValue<'ctx>;
|
type Value = NDArrayValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ndarray_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `NDArray` type, got {llvm_ndarray_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDArray",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for NDArrayType<'ctx> {
|
||||||
|
type StructFields = NDArrayStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.ty.get_context(), self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<NDArrayType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<NDArrayType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context},
|
context::{AsContextRef, Context},
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -11,7 +11,9 @@ use nac3core_derive::StructFields;
|
|||||||
use super::ProxyType;
|
use super::ProxyType;
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
irrt,
|
irrt,
|
||||||
types::structure::{check_struct_type_matches_fields, StructField, StructFields},
|
types::structure::{
|
||||||
|
check_struct_type_matches_fields, StructField, StructFields, StructProxyType,
|
||||||
|
},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayValue, NDIterValue},
|
ndarray::{NDArrayValue, NDIterValue},
|
||||||
ArrayLikeValue, ArraySliceValue, ProxyValue, TypedArrayLikeAdapter,
|
ArrayLikeValue, ArraySliceValue, ProxyValue, TypedArrayLikeAdapter,
|
||||||
@ -44,39 +46,12 @@ pub struct NDIterStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIterType<'ctx> {
|
impl<'ctx> NDIterType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `nditer` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `NDIter` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDIter",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(ctx: impl AsContextRef<'ctx>, llvm_usize: IntType<'ctx>) -> NDIterStructFields<'ctx> {
|
fn fields(ctx: impl AsContextRef<'ctx>, llvm_usize: IntType<'ctx>) -> NDIterStructFields<'ctx> {
|
||||||
NDIterStructFields::new(ctx, llvm_usize)
|
NDIterStructFields::new(ctx, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`NDIterType::fields`].
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self, ctx: impl AsContextRef<'ctx>) -> NDIterStructFields<'ctx> {
|
|
||||||
Self::fields(ctx, self.llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of an `NDIter`.
|
/// Creates an LLVM type corresponding to the expected structure of an `NDIter`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
@ -86,19 +61,37 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`NDIter`].
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
#[must_use]
|
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(generator: &G, ctx: &'ctx Context) -> Self {
|
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
|
||||||
let llvm_nditer = Self::llvm_type(ctx, llvm_usize);
|
let llvm_nditer = Self::llvm_type(ctx, llvm_usize);
|
||||||
|
|
||||||
Self { ty: llvm_nditer, llvm_usize }
|
Self { ty: llvm_nditer, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDIter`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`NDIter`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`NDIterType`] from a [`StructType`] representing an `NDIter`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an [`NDIterType`] from a [`PointerType`] representing an `NDIter`.
|
/// Creates an [`NDIterType`] from a [`PointerType`] representing an `NDIter`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -151,11 +144,6 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate an [`NDIter`] that iterates through the given `ndarray`.
|
/// Allocate an [`NDIter`] that iterates through the given `ndarray`.
|
||||||
///
|
|
||||||
/// Note: This function allocates an array on the stack at the current builder location, which
|
|
||||||
/// may lead to stack explosion if called in a hot loop. Therefore, callers are recommended to
|
|
||||||
/// call `llvm.stacksave` before calling this function and call `llvm.stackrestore` after the
|
|
||||||
/// [`NDIter`] is no longer needed.
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn construct<G: CodeGenerator + ?Sized>(
|
pub fn construct<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
@ -172,7 +160,8 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
let indices =
|
let indices =
|
||||||
TypedArrayLikeAdapter::from(indices, |_, _, v| v.into_int_value(), |_, _, v| v.into());
|
TypedArrayLikeAdapter::from(indices, |_, _, v| v.into_int_value(), |_, _, v| v.into());
|
||||||
|
|
||||||
let nditer = self.map_value(nditer, ndarray, indices.as_slice_value(ctx, generator), None);
|
let nditer =
|
||||||
|
self.map_pointer_value(nditer, ndarray, indices.as_slice_value(ctx, generator), None);
|
||||||
|
|
||||||
irrt::ndarray::call_nac3_nditer_initialize(generator, ctx, nditer, ndarray, &indices);
|
irrt::ndarray::call_nac3_nditer_initialize(generator, ctx, nditer, ndarray, &indices);
|
||||||
|
|
||||||
@ -180,9 +169,30 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
parent: NDArrayValue<'ctx>,
|
||||||
|
indices: ArraySliceValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
parent,
|
||||||
|
indices,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
parent: NDArrayValue<'ctx>,
|
parent: NDArrayValue<'ctx>,
|
||||||
indices: ArraySliceValue<'ctx>,
|
indices: ArraySliceValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
@ -198,36 +208,56 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for NDIterType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for NDIterType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDIterValue<'ctx>;
|
type Value = NDIterValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `NDIter` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDIter",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for NDIterType<'ctx> {
|
||||||
|
type StructFields = NDIterStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
Self::fields(self.ty.get_context(), self.llvm_usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<NDIterType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<NDIterType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -1,25 +1,167 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, ArrayType, BasicType, BasicTypeEnum, IntType, PointerType},
|
||||||
|
values::{ArrayValue, PointerValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ProxyType;
|
use super::ProxyType;
|
||||||
use crate::codegen::{
|
use crate::{
|
||||||
values::{ProxyValue, RangeValue},
|
codegen::{
|
||||||
{CodeGenContext, CodeGenerator},
|
values::RangeValue,
|
||||||
|
{CodeGenContext, CodeGenerator},
|
||||||
|
},
|
||||||
|
typecheck::typedef::{Type, TypeEnum},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Proxy type for a `range` type in LLVM.
|
/// Proxy type for a `range` type in LLVM.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct RangeType<'ctx> {
|
pub struct RangeType<'ctx> {
|
||||||
ty: PointerType<'ctx>,
|
ty: PointerType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> RangeType<'ctx> {
|
impl<'ctx> RangeType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `range` type, returning [Err] if it does not.
|
/// Creates an LLVM type corresponding to the expected structure of a `Range`.
|
||||||
pub fn is_representable(llvm_ty: PointerType<'ctx>) -> Result<(), String> {
|
#[must_use]
|
||||||
let llvm_range_ty = llvm_ty.get_element_type();
|
fn llvm_type(ctx: &'ctx Context) -> PointerType<'ctx> {
|
||||||
|
// typedef int32_t Range[3];
|
||||||
|
let llvm_i32 = ctx.i32_type();
|
||||||
|
llvm_i32.array_type(3).ptr_type(AddressSpace::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
let llvm_range = Self::llvm_type(ctx);
|
||||||
|
|
||||||
|
RangeType { ty: llvm_range, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`RangeType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`RangeType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`RangeType`] from a [unifier type][Type].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_unifier_type(ctx: &mut CodeGenContext<'ctx, '_>, ty: Type) -> Self {
|
||||||
|
// Check unifier type
|
||||||
|
assert!(
|
||||||
|
matches!(&*ctx.unifier.get_ty_immutable(ty), TypeEnum::TObj { obj_id, .. } if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`RangeType`] from a [`ArrayType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_array_type(arr_ty: ArrayType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_pointer_type(arr_ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`RangeType`] from a [`PointerType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
|
RangeType { ty: ptr_ty, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the type of all fields of this `range` type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn value_type(&self) -> IntType<'ctx> {
|
||||||
|
self.as_abi_type().get_element_type().into_array_type().get_element_type().into_int_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
|
self.raw_alloca(ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca_var`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca_var<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
|
self.raw_alloca_var(generator, ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`RangeValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_array_value<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: ArrayValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_array_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`RangeValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
|
type Base = PointerType<'ctx>;
|
||||||
|
type Value = RangeValue<'ctx>;
|
||||||
|
|
||||||
|
fn is_representable(
|
||||||
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_same_repr(ty: Self::Base, _: IntType<'ctx>) -> Result<(), String> {
|
||||||
|
let llvm_range_ty = ty.get_element_type();
|
||||||
let AnyTypeEnum::ArrayType(llvm_range_ty) = llvm_range_ty else {
|
let AnyTypeEnum::ArrayType(llvm_range_ty) = llvm_range_ty else {
|
||||||
return Err(format!("Expected array type for `range` type, got {llvm_range_ty}"));
|
return Err(format!("Expected array type for `range` type, got {llvm_range_ty}"));
|
||||||
};
|
};
|
||||||
@ -46,106 +188,17 @@ impl<'ctx> RangeType<'ctx> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a `Range`.
|
|
||||||
#[must_use]
|
|
||||||
fn llvm_type(ctx: &'ctx Context) -> PointerType<'ctx> {
|
|
||||||
// typedef int32_t Range[3];
|
|
||||||
let llvm_i32 = ctx.i32_type();
|
|
||||||
llvm_i32.array_type(3).ptr_type(AddressSpace::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an instance of [`RangeType`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(ctx: &'ctx Context) -> Self {
|
|
||||||
let llvm_range = Self::llvm_type(ctx);
|
|
||||||
|
|
||||||
RangeType::from_type(llvm_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`RangeType`] from a [`PointerType`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>) -> Self {
|
|
||||||
debug_assert!(Self::is_representable(ptr_ty).is_ok());
|
|
||||||
|
|
||||||
RangeType { ty: ptr_ty }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the type of all fields of this `range` type.
|
|
||||||
#[must_use]
|
|
||||||
pub fn value_type(&self) -> IntType<'ctx> {
|
|
||||||
self.as_base_type().get_element_type().into_array_type().get_element_type().into_int_type()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
|
||||||
///
|
|
||||||
/// See [`ProxyType::raw_alloca`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn alloca<G: CodeGenerator + ?Sized>(
|
|
||||||
&self,
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
name: Option<&'ctx str>,
|
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(self.raw_alloca(ctx, name), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
|
||||||
///
|
|
||||||
/// See [`ProxyType::raw_alloca_var`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn alloca_var<G: CodeGenerator + ?Sized>(
|
|
||||||
&self,
|
|
||||||
generator: &mut G,
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
name: Option<&'ctx str>,
|
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
|
||||||
self.raw_alloca_var(generator, ctx, name),
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts an existing value into a [`RangeValue`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn map_value(
|
|
||||||
&self,
|
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
|
||||||
name: Option<&'ctx str>,
|
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
|
|
||||||
type Base = PointerType<'ctx>;
|
|
||||||
type Value = RangeValue<'ctx>;
|
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
|
||||||
_: &G,
|
|
||||||
_: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<RangeType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<RangeType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -2,13 +2,55 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::AsContextRef,
|
context::AsContextRef,
|
||||||
types::{BasicTypeEnum, IntType, StructType},
|
types::{BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::{BasicValue, BasicValueEnum, IntValue, PointerValue, StructValue},
|
values::{AggregateValueEnum, BasicValue, BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||||
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use super::ProxyType;
|
||||||
use crate::codegen::CodeGenContext;
|
use crate::codegen::CodeGenContext;
|
||||||
|
|
||||||
|
/// A LLVM type that is used to represent a corresponding structure-like type in NAC3.
|
||||||
|
pub trait StructProxyType<'ctx>: ProxyType<'ctx, Base = PointerType<'ctx>> {
|
||||||
|
/// The concrete type of [`StructFields`].
|
||||||
|
type StructFields: StructFields<'ctx>;
|
||||||
|
|
||||||
|
/// Whether this [`StructProxyType`] has the same LLVM type representation as
|
||||||
|
/// [`llvm_ty`][StructType].
|
||||||
|
fn has_same_struct_repr(
|
||||||
|
llvm_ty: StructType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
Self::has_same_pointer_repr(llvm_ty.ptr_type(AddressSpace::default()), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this [`StructProxyType`] has the same LLVM type representation as
|
||||||
|
/// [`llvm_ty`][PointerType].
|
||||||
|
fn has_same_pointer_repr(
|
||||||
|
llvm_ty: PointerType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
Self::has_same_repr(llvm_ty, llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the fields present in this [`StructProxyType`].
|
||||||
|
#[must_use]
|
||||||
|
fn get_fields(&self) -> Self::StructFields;
|
||||||
|
|
||||||
|
/// Returns the [`StructType`].
|
||||||
|
#[must_use]
|
||||||
|
fn get_struct_type(&self) -> StructType<'ctx> {
|
||||||
|
self.as_base_type().get_element_type().into_struct_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`PointerType`] representing this type.
|
||||||
|
#[must_use]
|
||||||
|
fn get_pointer_type(&self) -> PointerType<'ctx> {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait indicating that the structure is a field-wise representation of an LLVM structure.
|
/// Trait indicating that the structure is a field-wise representation of an LLVM structure.
|
||||||
///
|
///
|
||||||
/// # Usage
|
/// # Usage
|
||||||
@ -161,17 +203,38 @@ where
|
|||||||
|
|
||||||
/// Gets the value of this field for a given `obj`.
|
/// Gets the value of this field for a given `obj`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_from_value(&self, obj: StructValue<'ctx>) -> Value {
|
pub fn extract_value(&self, ctx: &CodeGenContext<'ctx, '_>, obj: StructValue<'ctx>) -> Value {
|
||||||
obj.get_field_at_index(self.index).and_then(|value| Value::try_from(value).ok()).unwrap()
|
Value::try_from(
|
||||||
|
ctx.builder
|
||||||
|
.build_extract_value(
|
||||||
|
obj,
|
||||||
|
self.index,
|
||||||
|
&format!("{}.{}", obj.get_name().to_str().unwrap(), self.name),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of this field for a given `obj`.
|
/// Sets the value of this field for a given `obj`.
|
||||||
pub fn set_for_value(&self, obj: StructValue<'ctx>, value: Value) {
|
#[must_use]
|
||||||
obj.set_field_at_index(self.index, value);
|
pub fn insert_value(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
obj: StructValue<'ctx>,
|
||||||
|
value: Value,
|
||||||
|
) -> StructValue<'ctx> {
|
||||||
|
let obj_name = obj.get_name().to_str().unwrap();
|
||||||
|
let new_obj_name = if obj_name.chars().all(char::is_numeric) { "" } else { obj_name };
|
||||||
|
|
||||||
|
ctx.builder
|
||||||
|
.build_insert_value(obj, value, self.index, new_obj_name)
|
||||||
|
.map(AggregateValueEnum::into_struct_value)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the value of this field for a pointer-to-structure.
|
/// Loads the value of this field for a pointer-to-structure.
|
||||||
pub fn get(
|
pub fn load(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
pobj: PointerValue<'ctx>,
|
pobj: PointerValue<'ctx>,
|
||||||
@ -187,8 +250,8 @@ where
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value of this field for a pointer-to-structure.
|
/// Stores the value of this field for a pointer-to-structure.
|
||||||
pub fn set(
|
pub fn store(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
pobj: PointerValue<'ctx>,
|
pobj: PointerValue<'ctx>,
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
types::{BasicType, BasicTypeEnum, IntType, StructType},
|
types::{BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::BasicValueEnum,
|
values::{BasicValueEnum, PointerValue, StructValue},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::ProxyType;
|
use super::ProxyType;
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{values::TupleValue, CodeGenContext, CodeGenerator},
|
||||||
values::{ProxyValue, TupleValue},
|
|
||||||
CodeGenContext, CodeGenerator,
|
|
||||||
},
|
|
||||||
typecheck::typedef::{Type, TypeEnum},
|
typecheck::typedef::{Type, TypeEnum},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,28 +18,40 @@ pub struct TupleType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> TupleType<'ctx> {
|
impl<'ctx> TupleType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents any tuple type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(_value: StructType<'ctx>) -> Result<(), String> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a tuple.
|
/// Creates an LLVM type corresponding to the expected structure of a tuple.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, tys: &[BasicTypeEnum<'ctx>]) -> StructType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, tys: &[BasicTypeEnum<'ctx>]) -> StructType<'ctx> {
|
||||||
ctx.struct_type(tys, false)
|
ctx.struct_type(tys, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_impl(
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
tys: &[BasicTypeEnum<'ctx>],
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
let llvm_tuple = Self::llvm_type(ctx, tys);
|
||||||
|
|
||||||
|
Self { ty: llvm_tuple, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`TupleType`].
|
/// Creates an instance of [`TupleType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new<G: CodeGenerator + ?Sized>(
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>, tys: &[impl BasicType<'ctx>]) -> Self {
|
||||||
|
Self::new_impl(
|
||||||
|
ctx.ctx,
|
||||||
|
&tys.iter().map(BasicType::as_basic_type_enum).collect_vec(),
|
||||||
|
ctx.get_size_type(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`TupleType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
generator: &G,
|
generator: &G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
tys: &[BasicTypeEnum<'ctx>],
|
tys: &[BasicTypeEnum<'ctx>],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx, tys, generator.get_size_type(ctx))
|
||||||
let llvm_tuple = Self::llvm_type(ctx, tys);
|
|
||||||
|
|
||||||
Self { ty: llvm_tuple, llvm_usize }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`TupleType`] from a [unifier type][Type].
|
/// Creates an [`TupleType`] from a [unifier type][Type].
|
||||||
@ -52,7 +61,7 @@ impl<'ctx> TupleType<'ctx> {
|
|||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
// Sanity check on object type.
|
// Sanity check on object type.
|
||||||
let TypeEnum::TTuple { ty: tys, .. } = &*ctx.unifier.get_ty_immutable(ty) else {
|
let TypeEnum::TTuple { ty: tys, .. } = &*ctx.unifier.get_ty_immutable(ty) else {
|
||||||
@ -65,12 +74,18 @@ impl<'ctx> TupleType<'ctx> {
|
|||||||
|
|
||||||
/// Creates an [`TupleType`] from a [`StructType`].
|
/// Creates an [`TupleType`] from a [`StructType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(struct_ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_struct_type(struct_ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(struct_ty).is_ok());
|
debug_assert!(Self::has_same_repr(struct_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
TupleType { ty: struct_ty, llvm_usize }
|
TupleType { ty: struct_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an [`TupleType`] from a [`PointerType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
Self::from_struct_type(ptr_ty.get_element_type().into_struct_type(), llvm_usize)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of elements present in this [`TupleType`].
|
/// Returns the number of elements present in this [`TupleType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn num_elements(&self) -> u32 {
|
pub fn num_elements(&self) -> u32 {
|
||||||
@ -105,7 +120,10 @@ impl<'ctx> TupleType<'ctx> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
self.map_value(Self::llvm_type(ctx.ctx, &self.ty.get_field_types()).const_zero(), name)
|
self.map_struct_value(
|
||||||
|
Self::llvm_type(ctx.ctx, &self.ty.get_field_types()).const_zero(),
|
||||||
|
name,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a [`TupleValue`] from `objects`. The resulting tuple preserves the order of
|
/// Constructs a [`TupleValue`] from `objects`. The resulting tuple preserves the order of
|
||||||
@ -135,37 +153,44 @@ impl<'ctx> TupleType<'ctx> {
|
|||||||
|
|
||||||
/// Converts an existing value into a [`ListValue`].
|
/// Converts an existing value into a [`ListValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_struct_value(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
value: StructValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_struct_value(value, self.llvm_usize, name)
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(value, self.llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`TupleValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_pointer_value(
|
||||||
|
&self,
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
value: PointerValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(ctx, value, self.llvm_usize, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for TupleType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for TupleType<'ctx> {
|
||||||
|
type ABI = StructType<'ctx>;
|
||||||
type Base = StructType<'ctx>;
|
type Base = StructType<'ctx>;
|
||||||
type Value = TupleValue<'ctx>;
|
type Value = TupleValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::StructType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::StructType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected struct type, got {llvm_ty:?}"))
|
Err(format!("Expected struct type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(_: Self::Base, _: IntType<'ctx>) -> Result<(), String> {
|
||||||
_generator: &G,
|
Ok(())
|
||||||
_ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
@ -175,6 +200,10 @@ impl<'ctx> ProxyType<'ctx> for TupleType<'ctx> {
|
|||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<TupleType<'ctx>> for StructType<'ctx> {
|
impl<'ctx> From<TupleType<'ctx>> for StructType<'ctx> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::{AsContextRef, Context, ContextRef},
|
context::{AsContextRef, Context, ContextRef},
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
|
||||||
values::IntValue,
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -12,10 +12,11 @@ use crate::codegen::{
|
|||||||
types::{
|
types::{
|
||||||
structure::{
|
structure::{
|
||||||
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
check_struct_type_matches_fields, FieldIndexCounter, StructField, StructFields,
|
||||||
|
StructProxyType,
|
||||||
},
|
},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
},
|
},
|
||||||
values::{utils::SliceValue, ProxyValue},
|
values::utils::SliceValue,
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ pub struct SliceType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, StructFields)]
|
#[derive(PartialEq, Eq, Clone, Copy, StructFields)]
|
||||||
pub struct SliceFields<'ctx> {
|
pub struct SliceStructFields<'ctx> {
|
||||||
#[value_type(bool_type())]
|
#[value_type(bool_type())]
|
||||||
pub start_defined: StructField<'ctx, IntValue<'ctx>>,
|
pub start_defined: StructField<'ctx, IntValue<'ctx>>,
|
||||||
#[value_type(usize)]
|
#[value_type(usize)]
|
||||||
@ -42,14 +43,14 @@ pub struct SliceFields<'ctx> {
|
|||||||
pub step: StructField<'ctx, IntValue<'ctx>>,
|
pub step: StructField<'ctx, IntValue<'ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> SliceFields<'ctx> {
|
impl<'ctx> SliceStructFields<'ctx> {
|
||||||
/// Creates a new instance of [`SliceFields`] with a custom integer type for its range values.
|
/// Creates a new instance of [`SliceStructFields`] with a custom integer type for its range values.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_sized(ctx: &impl AsContextRef<'ctx>, int_ty: IntType<'ctx>) -> Self {
|
pub fn new_sized(ctx: &impl AsContextRef<'ctx>, int_ty: IntType<'ctx>) -> Self {
|
||||||
let ctx = unsafe { ContextRef::new(ctx.as_ctx_ref()) };
|
let ctx = unsafe { ContextRef::new(ctx.as_ctx_ref()) };
|
||||||
let mut counter = FieldIndexCounter::default();
|
let mut counter = FieldIndexCounter::default();
|
||||||
|
|
||||||
SliceFields {
|
SliceStructFields {
|
||||||
start_defined: StructField::create(&mut counter, "start_defined", ctx.bool_type()),
|
start_defined: StructField::create(&mut counter, "start_defined", ctx.bool_type()),
|
||||||
start: StructField::create(&mut counter, "start", int_ty),
|
start: StructField::create(&mut counter, "start", int_ty),
|
||||||
stop_defined: StructField::create(&mut counter, "stop_defined", ctx.bool_type()),
|
stop_defined: StructField::create(&mut counter, "stop_defined", ctx.bool_type()),
|
||||||
@ -61,60 +62,10 @@ impl<'ctx> SliceFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> SliceType<'ctx> {
|
impl<'ctx> SliceType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `slice` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let fields = SliceFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `Slice` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"Slice",
|
|
||||||
&[
|
|
||||||
(fields.start.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.start`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
(fields.stop.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.stop`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
(fields.step.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.step`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_fields(&self) -> SliceFields<'ctx> {
|
|
||||||
SliceFields::new_sized(&self.int_ty.get_context(), self.int_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a `Slice`.
|
/// Creates an LLVM type corresponding to the expected structure of a `Slice`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, int_ty: IntType<'ctx>) -> PointerType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, int_ty: IntType<'ctx>) -> PointerType<'ctx> {
|
||||||
let field_tys = SliceFields::new_sized(&int_ty.get_context(), int_ty)
|
let field_tys = SliceStructFields::new_sized(&int_ty.get_context(), int_ty)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|field| field.1)
|
.map(|field| field.1)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
@ -122,29 +73,61 @@ impl<'ctx> SliceType<'ctx> {
|
|||||||
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
ctx.struct_type(&field_tys, false).ptr_type(AddressSpace::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`SliceType`] with `int_ty` as its backing integer type.
|
fn new_impl(ctx: &'ctx Context, int_ty: IntType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
#[must_use]
|
|
||||||
pub fn new(ctx: &'ctx Context, int_ty: IntType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
|
||||||
let llvm_ty = Self::llvm_type(ctx, int_ty);
|
let llvm_ty = Self::llvm_type(ctx, int_ty);
|
||||||
|
|
||||||
Self { ty: llvm_ty, int_ty, llvm_usize }
|
Self { ty: llvm_ty, int_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`SliceType`] with `int_ty` as its backing integer type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>, int_ty: IntType<'ctx>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, int_ty, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`SliceType`] with `int_ty` as its backing integer type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
int_ty: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, int_ty, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an instance of [`SliceType`] with `usize` as its backing integer type.
|
/// Creates an instance of [`SliceType`] with `usize` as its backing integer type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_usize<G: CodeGenerator + ?Sized>(generator: &G, ctx: &'ctx Context) -> Self {
|
pub fn new_usize(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
let llvm_usize = generator.get_size_type(ctx);
|
Self::new_impl(ctx.ctx, ctx.get_size_type(), ctx.get_size_type())
|
||||||
Self::new(ctx, llvm_usize, llvm_usize)
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`SliceType`] with `usize` as its backing integer type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_usize_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx), generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`SliceType`] from a [`StructType`] representing a `slice`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_struct_type(
|
||||||
|
ty: StructType<'ctx>,
|
||||||
|
int_ty: IntType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), int_ty, llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`SliceType`] from a [`PointerType`] representing a `slice`.
|
/// Creates an [`SliceType`] from a [`PointerType`] representing a `slice`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(
|
pub fn from_pointer_type(
|
||||||
ptr_ty: PointerType<'ctx>,
|
ptr_ty: PointerType<'ctx>,
|
||||||
int_ty: IntType<'ctx>,
|
int_ty: IntType<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, int_ty).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, int_ty).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, int_ty, llvm_usize }
|
Self { ty: ptr_ty, int_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -189,11 +172,30 @@ impl<'ctx> SliceType<'ctx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts an existing value into a [`SliceValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
value: StructValue<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_struct_value(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
value,
|
||||||
|
self.int_ty,
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts an existing value into a [`ContiguousNDArrayValue`].
|
/// Converts an existing value into a [`ContiguousNDArrayValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_value(
|
pub fn map_pointer_value(
|
||||||
&self,
|
&self,
|
||||||
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
|
value: PointerValue<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
@ -206,36 +208,80 @@ impl<'ctx> SliceType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyType<'ctx> for SliceType<'ctx> {
|
impl<'ctx> ProxyType<'ctx> for SliceType<'ctx> {
|
||||||
|
type ABI = PointerType<'ctx>;
|
||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = SliceValue<'ctx>;
|
type Value = SliceValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let fields = SliceStructFields::new(ctx, llvm_usize);
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
let llvm_ty = ty.get_element_type();
|
||||||
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
|
return Err(format!("Expected struct type for `Slice` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"Slice",
|
||||||
|
&[
|
||||||
|
(fields.start.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.start`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(fields.stop.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.stop`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(fields.step.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.step`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_abi_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_type(&self) -> Self::Base {
|
fn as_base_type(&self) -> Self::Base {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_type(&self) -> Self::ABI {
|
||||||
|
self.as_base_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyType<'ctx> for SliceType<'ctx> {
|
||||||
|
type StructFields = SliceStructFields<'ctx>;
|
||||||
|
|
||||||
|
fn get_fields(&self) -> Self::StructFields {
|
||||||
|
SliceStructFields::new_sized(&self.ty.get_context(), self.int_ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<SliceType<'ctx>> for PointerType<'ctx> {
|
impl<'ctx> From<SliceType<'ctx>> for PointerType<'ctx> {
|
||||||
|
@ -418,7 +418,7 @@ impl<'ctx> ArrayLikeIndexer<'ctx> for ArraySliceValue<'ctx> {
|
|||||||
idx: &IntValue<'ctx>,
|
idx: &IntValue<'ctx>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx));
|
debug_assert_eq!(idx.get_type(), ctx.get_size_type());
|
||||||
|
|
||||||
let size = self.size(ctx, generator);
|
let size = self.size(ctx, generator);
|
||||||
let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, *idx, size, "").unwrap();
|
let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, *idx, size, "").unwrap();
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType},
|
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType},
|
||||||
values::{BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ProxyValue, UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
structure::StructProxyValue, ArrayLikeIndexer, ArrayLikeValue, ProxyValue,
|
||||||
|
UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
||||||
};
|
};
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
types::{structure::StructField, ListType, ProxyType},
|
types::{
|
||||||
|
structure::{StructField, StructProxyType},
|
||||||
|
ListType, ProxyType,
|
||||||
|
},
|
||||||
{CodeGenContext, CodeGenerator},
|
{CodeGenContext, CodeGenerator},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,13 +25,24 @@ pub struct ListValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ListValue<'ctx> {
|
impl<'ctx> ListValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `list`, returning [Err] if `value` is not an
|
/// Creates an [`ListValue`] from a [`PointerValue`].
|
||||||
/// instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
ListType::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ListValue`] from a [`PointerValue`].
|
/// Creates an [`ListValue`] from a [`PointerValue`].
|
||||||
@ -37,24 +52,18 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
ListValue { value: ptr, llvm_usize, name }
|
ListValue { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn items_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn items_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
self.get_type().get_fields(&ctx.ctx).items
|
self.get_type().get_fields().items
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
|
||||||
/// on the field.
|
|
||||||
fn pptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
|
||||||
self.items_field(ctx).ptr_by_gep(ctx, self.value, self.name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the array of data elements `data` into this instance.
|
/// Stores the array of data elements `data` into this instance.
|
||||||
fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) {
|
fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) {
|
||||||
self.items_field(ctx).set(ctx, self.value, data, self.name);
|
self.items_field().store(ctx, self.value, data, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for creating a new array storing data elements with the given element
|
/// Convenience method for creating a new array storing data elements with the given element
|
||||||
@ -92,20 +101,15 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
ListDataProxy(self)
|
ListDataProxy(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, IntValue<'ctx>> {
|
fn len_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
self.get_type().get_fields(&ctx.ctx).len
|
self.get_type().get_fields().len
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the `size` of this `list` into this instance.
|
/// Stores the `size` of this `list` into this instance.
|
||||||
pub fn store_size<G: CodeGenerator + ?Sized>(
|
pub fn store_size(&self, ctx: &CodeGenContext<'ctx, '_>, size: IntValue<'ctx>) {
|
||||||
&self,
|
debug_assert_eq!(size.get_type(), ctx.get_size_type());
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
generator: &G,
|
|
||||||
size: IntValue<'ctx>,
|
|
||||||
) {
|
|
||||||
debug_assert_eq!(size.get_type(), generator.get_size_type(ctx.ctx));
|
|
||||||
|
|
||||||
self.len_field(ctx).set(ctx, self.value, size, self.name);
|
self.len_field().store(ctx, self.value, size, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size of this `list` as a value.
|
/// Returns the size of this `list` as a value.
|
||||||
@ -114,21 +118,17 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
self.len_field(ctx).get(ctx, self.value, name)
|
self.len_field().load(ctx, self.value, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an instance of [`ListValue`] with the `items` pointer cast to `i8*`.
|
/// Returns an instance of [`ListValue`] with the `items` pointer cast to `i8*`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_i8_list<G: CodeGenerator + ?Sized>(
|
pub fn as_i8_list(&self, ctx: &CodeGenContext<'ctx, '_>) -> ListValue<'ctx> {
|
||||||
&self,
|
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> ListValue<'ctx> {
|
|
||||||
let llvm_i8 = ctx.ctx.i8_type();
|
let llvm_i8 = ctx.ctx.i8_type();
|
||||||
let llvm_list_i8 = <Self as ProxyValue>::Type::new(generator, ctx.ctx, llvm_i8.into());
|
let llvm_list_i8 = <Self as ProxyValue>::Type::new(ctx, &llvm_i8);
|
||||||
|
|
||||||
Self::from_pointer_value(
|
Self::from_pointer_value(
|
||||||
ctx.builder.build_pointer_cast(self.value, llvm_list_i8.as_base_type(), "").unwrap(),
|
ctx.builder.build_pointer_cast(self.value, llvm_list_i8.as_abi_type(), "").unwrap(),
|
||||||
self.llvm_usize,
|
self.llvm_usize,
|
||||||
self.name,
|
self.name,
|
||||||
)
|
)
|
||||||
@ -136,18 +136,25 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for ListValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for ListValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = ListType<'ctx>;
|
type Type = ListType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
ListType::from_type(self.as_base_value().get_type(), self.llvm_usize)
|
ListType::from_pointer_type(self.as_base_value().get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for ListValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<ListValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<ListValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: ListValue<'ctx>) -> Self {
|
fn from(value: ListValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -172,12 +179,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx, '_> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
_: &G,
|
_: &G,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let var_name = self.0.name.map(|v| format!("{v}.data")).unwrap_or_default();
|
self.0.items_field().load(ctx, self.0.value, self.0.name)
|
||||||
|
|
||||||
ctx.builder
|
|
||||||
.build_load(self.0.pptr_to_data(ctx), var_name.as_str())
|
|
||||||
.map(BasicValueEnum::into_pointer_value)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size<G: CodeGenerator + ?Sized>(
|
fn size<G: CodeGenerator + ?Sized>(
|
||||||
@ -213,7 +215,7 @@ impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx, '_> {
|
|||||||
idx: &IntValue<'ctx>,
|
idx: &IntValue<'ctx>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx));
|
debug_assert_eq!(idx.get_type(), ctx.get_size_type());
|
||||||
|
|
||||||
let size = self.size(ctx, generator);
|
let size = self.size(ctx, generator);
|
||||||
let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, *idx, size, "").unwrap();
|
let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, *idx, size, "").unwrap();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use inkwell::{context::Context, values::BasicValue};
|
use inkwell::{types::IntType, values::BasicValue};
|
||||||
|
|
||||||
use super::types::ProxyType;
|
use super::{types::ProxyType, CodeGenContext};
|
||||||
use crate::codegen::CodeGenerator;
|
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use range::*;
|
pub use range::*;
|
||||||
@ -11,34 +10,24 @@ mod array;
|
|||||||
mod list;
|
mod list;
|
||||||
pub mod ndarray;
|
pub mod ndarray;
|
||||||
mod range;
|
mod range;
|
||||||
|
pub mod structure;
|
||||||
mod tuple;
|
mod tuple;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
/// A LLVM type that is used to represent a non-primitive value in NAC3.
|
/// A LLVM type that is used to represent a non-primitive value in NAC3.
|
||||||
pub trait ProxyValue<'ctx>: Into<Self::Base> {
|
pub trait ProxyValue<'ctx>: Into<Self::Base> {
|
||||||
/// The type of LLVM values represented by this instance. This is usually the
|
/// The ABI type of LLVM values represented by this instance.
|
||||||
/// [LLVM pointer type][PointerValue].
|
type ABI: BasicValue<'ctx>;
|
||||||
|
|
||||||
|
/// The type of LLVM values represented by this instance.
|
||||||
type Base: BasicValue<'ctx>;
|
type Base: BasicValue<'ctx>;
|
||||||
|
|
||||||
/// The type of this value.
|
/// The type of this value.
|
||||||
type Type: ProxyType<'ctx, Value = Self>;
|
type Type: ProxyType<'ctx, Value = Self>;
|
||||||
|
|
||||||
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
||||||
fn is_instance<G: CodeGenerator + ?Sized>(
|
fn is_instance(value: impl BasicValue<'ctx>, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
Self::Type::is_representable(value.as_basic_value_enum().get_type(), llvm_usize)
|
||||||
ctx: &'ctx Context,
|
|
||||||
value: impl BasicValue<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::Type::is_type(generator, ctx, value.as_basic_value_enum().get_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
value: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_instance(generator, ctx, value.as_basic_value_enum())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [type][ProxyType] of this value.
|
/// Returns the [type][ProxyType] of this value.
|
||||||
@ -46,4 +35,10 @@ pub trait ProxyValue<'ctx>: Into<Self::Base> {
|
|||||||
|
|
||||||
/// Returns the [base value][Self::Base] of this proxy.
|
/// Returns the [base value][Self::Base] of this proxy.
|
||||||
fn as_base_value(&self) -> Self::Base;
|
fn as_base_value(&self) -> Self::Base;
|
||||||
|
|
||||||
|
/// Returns this proxy as its ABI value, i.e. the expected value representation if a value
|
||||||
|
/// represented by this [`ProxyValue`] is being passed into or returned from a function.
|
||||||
|
///
|
||||||
|
/// See [`CodeGenContext::get_llvm_abi_type`].
|
||||||
|
fn as_abi_value(&self, ctx: &CodeGenContext<'ctx, '_>) -> Self::ABI;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::IntType,
|
types::IntType,
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
@ -8,12 +8,13 @@ use crate::codegen::{
|
|||||||
irrt,
|
irrt,
|
||||||
types::{
|
types::{
|
||||||
ndarray::{NDArrayType, ShapeEntryType},
|
ndarray::{NDArrayType, ShapeEntryType},
|
||||||
structure::StructField,
|
structure::{StructField, StructProxyType},
|
||||||
ProxyType,
|
ProxyType,
|
||||||
},
|
},
|
||||||
values::{
|
values::{
|
||||||
ndarray::NDArrayValue, ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ProxyValue,
|
ndarray::NDArrayValue, structure::StructProxyValue, ArrayLikeIndexer, ArrayLikeValue,
|
||||||
TypedArrayLikeAccessor, TypedArrayLikeAdapter, TypedArrayLikeMutator,
|
ArraySliceValue, ProxyValue, TypedArrayLikeAccessor, TypedArrayLikeAdapter,
|
||||||
|
TypedArrayLikeMutator,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -26,13 +27,24 @@ pub struct ShapeEntryValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ShapeEntryValue<'ctx> {
|
impl<'ctx> ShapeEntryValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ShapeEntry`, returning [Err] if `value` is
|
/// Creates an [`ShapeEntryValue`] from a [`StructValue`].
|
||||||
/// not an instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ShapeEntryValue`] from a [`PointerValue`].
|
/// Creates an [`ShapeEntryValue`] from a [`PointerValue`].
|
||||||
@ -42,43 +54,50 @@ impl<'ctx> ShapeEntryValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, llvm_usize, name }
|
Self { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ndims_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
fn ndims_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
self.get_type().get_fields(self.value.get_type().get_context()).ndims
|
self.get_type().get_fields().ndims
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the number of dimensions into this value.
|
/// Stores the number of dimensions into this value.
|
||||||
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
self.ndims_field().set(ctx, self.value, value, self.name);
|
self.ndims_field().store(ctx, self.value, value, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn shape_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
self.get_type().get_fields(self.value.get_type().get_context()).shape
|
self.get_type().get_fields().shape
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the shape into this value.
|
/// Stores the shape into this value.
|
||||||
pub fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
pub fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
||||||
self.shape_field().set(ctx, self.value, value, self.name);
|
self.shape_field().store(ctx, self.value, value, self.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for ShapeEntryValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for ShapeEntryValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = ShapeEntryType<'ctx>;
|
type Type = ShapeEntryType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
Self::Type::from_type(self.value.get_type(), self.llvm_usize)
|
Self::Type::from_pointer_type(self.value.get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for ShapeEntryValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<ShapeEntryValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<ShapeEntryValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: ShapeEntryValue<'ctx>) -> Self {
|
fn from(value: ShapeEntryValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -104,7 +123,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
assert!(self.ndims <= target_ndims);
|
assert!(self.ndims <= target_ndims);
|
||||||
assert_eq!(target_shape.element_type(ctx, generator), self.llvm_usize.into());
|
assert_eq!(target_shape.element_type(ctx, generator), self.llvm_usize.into());
|
||||||
|
|
||||||
let broadcast_ndarray = NDArrayType::new(generator, ctx.ctx, self.dtype, target_ndims)
|
let broadcast_ndarray = NDArrayType::new(ctx, self.dtype, target_ndims)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
broadcast_ndarray.copy_shape_from_array(
|
broadcast_ndarray.copy_shape_from_array(
|
||||||
generator,
|
generator,
|
||||||
@ -112,7 +131,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
target_shape.base_ptr(ctx, generator),
|
target_shape.base_ptr(ctx, generator),
|
||||||
);
|
);
|
||||||
|
|
||||||
irrt::ndarray::call_nac3_ndarray_broadcast_to(generator, ctx, *self, broadcast_ndarray);
|
irrt::ndarray::call_nac3_ndarray_broadcast_to(ctx, *self, broadcast_ndarray);
|
||||||
broadcast_ndarray
|
broadcast_ndarray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,8 +165,8 @@ fn broadcast_shapes<'ctx, G, Shape>(
|
|||||||
Shape: TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>
|
Shape: TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>
|
||||||
+ TypedArrayLikeMutator<'ctx, G, IntValue<'ctx>>,
|
+ TypedArrayLikeMutator<'ctx, G, IntValue<'ctx>>,
|
||||||
{
|
{
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_shape_ty = ShapeEntryType::new(generator, ctx.ctx);
|
let llvm_shape_ty = ShapeEntryType::new(ctx);
|
||||||
|
|
||||||
assert!(in_shape_entries
|
assert!(in_shape_entries
|
||||||
.iter()
|
.iter()
|
||||||
@ -167,7 +186,7 @@ fn broadcast_shapes<'ctx, G, Shape>(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let shape_entry = llvm_shape_ty.map_value(pshape_entry, None);
|
let shape_entry = llvm_shape_ty.map_pointer_value(pshape_entry, None);
|
||||||
|
|
||||||
let in_ndims = llvm_usize.const_int(*in_ndims, false);
|
let in_ndims = llvm_usize.const_int(*in_ndims, false);
|
||||||
shape_entry.store_ndims(ctx, in_ndims);
|
shape_entry.store_ndims(ctx, in_ndims);
|
||||||
@ -199,7 +218,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
) -> BroadcastAllResult<'ctx, G> {
|
) -> BroadcastAllResult<'ctx, G> {
|
||||||
assert!(!ndarrays.is_empty());
|
assert!(!ndarrays.is_empty());
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
// Infer the broadcast output ndims.
|
// Infer the broadcast output ndims.
|
||||||
let broadcast_ndims_int =
|
let broadcast_ndims_int =
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{BasicType, BasicTypeEnum, IntType},
|
types::{BasicType, BasicTypeEnum, IntType},
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ArrayLikeValue, NDArrayValue, ProxyValue};
|
use super::NDArrayValue;
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
stmt::gen_if_callback,
|
stmt::gen_if_callback,
|
||||||
types::{
|
types::{
|
||||||
ndarray::{ContiguousNDArrayType, NDArrayType},
|
ndarray::{ContiguousNDArrayType, NDArrayType},
|
||||||
structure::StructField,
|
structure::{StructField, StructProxyType},
|
||||||
},
|
},
|
||||||
|
values::{structure::StructProxyValue, ArrayLikeValue, ProxyValue},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,13 +24,25 @@ pub struct ContiguousNDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ContiguousNDArray`, returning [Err] if `value` is
|
/// Creates an [`ContiguousNDArrayValue`] from a [`StructValue`].
|
||||||
/// not an instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, dtype, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`ContiguousNDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`ContiguousNDArrayValue`] from a [`PointerValue`].
|
||||||
@ -40,7 +53,7 @@ impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, item: dtype, llvm_usize, name }
|
Self { value: ptr, item: dtype, llvm_usize, name }
|
||||||
}
|
}
|
||||||
@ -50,7 +63,7 @@ impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
self.ndims_field().set(ctx, self.as_base_value(), value, self.name);
|
self.ndims_field().store(ctx, self.as_abi_value(ctx), value, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn shape_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
@ -58,11 +71,11 @@ impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
pub fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
||||||
self.shape_field().set(ctx, self.as_base_value(), value, self.name);
|
self.shape_field().store(ctx, self.as_abi_value(ctx), value, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_shape(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn load_shape(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
self.shape_field().get(ctx, self.value, self.name)
|
self.shape_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn data_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
@ -70,20 +83,21 @@ impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
pub fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
||||||
self.data_field().set(ctx, self.as_base_value(), value, self.name);
|
self.data_field().store(ctx, self.as_abi_value(ctx), value, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn load_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
self.data_field().get(ctx, self.value, self.name)
|
self.data_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for ContiguousNDArrayValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for ContiguousNDArrayValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = ContiguousNDArrayType<'ctx>;
|
type Type = ContiguousNDArrayType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
<Self as ProxyValue<'ctx>>::Type::from_type(
|
<Self as ProxyValue<'ctx>>::Type::from_pointer_type(
|
||||||
self.as_base_value().get_type(),
|
self.as_base_value().get_type(),
|
||||||
self.item,
|
self.item,
|
||||||
self.llvm_usize,
|
self.llvm_usize,
|
||||||
@ -93,8 +107,14 @@ impl<'ctx> ProxyValue<'ctx> for ContiguousNDArrayValue<'ctx> {
|
|||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for ContiguousNDArrayValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<ContiguousNDArrayValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<ContiguousNDArrayValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: ContiguousNDArrayValue<'ctx>) -> Self {
|
fn from(value: ContiguousNDArrayValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -117,8 +137,8 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
) -> ContiguousNDArrayValue<'ctx> {
|
) -> ContiguousNDArrayValue<'ctx> {
|
||||||
let result = ContiguousNDArrayType::new(generator, ctx.ctx, self.dtype)
|
let result =
|
||||||
.alloca_var(generator, ctx, self.name);
|
ContiguousNDArrayType::new(ctx, &self.dtype).alloca_var(generator, ctx, self.name);
|
||||||
|
|
||||||
// Set ndims and shape.
|
// Set ndims and shape.
|
||||||
let ndims = self.llvm_usize.const_int(self.ndims, false);
|
let ndims = self.llvm_usize.const_int(self.ndims, false);
|
||||||
@ -130,10 +150,10 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
gen_if_callback(
|
gen_if_callback(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
|generator, ctx| Ok(self.is_c_contiguous(generator, ctx)),
|
|_, ctx| Ok(self.is_c_contiguous(ctx)),
|
||||||
|_, ctx| {
|
|_, ctx| {
|
||||||
// This ndarray is contiguous.
|
// This ndarray is contiguous.
|
||||||
let data = self.data_field(ctx).get(ctx, self.as_base_value(), self.name);
|
let data = self.data_field().load(ctx, self.as_abi_value(ctx), self.name);
|
||||||
let data = ctx
|
let data = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_pointer_cast(data, result.item.ptr_type(AddressSpace::default()), "")
|
.build_pointer_cast(data, result.item.ptr_type(AddressSpace::default()), "")
|
||||||
@ -178,13 +198,16 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
// TODO: Debug assert `ndims == carray.ndims` to catch bugs.
|
// TODO: Debug assert `ndims == carray.ndims` to catch bugs.
|
||||||
|
|
||||||
// Allocate the resulting ndarray.
|
// Allocate the resulting ndarray.
|
||||||
let ndarray = NDArrayType::new(generator, ctx.ctx, carray.item, ndims)
|
let ndarray = NDArrayType::new(ctx, carray.item, ndims).construct_uninitialized(
|
||||||
.construct_uninitialized(generator, ctx, carray.name);
|
generator,
|
||||||
|
ctx,
|
||||||
|
carray.name,
|
||||||
|
);
|
||||||
|
|
||||||
// Copy shape and update strides
|
// Copy shape and update strides
|
||||||
let shape = carray.load_shape(ctx);
|
let shape = carray.load_shape(ctx);
|
||||||
ndarray.copy_shape_from_array(generator, ctx, shape);
|
ndarray.copy_shape_from_array(generator, ctx, shape);
|
||||||
ndarray.set_strides_contiguous(generator, ctx);
|
ndarray.set_strides_contiguous(ctx);
|
||||||
|
|
||||||
// Share data
|
// Share data
|
||||||
let data = carray.load_data(ctx);
|
let data = carray.load_data(ctx);
|
||||||
|
101
nac3core/src/codegen/values/ndarray/fold.rs
Normal file
101
nac3core/src/codegen/values/ndarray/fold.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use inkwell::values::{BasicValue, BasicValueEnum};
|
||||||
|
|
||||||
|
use super::{NDArrayValue, NDIterValue, ScalarOrNDArray};
|
||||||
|
use crate::codegen::{
|
||||||
|
stmt::{gen_for_callback, BreakContinueHooks},
|
||||||
|
types::ndarray::NDIterType,
|
||||||
|
CodeGenContext, CodeGenerator,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'ctx> NDArrayValue<'ctx> {
|
||||||
|
/// Folds the elements of this ndarray into an accumulator value by applying `f`, returning the
|
||||||
|
/// final value.
|
||||||
|
///
|
||||||
|
/// `f` has access to [`BreakContinueHooks`] to short-circuit the `fold` operation, an instance
|
||||||
|
/// of `V` representing the current accumulated value, and an [`NDIterValue`] to get the
|
||||||
|
/// properties of the current iterated element.
|
||||||
|
pub fn fold<'a, G, V, F>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
init: V,
|
||||||
|
f: F,
|
||||||
|
) -> Result<V, String>
|
||||||
|
where
|
||||||
|
G: CodeGenerator + ?Sized,
|
||||||
|
V: BasicValue<'ctx> + TryFrom<BasicValueEnum<'ctx>>,
|
||||||
|
<V as TryFrom<BasicValueEnum<'ctx>>>::Error: std::fmt::Debug,
|
||||||
|
F: FnOnce(
|
||||||
|
&mut G,
|
||||||
|
&mut CodeGenContext<'ctx, 'a>,
|
||||||
|
BreakContinueHooks<'ctx>,
|
||||||
|
V,
|
||||||
|
NDIterValue<'ctx>,
|
||||||
|
) -> Result<V, String>,
|
||||||
|
{
|
||||||
|
let acc_ptr =
|
||||||
|
generator.gen_var_alloc(ctx, init.as_basic_value_enum().get_type(), None).unwrap();
|
||||||
|
ctx.builder.build_store(acc_ptr, init).unwrap();
|
||||||
|
|
||||||
|
gen_for_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
Some("ndarray_fold"),
|
||||||
|
|generator, ctx| Ok(NDIterType::new(ctx).construct(generator, ctx, *self)),
|
||||||
|
|_, ctx, nditer| Ok(nditer.has_element(ctx)),
|
||||||
|
|generator, ctx, hooks, nditer| {
|
||||||
|
let acc = V::try_from(ctx.builder.build_load(acc_ptr, "").unwrap()).unwrap();
|
||||||
|
let acc = f(generator, ctx, hooks, acc, nditer)?;
|
||||||
|
ctx.builder.build_store(acc_ptr, acc).unwrap();
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, ctx, nditer| {
|
||||||
|
nditer.next(ctx);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let acc = ctx.builder.build_load(acc_ptr, "").unwrap();
|
||||||
|
Ok(V::try_from(acc).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ScalarOrNDArray<'ctx> {
|
||||||
|
/// See [`NDArrayValue::fold`].
|
||||||
|
///
|
||||||
|
/// The primary differences between this function and `NDArrayValue::fold` are:
|
||||||
|
///
|
||||||
|
/// - The 3rd parameter of `f` is an `Option` of hooks, since `break`/`continue` hooks are not
|
||||||
|
/// available if this instance represents a scalar value.
|
||||||
|
/// - The 5th parameter of `f` is a [`BasicValueEnum`], since no [iterator][`NDIterValue`] will
|
||||||
|
/// be created if this instance represents a scalar value.
|
||||||
|
pub fn fold<'a, G, V, F>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
init: V,
|
||||||
|
f: F,
|
||||||
|
) -> Result<V, String>
|
||||||
|
where
|
||||||
|
G: CodeGenerator + ?Sized,
|
||||||
|
V: BasicValue<'ctx> + TryFrom<BasicValueEnum<'ctx>>,
|
||||||
|
<V as TryFrom<BasicValueEnum<'ctx>>>::Error: std::fmt::Debug,
|
||||||
|
F: FnOnce(
|
||||||
|
&mut G,
|
||||||
|
&mut CodeGenContext<'ctx, 'a>,
|
||||||
|
Option<&BreakContinueHooks<'ctx>>,
|
||||||
|
V,
|
||||||
|
BasicValueEnum<'ctx>,
|
||||||
|
) -> Result<V, String>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
ScalarOrNDArray::Scalar(v) => f(generator, ctx, None, init, *v),
|
||||||
|
ScalarOrNDArray::NDArray(v) => {
|
||||||
|
v.fold(generator, ctx, init, |generator, ctx, hooks, acc, nditer| {
|
||||||
|
let elem = nditer.get_scalar(ctx);
|
||||||
|
f(generator, ctx, Some(&hooks), acc, elem)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::IntType,
|
types::IntType,
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -12,10 +12,12 @@ use crate::{
|
|||||||
irrt,
|
irrt,
|
||||||
types::{
|
types::{
|
||||||
ndarray::{NDArrayType, NDIndexType},
|
ndarray::{NDArrayType, NDIndexType},
|
||||||
structure::StructField,
|
structure::{StructField, StructProxyType},
|
||||||
utils::SliceType,
|
utils::SliceType,
|
||||||
},
|
},
|
||||||
values::{ndarray::NDArrayValue, utils::RustSlice, ProxyValue},
|
values::{
|
||||||
|
ndarray::NDArrayValue, structure::StructProxyValue, utils::RustSlice, ProxyValue,
|
||||||
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
typecheck::typedef::Type,
|
typecheck::typedef::Type,
|
||||||
@ -30,13 +32,24 @@ pub struct NDIndexValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIndexValue<'ctx> {
|
impl<'ctx> NDIndexValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ndindex`, returning [Err] if `value` is not an
|
/// Creates an [`NDIndexValue`] from a [`StructValue`].
|
||||||
/// instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`NDIndexValue`] from a [`PointerValue`].
|
/// Creates an [`NDIndexValue`] from a [`PointerValue`].
|
||||||
@ -46,7 +59,7 @@ impl<'ctx> NDIndexValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, llvm_usize, name }
|
Self { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
@ -56,11 +69,11 @@ impl<'ctx> NDIndexValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_type(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_type(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.type_field().get(ctx, self.value, self.name)
|
self.type_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_type(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
pub fn store_type(&self, ctx: &CodeGenContext<'ctx, '_>, value: IntValue<'ctx>) {
|
||||||
self.type_field().set(ctx, self.value, value, self.name);
|
self.type_field().store(ctx, self.value, value, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn data_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
@ -68,27 +81,34 @@ impl<'ctx> NDIndexValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn load_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
self.data_field().get(ctx, self.value, self.name)
|
self.data_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
pub fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, value: PointerValue<'ctx>) {
|
||||||
self.data_field().set(ctx, self.value, value, self.name);
|
self.data_field().store(ctx, self.value, value, self.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for NDIndexValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for NDIndexValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = NDIndexType<'ctx>;
|
type Type = NDIndexType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
Self::Type::from_type(self.value.get_type(), self.llvm_usize)
|
Self::Type::from_pointer_type(self.value.get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for NDIndexValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<NDIndexValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<NDIndexValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: NDIndexValue<'ctx>) -> Self {
|
fn from(value: NDIndexValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -128,11 +148,10 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
indices: &[RustNDIndex<'ctx>],
|
indices: &[RustNDIndex<'ctx>],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let dst_ndims = self.deduce_ndims_after_indexing_with(indices);
|
let dst_ndims = self.deduce_ndims_after_indexing_with(indices);
|
||||||
let dst_ndarray = NDArrayType::new(generator, ctx.ctx, self.dtype, dst_ndims)
|
let dst_ndarray = NDArrayType::new(ctx, self.dtype, dst_ndims)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
|
|
||||||
let indices =
|
let indices = NDIndexType::new(ctx).construct_ndindices(generator, ctx, indices);
|
||||||
NDIndexType::new(generator, ctx.ctx).construct_ndindices(generator, ctx, indices);
|
|
||||||
irrt::ndarray::call_nac3_ndarray_index(generator, ctx, indices, *self, dst_ndarray);
|
irrt::ndarray::call_nac3_ndarray_index(generator, ctx, indices, *self, dst_ndarray);
|
||||||
|
|
||||||
dst_ndarray
|
dst_ndarray
|
||||||
@ -245,8 +264,7 @@ impl<'ctx> RustNDIndex<'ctx> {
|
|||||||
}
|
}
|
||||||
RustNDIndex::Slice(in_rust_slice) => {
|
RustNDIndex::Slice(in_rust_slice) => {
|
||||||
let user_slice_ptr =
|
let user_slice_ptr =
|
||||||
SliceType::new(ctx.ctx, ctx.ctx.i32_type(), generator.get_size_type(ctx.ctx))
|
SliceType::new(ctx, ctx.ctx.i32_type()).alloca_var(generator, ctx, None);
|
||||||
.alloca_var(generator, ctx, None);
|
|
||||||
in_rust_slice.write_to_slice(ctx, user_slice_ptr);
|
in_rust_slice.write_to_slice(ctx, user_slice_ptr);
|
||||||
|
|
||||||
dst_ndindex.store_data(
|
dst_ndindex.store_data(
|
||||||
|
@ -35,7 +35,7 @@ fn matmul_at_least_2d<'ctx, G: CodeGenerator>(
|
|||||||
let lhs_dtype = arraylike_flatten_element_type(&mut ctx.unifier, in_a_ty);
|
let lhs_dtype = arraylike_flatten_element_type(&mut ctx.unifier, in_a_ty);
|
||||||
let rhs_dtype = arraylike_flatten_element_type(&mut ctx.unifier, in_b_ty);
|
let rhs_dtype = arraylike_flatten_element_type(&mut ctx.unifier, in_b_ty);
|
||||||
|
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let llvm_dst_dtype = ctx.get_llvm_type(generator, dst_dtype);
|
let llvm_dst_dtype = ctx.get_llvm_type(generator, dst_dtype);
|
||||||
|
|
||||||
// Deduce ndims of the result of matmul.
|
// Deduce ndims of the result of matmul.
|
||||||
@ -108,7 +108,7 @@ fn matmul_at_least_2d<'ctx, G: CodeGenerator>(
|
|||||||
let lhs = in_a.broadcast_to(generator, ctx, ndims_int, &lhs_shape);
|
let lhs = in_a.broadcast_to(generator, ctx, ndims_int, &lhs_shape);
|
||||||
let rhs = in_b.broadcast_to(generator, ctx, ndims_int, &rhs_shape);
|
let rhs = in_b.broadcast_to(generator, ctx, ndims_int, &rhs_shape);
|
||||||
|
|
||||||
let dst = NDArrayType::new(generator, ctx.ctx, llvm_dst_dtype, ndims_int)
|
let dst = NDArrayType::new(ctx, llvm_dst_dtype, ndims_int)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
dst.copy_shape_from_array(generator, ctx, dst_shape.base_ptr(ctx, generator));
|
dst.copy_shape_from_array(generator, ctx, dst_shape.base_ptr(ctx, generator));
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -315,7 +315,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
let result_shape = result.shape();
|
let result_shape = result.shape();
|
||||||
out_ndarray.assert_can_be_written_by_out(generator, ctx, result_shape);
|
out_ndarray.assert_can_be_written_by_out(generator, ctx, result_shape);
|
||||||
|
|
||||||
out_ndarray.copy_data_from(generator, ctx, result);
|
out_ndarray.copy_data_from(ctx, result);
|
||||||
out_ndarray
|
out_ndarray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ use std::iter::repeat_n;
|
|||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{AnyType, AnyTypeEnum, BasicType, BasicTypeEnum, IntType},
|
types::{AnyType, AnyTypeEnum, BasicType, BasicTypeEnum, IntType},
|
||||||
values::{BasicValue, BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValue, BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace, IntPredicate,
|
AddressSpace, IntPredicate,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ProxyValue, TupleValue, TypedArrayLikeAccessor,
|
structure::StructProxyValue, ArrayLikeIndexer, ArrayLikeValue, ProxyValue, TupleValue,
|
||||||
TypedArrayLikeAdapter, TypedArrayLikeMutator, UntypedArrayLikeAccessor,
|
TypedArrayLikeAccessor, TypedArrayLikeAdapter, TypedArrayLikeMutator, UntypedArrayLikeAccessor,
|
||||||
UntypedArrayLikeMutator,
|
UntypedArrayLikeMutator,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -18,7 +18,11 @@ use crate::{
|
|||||||
llvm_intrinsics::{call_int_umin, call_memcpy_generic_array},
|
llvm_intrinsics::{call_int_umin, call_memcpy_generic_array},
|
||||||
stmt::gen_for_callback_incrementing,
|
stmt::gen_for_callback_incrementing,
|
||||||
type_aligned_alloca,
|
type_aligned_alloca,
|
||||||
types::{ndarray::NDArrayType, structure::StructField, TupleType},
|
types::{
|
||||||
|
ndarray::NDArrayType,
|
||||||
|
structure::{StructField, StructProxyType},
|
||||||
|
TupleType,
|
||||||
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
typecheck::typedef::{Type, TypeEnum},
|
typecheck::typedef::{Type, TypeEnum},
|
||||||
@ -30,6 +34,7 @@ pub use nditer::*;
|
|||||||
|
|
||||||
mod broadcast;
|
mod broadcast;
|
||||||
mod contiguous;
|
mod contiguous;
|
||||||
|
mod fold;
|
||||||
mod indexing;
|
mod indexing;
|
||||||
mod map;
|
mod map;
|
||||||
mod matmul;
|
mod matmul;
|
||||||
@ -48,13 +53,26 @@ pub struct NDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDArrayValue<'ctx> {
|
impl<'ctx> NDArrayValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `NDArray`, returning [Err] if `value` is not an
|
/// Creates an [`NDArrayValue`] from a [`StructValue`].
|
||||||
/// instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
|
dtype: BasicTypeEnum<'ctx>,
|
||||||
|
ndims: u64,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
NDArrayType::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, dtype, ndims, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
||||||
@ -66,67 +84,50 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
NDArrayValue { value: ptr, dtype, ndims, llvm_usize, name }
|
NDArrayValue { value: ptr, dtype, ndims, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ndims_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, IntValue<'ctx>> {
|
fn ndims_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
self.get_type().get_fields(ctx.ctx).ndims
|
self.get_type().get_fields().ndims
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the pointer to the field storing the number of dimensions of this `NDArray`.
|
|
||||||
fn ptr_to_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
|
||||||
self.ndims_field(ctx).ptr_by_gep(ctx, self.value, self.name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the number of dimensions `ndims` into this instance.
|
/// Stores the number of dimensions `ndims` into this instance.
|
||||||
pub fn store_ndims<G: CodeGenerator + ?Sized>(
|
pub fn store_ndims(&self, ctx: &CodeGenContext<'ctx, '_>, ndims: IntValue<'ctx>) {
|
||||||
&self,
|
debug_assert_eq!(ndims.get_type(), ctx.get_size_type());
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
generator: &G,
|
|
||||||
ndims: IntValue<'ctx>,
|
|
||||||
) {
|
|
||||||
debug_assert_eq!(ndims.get_type(), generator.get_size_type(ctx.ctx));
|
|
||||||
|
|
||||||
let pndims = self.ptr_to_ndims(ctx);
|
self.ndims_field().store(ctx, self.value, ndims, self.name);
|
||||||
ctx.builder.build_store(pndims, ndims).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of dimensions of this `NDArray` as a value.
|
/// Returns the number of dimensions of this `NDArray` as a value.
|
||||||
pub fn load_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
let pndims = self.ptr_to_ndims(ctx);
|
self.ndims_field().load(ctx, self.value, self.name)
|
||||||
ctx.builder.build_load(pndims, "").map(BasicValueEnum::into_int_value).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn itemsize_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, IntValue<'ctx>> {
|
fn itemsize_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
self.get_type().get_fields(ctx.ctx).itemsize
|
self.get_type().get_fields().itemsize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the size of each element `itemsize` into this instance.
|
/// Stores the size of each element `itemsize` into this instance.
|
||||||
pub fn store_itemsize<G: CodeGenerator + ?Sized>(
|
pub fn store_itemsize(&self, ctx: &CodeGenContext<'ctx, '_>, itemsize: IntValue<'ctx>) {
|
||||||
&self,
|
debug_assert_eq!(itemsize.get_type(), ctx.get_size_type());
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
generator: &G,
|
|
||||||
itemsize: IntValue<'ctx>,
|
|
||||||
) {
|
|
||||||
debug_assert_eq!(itemsize.get_type(), generator.get_size_type(ctx.ctx));
|
|
||||||
|
|
||||||
self.itemsize_field(ctx).set(ctx, self.value, itemsize, self.name);
|
self.itemsize_field().store(ctx, self.value, itemsize, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size of each element of this `NDArray` as a value.
|
/// Returns the size of each element of this `NDArray` as a value.
|
||||||
pub fn load_itemsize(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_itemsize(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.itemsize_field(ctx).get(ctx, self.value, self.name)
|
self.itemsize_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn shape_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
self.get_type().get_fields(ctx.ctx).shape
|
self.get_type().get_fields().shape
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the array of dimension sizes `dims` into this instance.
|
/// Stores the array of dimension sizes `dims` into this instance.
|
||||||
fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, dims: PointerValue<'ctx>) {
|
fn store_shape(&self, ctx: &CodeGenContext<'ctx, '_>, dims: PointerValue<'ctx>) {
|
||||||
self.shape_field(ctx).set(ctx, self.as_base_value(), dims, self.name);
|
self.shape_field().store(ctx, self.value, dims, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for creating a new array storing dimension sizes with the given `size`.
|
/// Convenience method for creating a new array storing dimension sizes with the given `size`.
|
||||||
@ -145,16 +146,13 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
NDArrayShapeProxy(self)
|
NDArrayShapeProxy(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strides_field(
|
fn strides_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
&self,
|
self.get_type().get_fields().strides
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> StructField<'ctx, PointerValue<'ctx>> {
|
|
||||||
self.get_type().get_fields(ctx.ctx).strides
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the array of stride sizes `strides` into this instance.
|
/// Stores the array of stride sizes `strides` into this instance.
|
||||||
fn store_strides(&self, ctx: &CodeGenContext<'ctx, '_>, strides: PointerValue<'ctx>) {
|
fn store_strides(&self, ctx: &CodeGenContext<'ctx, '_>, strides: PointerValue<'ctx>) {
|
||||||
self.strides_field(ctx).set(ctx, self.as_base_value(), strides, self.name);
|
self.strides_field().store(ctx, self.value, strides, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for creating a new array storing the stride with the given `size`.
|
/// Convenience method for creating a new array storing the stride with the given `size`.
|
||||||
@ -173,14 +171,14 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
NDArrayStridesProxy(self)
|
NDArrayStridesProxy(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, PointerValue<'ctx>> {
|
fn data_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
self.get_type().get_fields(ctx.ctx).data
|
self.get_type().get_fields().data
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
|
||||||
/// on the field.
|
/// on the field.
|
||||||
pub fn ptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn ptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
self.data_field(ctx).ptr_by_gep(ctx, self.value, self.name)
|
self.data_field().ptr_by_gep(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the array of data elements `data` into this instance.
|
/// Stores the array of data elements `data` into this instance.
|
||||||
@ -189,7 +187,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
.builder
|
.builder
|
||||||
.build_bit_cast(data, ctx.ctx.i8_type().ptr_type(AddressSpace::default()), "")
|
.build_bit_cast(data, ctx.ctx.i8_type().ptr_type(AddressSpace::default()), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.data_field(ctx).set(ctx, self.as_base_value(), data.into_pointer_value(), self.name);
|
self.data_field().store(ctx, self.value, data.into_pointer_value(), self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for creating a new array storing data elements with the given element
|
/// Convenience method for creating a new array storing data elements with the given element
|
||||||
@ -205,12 +203,12 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
) {
|
) {
|
||||||
let nbytes = self.nbytes(generator, ctx);
|
let nbytes = self.nbytes(ctx);
|
||||||
|
|
||||||
let data = type_aligned_alloca(generator, ctx, self.dtype, nbytes, None);
|
let data = type_aligned_alloca(generator, ctx, self.dtype, nbytes, None);
|
||||||
self.store_data(ctx, data);
|
self.store_data(ctx, data);
|
||||||
|
|
||||||
self.set_strides_contiguous(generator, ctx);
|
self.set_strides_contiguous(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a proxy object to the field storing the data of this `NDArray`.
|
/// Returns a proxy object to the field storing the data of this `NDArray`.
|
||||||
@ -284,52 +282,32 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the `np.size()` of this ndarray.
|
/// Get the `np.size()` of this ndarray.
|
||||||
pub fn size<G: CodeGenerator + ?Sized>(
|
pub fn size(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
&self,
|
irrt::ndarray::call_nac3_ndarray_size(ctx, *self)
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
irrt::ndarray::call_nac3_ndarray_size(generator, ctx, *self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the `ndarray.nbytes` of this ndarray.
|
/// Get the `ndarray.nbytes` of this ndarray.
|
||||||
pub fn nbytes<G: CodeGenerator + ?Sized>(
|
pub fn nbytes(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
&self,
|
irrt::ndarray::call_nac3_ndarray_nbytes(ctx, *self)
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
irrt::ndarray::call_nac3_ndarray_nbytes(generator, ctx, *self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the `len()` of this ndarray.
|
/// Get the `len()` of this ndarray.
|
||||||
pub fn len<G: CodeGenerator + ?Sized>(
|
pub fn len(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
&self,
|
irrt::ndarray::call_nac3_ndarray_len(ctx, *self)
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
irrt::ndarray::call_nac3_ndarray_len(generator, ctx, *self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this ndarray is C-contiguous.
|
/// Check if this ndarray is C-contiguous.
|
||||||
///
|
///
|
||||||
/// See NumPy's `flags["C_CONTIGUOUS"]`: <https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flags.html#numpy.ndarray.flags>
|
/// See NumPy's `flags["C_CONTIGUOUS"]`: <https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flags.html#numpy.ndarray.flags>
|
||||||
pub fn is_c_contiguous<G: CodeGenerator + ?Sized>(
|
pub fn is_c_contiguous(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
&self,
|
irrt::ndarray::call_nac3_ndarray_is_c_contiguous(ctx, *self)
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
irrt::ndarray::call_nac3_ndarray_is_c_contiguous(generator, ctx, *self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call [`call_nac3_ndarray_set_strides_by_shape`] on this ndarray to update `strides`.
|
/// Call [`call_nac3_ndarray_set_strides_by_shape`] on this ndarray to update `strides`.
|
||||||
///
|
///
|
||||||
/// Update the ndarray's strides to make the ndarray contiguous.
|
/// Update the ndarray's strides to make the ndarray contiguous.
|
||||||
pub fn set_strides_contiguous<G: CodeGenerator + ?Sized>(
|
pub fn set_strides_contiguous(&self, ctx: &CodeGenContext<'ctx, '_>) {
|
||||||
&self,
|
irrt::ndarray::call_nac3_ndarray_set_strides_by_shape(ctx, *self);
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) {
|
|
||||||
irrt::ndarray::call_nac3_ndarray_set_strides_by_shape(generator, ctx, *self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone/Copy this ndarray - Allocate a new ndarray with the same shape as this ndarray and
|
/// Clone/Copy this ndarray - Allocate a new ndarray with the same shape as this ndarray and
|
||||||
@ -347,7 +325,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
let shape = self.shape();
|
let shape = self.shape();
|
||||||
clone.copy_shape_from_array(generator, ctx, shape.base_ptr(ctx, generator));
|
clone.copy_shape_from_array(generator, ctx, shape.base_ptr(ctx, generator));
|
||||||
unsafe { clone.create_data(generator, ctx) };
|
unsafe { clone.create_data(generator, ctx) };
|
||||||
clone.copy_data_from(generator, ctx, *self);
|
clone.copy_data_from(ctx, *self);
|
||||||
clone
|
clone
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,14 +335,9 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
/// do not matter. The copying order is determined by how their flattened views look.
|
/// do not matter. The copying order is determined by how their flattened views look.
|
||||||
///
|
///
|
||||||
/// Panics if the `dtype`s of ndarrays are different.
|
/// Panics if the `dtype`s of ndarrays are different.
|
||||||
pub fn copy_data_from<G: CodeGenerator + ?Sized>(
|
pub fn copy_data_from(&self, ctx: &CodeGenContext<'ctx, '_>, src: NDArrayValue<'ctx>) {
|
||||||
&self,
|
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
src: NDArrayValue<'ctx>,
|
|
||||||
) {
|
|
||||||
assert_eq!(self.dtype, src.dtype, "self and src dtype should match");
|
assert_eq!(self.dtype, src.dtype, "self and src dtype should match");
|
||||||
irrt::ndarray::call_nac3_ndarray_copy_data(generator, ctx, src, *self);
|
irrt::ndarray::call_nac3_ndarray_copy_data(ctx, src, *self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill the ndarray with a scalar.
|
/// Fill the ndarray with a scalar.
|
||||||
@ -412,12 +385,8 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
.map(|obj| obj.as_basic_value_enum())
|
.map(|obj| obj.as_basic_value_enum())
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
TupleType::new(
|
TupleType::new(ctx, &repeat_n(llvm_i32, self.ndims as usize).collect_vec())
|
||||||
generator,
|
.construct_from_objects(ctx, objects, None)
|
||||||
ctx.ctx,
|
|
||||||
&repeat_n(llvm_i32.into(), self.ndims as usize).collect_vec(),
|
|
||||||
)
|
|
||||||
.construct_from_objects(ctx, objects, None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the strides tuple of this ndarray like
|
/// Create the strides tuple of this ndarray like
|
||||||
@ -446,12 +415,8 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
.map(|obj| obj.as_basic_value_enum())
|
.map(|obj| obj.as_basic_value_enum())
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
TupleType::new(
|
TupleType::new(ctx, &repeat_n(llvm_i32, self.ndims as usize).collect_vec())
|
||||||
generator,
|
.construct_from_objects(ctx, objects, None)
|
||||||
ctx.ctx,
|
|
||||||
&repeat_n(llvm_i32.into(), self.ndims as usize).collect_vec(),
|
|
||||||
)
|
|
||||||
.construct_from_objects(ctx, objects, None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this ndarray is unsized - `ndims == 0` and only contains a scalar.
|
/// Returns true if this ndarray is unsized - `ndims == 0` and only contains a scalar.
|
||||||
@ -468,7 +433,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
if self.is_unsized() {
|
if self.is_unsized() {
|
||||||
// NOTE: `np.size(self) == 0` here is never possible.
|
// NOTE: `np.size(self) == 0` here is never possible.
|
||||||
let zero = generator.get_size_type(ctx.ctx).const_zero();
|
let zero = ctx.get_size_type().const_zero();
|
||||||
let value = unsafe { self.data().get_unchecked(ctx, generator, &zero, None) };
|
let value = unsafe { self.data().get_unchecked(ctx, generator, &zero, None) };
|
||||||
|
|
||||||
Some(value)
|
Some(value)
|
||||||
@ -513,11 +478,12 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = NDArrayType<'ctx>;
|
type Type = NDArrayType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
NDArrayType::from_type(
|
NDArrayType::from_pointer_type(
|
||||||
self.as_base_value().get_type(),
|
self.as_base_value().get_type(),
|
||||||
self.dtype,
|
self.dtype,
|
||||||
self.ndims,
|
self.ndims,
|
||||||
@ -528,8 +494,14 @@ impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {
|
|||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for NDArrayValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<NDArrayValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<NDArrayValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: NDArrayValue<'ctx>) -> Self {
|
fn from(value: NDArrayValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -554,7 +526,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayShapeProxy<'ctx, '_> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
_: &G,
|
_: &G,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
self.0.shape_field(ctx).get(ctx, self.0.as_base_value(), self.0.name)
|
self.0.shape_field().load(ctx, self.0.value, self.0.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size<G: CodeGenerator + ?Sized>(
|
fn size<G: CodeGenerator + ?Sized>(
|
||||||
@ -652,7 +624,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayStridesProxy<'ctx, '_> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
_: &G,
|
_: &G,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
self.0.strides_field(ctx).get(ctx, self.0.as_base_value(), self.0.name)
|
self.0.strides_field().load(ctx, self.0.value, self.0.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size<G: CodeGenerator + ?Sized>(
|
fn size<G: CodeGenerator + ?Sized>(
|
||||||
@ -750,15 +722,15 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
_: &G,
|
_: &G,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
self.0.data_field(ctx).get(ctx, self.0.as_base_value(), self.0.name)
|
self.0.data_field().load(ctx, self.0.value, self.0.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size<G: CodeGenerator + ?Sized>(
|
fn size<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
generator: &G,
|
_: &G,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
irrt::ndarray::call_nac3_ndarray_len(generator, ctx, *self.0)
|
irrt::ndarray::call_nac3_ndarray_len(ctx, *self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +742,7 @@ impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx, '_> {
|
|||||||
idx: &IntValue<'ctx>,
|
idx: &IntValue<'ctx>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let ptr = irrt::ndarray::call_nac3_ndarray_get_nth_pelement(generator, ctx, *self.0, *idx);
|
let ptr = irrt::ndarray::call_nac3_ndarray_get_nth_pelement(ctx, *self.0, *idx);
|
||||||
|
|
||||||
// Current implementation is transparent - The returned pointer type is
|
// Current implementation is transparent - The returned pointer type is
|
||||||
// already cast into the expected type, allowing for immediately
|
// already cast into the expected type, allowing for immediately
|
||||||
@ -834,7 +806,7 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
|
|||||||
indices: &Index,
|
indices: &Index,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
assert_eq!(indices.element_type(ctx, generator), generator.get_size_type(ctx.ctx).into());
|
assert_eq!(indices.element_type(ctx, generator), ctx.get_size_type().into());
|
||||||
|
|
||||||
let indices = TypedArrayLikeAdapter::from(
|
let indices = TypedArrayLikeAdapter::from(
|
||||||
indices.as_slice_value(ctx, generator),
|
indices.as_slice_value(ctx, generator),
|
||||||
@ -867,7 +839,7 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
|
|||||||
indices: &Index,
|
indices: &Index,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
let indices_size = indices.size(ctx, generator);
|
let indices_size = indices.size(ctx, generator);
|
||||||
let nidx_leq_ndims = ctx
|
let nidx_leq_ndims = ctx
|
||||||
@ -1004,7 +976,7 @@ impl<'ctx> ScalarOrNDArray<'ctx> {
|
|||||||
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.ndarray.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, object_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, object_ty)
|
||||||
.map_value(object.into_pointer_value(), None);
|
.map_pointer_value(object.into_pointer_value(), None);
|
||||||
ScalarOrNDArray::NDArray(ndarray)
|
ScalarOrNDArray::NDArray(ndarray)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,7 +989,7 @@ impl<'ctx> ScalarOrNDArray<'ctx> {
|
|||||||
pub fn to_basic_value_enum(self) -> BasicValueEnum<'ctx> {
|
pub fn to_basic_value_enum(self) -> BasicValueEnum<'ctx> {
|
||||||
match self {
|
match self {
|
||||||
ScalarOrNDArray::Scalar(scalar) => scalar,
|
ScalarOrNDArray::Scalar(scalar) => scalar,
|
||||||
ScalarOrNDArray::NDArray(ndarray) => ndarray.as_base_value().into(),
|
ScalarOrNDArray::NDArray(ndarray) => ndarray.value.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1033,10 +1005,8 @@ impl<'ctx> ScalarOrNDArray<'ctx> {
|
|||||||
) -> NDArrayValue<'ctx> {
|
) -> NDArrayValue<'ctx> {
|
||||||
match self {
|
match self {
|
||||||
ScalarOrNDArray::NDArray(ndarray) => *ndarray,
|
ScalarOrNDArray::NDArray(ndarray) => *ndarray,
|
||||||
ScalarOrNDArray::Scalar(scalar) => {
|
ScalarOrNDArray::Scalar(scalar) => NDArrayType::new_unsized(ctx, scalar.get_type())
|
||||||
NDArrayType::new_unsized(generator, ctx.ctx, scalar.get_type())
|
.construct_unsized(generator, ctx, scalar, None),
|
||||||
.construct_unsized(generator, ctx, scalar, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::{BasicType, IntType},
|
types::{BasicType, IntType},
|
||||||
values::{BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue, StructValue},
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{NDArrayValue, ProxyValue};
|
use super::NDArrayValue;
|
||||||
use crate::codegen::{
|
use crate::codegen::{
|
||||||
irrt,
|
irrt,
|
||||||
stmt::{gen_for_callback, BreakContinueHooks},
|
stmt::{gen_for_callback, BreakContinueHooks},
|
||||||
types::{ndarray::NDIterType, structure::StructField},
|
types::{
|
||||||
values::{ArraySliceValue, TypedArrayLikeAdapter},
|
ndarray::NDIterType,
|
||||||
|
structure::{StructField, StructProxyType},
|
||||||
|
},
|
||||||
|
values::{structure::StructProxyValue, ArraySliceValue, ProxyValue, TypedArrayLikeAdapter},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,13 +26,26 @@ pub struct NDIterValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIterValue<'ctx> {
|
impl<'ctx> NDIterValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `NDArray`, returning [Err] if `value` is not an
|
/// Creates an [`NDArrayValue`] from a [`StructValue`].
|
||||||
/// instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
|
parent: NDArrayValue<'ctx>,
|
||||||
|
indices: ArraySliceValue<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
<Self as ProxyValue>::Type::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, parent, indices, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
||||||
@ -41,7 +57,7 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, parent, indices, llvm_usize, name }
|
Self { value: ptr, parent, indices, llvm_usize, name }
|
||||||
}
|
}
|
||||||
@ -53,27 +69,20 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
/// If `ndarray` is unsized, this returns true only for the first iteration.
|
/// If `ndarray` is unsized, this returns true only for the first iteration.
|
||||||
/// If `ndarray` is 0-sized, this always returns false.
|
/// If `ndarray` is 0-sized, this always returns false.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn has_element<G: CodeGenerator + ?Sized>(
|
pub fn has_element(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
&self,
|
irrt::ndarray::call_nac3_nditer_has_element(ctx, *self)
|
||||||
generator: &G,
|
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> IntValue<'ctx> {
|
|
||||||
irrt::ndarray::call_nac3_nditer_has_element(generator, ctx, *self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Go to the next element. If `has_element()` is false, then this has undefined behavior.
|
/// Go to the next element. If `has_element()` is false, then this has undefined behavior.
|
||||||
///
|
///
|
||||||
/// If `ndarray` is unsized, this can only be called once.
|
/// If `ndarray` is unsized, this can only be called once.
|
||||||
/// If `ndarray` is 0-sized, this can never be called.
|
/// If `ndarray` is 0-sized, this can never be called.
|
||||||
pub fn next<G: CodeGenerator + ?Sized>(&self, generator: &G, ctx: &CodeGenContext<'ctx, '_>) {
|
pub fn next(&self, ctx: &CodeGenContext<'ctx, '_>) {
|
||||||
irrt::ndarray::call_nac3_nditer_next(generator, ctx, *self);
|
irrt::ndarray::call_nac3_nditer_next(ctx, *self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn element_field(
|
fn element_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
|
||||||
&self,
|
self.get_type().get_fields().element
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
|
||||||
) -> StructField<'ctx, PointerValue<'ctx>> {
|
|
||||||
self.get_type().get_fields(ctx.ctx).element
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get pointer to the current element.
|
/// Get pointer to the current element.
|
||||||
@ -81,7 +90,7 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
pub fn get_pointer(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
pub fn get_pointer(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
let elem_ty = self.parent.dtype;
|
let elem_ty = self.parent.dtype;
|
||||||
|
|
||||||
let p = self.element_field(ctx).get(ctx, self.as_base_value(), self.name);
|
let p = self.element_field().load(ctx, self.as_abi_value(ctx), self.name);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_pointer_cast(p, elem_ty.ptr_type(AddressSpace::default()), "element")
|
.build_pointer_cast(p, elem_ty.ptr_type(AddressSpace::default()), "element")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -94,14 +103,14 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
ctx.builder.build_load(p, "value").unwrap()
|
ctx.builder.build_load(p, "value").unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nth_field(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructField<'ctx, IntValue<'ctx>> {
|
fn nth_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
self.get_type().get_fields(ctx.ctx).nth
|
self.get_type().get_fields().nth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the index of the current element if this ndarray were a flat ndarray.
|
/// Get the index of the current element if this ndarray were a flat ndarray.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_index(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn get_index(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.nth_field(ctx).get(ctx, self.as_base_value(), self.name)
|
self.nth_field().load(ctx, self.as_abi_value(ctx), self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the indices of the current element.
|
/// Get the indices of the current element.
|
||||||
@ -118,18 +127,25 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for NDIterValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for NDIterValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = NDIterType<'ctx>;
|
type Type = NDIterType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
NDIterType::from_type(self.as_base_value().get_type(), self.llvm_usize)
|
NDIterType::from_pointer_type(self.as_base_value().get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for NDIterValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<NDIterValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<NDIterValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: NDIterValue<'ctx>) -> Self {
|
fn from(value: NDIterValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
@ -141,10 +157,6 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
///
|
///
|
||||||
/// `body` has access to [`BreakContinueHooks`] to short-circuit and [`NDIterValue`] to
|
/// `body` has access to [`BreakContinueHooks`] to short-circuit and [`NDIterValue`] to
|
||||||
/// get properties of the current iteration (e.g., the current element, indices, etc.)
|
/// get properties of the current iteration (e.g., the current element, indices, etc.)
|
||||||
///
|
|
||||||
/// Note: The caller is recommended to call `llvm.stacksave` and `llvm.stackrestore` before and
|
|
||||||
/// after invoking this function respectively. See [`NDIterType::construct`] for an explanation
|
|
||||||
/// on why this is suggested.
|
|
||||||
pub fn foreach<'a, G, F>(
|
pub fn foreach<'a, G, F>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
@ -164,13 +176,11 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
Some("ndarray_foreach"),
|
Some("ndarray_foreach"),
|
||||||
|generator, ctx| {
|
|generator, ctx| Ok(NDIterType::new(ctx).construct(generator, ctx, *self)),
|
||||||
Ok(NDIterType::new(generator, ctx.ctx).construct(generator, ctx, *self))
|
|_, ctx, nditer| Ok(nditer.has_element(ctx)),
|
||||||
},
|
|
||||||
|generator, ctx, nditer| Ok(nditer.has_element(generator, ctx)),
|
|
||||||
|generator, ctx, hooks, nditer| body(generator, ctx, hooks, nditer),
|
|generator, ctx, hooks, nditer| body(generator, ctx, hooks, nditer),
|
||||||
|generator, ctx, nditer| {
|
|_, ctx, nditer| {
|
||||||
nditer.next(generator, ctx);
|
nditer.next(ctx);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -30,7 +30,7 @@ pub fn parse_numpy_int_sequence<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
(input_seq_ty, input_seq): (Type, BasicValueEnum<'ctx>),
|
(input_seq_ty, input_seq): (Type, BasicValueEnum<'ctx>),
|
||||||
) -> impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>> {
|
) -> impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>> {
|
||||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
let llvm_usize = ctx.get_size_type();
|
||||||
let zero = llvm_usize.const_zero();
|
let zero = llvm_usize.const_zero();
|
||||||
let one = llvm_usize.const_int(1, false);
|
let one = llvm_usize.const_int(1, false);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ pub fn parse_numpy_int_sequence<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
// 1. A list of `int32`; e.g., `np.empty([600, 800, 3])`
|
// 1. A list of `int32`; e.g., `np.empty([600, 800, 3])`
|
||||||
|
|
||||||
let input_seq = ListType::from_unifier_type(generator, ctx, input_seq_ty)
|
let input_seq = ListType::from_unifier_type(generator, ctx, input_seq_ty)
|
||||||
.map_value(input_seq.into_pointer_value(), None);
|
.map_pointer_value(input_seq.into_pointer_value(), None);
|
||||||
|
|
||||||
let len = input_seq.load_size(ctx, None);
|
let len = input_seq.load_size(ctx, None);
|
||||||
// TODO: Find a way to remove this mid-BB allocation
|
// TODO: Find a way to remove this mid-BB allocation
|
||||||
@ -86,7 +86,7 @@ pub fn parse_numpy_int_sequence<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
// 2. A tuple of ints; e.g., `np.empty((600, 800, 3))`
|
// 2. A tuple of ints; e.g., `np.empty((600, 800, 3))`
|
||||||
|
|
||||||
let input_seq = TupleType::from_unifier_type(generator, ctx, input_seq_ty)
|
let input_seq = TupleType::from_unifier_type(generator, ctx, input_seq_ty)
|
||||||
.map_value(input_seq.into_struct_value(), None);
|
.map_struct_value(input_seq.into_struct_value(), None);
|
||||||
|
|
||||||
let len = input_seq.get_type().num_elements();
|
let len = input_seq.get_type().num_elements();
|
||||||
|
|
||||||
|
@ -65,12 +65,12 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
// not contiguous but could be reshaped without copying data. Look into how numpy does
|
// not contiguous but could be reshaped without copying data. Look into how numpy does
|
||||||
// it.
|
// it.
|
||||||
|
|
||||||
let dst_ndarray = NDArrayType::new(generator, ctx.ctx, self.dtype, new_ndims)
|
let dst_ndarray = NDArrayType::new(ctx, self.dtype, new_ndims)
|
||||||
.construct_uninitialized(generator, ctx, None);
|
.construct_uninitialized(generator, ctx, None);
|
||||||
dst_ndarray.copy_shape_from_array(generator, ctx, new_shape.base_ptr(ctx, generator));
|
dst_ndarray.copy_shape_from_array(generator, ctx, new_shape.base_ptr(ctx, generator));
|
||||||
|
|
||||||
// Resolve negative indices
|
// Resolve negative indices
|
||||||
let size = self.size(generator, ctx);
|
let size = self.size(ctx);
|
||||||
let dst_ndims = self.llvm_usize.const_int(dst_ndarray.get_type().ndims(), false);
|
let dst_ndims = self.llvm_usize.const_int(dst_ndarray.get_type().ndims(), false);
|
||||||
let dst_shape = dst_ndarray.shape();
|
let dst_shape = dst_ndarray.shape();
|
||||||
irrt::ndarray::call_nac3_ndarray_reshape_resolve_and_check_new_shape(
|
irrt::ndarray::call_nac3_ndarray_reshape_resolve_and_check_new_shape(
|
||||||
@ -84,10 +84,10 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
gen_if_callback(
|
gen_if_callback(
|
||||||
generator,
|
generator,
|
||||||
ctx,
|
ctx,
|
||||||
|generator, ctx| Ok(self.is_c_contiguous(generator, ctx)),
|
|_, ctx| Ok(self.is_c_contiguous(ctx)),
|
||||||
|generator, ctx| {
|
|generator, ctx| {
|
||||||
// Reshape is possible without copying
|
// Reshape is possible without copying
|
||||||
dst_ndarray.set_strides_contiguous(generator, ctx);
|
dst_ndarray.set_strides_contiguous(ctx);
|
||||||
dst_ndarray.store_data(ctx, self.data().base_ptr(ctx, generator));
|
dst_ndarray.store_data(ctx, self.data().base_ptr(ctx, generator));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -97,7 +97,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
dst_ndarray.create_data(generator, ctx);
|
dst_ndarray.create_data(generator, ctx);
|
||||||
}
|
}
|
||||||
dst_ndarray.copy_data_from(generator, ctx, *self);
|
dst_ndarray.copy_data_from(ctx, *self);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
@ -1,27 +1,50 @@
|
|||||||
use inkwell::values::{BasicValueEnum, IntValue, PointerValue};
|
use inkwell::{
|
||||||
|
types::IntType,
|
||||||
|
values::{ArrayValue, BasicValueEnum, IntValue, PointerValue},
|
||||||
|
};
|
||||||
|
|
||||||
use super::ProxyValue;
|
use super::ProxyValue;
|
||||||
use crate::codegen::{types::RangeType, CodeGenContext};
|
use crate::codegen::{types::RangeType, CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
/// Proxy type for accessing a `range` value in LLVM.
|
/// Proxy type for accessing a `range` value in LLVM.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct RangeValue<'ctx> {
|
pub struct RangeValue<'ctx> {
|
||||||
value: PointerValue<'ctx>,
|
value: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> RangeValue<'ctx> {
|
impl<'ctx> RangeValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `range`, returning [Err] if `value` is not an instance.
|
/// Creates an [`RangeValue`] from a [`PointerValue`].
|
||||||
pub fn is_representable(value: PointerValue<'ctx>) -> Result<(), String> {
|
#[must_use]
|
||||||
RangeType::is_representable(value.get_type())
|
pub fn from_array_value<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: ArrayValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`RangeValue`] from a [`PointerValue`].
|
/// Creates an [`RangeValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(ptr: PointerValue<'ctx>, name: Option<&'ctx str>) -> Self {
|
pub fn from_pointer_value(
|
||||||
debug_assert!(Self::is_representable(ptr).is_ok());
|
ptr: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
RangeValue { value: ptr, name }
|
RangeValue { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr_to_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
fn ptr_to_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
@ -31,7 +54,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_in_bounds_gep(
|
.build_in_bounds_gep(
|
||||||
self.as_base_value(),
|
self.as_abi_value(ctx),
|
||||||
&[llvm_i32.const_zero(), llvm_i32.const_int(0, false)],
|
&[llvm_i32.const_zero(), llvm_i32.const_int(0, false)],
|
||||||
var_name.as_str(),
|
var_name.as_str(),
|
||||||
)
|
)
|
||||||
@ -46,7 +69,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_in_bounds_gep(
|
.build_in_bounds_gep(
|
||||||
self.as_base_value(),
|
self.as_abi_value(ctx),
|
||||||
&[llvm_i32.const_zero(), llvm_i32.const_int(1, false)],
|
&[llvm_i32.const_zero(), llvm_i32.const_int(1, false)],
|
||||||
var_name.as_str(),
|
var_name.as_str(),
|
||||||
)
|
)
|
||||||
@ -61,7 +84,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_in_bounds_gep(
|
.build_in_bounds_gep(
|
||||||
self.as_base_value(),
|
self.as_abi_value(ctx),
|
||||||
&[llvm_i32.const_zero(), llvm_i32.const_int(2, false)],
|
&[llvm_i32.const_zero(), llvm_i32.const_int(2, false)],
|
||||||
var_name.as_str(),
|
var_name.as_str(),
|
||||||
)
|
)
|
||||||
@ -134,16 +157,21 @@ impl<'ctx> RangeValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for RangeValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for RangeValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = RangeType<'ctx>;
|
type Type = RangeType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
RangeType::from_type(self.value.get_type())
|
RangeType::from_pointer_type(self.value.get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<RangeValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<RangeValue<'ctx>> for PointerValue<'ctx> {
|
||||||
|
24
nac3core/src/codegen/values/structure.rs
Normal file
24
nac3core/src/codegen/values/structure.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use inkwell::values::{BasicValueEnum, PointerValue, StructValue};
|
||||||
|
|
||||||
|
use super::ProxyValue;
|
||||||
|
use crate::codegen::{types::structure::StructProxyType, CodeGenContext};
|
||||||
|
|
||||||
|
/// An LLVM value that is used to represent a corresponding structure-like value in NAC3.
|
||||||
|
pub trait StructProxyValue<'ctx>:
|
||||||
|
ProxyValue<'ctx, Base = PointerValue<'ctx>, Type: StructProxyType<'ctx, Value = Self>>
|
||||||
|
{
|
||||||
|
/// Returns this value as a [`StructValue`].
|
||||||
|
#[must_use]
|
||||||
|
fn get_struct_value(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructValue<'ctx> {
|
||||||
|
ctx.builder
|
||||||
|
.build_load(self.get_pointer_value(ctx), "")
|
||||||
|
.map(BasicValueEnum::into_struct_value)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns this value as a [`PointerValue`].
|
||||||
|
#[must_use]
|
||||||
|
fn get_pointer_value(&self, _: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::IntType,
|
types::IntType,
|
||||||
values::{BasicValue, BasicValueEnum, StructValue},
|
values::{BasicValue, BasicValueEnum, PointerValue, StructValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::ProxyValue;
|
use super::ProxyValue;
|
||||||
@ -14,15 +14,6 @@ pub struct TupleValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> TupleValue<'ctx> {
|
impl<'ctx> TupleValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `tuple`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: StructValue<'ctx>,
|
|
||||||
_llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
TupleType::is_representable(value.get_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`TupleValue`] from a [`StructValue`].
|
/// Creates an [`TupleValue`] from a [`StructValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_struct_value(
|
pub fn from_struct_value(
|
||||||
@ -30,11 +21,29 @@ impl<'ctx> TupleValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(value, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(value, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value, llvm_usize, name }
|
Self { value, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an [`TupleValue`] from a [`PointerValue`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_pointer_value(
|
||||||
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
|
ptr: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
Self::from_struct_value(
|
||||||
|
ctx.builder
|
||||||
|
.build_load(ptr, name.unwrap_or_default())
|
||||||
|
.map(BasicValueEnum::into_struct_value)
|
||||||
|
.unwrap(),
|
||||||
|
llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Stores a value into the tuple element at the given `index`.
|
/// Stores a value into the tuple element at the given `index`.
|
||||||
pub fn store_element(
|
pub fn store_element(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -66,16 +75,21 @@ impl<'ctx> TupleValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for TupleValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for TupleValue<'ctx> {
|
||||||
|
type ABI = StructValue<'ctx>;
|
||||||
type Base = StructValue<'ctx>;
|
type Base = StructValue<'ctx>;
|
||||||
type Type = TupleType<'ctx>;
|
type Type = TupleType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
TupleType::from_type(self.as_base_value().get_type(), self.llvm_usize)
|
TupleType::from_struct_type(self.as_base_value().get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> From<TupleValue<'ctx>> for StructValue<'ctx> {
|
impl<'ctx> From<TupleValue<'ctx>> for StructValue<'ctx> {
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::IntType,
|
types::IntType,
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue, StructValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
use nac3parser::ast::Expr;
|
use nac3parser::ast::Expr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{
|
codegen::{
|
||||||
types::{structure::StructField, utils::SliceType},
|
types::{
|
||||||
values::ProxyValue,
|
structure::{StructField, StructProxyType},
|
||||||
|
utils::SliceType,
|
||||||
|
},
|
||||||
|
values::{structure::StructProxyValue, ProxyValue},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
},
|
},
|
||||||
typecheck::typedef::Type,
|
typecheck::typedef::Type,
|
||||||
@ -24,13 +27,25 @@ pub struct SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> SliceValue<'ctx> {
|
impl<'ctx> SliceValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ContiguousNDArray`, returning [Err] if `value` is
|
/// Creates an [`SliceValue`] from a [`StructValue`].
|
||||||
/// not an instance.
|
#[must_use]
|
||||||
pub fn is_representable(
|
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
|
||||||
value: PointerValue<'ctx>,
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
val: StructValue<'ctx>,
|
||||||
|
int_ty: IntType<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
name: Option<&'ctx str>,
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
) -> Self {
|
||||||
|
let pval = generator
|
||||||
|
.gen_var_alloc(
|
||||||
|
ctx,
|
||||||
|
val.get_type().into(),
|
||||||
|
name.map(|name| format!("{name}.addr")).as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ctx.builder.build_store(pval, val).unwrap();
|
||||||
|
Self::from_pointer_value(pval, int_ty, llvm_usize, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`SliceValue`] from a [`PointerValue`].
|
/// Creates an [`SliceValue`] from a [`PointerValue`].
|
||||||
@ -41,7 +56,7 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, int_ty, llvm_usize, name }
|
Self { value: ptr, int_ty, llvm_usize, name }
|
||||||
}
|
}
|
||||||
@ -51,7 +66,7 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_start_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_start_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.start_defined_field().get(ctx, self.value, self.name)
|
self.start_defined_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
fn start_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
@ -59,22 +74,22 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.start_field().get(ctx, self.value, self.name)
|
self.start_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_start(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
pub fn store_start(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
||||||
match value {
|
match value {
|
||||||
Some(start) => {
|
Some(start) => {
|
||||||
self.start_defined_field().set(
|
self.start_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_all_ones(),
|
ctx.ctx.bool_type().const_all_ones(),
|
||||||
self.name,
|
self.name,
|
||||||
);
|
);
|
||||||
self.start_field().set(ctx, self.value, start, self.name);
|
self.start_field().store(ctx, self.value, start, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
None => self.start_defined_field().set(
|
None => self.start_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_zero(),
|
ctx.ctx.bool_type().const_zero(),
|
||||||
@ -88,7 +103,7 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_stop_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_stop_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.stop_defined_field().get(ctx, self.value, self.name)
|
self.stop_defined_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
fn stop_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
@ -96,22 +111,22 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_stop(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_stop(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.stop_field().get(ctx, self.value, self.name)
|
self.stop_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_stop(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
pub fn store_stop(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
||||||
match value {
|
match value {
|
||||||
Some(stop) => {
|
Some(stop) => {
|
||||||
self.stop_defined_field().set(
|
self.stop_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_all_ones(),
|
ctx.ctx.bool_type().const_all_ones(),
|
||||||
self.name,
|
self.name,
|
||||||
);
|
);
|
||||||
self.stop_field().set(ctx, self.value, stop, self.name);
|
self.stop_field().store(ctx, self.value, stop, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
None => self.stop_defined_field().set(
|
None => self.stop_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_zero(),
|
ctx.ctx.bool_type().const_zero(),
|
||||||
@ -125,7 +140,7 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_step_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_step_defined(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.step_defined_field().get(ctx, self.value, self.name)
|
self.step_defined_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
fn step_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
|
||||||
@ -133,22 +148,22 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_step(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
pub fn load_step(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
|
||||||
self.step_field().get(ctx, self.value, self.name)
|
self.step_field().load(ctx, self.value, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_step(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
pub fn store_step(&self, ctx: &CodeGenContext<'ctx, '_>, value: Option<IntValue<'ctx>>) {
|
||||||
match value {
|
match value {
|
||||||
Some(step) => {
|
Some(step) => {
|
||||||
self.step_defined_field().set(
|
self.step_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_all_ones(),
|
ctx.ctx.bool_type().const_all_ones(),
|
||||||
self.name,
|
self.name,
|
||||||
);
|
);
|
||||||
self.step_field().set(ctx, self.value, step, self.name);
|
self.step_field().store(ctx, self.value, step, self.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
None => self.step_defined_field().set(
|
None => self.step_defined_field().store(
|
||||||
ctx,
|
ctx,
|
||||||
self.value,
|
self.value,
|
||||||
ctx.ctx.bool_type().const_zero(),
|
ctx.ctx.bool_type().const_zero(),
|
||||||
@ -159,18 +174,25 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ProxyValue<'ctx> for SliceValue<'ctx> {
|
impl<'ctx> ProxyValue<'ctx> for SliceValue<'ctx> {
|
||||||
|
type ABI = PointerValue<'ctx>;
|
||||||
type Base = PointerValue<'ctx>;
|
type Base = PointerValue<'ctx>;
|
||||||
type Type = SliceType<'ctx>;
|
type Type = SliceType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
Self::Type::from_type(self.value.get_type(), self.int_ty, self.llvm_usize)
|
Self::Type::from_pointer_type(self.value.get_type(), self.int_ty, self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
|
||||||
|
self.as_base_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ctx> StructProxyValue<'ctx> for SliceValue<'ctx> {}
|
||||||
|
|
||||||
impl<'ctx> From<SliceValue<'ctx>> for PointerValue<'ctx> {
|
impl<'ctx> From<SliceValue<'ctx>> for PointerValue<'ctx> {
|
||||||
fn from(value: SliceValue<'ctx>) -> Self {
|
fn from(value: SliceValue<'ctx>) -> Self {
|
||||||
value.as_base_value()
|
value.as_base_value()
|
||||||
|
@ -598,10 +598,12 @@ impl dyn SymbolResolver + Send + Sync {
|
|||||||
unifier.internal_stringify(
|
unifier.internal_stringify(
|
||||||
ty,
|
ty,
|
||||||
&mut |id| {
|
&mut |id| {
|
||||||
let TopLevelDef::Class { name, .. } = &*top_level_defs[id].read() else {
|
let top_level_def = &*top_level_defs[id].read();
|
||||||
unreachable!("expected class definition")
|
let (TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. }) =
|
||||||
|
top_level_def
|
||||||
|
else {
|
||||||
|
unreachable!("expected class/module definition")
|
||||||
};
|
};
|
||||||
|
|
||||||
name.to_string()
|
name.to_string()
|
||||||
},
|
},
|
||||||
&mut |id| format!("typevar{id}"),
|
&mut |id| format!("typevar{id}"),
|
||||||
|
@ -6,7 +6,8 @@ use strum::IntoEnumIterator;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
helper::{
|
helper::{
|
||||||
debug_assert_prim_is_allowed, extract_ndims, make_exception_fields, PrimDef, PrimDefDetails,
|
arraylike_flatten_element_type, debug_assert_prim_is_allowed, extract_ndims,
|
||||||
|
make_exception_fields, PrimDef, PrimDefDetails,
|
||||||
},
|
},
|
||||||
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
||||||
*,
|
*,
|
||||||
@ -15,9 +16,12 @@ use crate::{
|
|||||||
codegen::{
|
codegen::{
|
||||||
builtin_fns,
|
builtin_fns,
|
||||||
numpy::*,
|
numpy::*,
|
||||||
stmt::exn_constructor,
|
stmt::{exn_constructor, gen_if_callback},
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{ndarray::shape::parse_numpy_int_sequence, ProxyValue, RangeValue},
|
values::{
|
||||||
|
ndarray::{shape::parse_numpy_int_sequence, ScalarOrNDArray},
|
||||||
|
ProxyValue,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
typecheck::typedef::{into_var_map, iter_type_vars, TypeVar, VarMap},
|
||||||
@ -405,6 +409,8 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
|
|
||||||
PrimDef::FunNpIsNan | PrimDef::FunNpIsInf => self.build_np_float_to_bool_function(prim),
|
PrimDef::FunNpIsNan | PrimDef::FunNpIsInf => self.build_np_float_to_bool_function(prim),
|
||||||
|
|
||||||
|
PrimDef::FunNpAny | PrimDef::FunNpAll => self.build_np_any_all_function(prim),
|
||||||
|
|
||||||
PrimDef::FunNpSin
|
PrimDef::FunNpSin
|
||||||
| PrimDef::FunNpCos
|
| PrimDef::FunNpCos
|
||||||
| PrimDef::FunNpTan
|
| PrimDef::FunNpTan
|
||||||
@ -571,7 +577,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let (zelf_ty, zelf) = obj.unwrap();
|
let (zelf_ty, zelf) = obj.unwrap();
|
||||||
let zelf =
|
let zelf =
|
||||||
zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
||||||
let zelf = RangeValue::from_pointer_value(zelf, Some("range"));
|
let zelf = RangeType::new(ctx).map_pointer_value(zelf, Some("range"));
|
||||||
|
|
||||||
let mut start = None;
|
let mut start = None;
|
||||||
let mut stop = None;
|
let mut stop = None;
|
||||||
@ -658,7 +664,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
zelf.store_end(ctx, stop);
|
zelf.store_end(ctx, stop);
|
||||||
zelf.store_step(ctx, step);
|
zelf.store_step(ctx, step);
|
||||||
|
|
||||||
Ok(Some(zelf.as_base_value().into()))
|
Ok(Some(zelf.as_abi_value(ctx).into()))
|
||||||
},
|
},
|
||||||
)))),
|
)))),
|
||||||
loc: None,
|
loc: None,
|
||||||
@ -1274,15 +1280,11 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let ndarray =
|
let ndarray =
|
||||||
args[0].1.clone().to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
args[0].1.clone().to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
||||||
.map_value(ndarray.into_pointer_value(), None);
|
.map_pointer_value(ndarray.into_pointer_value(), None);
|
||||||
|
|
||||||
let size = ctx
|
let size = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_truncate_or_bit_cast(
|
.build_int_truncate_or_bit_cast(ndarray.size(ctx), ctx.ctx.i32_type(), "")
|
||||||
ndarray.size(generator, ctx),
|
|
||||||
ctx.ctx.i32_type(),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(Some(size.into()))
|
Ok(Some(size.into()))
|
||||||
}),
|
}),
|
||||||
@ -1310,7 +1312,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
args[0].1.clone().to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
args[0].1.clone().to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
||||||
|
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
||||||
.map_value(ndarray.into_pointer_value(), None);
|
.map_pointer_value(ndarray.into_pointer_value(), None);
|
||||||
|
|
||||||
let result_tuple = match prim {
|
let result_tuple = match prim {
|
||||||
PrimDef::FunNpShape => ndarray.make_shape_tuple(generator, ctx),
|
PrimDef::FunNpShape => ndarray.make_shape_tuple(generator, ctx),
|
||||||
@ -1318,7 +1320,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(result_tuple.as_base_value().into()))
|
Ok(Some(result_tuple.as_abi_value(ctx).into()))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1351,10 +1353,10 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
let arg_val = args[0].1.clone().to_basic_value_enum(ctx, generator, arg_ty)?;
|
||||||
|
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, arg_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, arg_ty)
|
||||||
.map_value(arg_val.into_pointer_value(), None);
|
.map_pointer_value(arg_val.into_pointer_value(), None);
|
||||||
|
|
||||||
let ndarray = ndarray.transpose(generator, ctx, None); // TODO: Add axes argument
|
let ndarray = ndarray.transpose(generator, ctx, None); // TODO: Add axes argument
|
||||||
Ok(Some(ndarray.as_base_value().into()))
|
Ok(Some(ndarray.as_abi_value(ctx).into()))
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -1389,7 +1391,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
args[1].1.clone().to_basic_value_enum(ctx, generator, shape_ty)?;
|
args[1].1.clone().to_basic_value_enum(ctx, generator, shape_ty)?;
|
||||||
|
|
||||||
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
let ndarray = NDArrayType::from_unifier_type(generator, ctx, ndarray_ty)
|
||||||
.map_value(ndarray_val.into_pointer_value(), None);
|
.map_pointer_value(ndarray_val.into_pointer_value(), None);
|
||||||
|
|
||||||
let shape = parse_numpy_int_sequence(generator, ctx, (shape_ty, shape_val));
|
let shape = parse_numpy_int_sequence(generator, ctx, (shape_ty, shape_val));
|
||||||
|
|
||||||
@ -1408,7 +1410,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Ok(Some(new_ndarray.as_base_value().as_basic_value_enum()))
|
Ok(Some(new_ndarray.as_abi_value(ctx).as_basic_value_enum()))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1724,6 +1726,64 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_np_any_all_function(&mut self, prim: PrimDef) -> TopLevelDef {
|
||||||
|
debug_assert_prim_is_allowed(prim, &[PrimDef::FunNpAny, PrimDef::FunNpAll]);
|
||||||
|
|
||||||
|
let param_ty = &[(self.num_or_ndarray_ty.ty, "a")];
|
||||||
|
let ret_ty = self.primitives.bool;
|
||||||
|
let var_map = &self.num_or_ndarray_var_map;
|
||||||
|
let codegen_callback: Box<GenCallCallback> =
|
||||||
|
Box::new(move |ctx, _, fun, args, generator| {
|
||||||
|
let llvm_i1 = ctx.ctx.bool_type();
|
||||||
|
let llvm_i1_k0 = llvm_i1.const_zero();
|
||||||
|
let llvm_i1_k1 = llvm_i1.const_all_ones();
|
||||||
|
|
||||||
|
let a_ty = fun.0.args[0].ty;
|
||||||
|
let a_val = args[0].1.clone().to_basic_value_enum(ctx, generator, a_ty)?;
|
||||||
|
let a = ScalarOrNDArray::from_value(generator, ctx, (a_ty, a_val));
|
||||||
|
let a_elem_ty = arraylike_flatten_element_type(&mut ctx.unifier, a_ty);
|
||||||
|
|
||||||
|
let (init, sc_val) = match prim {
|
||||||
|
PrimDef::FunNpAny => (llvm_i1_k0, llvm_i1_k1),
|
||||||
|
PrimDef::FunNpAll => (llvm_i1_k1, llvm_i1_k0),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let acc = a.fold(generator, ctx, init, |generator, ctx, hooks, acc, elem| {
|
||||||
|
gen_if_callback(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
|_, ctx| {
|
||||||
|
Ok(ctx
|
||||||
|
.builder
|
||||||
|
.build_int_compare(IntPredicate::EQ, acc, sc_val, "")
|
||||||
|
.unwrap())
|
||||||
|
},
|
||||||
|
|_, ctx| {
|
||||||
|
if let Some(hooks) = hooks {
|
||||||
|
hooks.build_break_branch(&ctx.builder);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_, _| Ok(()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let is_truthy =
|
||||||
|
builtin_fns::call_bool(generator, ctx, (a_elem_ty, elem))?.into_int_value();
|
||||||
|
|
||||||
|
Ok(match prim {
|
||||||
|
PrimDef::FunNpAny => ctx.builder.build_or(acc, is_truthy, "").unwrap(),
|
||||||
|
PrimDef::FunNpAll => ctx.builder.build_and(acc, is_truthy, "").unwrap(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Some(acc.as_basic_value_enum()))
|
||||||
|
});
|
||||||
|
|
||||||
|
create_fn_by_codegen(self.unifier, var_map, prim.name(), ret_ty, param_ty, codegen_callback)
|
||||||
|
}
|
||||||
|
|
||||||
/// Build 1-ary numpy/scipy functions that take in a float or an ndarray and return a value of the same type as the input.
|
/// Build 1-ary numpy/scipy functions that take in a float or an ndarray and return a value of the same type as the input.
|
||||||
fn build_np_sp_float_or_ndarray_1ary_function(&mut self, prim: PrimDef) -> TopLevelDef {
|
fn build_np_sp_float_or_ndarray_1ary_function(&mut self, prim: PrimDef) -> TopLevelDef {
|
||||||
debug_assert_prim_is_allowed(
|
debug_assert_prim_is_allowed(
|
||||||
|
@ -101,7 +101,9 @@ impl TopLevelComposer {
|
|||||||
let builtin_name_list = definition_ast_list
|
let builtin_name_list = definition_ast_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|def_ast| match *def_ast.0.read() {
|
.map(|def_ast| match *def_ast.0.read() {
|
||||||
TopLevelDef::Class { name, .. } => name.to_string(),
|
TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. } => {
|
||||||
|
name.to_string()
|
||||||
|
}
|
||||||
TopLevelDef::Function { simple_name, .. }
|
TopLevelDef::Function { simple_name, .. }
|
||||||
| TopLevelDef::Variable { simple_name, .. } => simple_name.to_string(),
|
| TopLevelDef::Variable { simple_name, .. } => simple_name.to_string(),
|
||||||
})
|
})
|
||||||
@ -201,6 +203,43 @@ impl TopLevelComposer {
|
|||||||
self.definition_ast_list.iter().map(|(def, ..)| def.clone()).collect_vec()
|
self.definition_ast_list.iter().map(|(def, ..)| def.clone()).collect_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// register top level modules
|
||||||
|
pub fn register_top_level_module(
|
||||||
|
&mut self,
|
||||||
|
module_name: &str,
|
||||||
|
name_to_pyid: &Rc<HashMap<StrRef, u64>>,
|
||||||
|
resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||||
|
location: Option<Location>,
|
||||||
|
) -> Result<DefinitionId, String> {
|
||||||
|
let mut methods: HashMap<StrRef, DefinitionId> = HashMap::new();
|
||||||
|
let mut attributes: Vec<(StrRef, DefinitionId)> = Vec::new();
|
||||||
|
|
||||||
|
for (name, _) in name_to_pyid.iter() {
|
||||||
|
if let Ok(def_id) = resolver.get_identifier_def(*name) {
|
||||||
|
// Avoid repeated attribute instances resulting from multiple imports of same module
|
||||||
|
if self.defined_names.contains(&format!("{module_name}.{name}")) {
|
||||||
|
match &*self.definition_ast_list[def_id.0].0.read() {
|
||||||
|
TopLevelDef::Class { .. } | TopLevelDef::Function { .. } => {
|
||||||
|
methods.insert(*name, def_id);
|
||||||
|
}
|
||||||
|
_ => attributes.push((*name, def_id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let module_def = TopLevelDef::Module {
|
||||||
|
name: module_name.to_string().into(),
|
||||||
|
module_id: DefinitionId(self.definition_ast_list.len()),
|
||||||
|
methods,
|
||||||
|
attributes,
|
||||||
|
resolver: Some(resolver),
|
||||||
|
loc: location,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.definition_ast_list.push((Arc::new(RwLock::new(module_def)), None));
|
||||||
|
Ok(DefinitionId(self.definition_ast_list.len() - 1))
|
||||||
|
}
|
||||||
|
|
||||||
/// register, just remember the names of top level classes/function
|
/// register, just remember the names of top level classes/function
|
||||||
/// and check duplicate class/method/function definition
|
/// and check duplicate class/method/function definition
|
||||||
pub fn register_top_level(
|
pub fn register_top_level(
|
||||||
@ -434,7 +473,7 @@ impl TopLevelComposer {
|
|||||||
location: Location,
|
location: Location,
|
||||||
) -> Result<(StrRef, DefinitionId, Option<Type>), String> {
|
) -> Result<(StrRef, DefinitionId, Option<Type>), String> {
|
||||||
if self.keyword_list.contains(&name) {
|
if self.keyword_list.contains(&name) {
|
||||||
return Err(format!("cannot use keyword `{name}` as a variable name (at {location})"));
|
return Err(format!("cannot use keyword `{name}` as a class name (at {location})"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let global_var_name =
|
let global_var_name =
|
||||||
@ -1947,103 +1986,6 @@ impl TopLevelComposer {
|
|||||||
let temp_def_list = self.extract_def_list();
|
let temp_def_list = self.extract_def_list();
|
||||||
let unifier = &mut self.unifier;
|
let unifier = &mut self.unifier;
|
||||||
let primitives_store = &self.primitives_ty;
|
let primitives_store = &self.primitives_ty;
|
||||||
|
|
||||||
|
|
||||||
// let dummy_field_type = unifier.get_dummy_var().ty;
|
|
||||||
|
|
||||||
// let annotation = match value {
|
|
||||||
// None => {
|
|
||||||
// // handle Kernel[T], KernelInvariant[T]
|
|
||||||
// let (annotation, mutable) = match &annotation.node {
|
|
||||||
// ExprKind::Subscript { value, slice, .. }
|
|
||||||
// if matches!(
|
|
||||||
// &value.node,
|
|
||||||
// ast::ExprKind::Name { id, .. } if id == &core_config.kernel_invariant_ann.into()
|
|
||||||
// ) =>
|
|
||||||
// {
|
|
||||||
// (slice, false)
|
|
||||||
// }
|
|
||||||
// ExprKind::Subscript { value, slice, .. }
|
|
||||||
// if matches!(
|
|
||||||
// &value.node,
|
|
||||||
// ast::ExprKind::Name { id, .. } if core_config.kernel_ann.map_or(false, |c| id == &c.into())
|
|
||||||
// ) =>
|
|
||||||
// {
|
|
||||||
// (slice, true)
|
|
||||||
// }
|
|
||||||
// _ if core_config.kernel_ann.is_none() => (annotation, true),
|
|
||||||
// _ => continue, // ignore fields annotated otherwise
|
|
||||||
// };
|
|
||||||
// class_fields_def.push((*attr, dummy_field_type, mutable));
|
|
||||||
// annotation
|
|
||||||
// }
|
|
||||||
// // Supporting Class Attributes
|
|
||||||
// Some(boxed_expr) => {
|
|
||||||
// // Class attributes are set as immutable regardless
|
|
||||||
// let (annotation, _) = match &annotation.node {
|
|
||||||
// ExprKind::Subscript { slice, .. } => (slice, false),
|
|
||||||
// _ if core_config.kernel_ann.is_none() => (annotation, false),
|
|
||||||
// _ => continue,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// match &**boxed_expr {
|
|
||||||
// ast::Located {location: _, custom: (), node: ExprKind::Constant { value: v, kind: _ }} => {
|
|
||||||
// // Restricting the types allowed to be defined as class attributes
|
|
||||||
// match v {
|
|
||||||
// ast::Constant::Bool(_) | ast::Constant::Str(_) | ast::Constant::Int(_) | ast::Constant::Float(_) => {}
|
|
||||||
// _ => {
|
|
||||||
// return Err(HashSet::from([
|
|
||||||
// format!(
|
|
||||||
// "unsupported statement in class definition body (at {})",
|
|
||||||
// b.location
|
|
||||||
// ),
|
|
||||||
// ]))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// class_attributes_def.push((*attr, dummy_field_type, v.clone()));
|
|
||||||
// }
|
|
||||||
// _ => {
|
|
||||||
// return Err(HashSet::from([
|
|
||||||
// format!(
|
|
||||||
// "unsupported statement in class definition body (at {})",
|
|
||||||
// b.location
|
|
||||||
// ),
|
|
||||||
// ]))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// annotation
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// let parsed_annotation = parse_ast_to_type_annotation_kinds(
|
|
||||||
// class_resolver,
|
|
||||||
// temp_def_list,
|
|
||||||
// unifier,
|
|
||||||
// primitives,
|
|
||||||
// annotation.as_ref(),
|
|
||||||
// vec![(class_id, class_type_vars_def.clone())]
|
|
||||||
// .into_iter()
|
|
||||||
// .collect::<HashMap<_, _>>(),
|
|
||||||
// )?;
|
|
||||||
// // find type vars within this return type annotation
|
|
||||||
// let type_vars_within =
|
|
||||||
// get_type_var_contained_in_type_annotation(&parsed_annotation);
|
|
||||||
// // handle the class type var and the method type var
|
|
||||||
// for type_var_within in type_vars_within {
|
|
||||||
// let TypeAnnotation::TypeVar(t) = type_var_within else {
|
|
||||||
// unreachable!("must be type var annotation")
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if !class_type_vars_def.contains(&t){
|
|
||||||
// return Err(HashSet::from([
|
|
||||||
// format!(
|
|
||||||
// "class fields can only use type \
|
|
||||||
// vars over which the class is generic (at {})",
|
|
||||||
// annotation.location
|
|
||||||
// ),
|
|
||||||
// ]))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// type_var_to_concrete_def.insert(dummy_field_type, parsed_annotation);
|
|
||||||
|
|
||||||
let mut analyze = |variable_def: &Arc<RwLock<TopLevelDef>>| -> Result<_, HashSet<String>> {
|
let mut analyze = |variable_def: &Arc<RwLock<TopLevelDef>>| -> Result<_, HashSet<String>> {
|
||||||
let TopLevelDef::Variable { ty: dummy_ty, ty_decl, resolver, loc, .. } =
|
let TopLevelDef::Variable { ty: dummy_ty, ty_decl, resolver, loc, .. } =
|
||||||
@ -2052,7 +1994,7 @@ impl TopLevelComposer {
|
|||||||
// not top level variable def, skip
|
// not top level variable def, skip
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let resolver = &**resolver.as_ref().unwrap();
|
let resolver = &**resolver.as_ref().unwrap();
|
||||||
|
|
||||||
if let Some(ty_decl) = ty_decl {
|
if let Some(ty_decl) = ty_decl {
|
||||||
@ -2063,10 +2005,10 @@ impl TopLevelComposer {
|
|||||||
ast::ExprKind::Name { id, .. } if self.core_config.kernel_ann.map_or(false, |c| id == &c.into())
|
ast::ExprKind::Name { id, .. } if self.core_config.kernel_ann.map_or(false, |c| id == &c.into())
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
slice
|
slice
|
||||||
}
|
}
|
||||||
_ if self.core_config.kernel_ann.is_none() => ty_decl,
|
_ if self.core_config.kernel_ann.is_none() => ty_decl,
|
||||||
_ => unreachable!("Global variables should be annotated with Kernel[]") // ignore fields annotated otherwise
|
_ => unreachable!("Global variables should be annotated with Kernel[]"), // ignore fields annotated otherwise
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_annotation = parse_ast_to_type_annotation_kinds(
|
let ty_annotation = parse_ast_to_type_annotation_kinds(
|
||||||
|
@ -111,6 +111,8 @@ pub enum PrimDef {
|
|||||||
FunNpLdExp,
|
FunNpLdExp,
|
||||||
FunNpHypot,
|
FunNpHypot,
|
||||||
FunNpNextAfter,
|
FunNpNextAfter,
|
||||||
|
FunNpAny,
|
||||||
|
FunNpAll,
|
||||||
|
|
||||||
// Linalg functions
|
// Linalg functions
|
||||||
FunNpDot,
|
FunNpDot,
|
||||||
@ -305,6 +307,8 @@ impl PrimDef {
|
|||||||
PrimDef::FunNpLdExp => fun("np_ldexp", None),
|
PrimDef::FunNpLdExp => fun("np_ldexp", None),
|
||||||
PrimDef::FunNpHypot => fun("np_hypot", None),
|
PrimDef::FunNpHypot => fun("np_hypot", None),
|
||||||
PrimDef::FunNpNextAfter => fun("np_nextafter", None),
|
PrimDef::FunNpNextAfter => fun("np_nextafter", None),
|
||||||
|
PrimDef::FunNpAny => fun("np_any", None),
|
||||||
|
PrimDef::FunNpAll => fun("np_all", None),
|
||||||
|
|
||||||
// Linalg functions
|
// Linalg functions
|
||||||
PrimDef::FunNpDot => fun("np_dot", None),
|
PrimDef::FunNpDot => fun("np_dot", None),
|
||||||
@ -375,21 +379,37 @@ pub fn make_exception_fields(int32: Type, int64: Type, str: Type) -> Vec<(StrRef
|
|||||||
impl TopLevelDef {
|
impl TopLevelDef {
|
||||||
pub fn to_string(&self, unifier: &mut Unifier) -> String {
|
pub fn to_string(&self, unifier: &mut Unifier) -> String {
|
||||||
match self {
|
match self {
|
||||||
TopLevelDef::Class { name, ancestors, fields, methods, type_vars, .. } => {
|
TopLevelDef::Module { name, attributes, methods, .. } => {
|
||||||
|
format!(
|
||||||
|
"Module {{\nname: {:?},\nattributes: {:?}\nmethods: {:?}\n}}",
|
||||||
|
name,
|
||||||
|
attributes.iter().map(|(n, _)| n.to_string()).collect_vec(),
|
||||||
|
methods.iter().map(|(n, _)| n.to_string()).collect_vec()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TopLevelDef::Class {
|
||||||
|
name, ancestors, fields, methods, attributes, type_vars, ..
|
||||||
|
} => {
|
||||||
let fields_str = fields
|
let fields_str = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, ty, _)| (n.to_string(), unifier.stringify(*ty)))
|
.map(|(n, ty, _)| (n.to_string(), unifier.stringify(*ty)))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
|
let attributes_str = attributes
|
||||||
|
.iter()
|
||||||
|
.map(|(n, ty, _)| (n.to_string(), unifier.stringify(*ty)))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
let methods_str = methods
|
let methods_str = methods
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, ty, id)| (n.to_string(), unifier.stringify(*ty), *id))
|
.map(|(n, ty, id)| (n.to_string(), unifier.stringify(*ty), *id))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
format!(
|
format!(
|
||||||
"Class {{\nname: {:?},\nancestors: {:?},\nfields: {:?},\nmethods: {:?},\ntype_vars: {:?}\n}}",
|
"Class {{\nname: {:?},\nancestors: {:?},\nfields: {:?},\nattributes: {:?},\nmethods: {:?},\ntype_vars: {:?}\n}}",
|
||||||
name,
|
name,
|
||||||
ancestors.iter().map(|ancestor| ancestor.stringify(unifier)).collect_vec(),
|
ancestors.iter().map(|ancestor| ancestor.stringify(unifier)).collect_vec(),
|
||||||
fields_str.iter().map(|(a, _)| a).collect_vec(),
|
fields_str.iter().map(|(a, _)| a).collect_vec(),
|
||||||
|
attributes_str.iter().map(|(a, _)| a).collect_vec(),
|
||||||
methods_str.iter().map(|(a, b, _)| (a, b)).collect_vec(),
|
methods_str.iter().map(|(a, b, _)| (a, b)).collect_vec(),
|
||||||
type_vars.iter().map(|id| unifier.stringify(*id)).collect_vec(),
|
type_vars.iter().map(|id| unifier.stringify(*id)).collect_vec(),
|
||||||
)
|
)
|
||||||
|
@ -92,6 +92,20 @@ pub struct FunInstance {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TopLevelDef {
|
pub enum TopLevelDef {
|
||||||
|
Module {
|
||||||
|
/// Name of the module
|
||||||
|
name: StrRef,
|
||||||
|
/// Module ID used for [`TypeEnum`]
|
||||||
|
module_id: DefinitionId,
|
||||||
|
/// `DefinitionId` of `TopLevelDef::{Class, Function}` within the module
|
||||||
|
methods: HashMap<StrRef, DefinitionId>,
|
||||||
|
/// `DefinitionId` of `TopLevelDef::{Variable}` within the module
|
||||||
|
attributes: Vec<(StrRef, DefinitionId)>,
|
||||||
|
/// Symbol resolver of the module defined the class.
|
||||||
|
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,
|
||||||
|
/// Definition location.
|
||||||
|
loc: Option<Location>,
|
||||||
|
},
|
||||||
Class {
|
Class {
|
||||||
/// Name for error messages and symbols.
|
/// Name for error messages and symbols.
|
||||||
name: StrRef,
|
name: StrRef,
|
||||||
|
@ -3,10 +3,10 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
||||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(261)]\n}\n",
|
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(261)]\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -3,13 +3,13 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[T]\"],\nfields: [\"a\", \"b\", \"c\"],\nmethods: [(\"__init__\", \"fn[[t:T], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"T\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[T]\"],\nfields: [\"a\", \"b\", \"c\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[t:T], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"T\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar245]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar245\"]\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B[typevar245]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar245\"]\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -4,10 +4,10 @@ expression: res_vec
|
|||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(258)]\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(258)]\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(263)]\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(263)]\n}\n",
|
||||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -3,10 +3,10 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar244, typevar245]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar244\", \"typevar245\"]\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A[typevar244, typevar245]\"],\nfields: [\"a\", \"b\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar244\", \"typevar245\"]\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:B], B]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.bar\",\nsig: \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\",\nvar_id: []\n}\n",
|
||||||
|
@ -3,14 +3,14 @@ source: nac3core/src/toplevel/test.rs
|
|||||||
expression: res_vec
|
expression: res_vec
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(264)]\n}\n",
|
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(264)]\n}\n",
|
||||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nattributes: [],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
||||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(272)]\n}\n",
|
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(272)]\n}\n",
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
---
|
---
|
||||||
source: nac3core/src/toplevel/test.rs
|
source: nac3core/src/toplevel/test.rs
|
||||||
assertion_line: 549
|
|
||||||
expression: res_vec
|
expression: res_vec
|
||||||
|
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [],\nmethods: [],\ntype_vars: []\n}\n",
|
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [],\nattributes: [],\nmethods: [],\ntype_vars: []\n}\n",
|
||||||
]
|
]
|
||||||
|
@ -2008,72 +2008,90 @@ impl Inferencer<'_> {
|
|||||||
ctx: ExprContext,
|
ctx: ExprContext,
|
||||||
) -> InferenceResult {
|
) -> InferenceResult {
|
||||||
let ty = value.custom.unwrap();
|
let ty = value.custom.unwrap();
|
||||||
if let TypeEnum::TObj { obj_id, fields, .. } = &*self.unifier.get_ty(ty) {
|
match &*self.unifier.get_ty(ty) {
|
||||||
// just a fast path
|
TypeEnum::TObj { obj_id, fields, .. } => {
|
||||||
match (fields.get(&attr), ctx == ExprContext::Store) {
|
// just a fast path
|
||||||
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
match (fields.get(&attr), ctx == ExprContext::Store) {
|
||||||
(Some((ty, false)), true) => report_type_error(
|
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
||||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
(Some((ty, false)), true) => report_type_error(
|
||||||
Some(value.location),
|
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||||
self.unifier,
|
Some(value.location),
|
||||||
),
|
self.unifier,
|
||||||
(None, mutable) => {
|
),
|
||||||
// Check whether it is a class attribute
|
(None, mutable) => {
|
||||||
let defs = self.top_level.definitions.read();
|
// Check whether it is a class attribute
|
||||||
let result = {
|
let defs = self.top_level.definitions.read();
|
||||||
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
let result = {
|
||||||
attributes.iter().find_map(|f| {
|
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
||||||
if f.0 == attr {
|
attributes.iter().find_map(|f| {
|
||||||
return Some(f.1);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Some(res) if !mutable => Ok(res),
|
|
||||||
Some(_) => report_error(
|
|
||||||
&format!("Class Attribute `{attr}` is immutable"),
|
|
||||||
value.location,
|
|
||||||
),
|
|
||||||
None => report_type_error(
|
|
||||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
|
||||||
Some(value.location),
|
|
||||||
self.unifier,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(ty) {
|
|
||||||
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
|
||||||
let result = {
|
|
||||||
self.top_level.definitions.read().iter().find_map(|def| {
|
|
||||||
if let Some(rear_guard) = def.try_read() {
|
|
||||||
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
|
||||||
if name.to_string() == self.unifier.stringify(sign.ret) {
|
|
||||||
return attributes.iter().find_map(|f| {
|
|
||||||
if f.0 == attr {
|
if f.0 == attr {
|
||||||
return Some(f.clone().1);
|
return Some(f.1);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
});
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
Some(res) if !mutable => Ok(res),
|
||||||
|
Some(_) => report_error(
|
||||||
|
&format!("Class Attribute `{attr}` is immutable"),
|
||||||
|
value.location,
|
||||||
|
),
|
||||||
|
None => report_type_error(
|
||||||
|
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
})
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Some(f) if ctx != ExprContext::Store => Ok(f),
|
|
||||||
Some(_) => {
|
|
||||||
report_error(&format!("Class Attribute `{attr}` is immutable"), value.location)
|
|
||||||
}
|
}
|
||||||
None => self.infer_general_attribute(value, attr, ctx),
|
|
||||||
}
|
}
|
||||||
} else {
|
TypeEnum::TFunc(sign) => {
|
||||||
self.infer_general_attribute(value, attr, ctx)
|
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
||||||
|
let result = {
|
||||||
|
self.top_level.definitions.read().iter().find_map(|def| {
|
||||||
|
if let Some(rear_guard) = def.try_read() {
|
||||||
|
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
||||||
|
if name.to_string() == self.unifier.stringify(sign.ret) {
|
||||||
|
return attributes.iter().find_map(|f| {
|
||||||
|
if f.0 == attr {
|
||||||
|
return Some(f.clone().1);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
Some(f) if ctx != ExprContext::Store => Ok(f),
|
||||||
|
Some(_) => report_error(
|
||||||
|
&format!("Class Attribute `{attr}` is immutable"),
|
||||||
|
value.location,
|
||||||
|
),
|
||||||
|
None => self.infer_general_attribute(value, attr, ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeEnum::TModule { attributes, .. } => {
|
||||||
|
match (attributes.get(&attr), ctx == ExprContext::Load) {
|
||||||
|
(Some((ty, _)), true) | (Some((ty, false)), false) => Ok(*ty),
|
||||||
|
(Some((ty, true)), false) => report_type_error(
|
||||||
|
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
|
(None, _) => report_type_error(
|
||||||
|
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.infer_general_attribute(value, attr, ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2734,7 +2752,7 @@ impl Inferencer<'_> {
|
|||||||
.read()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|def| match *def.read() {
|
.map(|def| match *def.read() {
|
||||||
TopLevelDef::Class { name, .. } => (name, false),
|
TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. } => (name, false),
|
||||||
TopLevelDef::Function { simple_name, .. } => (simple_name, false),
|
TopLevelDef::Function { simple_name, .. } => (simple_name, false),
|
||||||
TopLevelDef::Variable { simple_name, .. } => (simple_name, true),
|
TopLevelDef::Variable { simple_name, .. } => (simple_name, true),
|
||||||
})
|
})
|
||||||
|
@ -270,6 +270,19 @@ pub enum TypeEnum {
|
|||||||
|
|
||||||
/// A function type.
|
/// A function type.
|
||||||
TFunc(FunSignature),
|
TFunc(FunSignature),
|
||||||
|
|
||||||
|
/// Module Type
|
||||||
|
TModule {
|
||||||
|
/// The [`DefinitionId`] of this object type.
|
||||||
|
module_id: DefinitionId,
|
||||||
|
|
||||||
|
/// The attributes present in this object type.
|
||||||
|
///
|
||||||
|
/// The key of the [Mapping] is the identifier of the field, while the value is a tuple
|
||||||
|
/// containing the [Type] of the field, and a `bool` indicating whether the field is a
|
||||||
|
/// variable (as opposed to a function).
|
||||||
|
attributes: Mapping<StrRef, (Type, bool)>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeEnum {
|
impl TypeEnum {
|
||||||
@ -284,6 +297,7 @@ impl TypeEnum {
|
|||||||
TypeEnum::TVirtual { .. } => "TVirtual",
|
TypeEnum::TVirtual { .. } => "TVirtual",
|
||||||
TypeEnum::TCall { .. } => "TCall",
|
TypeEnum::TCall { .. } => "TCall",
|
||||||
TypeEnum::TFunc { .. } => "TFunc",
|
TypeEnum::TFunc { .. } => "TFunc",
|
||||||
|
TypeEnum::TModule { .. } => "TModule",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,7 +607,8 @@ impl Unifier {
|
|||||||
| TLiteral { .. }
|
| TLiteral { .. }
|
||||||
// functions are instantiated for each call sites, so the function type can contain
|
// functions are instantiated for each call sites, so the function type can contain
|
||||||
// type variables.
|
// type variables.
|
||||||
| TFunc { .. } => true,
|
| TFunc { .. }
|
||||||
|
| TModule { .. } => true,
|
||||||
|
|
||||||
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
||||||
TCall { .. } => false,
|
TCall { .. } => false,
|
||||||
@ -1315,10 +1330,12 @@ impl Unifier {
|
|||||||
|| format!("{id}"),
|
|| format!("{id}"),
|
||||||
|top_level| {
|
|top_level| {
|
||||||
let top_level_def = &top_level.definitions.read()[id];
|
let top_level_def = &top_level.definitions.read()[id];
|
||||||
let TopLevelDef::Class { name, .. } = &*top_level_def.read() else {
|
let top_level_def = top_level_def.read();
|
||||||
unreachable!("expected class definition")
|
let (TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. }) =
|
||||||
|
&*top_level_def
|
||||||
|
else {
|
||||||
|
unreachable!("expected module/class definition")
|
||||||
};
|
};
|
||||||
|
|
||||||
name.to_string()
|
name.to_string()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -1446,6 +1463,10 @@ impl Unifier {
|
|||||||
let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes);
|
let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes);
|
||||||
format!("fn[[{params}], {ret}]")
|
format!("fn[[{params}], {ret}]")
|
||||||
}
|
}
|
||||||
|
TypeEnum::TModule { module_id, .. } => {
|
||||||
|
let name = obj_to_name(module_id.0);
|
||||||
|
name.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,7 +1542,9 @@ impl Unifier {
|
|||||||
// variables, i.e. things like TRecord, TCall should not occur, and we
|
// variables, i.e. things like TRecord, TCall should not occur, and we
|
||||||
// should be safe to not implement the substitution for those variants.
|
// should be safe to not implement the substitution for those variants.
|
||||||
match &*ty {
|
match &*ty {
|
||||||
TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } => None,
|
TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } | TypeEnum::TModule { .. } => {
|
||||||
|
None
|
||||||
|
}
|
||||||
TypeEnum::TVar { id, .. } => mapping.get(id).copied(),
|
TypeEnum::TVar { id, .. } => mapping.get(id).copied(),
|
||||||
TypeEnum::TTuple { ty, is_vararg_ctx } => {
|
TypeEnum::TTuple { ty, is_vararg_ctx } => {
|
||||||
let mut new_ty = Cow::from(ty);
|
let mut new_ty = Cow::from(ty);
|
||||||
|
@ -232,6 +232,8 @@ def patch(module):
|
|||||||
module.np_ldexp = np.ldexp
|
module.np_ldexp = np.ldexp
|
||||||
module.np_hypot = np.hypot
|
module.np_hypot = np.hypot
|
||||||
module.np_nextafter = np.nextafter
|
module.np_nextafter = np.nextafter
|
||||||
|
module.np_any = np.any
|
||||||
|
module.np_all = np.all
|
||||||
|
|
||||||
# SciPy Math functions
|
# SciPy Math functions
|
||||||
module.sp_spec_erf = special.erf
|
module.sp_spec_erf = special.erf
|
||||||
|
@ -58,7 +58,7 @@ rm -f ./*.o ./*.bc demo
|
|||||||
if [ -z "$i686" ]; then
|
if [ -z "$i686" ]; then
|
||||||
$nac3standalone "${nac3args[@]}"
|
$nac3standalone "${nac3args[@]}"
|
||||||
clang -c -std=gnu11 -Wall -Wextra -O3 -o demo.o demo.c
|
clang -c -std=gnu11 -Wall -Wextra -O3 -o demo.o demo.c
|
||||||
clang -o demo module.o demo.o $DEMO_LINALG_STUB -lm -Wl,--no-warn-search-mismatch
|
clang -o demo module.o demo.o $DEMO_LINALG_STUB -fuse-ld=lld -lm
|
||||||
else
|
else
|
||||||
$nac3standalone --triple i686-unknown-linux-gnu --target-features +sse2 "${nac3args[@]}"
|
$nac3standalone --triple i686-unknown-linux-gnu --target-features +sse2 "${nac3args[@]}"
|
||||||
clang -m32 -c -std=gnu11 -Wall -Wextra -O3 -msse2 -o demo.o demo.c
|
clang -m32 -c -std=gnu11 -Wall -Wextra -O3 -msse2 -o demo.o demo.c
|
||||||
|
35
nac3standalone/demo/src/class_attributes.py
Normal file
35
nac3standalone/demo/src/class_attributes.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@extern
|
||||||
|
def output_int32(x: int32):
|
||||||
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_strln(x: str):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class A:
|
||||||
|
a: int32 = 1
|
||||||
|
b: int32
|
||||||
|
c: str = "test"
|
||||||
|
d: str
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.b = 2
|
||||||
|
self.d = "test"
|
||||||
|
|
||||||
|
output_int32(self.a) # Attributes can be accessed within class
|
||||||
|
|
||||||
|
|
||||||
|
def run() -> int32:
|
||||||
|
output_int32(A.a) # Attributes can be directly accessed with class name
|
||||||
|
# A.b # Only attributes can be accessed in this way
|
||||||
|
# A.a = 2 # Attributes are immutable
|
||||||
|
|
||||||
|
obj = A()
|
||||||
|
output_int32(obj.a) # Attributes can be accessed by class objects
|
||||||
|
|
||||||
|
output_strln(obj.c)
|
||||||
|
output_strln(obj.d)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
@ -1551,6 +1551,59 @@ def test_ndarray_nextafter_broadcast_rhs_scalar():
|
|||||||
output_ndarray_float_2(nextafter_x_zeros)
|
output_ndarray_float_2(nextafter_x_zeros)
|
||||||
output_ndarray_float_2(nextafter_x_ones)
|
output_ndarray_float_2(nextafter_x_ones)
|
||||||
|
|
||||||
|
|
||||||
|
def test_ndarray_any():
|
||||||
|
s0 = 0
|
||||||
|
output_bool(np_any(s0))
|
||||||
|
s1 = 1
|
||||||
|
output_bool(np_any(s1))
|
||||||
|
|
||||||
|
x1 = np_identity(5)
|
||||||
|
y1 = np_any(x1)
|
||||||
|
output_ndarray_float_2(x1)
|
||||||
|
output_bool(y1)
|
||||||
|
|
||||||
|
x2 = np_identity(1)
|
||||||
|
y2 = np_any(x2)
|
||||||
|
output_ndarray_float_2(x2)
|
||||||
|
output_bool(y2)
|
||||||
|
|
||||||
|
x3 = np_array([[1.0, 2.0], [3.0, 4.0]])
|
||||||
|
y3 = np_any(x3)
|
||||||
|
output_ndarray_float_2(x3)
|
||||||
|
output_bool(y3)
|
||||||
|
|
||||||
|
x4 = np_zeros([3, 5])
|
||||||
|
y4 = np_any(x4)
|
||||||
|
output_ndarray_float_2(x4)
|
||||||
|
output_bool(y4)
|
||||||
|
|
||||||
|
def test_ndarray_all():
|
||||||
|
s0 = 0
|
||||||
|
output_bool(np_all(s0))
|
||||||
|
s1 = 1
|
||||||
|
output_bool(np_all(s1))
|
||||||
|
|
||||||
|
x1 = np_identity(5)
|
||||||
|
y1 = np_all(x1)
|
||||||
|
output_ndarray_float_2(x1)
|
||||||
|
output_bool(y1)
|
||||||
|
|
||||||
|
x2 = np_identity(1)
|
||||||
|
y2 = np_all(x2)
|
||||||
|
output_ndarray_float_2(x2)
|
||||||
|
output_bool(y2)
|
||||||
|
|
||||||
|
x3 = np_array([[1.0, 2.0], [3.0, 4.0]])
|
||||||
|
y3 = np_all(x3)
|
||||||
|
output_ndarray_float_2(x3)
|
||||||
|
output_bool(y3)
|
||||||
|
|
||||||
|
x4 = np_zeros([3, 5])
|
||||||
|
y4 = np_all(x4)
|
||||||
|
output_ndarray_float_2(x4)
|
||||||
|
output_bool(y4)
|
||||||
|
|
||||||
def test_ndarray_dot():
|
def test_ndarray_dot():
|
||||||
x1: ndarray[float, 1] = np_array([5.0, 1.0, 4.0, 2.0])
|
x1: ndarray[float, 1] = np_array([5.0, 1.0, 4.0, 2.0])
|
||||||
y1: ndarray[float, 1] = np_array([5.0, 1.0, 6.0, 6.0])
|
y1: ndarray[float, 1] = np_array([5.0, 1.0, 6.0, 6.0])
|
||||||
@ -1851,6 +1904,9 @@ def run() -> int32:
|
|||||||
test_ndarray_nextafter_broadcast_lhs_scalar()
|
test_ndarray_nextafter_broadcast_lhs_scalar()
|
||||||
test_ndarray_nextafter_broadcast_rhs_scalar()
|
test_ndarray_nextafter_broadcast_rhs_scalar()
|
||||||
|
|
||||||
|
test_ndarray_any()
|
||||||
|
test_ndarray_all()
|
||||||
|
|
||||||
test_ndarray_dot()
|
test_ndarray_dot()
|
||||||
test_ndarray_cholesky()
|
test_ndarray_cholesky()
|
||||||
test_ndarray_qr()
|
test_ndarray_qr()
|
||||||
|
@ -456,7 +456,13 @@ fn main() {
|
|||||||
membuffer.lock().push(buffer);
|
membuffer.lock().push(buffer);
|
||||||
})));
|
})));
|
||||||
let threads = (0..threads)
|
let threads = (0..threads)
|
||||||
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), size_t)))
|
.map(|i| {
|
||||||
|
Box::new(DefaultCodeGenerator::with_target_machine(
|
||||||
|
format!("module{i}"),
|
||||||
|
&context,
|
||||||
|
&target_machine,
|
||||||
|
))
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
{ pkgs } : [
|
{ pkgs } : [
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "0frb5k16bbxdf8g379d16vl3qrh7n9pydn83gpfxpvwf3qlvnzyl";
|
sha256 = "1gv6hbqvfgjzirpljql1shlchldmf5ww3rfsspg90pq1frnwavjl";
|
||||||
name = "mingw-w64-clang-x86_64-libunwind-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libunwind-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "0wh5km0v8j50pqz9bxb4f0w7r8zhsvssrjvc94np53iq8wjagk86";
|
sha256 = "1wbkvrx14ahc04cgkydvlxwmsl8jfnqwhy9sy4kn4wkdzmlcp1ax";
|
||||||
name = "mingw-w64-clang-x86_64-libc++-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libc++-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -19,15 +19,15 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libiconv-1.17-4-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libiconv-1.18-1-any.pkg.tar.zst";
|
||||||
sha256 = "1g2bkhgf60dywccxw911ydyigf3m25yqfh81m5099swr7mjsmzyf";
|
sha256 = "0vn5xgx9jjg66f8r9ylm9220qdbjdkffykfl6nwj14zv9y7xh4nj";
|
||||||
name = "mingw-w64-clang-x86_64-libiconv-1.17-4-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libiconv-1.18-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-gettext-runtime-0.22.5-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-gettext-runtime-0.23.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "0ll6ci6d3mc7g04q0xixjc209bh8r874dqbczgns69jsad3wg6mi";
|
sha256 = "0wbp5pmrr0rk4mx7d1frvqlk4a061zw31zscs57srmvl0wv3pi2a";
|
||||||
name = "mingw-w64-clang-x86_64-gettext-runtime-0.22.5-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-gettext-runtime-0.23.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -55,69 +55,69 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1clrbm8dk893byj8s15pgcgqqijm2zkd10zgyakamd8m354kj9q4";
|
sha256 = "0fpsnfyf0bg39a4ygzga06sr4wv4jp1jnc8lk6sr3z0nim0nlhjn";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-libs-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-llvm-libs-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1iz2c9475h8p20ydpp0znbhyb62rlrk7wr7xl7cmwbam7wkwr8rn";
|
sha256 = "0whqs9nvfmgxj3c83px6dipcdw9zi858kgd8130201fy1mbnafp1";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-llvm-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1hidciwlakxrp4kyb0j2v6g4lv76nn834g6b88w1j94fk3qc765d";
|
sha256 = "0rmzri7h043i73jy3c2jcrg3hy40dr5s9n96kmxgaghfhvlpilps";
|
||||||
name = "mingw-w64-clang-x86_64-clang-libs-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-clang-libs-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1m1yhjkgzlbk10sv966qk4yji009ga0lr25gpgj2w7mcd2wixcr3";
|
sha256 = "04cqlh35asvlh06nmhwnx9h0yrqk8zxd9lpzxmm1xh64kvm9maxn";
|
||||||
name = "mingw-w64-clang-x86_64-compiler-rt-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-compiler-rt-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
sha256 = "08gxc7h2achckknn6fz3p6yi7gxxvbaday8fpm4j56c4sa04n0df";
|
sha256 = "05zsqgq8zwdcfacyqdxdjcf80447bgnrz71xv5cds0y135yziy7l";
|
||||||
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
sha256 = "0fxd1pb197ki0gzw6z8gmd6wgpd9d28js6cp5d31d55kw7d1vz13";
|
sha256 = "12fkxpk7rwy36snvvc7sdivx81pd4ckzh5ilyh7gl6ly4qayppp6";
|
||||||
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1a8pjyhrzpc2z3784xxwix4i7yrz03ygnsk1wv9k0yq8m8wi9nbw";
|
sha256 = "102bbv5acq1fvrfn8bp1x3503cb8hvcxmlpr86qsba4vm11l0wrw";
|
||||||
name = "mingw-w64-clang-x86_64-lld-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-lld-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
sha256 = "140m312jx1sywqjkvfij69d268m4jpdmilq5bb8khkf0ayb16036";
|
sha256 = "1sris0qczxk5px9xy85976hbmqrpg49ns7yyzd9p455ckf740cid";
|
||||||
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
sha256 = "017j4h511wg37bacym73f8g6s0jcfgzbzabzxpc6anr3gy4kkpbg";
|
sha256 = "1r0m5xpsxdl00a2daj4p0wgl6037700pvw6p6zl91h1dr092r6pa";
|
||||||
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r423.g8bcd5fc1a-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-19.1.4-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "11f4i4ai2bzvq6f06vxk1ymv7056c9707vdw489f1i2bdrf0c0ii";
|
sha256 = "0j4a642fpnvqs79chhinc8r5q53q1wllmc1bzb01a4y7w9rqg4hw";
|
||||||
name = "mingw-w64-clang-x86_64-clang-19.1.4-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-clang-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.83.0-3-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.84.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "0nxs571vb4f1i5vp91134p5blns9ml2r25nx6kdlg0zhd5x85kvm";
|
sha256 = "0nrz9788grl50nkbhxswry143rrwpdnc6pk6f0k30kcp19qq6y2d";
|
||||||
name = "mingw-w64-clang-x86_64-rust-1.83.0-3-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-rust-1.84.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -127,9 +127,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.34.3-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-c-ares-1.34.4-1-any.pkg.tar.zst";
|
||||||
sha256 = "1mpn397qsdz3l2fav6ymwjlj96ialn9m8sldii3ymbcyhranl3xx";
|
sha256 = "1dppwwx3wrn0lzrlk2q7bpsainbidrpw1ndp1aasyv42xhxl1sn1";
|
||||||
name = "mingw-w64-clang-x86_64-c-ares-1.34.3-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-c-ares-1.34.4-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -139,9 +139,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunistring-1.3-1-any.pkg.tar.zst";
|
||||||
sha256 = "13nz49li39z1zgfx1q9jg4vrmyrmqb6qdq0nqshidaqc6zr16k3g";
|
sha256 = "1zg58qbfybyqzcj0dalb13l48f9jsras318h02rka65r7wi0pdcg";
|
||||||
name = "mingw-w64-clang-x86_64-libunistring-1.2-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-libunistring-1.3-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -169,9 +169,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ca-certificates-20240203-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ca-certificates-20241223-1-any.pkg.tar.zst";
|
||||||
sha256 = "1q5nxhsk04gidz66ai5wgd4dr04lfyakkfja9p0r5hrgg4ppqqjg";
|
sha256 = "0c36lg63imzw8i6j1ard42v5wgzpc83phzk8lvifvm0djndq2bbj";
|
||||||
name = "mingw-w64-clang-x86_64-ca-certificates-20240203-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-ca-certificates-20241223-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -193,9 +193,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp3-1.6.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-nghttp3-1.7.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "1p7q47fin12vzyf126v1azbbpgpa0y6ighfh6mbfdb6zcyq74kbd";
|
sha256 = "0kd2f7yh90815kyldxvdy8c6jyxyw0wv4f7k3shwp98w874m0mxd";
|
||||||
name = "mingw-w64-clang-x86_64-nghttp3-1.6.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-nghttp3-1.7.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -271,15 +271,15 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rhash-1.4.4-3-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rhash-1.4.5-1-any.pkg.tar.zst";
|
||||||
sha256 = "1ysbxirpfr0yf7pvyps75lnwc897w2a2kcid3nb4j6ilw6n64jmc";
|
sha256 = "0gdn1351knjwgsqgyaa3l55qs135k7dn6mlf04vzjxlc1895wx5z";
|
||||||
name = "mingw-w64-clang-x86_64-rhash-1.4.4-3-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-rhash-1.4.5-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.31.2-3-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.31.4-1-any.pkg.tar.zst";
|
||||||
sha256 = "139f91r392c68hsajm0c81690pmzkywb0p4x8ms8ms53ncxnz6gz";
|
sha256 = "1xjjwgkqf2j97pcx0yd6j0lgmzgbgqjjf0s7j29mc03g89fhdhw0";
|
||||||
name = "mingw-w64-clang-x86_64-cmake-3.31.2-3-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-cmake-3.31.4-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -289,9 +289,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ncurses-6.5.20240831-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-ncurses-6.5.20241228-3-any.pkg.tar.zst";
|
||||||
sha256 = "1hlfj9g4s767s502sawwbcv4a0xd3ym3ip4jswmhq48wh5050iyb";
|
sha256 = "0f98pzrwsxil90n55hz2ym2x2rzrrjrmnj8i2203n189qbxbg2c9";
|
||||||
name = "mingw-w64-clang-x86_64-ncurses-6.5.20240831-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-ncurses-6.5.20241228-3-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
@ -331,32 +331,32 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.12.7-3-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.12.8-2-any.pkg.tar.zst";
|
||||||
sha256 = "1v15j2pzy9wj4n1rjngdi2hf8h0l9z4lri3xb86yvdv1xl2msj6h";
|
sha256 = "0lksgrmylvpr7yyjcc1szm30pnag7ixrj7vhdql1ryi4k9309v8s";
|
||||||
name = "mingw-w64-clang-x86_64-python-3.12.7-3-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-python-3.12.8-2-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-19.1.4-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-19.1.6-1-any.pkg.tar.zst";
|
||||||
sha256 = "1pn1fbj74rx837s9z8gqs4b0cr7kqi5m1m2mi9ibjpw64m1aqwxv";
|
sha256 = "0d3mm26hnw716n0ppzqhydxcgm4im081hiiy6l4zp267ad3kfg93";
|
||||||
name = "mingw-w64-clang-x86_64-llvm-openmp-19.1.4-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-llvm-openmp-19.1.6-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.28-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openblas-0.3.29-1-any.pkg.tar.zst";
|
||||||
sha256 = "18p1zhf7h3k3phf3bl483jg3k7y9zq375z6ww75g62158ic9lfyc";
|
sha256 = "006f2s12jmk35rppkp20rlm7k4kknsnh5h4krqs2ry2rd6qqkk9h";
|
||||||
name = "mingw-w64-clang-x86_64-openblas-0.3.28-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-openblas-0.3.29-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-numpy-2.1.1-2-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-numpy-2.2.1-1-any.pkg.tar.zst";
|
||||||
sha256 = "1kiy7ail04ias47xbbhl9vpsz02g0g3f29ncgx5gcks9vgqldp6m";
|
sha256 = "0sgkhax9cwmkkrfrir45l91h6pgg339gaw6147gsayf8h8ag4brg";
|
||||||
name = "mingw-w64-clang-x86_64-python-numpy-2.1.1-2-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-python-numpy-2.2.1-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
|
|
||||||
(pkgs.fetchurl {
|
(pkgs.fetchurl {
|
||||||
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-75.6.0-1-any.pkg.tar.zst";
|
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-setuptools-75.8.0-1-any.pkg.tar.zst";
|
||||||
sha256 = "03l04kjmy5p9whaw0h619gdg7yw1gxbz8phifq4pzh3c1wlw7yfd";
|
sha256 = "12ivpaj967y4bi8396q3fpii4fy5aakidxpv16rkyg1b831k0h93";
|
||||||
name = "mingw-w64-clang-x86_64-python-setuptools-75.6.0-1-any.pkg.tar.zst";
|
name = "mingw-w64-clang-x86_64-python-setuptools-75.8.0-1-any.pkg.tar.zst";
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user