diff --git a/Cargo.lock b/Cargo.lock index 4c4ec99..9de4130 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -17,18 +17,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -59,7 +59,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -69,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -110,9 +110,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "byteorder" @@ -122,9 +122,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.86" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -134,9 +134,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.1" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -156,14 +156,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] @@ -187,7 +187,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -205,9 +205,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -252,12 +252,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "dirs-next" version = "2.0.0" @@ -313,7 +307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -379,10 +373,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.3.6" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" @@ -396,9 +390,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -432,7 +426,7 @@ checksum = "4fa4d8d74483041a882adaa9a29f633253a66dde85055f0495c121620ac484b2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] @@ -449,22 +443,11 @@ dependencies = [ "similar", ] -[[package]] -name = "is-terminal" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -486,34 +469,33 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lalrpop" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", - "diff", "ena", - "is-terminal", - "itertools 0.10.5", + "itertools 0.11.0", "lalrpop-util", "petgraph", "pico-args", "regex", - "regex-syntax 0.7.5", + "regex-syntax", "string_cache", "term", "tiny-keccak", "unicode-xid", + "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex", + "regex-automata", ] [[package]] @@ -530,12 +512,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.4", ] [[package]] @@ -544,7 +526,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall", ] @@ -586,9 +568,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" @@ -681,9 +663,9 @@ dependencies = [ [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "once_cell" @@ -721,7 +703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.2.5", ] [[package]] @@ -764,7 +746,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] @@ -791,6 +773,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -805,24 +793,25 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89dc7a5850d0e983be1ec2a463a171d20990487c3cfcd68b5363f1ee3d6fe0" +checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "parking_lot", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -831,9 +820,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07426f0d8fe5a601f26293f300afd1a7b1ed5e78b2a705870c5f30893c5163be" +checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" dependencies = [ "once_cell", "target-lexicon", @@ -841,9 +830,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb7dec17e17766b46bca4f1a4215a85006b4c2ecde122076c562dd058da6cf1" +checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" dependencies = [ "libc", "pyo3-build-config", @@ -851,26 +840,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f738b4e40d50b5711957f142878cfa0f28e054aa0ebdfc3fd137a843f74ed3" +checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] name = "pyo3-macros-backend" -version = "0.20.2" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc910d4851847827daf9d6cdd4a823fbdaab5b8818325c5e97a86da79e8881f" +checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", + "pyo3-build-config", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] @@ -914,9 +904,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -961,26 +951,20 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.2", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -996,15 +980,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1019,6 +1003,15 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1048,7 +1041,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] [[package]] @@ -1088,9 +1081,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "string-interner" @@ -1135,9 +1128,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -1152,14 +1145,14 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1188,40 +1181,24 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] -[[package]] -name = "time" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" -dependencies = [ - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1303,9 +1280,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unicode_names2" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac64ef2f016dc69dfa8283394a70b057066eb054d5fcb6b9eb17bd2ec5097211" +checksum = "addeebf294df7922a1164f729fb27ebbbcea99cc32b3bf08afab62757f707677" dependencies = [ "phf", "unicode_names2_generator", @@ -1313,15 +1290,14 @@ dependencies = [ [[package]] name = "unicode_names2_generator" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "013f6a731e80f3930de580e55ba41dfa846de4e0fdee4a701f97989cb1597d6a" +checksum = "f444b8bba042fe3c1251ffaca35c603f2dc2ccc08d595c65a8c4f76f3e8426c0" dependencies = [ "getopts", "log", "phf_codegen", "rand", - "time", ] [[package]] @@ -1342,6 +1318,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1364,28 +1350,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -1405,17 +1391,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -1426,9 +1412,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -1438,9 +1424,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -1450,9 +1436,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -1462,9 +1448,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -1474,9 +1460,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -1486,9 +1472,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -1498,9 +1484,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "yaml-rust" @@ -1528,5 +1514,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.53", ] diff --git a/nac3core/build.rs b/nac3core/build.rs index 5ed3acf..91060f9 100644 --- a/nac3core/build.rs +++ b/nac3core/build.rs @@ -21,7 +21,7 @@ fn main() { match env::var("PROFILE").as_deref() { Ok("debug") => "-O0", Ok("release") => "-O3", - flavor => panic!("Unknown or missing build flavor {:?}", flavor), + flavor => panic!("Unknown or missing build flavor {flavor:?}"), }, "-emit-llvm", "-S", diff --git a/nac3core/src/codegen/classes.rs b/nac3core/src/codegen/classes.rs index 34463ef..3b23999 100644 --- a/nac3core/src/codegen/classes.rs +++ b/nac3core/src/codegen/classes.rs @@ -8,17 +8,392 @@ use crate::codegen::{ CodeGenerator, irrt::{call_ndarray_calc_size, call_ndarray_flatten_index, call_ndarray_flatten_index_const}, llvm_intrinsics::call_int_umin, - stmt::gen_for_callback, + stmt::gen_for_callback_incrementing, }; +/// An LLVM value that is array-like, i.e. it contains a contiguous, sequenced collection of +/// elements. +pub trait ArrayLikeValue<'ctx> { + /// Returns the element type of this array-like value. + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx>; + + /// Returns the base pointer to the array. + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> PointerValue<'ctx>; + + /// Returns the size of this array-like value. + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> IntValue<'ctx>; + + /// Returns a [`ArraySliceValue`] representing this value. + fn as_slice_value( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> ArraySliceValue<'ctx> { + ArraySliceValue::from_ptr_val( + self.base_ptr(ctx, generator), + self.size(ctx, generator), + None, + ) + } +} + +/// An array-like value that can be indexed by memory offset. +pub trait ArrayLikeIndexer<'ctx, Index = IntValue<'ctx>>: ArrayLikeValue<'ctx> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx>; + + /// Returns the pointer to the data at the `idx`-th index. + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx>; +} + +/// An array-like value that can have its array elements accessed as a [`BasicValueEnum`]. +pub trait UntypedArrayLikeAccessor<'ctx, Index = IntValue<'ctx>>: ArrayLikeIndexer<'ctx, Index> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn get_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> BasicValueEnum<'ctx> { + let ptr = self.ptr_offset_unchecked(ctx, generator, idx, name); + ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() + } + + /// Returns the data at the `idx`-th index. + fn get( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> BasicValueEnum<'ctx> { + let ptr = self.ptr_offset(ctx, generator, idx, name); + ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() + } +} + +/// An array-like value that can have its array elements mutated as a [`BasicValueEnum`]. +pub trait UntypedArrayLikeMutator<'ctx, Index = IntValue<'ctx>>: ArrayLikeIndexer<'ctx, Index> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn set_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: BasicValueEnum<'ctx>, + ) { + let ptr = self.ptr_offset_unchecked(ctx, generator, idx, None); + ctx.builder.build_store(ptr, value).unwrap(); + } + + /// Sets the data at the `idx`-th index. + fn set( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: BasicValueEnum<'ctx>, + ) { + let ptr = self.ptr_offset(ctx, generator, idx, None); + ctx.builder.build_store(ptr, value).unwrap(); + } +} + +/// An array-like value that can have its array elements accessed as an arbitrary type `T`. +pub trait TypedArrayLikeAccessor<'ctx, T, Index = IntValue<'ctx>>: UntypedArrayLikeAccessor<'ctx, Index> { + /// Casts an element from [`BasicValueEnum`] into `T`. + fn downcast_to_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: BasicValueEnum<'ctx>) -> T; + + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn get_typed_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> T { + let value = self.get_unchecked(ctx, generator, idx, name); + self.downcast_to_type(ctx, value) + } + + /// Returns the data at the `idx`-th index. + fn get_typed( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> T { + let value = self.get(ctx, generator, idx, name); + self.downcast_to_type(ctx, value) + } +} + +/// An array-like value that can have its array elements mutated as an arbitrary type `T`. +pub trait TypedArrayLikeMutator<'ctx, T, Index = IntValue<'ctx>>: UntypedArrayLikeMutator<'ctx, Index> { + /// Casts an element from T into [`BasicValueEnum`]. + fn upcast_from_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: T) -> BasicValueEnum<'ctx>; + + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn set_typed_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: T, + ) { + let value = self.upcast_from_type(ctx, value); + self.set_unchecked(ctx, generator, idx, value); + } + + /// Sets the data at the `idx`-th index. + fn set_typed( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: T, + ) { + let value = self.upcast_from_type(ctx, value); + self.set(ctx, generator, idx, value); + } +} + +/// Type alias for a function that casts a [`BasicValueEnum`] into a `T`. +type ValueDowncastFn<'ctx, T> = Box, BasicValueEnum<'ctx>) -> T>; +/// Type alias for a function that casts a `T` into a [`BasicValueEnum`]. +type ValueUpcastFn<'ctx, T> = Box, T) -> BasicValueEnum<'ctx>>; + +/// An adapter for constraining untyped array values as typed values. +pub struct TypedArrayLikeAdapter<'ctx, T, Adapted: ArrayLikeValue<'ctx> = ArraySliceValue<'ctx>> { + adapted: Adapted, + downcast_fn: ValueDowncastFn<'ctx, T>, + upcast_fn: ValueUpcastFn<'ctx, T>, +} + +impl<'ctx, T, Adapted> TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeValue<'ctx> { + /// Creates a [`TypedArrayLikeAdapter`]. + /// + /// * `adapted` - The value to be adapted. + /// * `downcast_fn` - The function converting a [`BasicValueEnum`] into a `T`. + /// * `upcast_fn` - The function converting a T into a [`BasicValueEnum`]. + pub fn from( + adapted: Adapted, + downcast_fn: ValueDowncastFn<'ctx, T>, + upcast_fn: ValueUpcastFn<'ctx, T>, + ) -> Self { + TypedArrayLikeAdapter { adapted, downcast_fn, upcast_fn } + } +} + +impl<'ctx, T, Adapted> ArrayLikeValue<'ctx> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeValue<'ctx> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.adapted.element_type(ctx, generator) + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> PointerValue<'ctx> { + self.adapted.base_ptr(ctx, generator) + } + + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> IntValue<'ctx> { + self.adapted.size(ctx, generator) + } +} + +impl<'ctx, T, Index, Adapted> ArrayLikeIndexer<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeIndexer<'ctx, Index> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + self.adapted.ptr_offset_unchecked(ctx, generator, idx, name) + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + self.adapted.ptr_offset(ctx, generator, idx, name) + } +} + +impl<'ctx, T, Index, Adapted> UntypedArrayLikeAccessor<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeAccessor<'ctx, Index> {} +impl<'ctx, T, Index, Adapted> UntypedArrayLikeMutator<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeMutator<'ctx, Index> {} + +impl<'ctx, T, Index, Adapted> TypedArrayLikeAccessor<'ctx, T, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeAccessor<'ctx, Index> { + fn downcast_to_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: BasicValueEnum<'ctx>) -> T { + (self.downcast_fn)(ctx, value) + } +} + +impl<'ctx, T, Index, Adapted> TypedArrayLikeMutator<'ctx, T, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeMutator<'ctx, Index> { + fn upcast_from_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: T) -> BasicValueEnum<'ctx> { + (self.upcast_fn)(ctx, value) + } +} + +/// An LLVM value representing an array slice, consisting of a pointer to the data and the size of +/// the slice. +#[derive(Copy, Clone)] +pub struct ArraySliceValue<'ctx>(PointerValue<'ctx>, IntValue<'ctx>, Option<&'ctx str>); + +impl<'ctx> ArraySliceValue<'ctx> { + /// Creates an [`ArraySliceValue`] from a [`PointerValue`] and its size. + #[must_use] + pub fn from_ptr_val( + ptr: PointerValue<'ctx>, + size: IntValue<'ctx>, + name: Option<&'ctx str>, + ) -> Self { + ArraySliceValue(ptr, size, name) + } +} + +impl<'ctx> From> for PointerValue<'ctx> { + fn from(value: ArraySliceValue<'ctx>) -> Self { + value.0 + } +} + +impl<'ctx> ArrayLikeValue<'ctx> for ArraySliceValue<'ctx> { + fn element_type( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.get_type().get_element_type() + } + + fn base_ptr( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { + self.0 + } + + fn size( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.1 + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx> for ArraySliceValue<'ctx> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let var_name = name + .map(|v| format!("{v}.addr")) + .unwrap_or_default(); + + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[idx], + var_name.as_str(), + ).unwrap() + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx)); + + let size = self.size(ctx, generator); + let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, idx, size, "").unwrap(); + ctx.make_assert( + generator, + in_range, + "0:IndexError", + "list index out of range", + [None, None, None], + ctx.current_loc, + ); + + unsafe { + self.ptr_offset_unchecked(ctx, generator, idx, name) + } + } +} + +impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ArraySliceValue<'ctx> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx> for ArraySliceValue<'ctx> {} + #[cfg(not(debug_assertions))] pub fn assert_is_list<'ctx>(_value: PointerValue<'ctx>, _llvm_usize: IntType<'ctx>) {} #[cfg(debug_assertions)] pub fn assert_is_list<'ctx>(value: PointerValue<'ctx>, llvm_usize: IntType<'ctx>) { - if let Err(msg) = ListValue::is_instance(value, llvm_usize) { - panic!("{msg}") - } + ListValue::is_instance(value, llvm_usize).unwrap(); } /// Proxy type for accessing a `list` value in LLVM. @@ -67,19 +442,19 @@ impl<'ctx> ListValue<'ctx> { /// Returns the underlying [`PointerValue`] pointing to the `list` instance. #[must_use] - pub fn get_ptr(&self) -> PointerValue<'ctx> { + pub fn as_ptr_value(&self) -> PointerValue<'ctx> { self.0 } /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// on the field. - fn get_data_pptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn pptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.data.addr")).unwrap_or_default(); unsafe { ctx.builder.build_in_bounds_gep( - self.get_ptr(), + self.as_ptr_value(), &[llvm_i32.const_zero(), llvm_i32.const_zero()], var_name.as_str(), ).unwrap() @@ -87,7 +462,7 @@ impl<'ctx> ListValue<'ctx> { } /// Returns the pointer to the field storing the size of this `list`. - fn get_size_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_size(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.size.addr")).unwrap_or_default(); @@ -102,7 +477,7 @@ impl<'ctx> ListValue<'ctx> { /// Stores the array of data elements `data` into this instance. fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) { - ctx.builder.build_store(self.get_data_pptr(ctx), data).unwrap(); + ctx.builder.build_store(self.pptr_to_data(ctx), data).unwrap(); } /// Convenience method for creating a new array storing data elements with the given element @@ -122,26 +497,26 @@ impl<'ctx> ListValue<'ctx> { /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// on the field. #[must_use] - pub fn get_data(&self) -> ListDataProxy<'ctx> { - ListDataProxy(*self) + pub fn data(&self) -> ListDataProxy<'ctx, '_> { + ListDataProxy(self) } /// Stores the `size` of this `list` into this instance. - pub fn store_size( + pub fn store_size( &self, ctx: &CodeGenContext<'ctx, '_>, - generator: &dyn CodeGenerator, + generator: &G, size: IntValue<'ctx>, ) { debug_assert_eq!(size.get_type(), generator.get_size_type(ctx.ctx)); - let psize = self.get_size_ptr(ctx); + let psize = self.ptr_to_size(ctx); ctx.builder.build_store(psize, size).unwrap(); } /// Returns the size of this `list` as a value. pub fn load_size(&self, ctx: &CodeGenContext<'ctx, '_>, name: Option<&str>) -> IntValue<'ctx> { - let psize = self.get_size_ptr(ctx); + let psize = self.ptr_to_size(ctx); let var_name = name .map(ToString::to_string) .or_else(|| self.1.map(|v| format!("{v}.size"))) @@ -155,30 +530,49 @@ impl<'ctx> ListValue<'ctx> { impl<'ctx> From> for PointerValue<'ctx> { fn from(value: ListValue<'ctx>) -> Self { - value.get_ptr() + value.as_ptr_value() } } /// Proxy type for accessing the `data` array of an `list` instance in LLVM. #[derive(Copy, Clone)] -pub struct ListDataProxy<'ctx>(ListValue<'ctx>); +pub struct ListDataProxy<'ctx, 'a>(&'a ListValue<'ctx>); -impl<'ctx> ListDataProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn get_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { +impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx, '_> { + fn element_type( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.0.get_type().get_element_type() + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); - ctx.builder.build_load(self.0.get_data_pptr(ctx), var_name.as_str()) + ctx.builder.build_load(self.0.pptr_to_data(ctx), var_name.as_str()) .map(BasicValueEnum::into_pointer_value) .unwrap() } - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn ptr_offset_unchecked( + fn size( &self, ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.0.load_size(ctx, None) + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { @@ -187,28 +581,23 @@ impl<'ctx> ListDataProxy<'ctx> { .unwrap_or_default(); ctx.builder.build_in_bounds_gep( - self.get_ptr(ctx), + self.base_ptr(ctx, generator), &[idx], var_name.as_str(), ).unwrap() } - /// Returns the pointer to the data at the `idx`-th index. - pub fn ptr_offset( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx)); - let in_range = ctx.builder.build_int_compare( - IntPredicate::ULT, - idx, - self.0.load_size(ctx, None), - "" - ).unwrap(); + let size = self.size(ctx, generator); + let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, idx, size, "").unwrap(); ctx.make_assert( generator, in_range, @@ -219,44 +608,20 @@ impl<'ctx> ListDataProxy<'ctx> { ); unsafe { - self.ptr_offset_unchecked(ctx, idx, name) + self.ptr_offset_unchecked(ctx, generator, idx, name) } } - - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn get_unchecked( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked(ctx, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the `idx`-th flattened index. - pub fn get( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } } +impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ListDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx> for ListDataProxy<'ctx, '_> {} + #[cfg(not(debug_assertions))] pub fn assert_is_range(_value: PointerValue) {} #[cfg(debug_assertions)] pub fn assert_is_range(value: PointerValue) { - if let Err(msg) = RangeValue::is_instance(value) { - panic!("{msg}") - } + RangeValue::is_instance(value).unwrap(); } /// Proxy type for accessing a `range` value in LLVM. @@ -295,11 +660,11 @@ impl<'ctx> RangeValue<'ctx> { /// Returns the underlying [`PointerValue`] pointing to the `range` instance. #[must_use] - pub fn get_ptr(&self) -> PointerValue<'ctx> { + pub fn as_ptr_value(&self) -> PointerValue<'ctx> { self.0 } - fn get_start_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.start.addr")).unwrap_or_default(); @@ -312,7 +677,7 @@ impl<'ctx> RangeValue<'ctx> { } } - fn get_end_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_end(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.end.addr")).unwrap_or_default(); @@ -325,7 +690,7 @@ impl<'ctx> RangeValue<'ctx> { } } - fn get_step_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_step(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.step.addr")).unwrap_or_default(); @@ -346,13 +711,13 @@ impl<'ctx> RangeValue<'ctx> { ) { debug_assert_eq!(start.get_type().get_bit_width(), 32); - let pstart = self.get_start_ptr(ctx); + let pstart = self.ptr_to_start(ctx); ctx.builder.build_store(pstart, start).unwrap(); } /// Returns the `start` value of this `range`. pub fn load_start(&self, ctx: &CodeGenContext<'ctx, '_>, name: Option<&str>) -> IntValue<'ctx> { - let pstart = self.get_start_ptr(ctx); + let pstart = self.ptr_to_start(ctx); let var_name = name .map(ToString::to_string) .or_else(|| self.1.map(|v| format!("{v}.start"))) @@ -371,13 +736,13 @@ impl<'ctx> RangeValue<'ctx> { ) { debug_assert_eq!(end.get_type().get_bit_width(), 32); - let pend = self.get_start_ptr(ctx); + let pend = self.ptr_to_start(ctx); ctx.builder.build_store(pend, end).unwrap(); } /// Returns the `end` value of this `range`. pub fn load_end(&self, ctx: &CodeGenContext<'ctx, '_>, name: Option<&str>) -> IntValue<'ctx> { - let pend = self.get_end_ptr(ctx); + let pend = self.ptr_to_end(ctx); let var_name = name .map(ToString::to_string) .or_else(|| self.1.map(|v| format!("{v}.end"))) @@ -396,13 +761,13 @@ impl<'ctx> RangeValue<'ctx> { ) { debug_assert_eq!(step.get_type().get_bit_width(), 32); - let pstep = self.get_start_ptr(ctx); + let pstep = self.ptr_to_start(ctx); ctx.builder.build_store(pstep, step).unwrap(); } /// Returns the `step` value of this `range`. pub fn load_step(&self, ctx: &CodeGenContext<'ctx, '_>, name: Option<&str>) -> IntValue<'ctx> { - let pstep = self.get_step_ptr(ctx); + let pstep = self.ptr_to_step(ctx); let var_name = name .map(ToString::to_string) .or_else(|| self.1.map(|v| format!("{v}.step"))) @@ -416,7 +781,7 @@ impl<'ctx> RangeValue<'ctx> { impl<'ctx> From> for PointerValue<'ctx> { fn from(value: RangeValue<'ctx>) -> Self { - value.get_ptr() + value.as_ptr_value() } } @@ -425,9 +790,7 @@ pub fn assert_is_ndarray<'ctx>(_value: PointerValue<'ctx>, _llvm_usize: IntType< #[cfg(debug_assertions)] pub fn assert_is_ndarray<'ctx>(value: PointerValue<'ctx>, llvm_usize: IntType<'ctx>) { - if let Err(msg) = NDArrayValue::is_instance(value, llvm_usize) { - panic!("{msg}") - } + NDArrayValue::is_instance(value, llvm_usize).unwrap(); } /// Proxy type for accessing an `NDArray` value in LLVM. @@ -494,12 +857,12 @@ impl<'ctx> NDArrayValue<'ctx> { /// Returns the underlying [`PointerValue`] pointing to the `NDArray` instance. #[must_use] - pub fn get_ptr(&self) -> PointerValue<'ctx> { + pub fn as_ptr_value(&self) -> PointerValue<'ctx> { self.0 } /// Returns the pointer to the field storing the number of dimensions of this `NDArray`. - fn get_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.ndims.addr")).unwrap_or_default(); @@ -513,21 +876,21 @@ impl<'ctx> NDArrayValue<'ctx> { } /// Stores the number of dimensions `ndims` into this instance. - pub fn store_ndims( + pub fn store_ndims( &self, ctx: &CodeGenContext<'ctx, '_>, - generator: &dyn CodeGenerator, + generator: &G, ndims: IntValue<'ctx>, ) { debug_assert_eq!(ndims.get_type(), generator.get_size_type(ctx.ctx)); - let pndims = self.get_ndims(ctx); + let pndims = self.ptr_to_ndims(ctx); ctx.builder.build_store(pndims, ndims).unwrap(); } /// Returns the number of dimensions of this `NDArray` as a value. pub fn load_ndims(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> { - let pndims = self.get_ndims(ctx); + let pndims = self.ptr_to_ndims(ctx); ctx.builder.build_load(pndims, "") .map(BasicValueEnum::into_int_value) .unwrap() @@ -535,13 +898,13 @@ impl<'ctx> NDArrayValue<'ctx> { /// Returns the double-indirection pointer to the `dims` array, as if by calling `getelementptr` /// on the field. - fn get_dims_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_dims(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.dims.addr")).unwrap_or_default(); unsafe { ctx.builder.build_in_bounds_gep( - self.get_ptr(), + self.as_ptr_value(), &[llvm_i32.const_zero(), llvm_i32.const_int(1, true)], var_name.as_str(), ).unwrap() @@ -549,35 +912,35 @@ impl<'ctx> NDArrayValue<'ctx> { } /// Stores the array of dimension sizes `dims` into this instance. - fn store_dims(&self, ctx: &CodeGenContext<'ctx, '_>, dims: PointerValue<'ctx>) { - ctx.builder.build_store(self.get_dims_ptr(ctx), dims).unwrap(); + fn store_dim_sizes(&self, ctx: &CodeGenContext<'ctx, '_>, dims: PointerValue<'ctx>) { + ctx.builder.build_store(self.ptr_to_dims(ctx), dims).unwrap(); } /// Convenience method for creating a new array storing dimension sizes with the given `size`. - pub fn create_dims( + pub fn create_dim_sizes( &self, ctx: &CodeGenContext<'ctx, '_>, llvm_usize: IntType<'ctx>, size: IntValue<'ctx>, ) { - self.store_dims(ctx, ctx.builder.build_array_alloca(llvm_usize, size, "").unwrap()); + self.store_dim_sizes(ctx, ctx.builder.build_array_alloca(llvm_usize, size, "").unwrap()); } /// Returns a proxy object to the field storing the size of each dimension of this `NDArray`. #[must_use] - pub fn get_dims(&self) -> NDArrayDimsProxy<'ctx> { - NDArrayDimsProxy(*self) + pub fn dim_sizes(&self) -> NDArrayDimsProxy<'ctx, '_> { + NDArrayDimsProxy(self) } /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// on the field. - fn get_data_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { + fn ptr_to_data(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { let llvm_i32 = ctx.ctx.i32_type(); let var_name = self.1.map(|v| format!("{v}.data.addr")).unwrap_or_default(); unsafe { ctx.builder.build_in_bounds_gep( - self.get_ptr(), + self.as_ptr_value(), &[llvm_i32.const_zero(), llvm_i32.const_int(2, true)], var_name.as_str(), ).unwrap() @@ -586,7 +949,7 @@ impl<'ctx> NDArrayValue<'ctx> { /// Stores the array of data elements `data` into this instance. fn store_data(&self, ctx: &CodeGenContext<'ctx, '_>, data: PointerValue<'ctx>) { - ctx.builder.build_store(self.get_data_ptr(ctx), data).unwrap(); + ctx.builder.build_store(self.ptr_to_data(ctx), data).unwrap(); } /// Convenience method for creating a new array storing data elements with the given element @@ -602,43 +965,82 @@ impl<'ctx> NDArrayValue<'ctx> { /// Returns a proxy object to the field storing the data of this `NDArray`. #[must_use] - pub fn get_data(&self) -> NDArrayDataProxy<'ctx> { - NDArrayDataProxy(*self) + pub fn data(&self) -> NDArrayDataProxy<'ctx, '_> { + NDArrayDataProxy(self) } } impl<'ctx> From> for PointerValue<'ctx> { fn from(value: NDArrayValue<'ctx>) -> Self { - value.get_ptr() + value.as_ptr_value() } } /// Proxy type for accessing the `dims` array of an `NDArray` instance in LLVM. #[derive(Copy, Clone)] -pub struct NDArrayDimsProxy<'ctx>(NDArrayValue<'ctx>); +pub struct NDArrayDimsProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); -impl<'ctx> NDArrayDimsProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn get_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { - let var_name = self.0.1.map(|v| format!("{v}.dims")).unwrap_or_default(); +impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDimsProxy<'ctx, '_> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.dim_sizes().base_ptr(ctx, generator).get_type().get_element_type() + } - ctx.builder.build_load(self.0.get_dims_ptr(ctx), var_name.as_str()) + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { + let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); + + ctx.builder.build_load(self.0.ptr_to_dims(ctx), var_name.as_str()) .map(BasicValueEnum::into_pointer_value) .unwrap() } - /// Returns the pointer to the size of the `idx`-th dimension. - pub fn ptr_offset( + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.0.load_ndims(ctx) + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { + let var_name = name + .map(|v| format!("{v}.addr")) + .unwrap_or_default(); + + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[idx], + var_name.as_str(), + ).unwrap() + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let size = self.size(ctx, generator); let in_range = ctx.builder.build_int_compare( IntPredicate::ULT, idx, - self.0.load_ndims(ctx), + size, "" ).unwrap(); ctx.make_assert( @@ -650,76 +1052,92 @@ impl<'ctx> NDArrayDimsProxy<'ctx> { ctx.current_loc, ); - let var_name = name - .map(|v| format!("{v}.addr")) - .unwrap_or_default(); - unsafe { - ctx.builder.build_in_bounds_gep( - self.get_ptr(ctx), - &[idx], - var_name.as_str(), - ).unwrap() + self.ptr_offset_unchecked(ctx, generator, idx, name) } } +} - /// Returns the size of the `idx`-th dimension. - pub fn get( +impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} + +impl<'ctx> TypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + fn downcast_to_type( &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - idx: IntValue<'ctx>, - name: Option<&str>, + _: &mut CodeGenContext<'ctx, '_>, + value: BasicValueEnum<'ctx>, ) -> IntValue<'ctx> { - let ptr = self.ptr_offset(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()) - .map(BasicValueEnum::into_int_value) - .unwrap() + value.into_int_value() + } +} + +impl<'ctx> TypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + fn upcast_from_type( + &self, + _: &mut CodeGenContext<'ctx, '_>, + value: IntValue<'ctx>, + ) -> BasicValueEnum<'ctx> { + value.into() } } /// Proxy type for accessing the `data` array of an `NDArray` instance in LLVM. #[derive(Copy, Clone)] -pub struct NDArrayDataProxy<'ctx>(NDArrayValue<'ctx>); +pub struct NDArrayDataProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); -impl<'ctx> NDArrayDataProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn get_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { +impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.data().base_ptr(ctx, generator).get_type().get_element_type() + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); - ctx.builder.build_load(self.0.get_data_ptr(ctx), var_name.as_str()) + ctx.builder.build_load(self.0.ptr_to_data(ctx), var_name.as_str()) .map(BasicValueEnum::into_pointer_value) .unwrap() } - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn ptr_to_data_flattened_unchecked( + fn size( &self, ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> IntValue<'ctx> { + call_ndarray_calc_size(generator, ctx, &self.as_slice_value(ctx, generator)) + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { ctx.builder.build_in_bounds_gep( - self.get_ptr(ctx), + self.base_ptr(ctx, generator), &[idx], name.unwrap_or_default(), ).unwrap() } - /// Returns the pointer to the data at the `idx`-th flattened index. - pub fn ptr_to_data_flattened( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { - let ndims = self.0.load_ndims(ctx); - let dims = self.0.get_dims().get_ptr(ctx); - let data_sz = call_ndarray_calc_size(generator, ctx, ndims, dims); - + let data_sz = self.size(ctx, generator); let in_range = ctx.builder.build_int_compare( IntPredicate::ULT, idx, @@ -736,98 +1154,42 @@ impl<'ctx> NDArrayDataProxy<'ctx> { ); unsafe { - self.ptr_to_data_flattened_unchecked(ctx, idx, name) + self.ptr_offset_unchecked(ctx, generator, idx, name) } } +} - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn get_flattened_unchecked( +impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} + +impl<'ctx> ArrayLikeIndexer<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_to_data_flattened_unchecked(ctx, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the `idx`-th flattened index. - pub fn get_flattened( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_to_data_flattened(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn ptr_offset_unchecked( - &self, - ctx: &CodeGenContext<'ctx, '_>, - generator: &dyn CodeGenerator, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> PointerValue<'ctx> { - let indices_elem_ty = indices.get_data().get_ptr(ctx).get_type().get_element_type(); - let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else { - panic!("Expected list[int32] but got {indices_elem_ty}") - }; - assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got {indices_elem_ty}"); - - let index = call_ndarray_flatten_index( - generator, - ctx, - self.0, - indices, - ); - - unsafe { - ctx.builder.build_in_bounds_gep( - self.get_ptr(ctx), - &[index], - name.unwrap_or_default(), - ).unwrap() - } - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn ptr_offset_unchecked_const( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, + generator: &mut G, indices: ArrayValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { let index = call_ndarray_flatten_index_const( generator, ctx, - self.0, + *self.0, indices, ); unsafe { ctx.builder.build_in_bounds_gep( - self.get_ptr(ctx), + self.base_ptr(ctx, generator), &[index], name.unwrap_or_default(), ) }.unwrap() } - /// Returns the pointer to the data at the index specified by `indices`. - pub fn ptr_offset_const( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, + generator: &mut G, indices: ArrayValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { @@ -862,7 +1224,9 @@ impl<'ctx> NDArrayDataProxy<'ctx> { .map(BasicValueEnum::into_int_value) .map(|v| ctx.builder.build_int_z_extend_or_bit_cast(v, llvm_usize, "").unwrap()) .unwrap(); - let dim_sz = self.0.get_dims().get(ctx, generator, i, None); + let dim_sz = unsafe { + self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None) + }; let dim_lt = ctx.builder.build_int_compare( IntPredicate::SLT, @@ -882,23 +1246,59 @@ impl<'ctx> NDArrayDataProxy<'ctx> { } unsafe { - self.ptr_offset_unchecked_const(ctx, generator, indices, name) + self.ptr_offset_unchecked(ctx, generator, indices, name) } } +} - /// Returns the pointer to the data at the index specified by `indices`. - pub fn ptr_offset( +impl<'ctx> UntypedArrayLikeAccessor<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} + +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - indices: ListValue<'ctx>, + generator: &mut G, + indices: Index, name: Option<&str>, ) -> PointerValue<'ctx> { let llvm_usize = generator.get_size_type(ctx.ctx); + let indices_elem_ty = indices.ptr_offset(ctx, generator, llvm_usize.const_zero(), None).get_type().get_element_type(); + let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else { + panic!("Expected list[int32] but got {indices_elem_ty}") + }; + assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got list[int{}]", indices_elem_ty.get_bit_width()); + + let index = call_ndarray_flatten_index( + generator, + ctx, + *self.0, + &indices, + ); + + unsafe { + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[index], + name.unwrap_or_default(), + ).unwrap() + } + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + indices: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let llvm_usize = generator.get_size_type(ctx.ctx); + + let indices_size = indices.size(ctx, generator); let nidx_leq_ndims = ctx.builder.build_int_compare( IntPredicate::SLE, - indices.load_size(ctx, None), + indices_size, self.0.load_ndims(ctx), "" ).unwrap(); @@ -911,34 +1311,19 @@ impl<'ctx> NDArrayDataProxy<'ctx> { ctx.current_loc, ); - gen_for_callback( + let indices_len = indices.size(ctx, generator); + let ndarray_len = self.0.load_ndims(ctx); + let len = call_int_umin(ctx, indices_len, ndarray_len, None); + gen_for_callback_incrementing( generator, ctx, - |generator, ctx| { - let i = generator.gen_var_alloc(ctx, llvm_usize.into(), None)?; - ctx.builder.build_store(i, llvm_usize.const_zero()).unwrap(); - - Ok(i) - }, - |_, ctx, i_addr| { - let indices_len = indices.load_size(ctx, None); - let ndarray_len = self.0.load_ndims(ctx); - - let len = call_int_umin(ctx, indices_len, ndarray_len, None); - - let i = ctx.builder.build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - Ok(ctx.builder.build_int_compare(IntPredicate::SLT, i, len, "").unwrap()) - }, - |generator, ctx, i_addr| { - let i = ctx.builder.build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); + llvm_usize.const_zero(), + (len, false), + |generator, ctx, i| { let (dim_idx, dim_sz) = unsafe { ( - indices.get_data().get_unchecked(ctx, i, None).into_int_value(), - self.0.get_dims().get(ctx, generator, i, None), + indices.get_unchecked(ctx, generator, i, None).into_int_value(), + self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None), ) }; @@ -960,72 +1345,14 @@ impl<'ctx> NDArrayDataProxy<'ctx> { Ok(()) }, - |_, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let i = ctx.builder.build_int_add(i, llvm_usize.const_int(1, true), "").unwrap(); - ctx.builder.build_store(i_addr, i).unwrap(); - - Ok(()) - }, + llvm_usize.const_int(1, false), ).unwrap(); unsafe { self.ptr_offset_unchecked(ctx, generator, indices, name) } } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn get_unsafe_const( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - indices: ArrayValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked_const(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn get_unsafe( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &dyn CodeGenerator, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the index specified by `indices`. - pub fn get_const( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - indices: ArrayValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_const(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the index specified by `indices`. - pub fn get( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut dyn CodeGenerator, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } } + +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeAccessor<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeMutator<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 546a82f..703fe16 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -2,7 +2,14 @@ use std::{collections::HashMap, convert::TryInto, iter::once, iter::zip}; use crate::{ codegen::{ - classes::{ListValue, NDArrayValue, RangeValue}, + classes::{ + ArrayLikeIndexer, + ArrayLikeValue, + ListValue, + NDArrayValue, + RangeValue, + UntypedArrayLikeAccessor, + }, concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore}, gen_in_range_check, get_llvm_type, @@ -103,9 +110,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { index } - pub fn gen_symbol_val( + pub fn gen_symbol_val( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, val: &SymbolValue, ty: Type, ) -> BasicValueEnum<'ctx> { @@ -174,9 +181,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } /// See [`get_llvm_type`]. - pub fn get_llvm_type( + pub fn get_llvm_type( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, ty: Type, ) -> BasicTypeEnum<'ctx> { get_llvm_type( @@ -191,9 +198,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } /// See [`get_llvm_abi_type`]. - pub fn get_llvm_abi_type( + pub fn get_llvm_abi_type( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, ty: Type, ) -> BasicTypeEnum<'ctx> { get_llvm_abi_type( @@ -209,9 +216,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } /// Generates an LLVM variable for a [constant value][value] with a given [type][ty]. - pub fn gen_const( + pub fn gen_const( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, value: &Constant, ty: Type, ) -> Option> { @@ -291,9 +298,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } /// Generates a binary operation `op` between two integral operands `lhs` and `rhs`. - pub fn gen_int_ops( + pub fn gen_int_ops( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, op: &Operator, lhs: BasicValueEnum<'ctx>, rhs: BasicValueEnum<'ctx>, @@ -492,17 +499,21 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { } /// Helper function for generating a LLVM variable storing a [String]. - pub fn gen_string>( + pub fn gen_string( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, s: S, - ) -> BasicValueEnum<'ctx> { + ) -> BasicValueEnum<'ctx> + where + G: CodeGenerator + ?Sized, + S: Into, + { self.gen_const(generator, &Constant::Str(s.into()), self.primitives.str).unwrap() } - pub fn raise_exn( + pub fn raise_exn( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, name: &str, msg: BasicValueEnum<'ctx>, params: [Option>; 3], @@ -546,9 +557,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { gen_raise(generator, self, Some(&zelf.into()), loc); } - pub fn make_assert( + pub fn make_assert( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, cond: IntValue<'ctx>, err_name: &str, err_msg: &str, @@ -559,9 +570,9 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> { self.make_assert_impl(generator, cond, err_name, err_msg, params, loc); } - pub fn make_assert_impl( + pub fn make_assert_impl( &mut self, - generator: &mut dyn CodeGenerator, + generator: &mut G, cond: IntValue<'ctx>, err_name: &str, err_msg: BasicValueEnum<'ctx>, @@ -878,7 +889,7 @@ pub fn destructure_range<'ctx>( /// Returns an instance of [`PointerValue`] pointing to the List structure. The List structure is /// defined as `type { ty*, size_t }` in LLVM, where the first element stores the pointer to the /// data, and the second element stores the size of the List. -pub fn allocate_list<'ctx, G: CodeGenerator>( +pub fn allocate_list<'ctx, G: CodeGenerator + ?Sized>( generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, ty: BasicTypeEnum<'ctx>, @@ -978,7 +989,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( list_alloc_size.into_int_value(), Some("listcomp.addr") ); - list_content = list.get_data().get_ptr(ctx); + list_content = list.data().base_ptr(ctx, generator); let i = generator.gen_store_target(ctx, target, Some("i.addr"))?.unwrap(); ctx.builder @@ -1011,7 +1022,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( ) .into_int_value(); list = allocate_list(generator, ctx, elem_ty, length, Some("listcomp")); - list_content = list.get_data().get_ptr(ctx); + list_content = list.data().base_ptr(ctx, generator); let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?; // counter = -1 ctx.builder.build_store(counter, size_t.const_int(u64::MAX, true)).unwrap(); @@ -1075,7 +1086,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( emit_cont_bb(ctx, generator, list); - Ok(Some(list.get_ptr().into())) + Ok(Some(list.as_ptr_value().into())) } /// Generates LLVM IR for a [binary operator expression][expr]. @@ -1255,8 +1266,8 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( return Ok(None) }; - Ok(Some(v.get_data() - .get_const( + Ok(Some(v.data() + .get( ctx, generator, ctx.ctx.i32_type().const_array(&[index]), @@ -1297,18 +1308,20 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( ); let ndarray_num_dims = ndarray.load_ndims(ctx); - ndarray.create_dims(ctx, llvm_usize, ndarray_num_dims); + ndarray.create_dim_sizes(ctx, llvm_usize, ndarray_num_dims); let ndarray_num_dims = ndarray.load_ndims(ctx); - let v_dims_src_ptr = v.get_dims().ptr_offset( - ctx, - generator, - llvm_usize.const_int(1, false), - None, - ); + let v_dims_src_ptr = unsafe { + v.dim_sizes().ptr_offset_unchecked( + ctx, + generator, + llvm_usize.const_int(1, false), + None, + ) + }; call_memcpy_generic( ctx, - ndarray.get_dims().get_ptr(ctx), + ndarray.dim_sizes().base_ptr(ctx, generator), v_dims_src_ptr, ctx.builder .build_int_mul(ndarray_num_dims, llvm_usize.size_of(), "") @@ -1320,12 +1333,11 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( let ndarray_num_elems = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray.get_dims().get_ptr(ctx), + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); - let v_data_src_ptr = v.get_data().ptr_offset_const( + let v_data_src_ptr = v.data().ptr_offset( ctx, generator, ctx.ctx.i32_type().const_array(&[index]), @@ -1333,7 +1345,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( ); call_memcpy_generic( ctx, - ndarray.get_data().get_ptr(ctx), + ndarray.data().base_ptr(ctx, generator), v_data_src_ptr, ctx.builder .build_int_mul(ndarray_num_elems, llvm_ndarray_data_t.size_of().unwrap(), "") @@ -1342,7 +1354,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( llvm_i1.const_zero(), ); - Ok(Some(ndarray.get_ptr().into())) + Ok(Some(ndarray.as_ptr_value().into())) } } @@ -1425,13 +1437,13 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( }; let length = generator.get_size_type(ctx.ctx).const_int(elements.len() as u64, false); let arr_str_ptr = allocate_list(generator, ctx, ty, length, Some("list")); - let arr_ptr = arr_str_ptr.get_data(); + let arr_ptr = arr_str_ptr.data(); for (i, v) in elements.iter().enumerate() { let elem_ptr = arr_ptr .ptr_offset(ctx, generator, usize.const_int(i as u64, false), Some("elem_ptr")); ctx.builder.build_store(elem_ptr, *v).unwrap(); } - arr_str_ptr.get_ptr().into() + arr_str_ptr.as_ptr_value().into() } ExprKind::Tuple { elts, .. } => { let elements_val = elts @@ -1924,7 +1936,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( v, (start, end, step), ); - res_array_ret.get_ptr().into() + res_array_ret.as_ptr_value().into() } else { let len = v.load_size(ctx, Some("len")); let raw_index = if let Some(v) = generator.gen_expr(ctx, slice)? { @@ -1966,7 +1978,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( [Some(raw_index), Some(len), None], expr.location, ); - v.get_data().get(ctx, generator, index, None).into() + v.data().get(ctx, generator, index, None).into() } } TypeEnum::TObj { obj_id, params, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => { diff --git a/nac3core/src/codegen/generator.rs b/nac3core/src/codegen/generator.rs index 595313c..4f7dd0d 100644 --- a/nac3core/src/codegen/generator.rs +++ b/nac3core/src/codegen/generator.rs @@ -1,5 +1,5 @@ use crate::{ - codegen::{expr::*, stmt::*, bool_to_i1, bool_to_i8, CodeGenContext}, + codegen::{classes::ArraySliceValue, expr::*, stmt::*, bool_to_i1, bool_to_i8, CodeGenContext}, symbol_resolver::ValueEnum, toplevel::{DefinitionId, TopLevelDef}, typecheck::typedef::{FunSignature, Type}, @@ -99,8 +99,8 @@ pub trait CodeGenerator { ctx: &mut CodeGenContext<'ctx, '_>, ty: BasicTypeEnum<'ctx>, size: IntValue<'ctx>, - name: Option<&str>, - ) -> Result, String> { + name: Option<&'ctx str>, + ) -> Result, String> { gen_array_var(ctx, ty, size, name) } diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index 8caccf0..0008d7b 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -1,7 +1,7 @@ use crate::typecheck::typedef::Type; use super::{ - classes::{ListValue, NDArrayValue}, + classes::{ArrayLikeIndexer, ArrayLikeValue, ListValue, NDArrayValue, UntypedArrayLikeMutator}, CodeGenContext, CodeGenerator, }; @@ -39,8 +39,8 @@ pub fn load_irrt(ctx: &Context) -> Module { // repeated squaring method adapted from GNU Scientific Library: // https://git.savannah.gnu.org/cgit/gsl.git/tree/sys/pow_int.c -pub fn integer_power<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn integer_power<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, base: IntValue<'ctx>, exp: IntValue<'ctx>, @@ -81,8 +81,8 @@ pub fn integer_power<'ctx>( .unwrap() } -pub fn calculate_len_for_slice_range<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn calculate_len_for_slice_range<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, start: IntValue<'ctx>, end: IntValue<'ctx>, @@ -303,8 +303,8 @@ pub fn handle_slice_index_bound<'ctx, G: CodeGenerator>( /// This function handles 'end' **inclusively**. /// Order of tuples `assign_idx` and `value_idx` is ('start', 'end', 'step'). /// Negative index should be handled before entering this function -pub fn list_slice_assignment<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, ty: BasicTypeEnum<'ctx>, dest_arr: ListValue<'ctx>, @@ -338,7 +338,7 @@ pub fn list_slice_assignment<'ctx>( let zero = int32.const_zero(); let one = int32.const_int(1, false); - let dest_arr_ptr = dest_arr.get_data().get_ptr(ctx); + let dest_arr_ptr = dest_arr.data().base_ptr(ctx, generator); let dest_arr_ptr = ctx.builder.build_pointer_cast( dest_arr_ptr, elem_ptr_type, @@ -346,7 +346,7 @@ pub fn list_slice_assignment<'ctx>( ).unwrap(); let dest_len = dest_arr.load_size(ctx, Some("dest.len")); let dest_len = ctx.builder.build_int_truncate_or_bit_cast(dest_len, int32, "srclen32").unwrap(); - let src_arr_ptr = src_arr.get_data().get_ptr(ctx); + let src_arr_ptr = src_arr.data().base_ptr(ctx, generator); let src_arr_ptr = ctx.builder.build_pointer_cast( src_arr_ptr, elem_ptr_type, @@ -468,8 +468,8 @@ pub fn list_slice_assignment<'ctx>( } /// Generates a call to `isinf` in IR. Returns an `i1` representing the result. -pub fn call_isinf<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn call_isinf<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>, ) -> IntValue<'ctx> { @@ -489,8 +489,8 @@ pub fn call_isinf<'ctx>( } /// Generates a call to `isnan` in IR. Returns an `i1` representing the result. -pub fn call_isnan<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn call_isnan<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>, ) -> IntValue<'ctx> { @@ -574,12 +574,14 @@ pub fn call_j0<'ctx>( /// /// * `num_dims` - An [`IntValue`] containing the number of dimensions. /// * `dims` - A [`PointerValue`] to an array containing the size of each dimension. -pub fn call_ndarray_calc_size<'ctx>( - generator: &dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - num_dims: IntValue<'ctx>, - dims: PointerValue<'ctx>, -) -> IntValue<'ctx> { +pub fn call_ndarray_calc_size<'ctx, G, Dims>( + generator: &G, + ctx: &CodeGenContext<'ctx, '_>, + dims: &Dims, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Dims: ArrayLikeIndexer<'ctx>, { let llvm_i64 = ctx.ctx.i64_type(); let llvm_usize = generator.get_size_type(ctx.ctx); @@ -606,8 +608,8 @@ pub fn call_ndarray_calc_size<'ctx>( .build_call( ndarray_calc_size_fn, &[ - dims.into(), - num_dims.into(), + dims.base_ptr(ctx, generator).into(), + dims.size(ctx, generator).into(), ], "", ) @@ -622,8 +624,8 @@ pub fn call_ndarray_calc_size<'ctx>( /// * `index` - The index to compute the multidimensional index for. /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// `NDArray`. -pub fn call_ndarray_calc_nd_indices<'ctx>( - generator: &dyn CodeGenerator, +pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>( + generator: &G, ctx: &mut CodeGenContext<'ctx, '_>, index: IntValue<'ctx>, ndarray: NDArrayValue<'ctx>, @@ -653,7 +655,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx>( }); let ndarray_num_dims = ndarray.load_ndims(ctx); - let ndarray_dims = ndarray.get_dims(); + let ndarray_dims = ndarray.dim_sizes(); let indices = ctx.builder.build_array_alloca( llvm_usize, @@ -666,7 +668,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx>( ndarray_calc_nd_indices_fn, &[ index.into(), - ndarray_dims.get_ptr(ctx).into(), + ndarray_dims.base_ptr(ctx, generator).into(), ndarray_num_dims.into(), indices.into(), ], @@ -677,13 +679,15 @@ pub fn call_ndarray_calc_nd_indices<'ctx>( indices } -fn call_ndarray_flatten_index_impl<'ctx>( - generator: &dyn CodeGenerator, +fn call_ndarray_flatten_index_impl<'ctx, G, Indices>( + generator: &G, ctx: &CodeGenContext<'ctx, '_>, ndarray: NDArrayValue<'ctx>, - indices: PointerValue<'ctx>, - indices_size: IntValue<'ctx>, -) -> IntValue<'ctx> { + indices: &Indices, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Indices: ArrayLikeIndexer<'ctx>, { let llvm_i32 = ctx.ctx.i32_type(); let llvm_usize = generator.get_size_type(ctx.ctx); @@ -691,14 +695,14 @@ fn call_ndarray_flatten_index_impl<'ctx>( let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); debug_assert_eq!( - IntType::try_from(indices.get_type().get_element_type()) + IntType::try_from(indices.element_type(ctx, generator)) .map(IntType::get_bit_width) .unwrap_or_default(), llvm_i32.get_bit_width(), "Expected i32 value for argument `indices` to `call_ndarray_flatten_index_impl`" ); debug_assert_eq!( - indices_size.get_type().get_bit_width(), + indices.size(ctx, generator).get_type().get_bit_width(), llvm_usize.get_bit_width(), "Expected usize integer value for argument `indices_size` to `call_ndarray_flatten_index_impl`" ); @@ -723,16 +727,16 @@ fn call_ndarray_flatten_index_impl<'ctx>( }); let ndarray_num_dims = ndarray.load_ndims(ctx); - let ndarray_dims = ndarray.get_dims(); + let ndarray_dims = ndarray.dim_sizes(); let index = ctx.builder .build_call( ndarray_flatten_index_fn, &[ - ndarray_dims.get_ptr(ctx).into(), + ndarray_dims.base_ptr(ctx, generator).into(), ndarray_num_dims.into(), - indices.into(), - indices_size.into(), + indices.base_ptr(ctx, generator).into(), + indices.size(ctx, generator).into(), ], "", ) @@ -750,21 +754,21 @@ fn call_ndarray_flatten_index_impl<'ctx>( /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// `NDArray`. /// * `indices` - The multidimensional index to compute the flattened index for. -pub fn call_ndarray_flatten_index<'ctx>( - generator: &dyn CodeGenerator, - ctx: &CodeGenContext<'ctx, '_>, +pub fn call_ndarray_flatten_index<'ctx, G, Index>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, ndarray: NDArrayValue<'ctx>, - indices: ListValue<'ctx>, -) -> IntValue<'ctx> { - let indices_size = indices.load_size(ctx, None); - let indices_data = indices.get_data(); + indices: &Index, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Index: ArrayLikeIndexer<'ctx>, { call_ndarray_flatten_index_impl( generator, ctx, ndarray, - indices_data.get_ptr(ctx), - indices_size, + indices, ) } /// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the @@ -773,8 +777,8 @@ pub fn call_ndarray_flatten_index<'ctx>( /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// `NDArray`. /// * `indices` - The multidimensional index to compute the flattened index for. -pub fn call_ndarray_flatten_index_const<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn call_ndarray_flatten_index_const<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, ndarray: NDArrayValue<'ctx>, indices: ArrayValue<'ctx>, @@ -786,27 +790,27 @@ pub fn call_ndarray_flatten_index_const<'ctx>( ctx, indices.get_type().get_element_type(), llvm_usize.const_int(indices_size as u64, false), - None + None, ).unwrap(); for i in 0..indices_size { let v = ctx.builder.build_extract_value(indices, i, "") .unwrap() .into_int_value(); - let elem_ptr = unsafe { - ctx.builder.build_in_bounds_gep( - indices_alloca, - &[ctx.ctx.i32_type().const_int(i as u64, false)], - "" - ) - }.unwrap(); - ctx.builder.build_store(elem_ptr, v).unwrap(); + + unsafe { + indices_alloca.set_unchecked( + ctx, + generator, + ctx.ctx.i32_type().const_int(i as u64, false), + v.into(), + ); + } } call_ndarray_flatten_index_impl( generator, ctx, ndarray, - indices_alloca, - llvm_usize.const_int(indices_size as u64, false), + &indices_alloca, ) } \ No newline at end of file diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 0104879..c528eab 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -45,6 +45,7 @@ pub mod expr; mod generator; pub mod irrt; pub mod llvm_intrinsics; +pub mod numpy; pub mod stmt; #[cfg(test)] @@ -415,10 +416,10 @@ pub struct CodeGenTask { /// This function is used to obtain the in-memory representation of `ty`, e.g. a `bool` variable /// would be represented by an `i8`. #[allow(clippy::too_many_arguments)] -fn get_llvm_type<'ctx>( +fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>( ctx: &'ctx Context, module: &Module<'ctx>, - generator: &mut dyn CodeGenerator, + generator: &mut G, unifier: &mut Unifier, top_level: &TopLevelContext, type_cache: &mut HashMap>, @@ -553,10 +554,10 @@ fn get_llvm_type<'ctx>( /// be byte-aligned for the variable to be addressable in memory, whereas there is no such /// restriction for ABI representations. #[allow(clippy::too_many_arguments)] -fn get_llvm_abi_type<'ctx>( +fn get_llvm_abi_type<'ctx, G: CodeGenerator + ?Sized>( ctx: &'ctx Context, module: &Module<'ctx>, - generator: &mut dyn CodeGenerator, + generator: &mut G, unifier: &mut Unifier, top_level: &TopLevelContext, type_cache: &mut HashMap>, diff --git a/nac3core/src/codegen/numpy.rs b/nac3core/src/codegen/numpy.rs new file mode 100644 index 0000000..92598eb --- /dev/null +++ b/nac3core/src/codegen/numpy.rs @@ -0,0 +1,837 @@ +use inkwell::{ + IntPredicate, + types::BasicType, + values::{AggregateValueEnum, ArrayValue, BasicValueEnum, IntValue, PointerValue} +}; +use nac3parser::ast::StrRef; +use crate::{ + codegen::{ + classes::{ + ArrayLikeIndexer, + ArrayLikeValue, + ListValue, + NDArrayValue, + TypedArrayLikeAccessor, + UntypedArrayLikeAccessor, + }, + CodeGenContext, + CodeGenerator, + irrt::{ + call_ndarray_calc_nd_indices, + call_ndarray_calc_size, + }, + llvm_intrinsics::call_memcpy_generic, + stmt::gen_for_callback_incrementing, + }, + symbol_resolver::ValueEnum, + toplevel::{ + DefinitionId, + numpy::{make_ndarray_ty, unpack_ndarray_tvars}, + }, + typecheck::typedef::{FunSignature, Type}, +}; + +/// Creates an `NDArray` instance from a dynamic shape. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The shape of the `NDArray`. +/// * `shape_len_fn` - A function that retrieves the number of dimensions from `shape`. +/// * `shape_data_fn` - A function that retrieves the size of a dimension from `shape`. +fn create_ndarray_dyn_shape<'ctx, 'a, G, V, LenFn, DataFn>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, 'a>, + elem_ty: Type, + shape: &V, + shape_len_fn: LenFn, + shape_data_fn: DataFn, +) -> Result, String> + where + G: CodeGenerator + ?Sized, + LenFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>, &V) -> Result, String>, + DataFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>, &V, IntValue<'ctx>) -> Result, String>, +{ + let ndarray_ty = make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(elem_ty), None); + + let llvm_usize = generator.get_size_type(ctx.ctx); + + let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type(); + let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type(); + let llvm_ndarray_data_t = ctx.get_llvm_type(generator, elem_ty).as_basic_type_enum(); + assert!(llvm_ndarray_data_t.is_sized()); + + // Assert that all dimensions are non-negative + let shape_len = shape_len_fn(generator, ctx, shape)?; + gen_for_callback_incrementing( + generator, + ctx, + llvm_usize.const_zero(), + (shape_len, false), + |generator, ctx, i| { + let shape_dim = shape_data_fn(generator, ctx, shape, i)?; + debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width()); + + let shape_dim_gez = ctx.builder + .build_int_compare(IntPredicate::SGE, shape_dim, shape_dim.get_type().const_zero(), "") + .unwrap(); + + ctx.make_assert( + generator, + shape_dim_gez, + "0:ValueError", + "negative dimensions not supported", + [None, None, None], + ctx.current_loc, + ); + + Ok(()) + }, + llvm_usize.const_int(1, false), + )?; + + let ndarray = generator.gen_var_alloc( + ctx, + llvm_ndarray_t.into(), + None, + )?; + let ndarray = NDArrayValue::from_ptr_val(ndarray, llvm_usize, None); + + let num_dims = shape_len_fn(generator, ctx, shape)?; + ndarray.store_ndims(ctx, generator, num_dims); + + let ndarray_num_dims = ndarray.load_ndims(ctx); + ndarray.create_dim_sizes(ctx, llvm_usize, ndarray_num_dims); + + // Copy the dimension sizes from shape to ndarray.dims + let shape_len = shape_len_fn(generator, ctx, shape)?; + gen_for_callback_incrementing( + generator, + ctx, + llvm_usize.const_zero(), + (shape_len, false), + |generator, ctx, i| { + let shape_dim = shape_data_fn(generator, ctx, shape, i)?; + debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width()); + let shape_dim = ctx.builder + .build_int_z_extend(shape_dim, llvm_usize, "") + .unwrap(); + + let ndarray_pdim = unsafe { + ndarray.dim_sizes().ptr_offset_unchecked(ctx, generator, i, None) + }; + + ctx.builder.build_store(ndarray_pdim, shape_dim).unwrap(); + + Ok(()) + }, + llvm_usize.const_int(1, false), + )?; + + let ndarray_num_elems = call_ndarray_calc_size( + generator, + ctx, + &ndarray.dim_sizes().as_slice_value(ctx, generator), + ); + ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); + + Ok(ndarray) +} + +/// Creates an `NDArray` instance from a constant shape. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The shape of the `NDArray`, represented as an LLVM [`ArrayValue`]. +fn create_ndarray_const_shape<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + shape: ArrayValue<'ctx> +) -> Result, String> { + let ndarray_ty = make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(elem_ty), None); + + let llvm_usize = generator.get_size_type(ctx.ctx); + + let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type(); + let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type(); + let llvm_ndarray_data_t = ctx.get_llvm_type(generator, elem_ty).as_basic_type_enum(); + assert!(llvm_ndarray_data_t.is_sized()); + + for i in 0..shape.get_type().len() { + let shape_dim = ctx.builder + .build_extract_value(shape, i, "") + .map(BasicValueEnum::into_int_value) + .unwrap(); + + let shape_dim_gez = ctx.builder + .build_int_compare(IntPredicate::SGE, shape_dim, llvm_usize.const_zero(), "") + .unwrap(); + + ctx.make_assert( + generator, + shape_dim_gez, + "0:ValueError", + "negative dimensions not supported", + [None, None, None], + ctx.current_loc, + ); + } + + let ndarray = generator.gen_var_alloc( + ctx, + llvm_ndarray_t.into(), + None, + )?; + let ndarray = NDArrayValue::from_ptr_val(ndarray, llvm_usize, None); + + let num_dims = llvm_usize.const_int(shape.get_type().len() as u64, false); + ndarray.store_ndims(ctx, generator, num_dims); + + let ndarray_num_dims = ndarray.load_ndims(ctx); + ndarray.create_dim_sizes(ctx, llvm_usize, ndarray_num_dims); + + for i in 0..shape.get_type().len() { + let ndarray_dim = ndarray + .dim_sizes() + .ptr_offset(ctx, generator, llvm_usize.const_int(i as u64, true), None); + let shape_dim = ctx.builder.build_extract_value(shape, i, "") + .map(BasicValueEnum::into_int_value) + .unwrap(); + + ctx.builder.build_store(ndarray_dim, shape_dim).unwrap(); + } + + let ndarray_num_elems = call_ndarray_calc_size( + generator, + ctx, + &ndarray.dim_sizes().as_slice_value(ctx, generator), + ); + ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); + + Ok(ndarray) +} + +fn ndarray_zero_value<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, +) -> BasicValueEnum<'ctx> { + if [ctx.primitives.int32, ctx.primitives.uint32].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { + ctx.ctx.i32_type().const_zero().into() + } else if [ctx.primitives.int64, ctx.primitives.uint64].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { + ctx.ctx.i64_type().const_zero().into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.float) { + ctx.ctx.f64_type().const_zero().into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) { + ctx.ctx.bool_type().const_zero().into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { + ctx.gen_string(generator, "") + } else { + unreachable!() + } +} + +fn ndarray_one_value<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, +) -> BasicValueEnum<'ctx> { + if [ctx.primitives.int32, ctx.primitives.uint32].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { + let is_signed = ctx.unifier.unioned(elem_ty, ctx.primitives.int32); + ctx.ctx.i32_type().const_int(1, is_signed).into() + } else if [ctx.primitives.int64, ctx.primitives.uint64].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { + let is_signed = ctx.unifier.unioned(elem_ty, ctx.primitives.int64); + ctx.ctx.i64_type().const_int(1, is_signed).into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.float) { + ctx.ctx.f64_type().const_float(1.0).into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) { + ctx.ctx.bool_type().const_int(1, false).into() + } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { + ctx.gen_string(generator, "1") + } else { + unreachable!() + } +} + +/// LLVM-typed implementation for generating the implementation for constructing an `NDArray`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The `shape` parameter used to construct the `NDArray`. +fn call_ndarray_empty_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + shape: ListValue<'ctx>, +) -> Result, String> { + create_ndarray_dyn_shape( + generator, + ctx, + elem_ty, + &shape, + |_, ctx, shape| { + Ok(shape.load_size(ctx, None)) + }, + |generator, ctx, shape, idx| { + Ok(shape.data().get(ctx, generator, idx, None).into_int_value()) + }, + ) +} + +/// Generates LLVM IR for populating the entire `NDArray` using a lambda with its flattened index as +/// its input. +fn ndarray_fill_flattened<'ctx, 'a, G, ValueFn>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, 'a>, + ndarray: NDArrayValue<'ctx>, + value_fn: ValueFn, +) -> Result<(), String> + where + G: CodeGenerator + ?Sized, + ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, 'a>, IntValue<'ctx>) -> Result, String>, +{ + let llvm_usize = generator.get_size_type(ctx.ctx); + + let ndarray_num_elems = call_ndarray_calc_size( + generator, + ctx, + &ndarray.dim_sizes().as_slice_value(ctx, generator), + ); + + gen_for_callback_incrementing( + generator, + ctx, + llvm_usize.const_zero(), + (ndarray_num_elems, false), + |generator, ctx, i| { + let elem = unsafe { + ndarray.data().ptr_offset_unchecked(ctx, generator, i, None) + }; + + let value = value_fn(generator, ctx, i)?; + ctx.builder.build_store(elem, value).unwrap(); + + Ok(()) + }, + llvm_usize.const_int(1, false), + ) +} + +/// Generates LLVM IR for populating the entire `NDArray` using a lambda with the dimension-indices +/// as its input. +fn ndarray_fill_indexed<'ctx, G, ValueFn>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, + value_fn: ValueFn, +) -> Result<(), String> + where + G: CodeGenerator + ?Sized, + ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, PointerValue<'ctx>) -> Result, String>, +{ + ndarray_fill_flattened( + generator, + ctx, + ndarray, + |generator, ctx, idx| { + let indices = call_ndarray_calc_nd_indices( + generator, + ctx, + idx, + ndarray, + ); + + value_fn(generator, ctx, indices) + } + ) +} + +/// LLVM-typed implementation for generating the implementation for `ndarray.zeros`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The `shape` parameter used to construct the `NDArray`. +fn call_ndarray_zeros_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + shape: ListValue<'ctx>, +) -> Result, String> { + let supported_types = [ + ctx.primitives.int32, + ctx.primitives.int64, + ctx.primitives.uint32, + ctx.primitives.uint64, + ctx.primitives.float, + ctx.primitives.bool, + ctx.primitives.str, + ]; + assert!(supported_types.iter().any(|supported_ty| ctx.unifier.unioned(*supported_ty, elem_ty))); + + let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; + ndarray_fill_flattened( + generator, + ctx, + ndarray, + |generator, ctx, _| { + let value = ndarray_zero_value(generator, ctx, elem_ty); + + Ok(value) + } + )?; + + Ok(ndarray) +} + +/// LLVM-typed implementation for generating the implementation for `ndarray.ones`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The `shape` parameter used to construct the `NDArray`. +fn call_ndarray_ones_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + shape: ListValue<'ctx>, +) -> Result, String> { + let supported_types = [ + ctx.primitives.int32, + ctx.primitives.int64, + ctx.primitives.uint32, + ctx.primitives.uint64, + ctx.primitives.float, + ctx.primitives.bool, + ctx.primitives.str, + ]; + assert!(supported_types.iter().any(|supported_ty| ctx.unifier.unioned(*supported_ty, elem_ty))); + + let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; + ndarray_fill_flattened( + generator, + ctx, + ndarray, + |generator, ctx, _| { + let value = ndarray_one_value(generator, ctx, elem_ty); + + Ok(value) + } + )?; + + Ok(ndarray) +} + +/// LLVM-typed implementation for generating the implementation for `ndarray.full`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +/// * `shape` - The `shape` parameter used to construct the `NDArray`. +fn call_ndarray_full_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + shape: ListValue<'ctx>, + fill_value: BasicValueEnum<'ctx>, +) -> Result, String> { + let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; + ndarray_fill_flattened( + generator, + ctx, + ndarray, + |generator, ctx, _| { + let value = if fill_value.is_pointer_value() { + let llvm_i1 = ctx.ctx.bool_type(); + + let copy = generator.gen_var_alloc(ctx, fill_value.get_type(), None)?; + + call_memcpy_generic( + ctx, + copy, + fill_value.into_pointer_value(), + fill_value.get_type().size_of().map(Into::into).unwrap(), + llvm_i1.const_zero(), + ); + + copy.into() + } else if fill_value.is_int_value() || fill_value.is_float_value() { + fill_value + } else { + unreachable!() + }; + + Ok(value) + } + )?; + + Ok(ndarray) +} + +/// LLVM-typed implementation for generating the implementation for `ndarray.eye`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +fn call_ndarray_eye_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + nrows: IntValue<'ctx>, + ncols: IntValue<'ctx>, + offset: IntValue<'ctx>, +) -> Result, String> { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_usize_2 = llvm_usize.array_type(2); + + let shape_addr = generator.gen_var_alloc(ctx, llvm_usize_2.into(), None)?; + + let shape = ctx.builder.build_load(shape_addr, "") + .map(BasicValueEnum::into_array_value) + .unwrap(); + + let nrows = ctx.builder.build_int_z_extend_or_bit_cast(nrows, llvm_usize, "").unwrap(); + let shape = ctx.builder + .build_insert_value(shape, nrows, 0, "") + .map(AggregateValueEnum::into_array_value) + .unwrap(); + + let ncols = ctx.builder.build_int_z_extend_or_bit_cast(ncols, llvm_usize, "").unwrap(); + let shape = ctx.builder + .build_insert_value(shape, ncols, 1, "") + .map(AggregateValueEnum::into_array_value) + .unwrap(); + + let ndarray = create_ndarray_const_shape(generator, ctx, elem_ty, shape)?; + + ndarray_fill_indexed( + generator, + ctx, + ndarray, + |generator, ctx, indices| { + let row = ctx.build_gep_and_load( + indices, + &[llvm_usize.const_int(0, false)], + None, + ).into_int_value(); + let col = ctx.build_gep_and_load( + indices, + &[llvm_usize.const_int(1, false)], + None, + ).into_int_value(); + + let col_with_offset = ctx.builder + .build_int_add( + col, + ctx.builder.build_int_s_extend_or_bit_cast(offset, llvm_usize, "").unwrap(), + "", + ) + .unwrap(); + let is_on_diag = ctx.builder + .build_int_compare(IntPredicate::EQ, row, col_with_offset, "") + .unwrap(); + + let zero = ndarray_zero_value(generator, ctx, elem_ty); + let one = ndarray_one_value(generator, ctx, elem_ty); + + let value = ctx.builder.build_select(is_on_diag, one, zero, "").unwrap(); + + Ok(value) + }, + )?; + + Ok(ndarray) +} + +/// LLVM-typed implementation for generating the implementation for `ndarray.copy`. +/// +/// * `elem_ty` - The element type of the `NDArray`. +fn ndarray_copy_impl<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + elem_ty: Type, + this: NDArrayValue<'ctx>, +) -> Result, String> { + let llvm_i1 = ctx.ctx.bool_type(); + + let ndarray = create_ndarray_dyn_shape( + generator, + ctx, + elem_ty, + &this, + |_, ctx, shape| { + Ok(shape.load_ndims(ctx)) + }, + |generator, ctx, shape, idx| { + unsafe { Ok(shape.dim_sizes().get_typed_unchecked(ctx, generator, idx, None)) } + }, + )?; + + let len = call_ndarray_calc_size( + generator, + ctx, + &ndarray.dim_sizes().as_slice_value(ctx, generator), + ); + let sizeof_ty = ctx.get_llvm_type(generator, elem_ty); + let len_bytes = ctx.builder + .build_int_mul( + len, + sizeof_ty.size_of().unwrap(), + "", + ) + .unwrap(); + + call_memcpy_generic( + ctx, + ndarray.data().base_ptr(ctx, generator), + this.data().base_ptr(ctx, generator), + len_bytes, + llvm_i1.const_zero(), + ); + + Ok(ndarray) +} + +/// Generates LLVM IR for `ndarray.empty`. +pub fn gen_ndarray_empty<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert_eq!(args.len(), 1); + + let llvm_usize = generator.get_size_type(context.ctx); + let shape_ty = fun.0.args[0].ty; + let shape_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, shape_ty)?; + + call_ndarray_empty_impl( + generator, + context, + context.primitives.float, + ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.zeros`. +pub fn gen_ndarray_zeros<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert_eq!(args.len(), 1); + + let llvm_usize = generator.get_size_type(context.ctx); + let shape_ty = fun.0.args[0].ty; + let shape_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, shape_ty)?; + + call_ndarray_zeros_impl( + generator, + context, + context.primitives.float, + ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.ones`. +pub fn gen_ndarray_ones<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert_eq!(args.len(), 1); + + let llvm_usize = generator.get_size_type(context.ctx); + let shape_ty = fun.0.args[0].ty; + let shape_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, shape_ty)?; + + call_ndarray_ones_impl( + generator, + context, + context.primitives.float, + ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.full`. +pub fn gen_ndarray_full<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert_eq!(args.len(), 2); + + let llvm_usize = generator.get_size_type(context.ctx); + let shape_ty = fun.0.args[0].ty; + let shape_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, shape_ty)?; + let fill_value_ty = fun.0.args[1].ty; + let fill_value_arg = args[1].1.clone() + .to_basic_value_enum(context, generator, fill_value_ty)?; + + call_ndarray_full_impl( + generator, + context, + fill_value_ty, + ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), + fill_value_arg, + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.eye`. +pub fn gen_ndarray_eye<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert!(matches!(args.len(), 1..=3)); + + let nrows_ty = fun.0.args[0].ty; + let nrows_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, nrows_ty)?; + + let ncols_ty = fun.0.args[1].ty; + let ncols_arg = args.iter() + .find(|arg| arg.0.is_some_and(|name| name == fun.0.args[1].name)) + .map(|arg| arg.1.clone().to_basic_value_enum(context, generator, ncols_ty)) + .unwrap_or_else(|| { + args[0].1.clone().to_basic_value_enum(context, generator, nrows_ty) + })?; + + let offset_ty = fun.0.args[2].ty; + let offset_arg = args.iter() + .find(|arg| arg.0.is_some_and(|name| name == fun.0.args[2].name)) + .map(|arg| arg.1.clone().to_basic_value_enum(context, generator, offset_ty)) + .unwrap_or_else(|| { + Ok(context.gen_symbol_val( + generator, + fun.0.args[2].default_value.as_ref().unwrap(), + offset_ty + )) + })?; + + call_ndarray_eye_impl( + generator, + context, + context.primitives.float, + nrows_arg.into_int_value(), + ncols_arg.into_int_value(), + offset_arg.into_int_value(), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.identity`. +pub fn gen_ndarray_identity<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_none()); + assert_eq!(args.len(), 1); + + let llvm_usize = generator.get_size_type(context.ctx); + + let n_ty = fun.0.args[0].ty; + let n_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, n_ty)?; + + call_ndarray_eye_impl( + generator, + context, + context.primitives.float, + n_arg.into_int_value(), + n_arg.into_int_value(), + llvm_usize.const_zero(), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.copy`. +pub fn gen_ndarray_copy<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + _fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result, String> { + assert!(obj.is_some()); + assert!(args.is_empty()); + + let llvm_usize = generator.get_size_type(context.ctx); + + let this_ty = obj.as_ref().unwrap().0; + let (this_elem_ty, _) = unpack_ndarray_tvars(&mut context.unifier, this_ty); + let this_arg = obj + .as_ref() + .unwrap() + .1 + .clone() + .to_basic_value_enum(context, generator, this_ty)?; + + ndarray_copy_impl( + generator, + context, + this_elem_ty, + NDArrayValue::from_ptr_val(this_arg.into_pointer_value(), llvm_usize, None), + ).map(NDArrayValue::into) +} + +/// Generates LLVM IR for `ndarray.fill`. +pub fn gen_ndarray_fill<'ctx>( + context: &mut CodeGenContext<'ctx, '_>, + obj: &Option<(Type, ValueEnum<'ctx>)>, + fun: (&FunSignature, DefinitionId), + args: &[(Option, ValueEnum<'ctx>)], + generator: &mut dyn CodeGenerator, +) -> Result<(), String> { + assert!(obj.is_some()); + assert_eq!(args.len(), 1); + + let llvm_usize = generator.get_size_type(context.ctx); + + let this_ty = obj.as_ref().unwrap().0; + let this_arg = obj.as_ref().unwrap().1.clone() + .to_basic_value_enum(context, generator, this_ty)? + .into_pointer_value(); + let value_ty = fun.0.args[0].ty; + let value_arg = args[0].1.clone() + .to_basic_value_enum(context, generator, value_ty)?; + + ndarray_fill_flattened( + generator, + context, + NDArrayValue::from_ptr_val(this_arg, llvm_usize, None), + |generator, ctx, _| { + let value = if value_arg.is_pointer_value() { + let llvm_i1 = ctx.ctx.bool_type(); + + let copy = generator.gen_var_alloc(ctx, value_arg.get_type(), None)?; + + call_memcpy_generic( + ctx, + copy, + value_arg.into_pointer_value(), + value_arg.get_type().size_of().map(Into::into).unwrap(), + llvm_i1.const_zero(), + ); + + copy.into() + } else if value_arg.is_int_value() || value_arg.is_float_value() { + value_arg + } else { + unreachable!() + }; + + Ok(value) + } + )?; + + Ok(()) +} \ No newline at end of file diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index d7a3d6f..61018a3 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -6,7 +6,7 @@ use super::{ }; use crate::{ codegen::{ - classes::{ListValue, RangeValue}, + classes::{ArrayLikeIndexer, ArraySliceValue, ListValue, RangeValue}, expr::gen_binop_expr, gen_in_range_check, }, @@ -65,8 +65,8 @@ pub fn gen_array_var<'ctx, 'a, T: BasicType<'ctx>>( ctx: &mut CodeGenContext<'ctx, 'a>, ty: T, size: IntValue<'ctx>, - name: Option<&str>, -) -> Result, String> { + name: Option<&'ctx str>, +) -> Result, String> { // Restore debug location let di_loc = ctx.debug_info.0.create_debug_location( ctx.ctx, @@ -84,6 +84,7 @@ pub fn gen_array_var<'ctx, 'a, T: BasicType<'ctx>>( ctx.builder.set_current_debug_location(di_loc); let ptr = ctx.builder.build_array_alloca(ty, size, name.unwrap_or("")).unwrap(); + let ptr = ArraySliceValue::from_ptr_val(ptr, size, name); ctx.builder.position_at_end(current); ctx.builder.set_current_debug_location(di_loc); @@ -188,7 +189,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>( [Some(raw_index), Some(len), None], slice.location, ); - v.get_data().ptr_offset(ctx, generator, index, name) + v.data().ptr_offset(ctx, generator, index, name) } TypeEnum::TObj { obj_id, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => { @@ -478,8 +479,8 @@ pub fn gen_for( /// executing. The result value must be an `i1` indicating if the loop should continue. /// * `body` - A lambda containing IR statements within the loop body. /// * `update` - A lambda containing IR statements updating loop variables. -pub fn gen_for_callback<'ctx, 'a, I, InitFn, CondFn, BodyFn, UpdateFn>( - generator: &mut dyn CodeGenerator, +pub fn gen_for_callback<'ctx, 'a, G, I, InitFn, CondFn, BodyFn, UpdateFn>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, 'a>, init: InitFn, cond: CondFn, @@ -487,11 +488,12 @@ pub fn gen_for_callback<'ctx, 'a, I, InitFn, CondFn, BodyFn, UpdateFn>( update: UpdateFn, ) -> Result<(), String> where + G: CodeGenerator + ?Sized, I: Clone, - InitFn: FnOnce(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>) -> Result, - CondFn: FnOnce(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, I) -> Result, String>, - BodyFn: FnOnce(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>, - UpdateFn: FnOnce(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>, + InitFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>) -> Result, + CondFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result, String>, + BodyFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>, + UpdateFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, I) -> Result<(), String>, { let current = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap(); let init_bb = ctx.ctx.append_basic_block(current, "for.init"); @@ -536,6 +538,85 @@ pub fn gen_for_callback<'ctx, 'a, I, InitFn, CondFn, BodyFn, UpdateFn>( Ok(()) } +/// Generates a C-style monotonically-increasing `for` construct using lambdas, similar to the +/// following C code: +/// +/// ```c +/// for (int x = init_val; x /* < or <= ; see `max_val` */ max_val; x += incr_val) { +/// body(x); +/// } +/// ``` +/// +/// * `init_val` - The initial value of the loop variable. The type of this value will also be used +/// as the type of the loop variable. +/// * `max_val` - A tuple containing the maximum value of the loop variable, and whether the maximum +/// value should be treated as inclusive (as opposed to exclusive). +/// * `body` - A lambda containing IR statements within the loop body. +/// * `incr_val` - The value to increment the loop variable on each iteration. +pub fn gen_for_callback_incrementing<'ctx, 'a, G, BodyFn>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, 'a>, + init_val: IntValue<'ctx>, + max_val: (IntValue<'ctx>, bool), + body: BodyFn, + incr_val: IntValue<'ctx>, +) -> Result<(), String> + where + G: CodeGenerator + ?Sized, + BodyFn: FnOnce(&mut G, &mut CodeGenContext<'ctx, 'a>, IntValue<'ctx>) -> Result<(), String>, +{ + let init_val_t = init_val.get_type(); + + gen_for_callback( + generator, + ctx, + |generator, ctx| { + let i_addr = generator.gen_var_alloc(ctx, init_val_t.into(), None)?; + ctx.builder.build_store(i_addr, init_val).unwrap(); + + Ok(i_addr) + }, + |_, ctx, i_addr| { + let cmp_op = if max_val.1 { + IntPredicate::ULE + } else { + IntPredicate::ULT + }; + + let i = ctx.builder + .build_load(i_addr, "") + .map(BasicValueEnum::into_int_value) + .unwrap(); + let max_val = ctx.builder + .build_int_z_extend_or_bit_cast(max_val.0, init_val_t, "") + .unwrap(); + + Ok(ctx.builder.build_int_compare(cmp_op, i, max_val, "").unwrap()) + }, + |generator, ctx, i_addr| { + let i = ctx.builder + .build_load(i_addr, "") + .map(BasicValueEnum::into_int_value) + .unwrap(); + + body(generator, ctx, i) + }, + |_, ctx, i_addr| { + let i = ctx.builder + .build_load(i_addr, "") + .map(BasicValueEnum::into_int_value) + .unwrap(); + let incr_val = ctx.builder + .build_int_z_extend_or_bit_cast(incr_val, init_val_t, "") + .unwrap(); + let i = ctx.builder.build_int_add(i, incr_val, "").unwrap(); + ctx.builder.build_store(i_addr, i).unwrap(); + + Ok(()) + }, + ) +} + /// See [`CodeGenerator::gen_while`]. pub fn gen_while( generator: &mut G, @@ -701,8 +782,8 @@ pub fn final_proxy<'ctx>( /// Inserts the declaration of the builtin function with the specified `symbol` name, and returns /// the function. -pub fn get_builtins<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn get_builtins<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, symbol: &str, ) -> FunctionValue<'ctx> { @@ -795,8 +876,8 @@ pub fn exn_constructor<'ctx>( /// /// * `exception` - The exception thrown by the `raise` statement. /// * `loc` - The location where the exception is raised from. -pub fn gen_raise<'ctx>( - generator: &mut dyn CodeGenerator, +pub fn gen_raise<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, exception: Option<&BasicValueEnum<'ctx>>, loc: Location, diff --git a/nac3core/src/toplevel/builtins.rs b/nac3core/src/toplevel/builtins.rs index 5c82908..20cefc7 100644 --- a/nac3core/src/toplevel/builtins.rs +++ b/nac3core/src/toplevel/builtins.rs @@ -5,11 +5,14 @@ use crate::{ expr::destructure_range, irrt::*, llvm_intrinsics::*, + numpy::*, stmt::exn_constructor, }, symbol_resolver::SymbolValue, - toplevel::helper::PRIMITIVE_DEF_IDS, - toplevel::numpy::*, + toplevel::{ + helper::PRIMITIVE_DEF_IDS, + numpy::make_ndarray_ty, + }, typecheck::typedef::VarMap, }; use inkwell::{ diff --git a/nac3core/src/toplevel/numpy.rs b/nac3core/src/toplevel/numpy.rs index e6ecb1a..f9ac2eb 100644 --- a/nac3core/src/toplevel/numpy.rs +++ b/nac3core/src/toplevel/numpy.rs @@ -1,24 +1,9 @@ -use inkwell::{IntPredicate, types::BasicType, values::{BasicValueEnum, PointerValue}}; -use inkwell::values::{AggregateValueEnum, ArrayValue, IntValue}; use itertools::Itertools; -use nac3parser::ast::StrRef; use crate::{ - codegen::{ - classes::{ListValue, NDArrayValue}, - CodeGenContext, - CodeGenerator, - irrt::{ - call_ndarray_calc_nd_indices, - call_ndarray_calc_size, - }, - llvm_intrinsics::call_memcpy_generic, - stmt::gen_for_callback - }, - symbol_resolver::ValueEnum, - toplevel::{DefinitionId, helper::PRIMITIVE_DEF_IDS}, + toplevel::helper::PRIMITIVE_DEF_IDS, typecheck::{ type_inferencer::PrimitiveStore, - typedef::{FunSignature, Type, TypeEnum, Unifier, VarMap}, + typedef::{Type, TypeEnum, Unifier, VarMap}, }, }; @@ -76,885 +61,3 @@ pub fn unpack_ndarray_tvars( .collect_tuple() .unwrap() } - -/// Creates an `NDArray` instance from a dynamic shape. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The shape of the `NDArray`. -/// * `shape_len_fn` - A function that retrieves the number of dimensions from `shape`. -/// * `shape_data_fn` - A function that retrieves the size of a dimension from `shape`. -fn create_ndarray_dyn_shape<'ctx, 'a, V, LenFn, DataFn>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, 'a>, - elem_ty: Type, - shape: &V, - shape_len_fn: LenFn, - shape_data_fn: DataFn, -) -> Result, String> - where - LenFn: Fn(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, &V) -> Result, String>, - DataFn: Fn(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, &V, IntValue<'ctx>) -> Result, String>, -{ - let ndarray_ty = make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(elem_ty), None); - - let llvm_usize = generator.get_size_type(ctx.ctx); - - let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type(); - let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type(); - let llvm_ndarray_data_t = ctx.get_llvm_type(generator, elem_ty).as_basic_type_enum(); - assert!(llvm_ndarray_data_t.is_sized()); - - // Assert that all dimensions are non-negative - gen_for_callback( - generator, - ctx, - |generator, ctx| { - let i = generator.gen_var_alloc(ctx, llvm_usize.into(), None)?; - ctx.builder.build_store(i, llvm_usize.const_zero()).unwrap(); - - Ok(i) - }, - |generator, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let shape_len = shape_len_fn(generator, ctx, shape)?; - debug_assert!(shape_len.get_type().get_bit_width() <= llvm_usize.get_bit_width()); - - Ok(ctx.builder.build_int_compare(IntPredicate::ULT, i, shape_len, "").unwrap()) - }, - |generator, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let shape_dim = shape_data_fn(generator, ctx, shape, i)?; - debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width()); - - let shape_dim_gez = ctx.builder - .build_int_compare(IntPredicate::SGE, shape_dim, shape_dim.get_type().const_zero(), "") - .unwrap(); - - ctx.make_assert( - generator, - shape_dim_gez, - "0:ValueError", - "negative dimensions not supported", - [None, None, None], - ctx.current_loc, - ); - - Ok(()) - }, - |_, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let i = ctx.builder.build_int_add(i, llvm_usize.const_int(1, true), "").unwrap(); - ctx.builder.build_store(i_addr, i).unwrap(); - - Ok(()) - }, - )?; - - let ndarray = generator.gen_var_alloc( - ctx, - llvm_ndarray_t.into(), - None, - )?; - let ndarray = NDArrayValue::from_ptr_val(ndarray, llvm_usize, None); - - let num_dims = shape_len_fn(generator, ctx, shape)?; - ndarray.store_ndims(ctx, generator, num_dims); - - let ndarray_num_dims = ndarray.load_ndims(ctx); - ndarray.create_dims(ctx, llvm_usize, ndarray_num_dims); - - // Copy the dimension sizes from shape to ndarray.dims - gen_for_callback( - generator, - ctx, - |generator, ctx| { - let i = generator.gen_var_alloc(ctx, llvm_usize.into(), None)?; - ctx.builder.build_store(i, llvm_usize.const_zero()).unwrap(); - - Ok(i) - }, - |generator, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let shape_len = shape_len_fn(generator, ctx, shape)?; - debug_assert!(shape_len.get_type().get_bit_width() <= llvm_usize.get_bit_width()); - - Ok(ctx.builder.build_int_compare(IntPredicate::ULT, i, shape_len, "").unwrap()) - }, - |generator, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let shape_dim = shape_data_fn(generator, ctx, shape, i)?; - debug_assert!(shape_dim.get_type().get_bit_width() <= llvm_usize.get_bit_width()); - let shape_dim = ctx.builder - .build_int_z_extend(shape_dim, llvm_usize, "") - .unwrap(); - - let ndarray_pdim = ndarray.get_dims().ptr_offset(ctx, generator, i, None); - - ctx.builder.build_store(ndarray_pdim, shape_dim).unwrap(); - - Ok(()) - }, - |_, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let i = ctx.builder.build_int_add(i, llvm_usize.const_int(1, true), "").unwrap(); - ctx.builder.build_store(i_addr, i).unwrap(); - - Ok(()) - }, - )?; - - let ndarray_num_elems = call_ndarray_calc_size( - generator, - ctx, - ndarray.load_ndims(ctx), - ndarray.get_dims().get_ptr(ctx), - ); - ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); - - Ok(ndarray) -} - -/// Creates an `NDArray` instance from a constant shape. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The shape of the `NDArray`, represented as an LLVM [`ArrayValue`]. -fn create_ndarray_const_shape<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - shape: ArrayValue<'ctx> -) -> Result, String> { - let ndarray_ty = make_ndarray_ty(&mut ctx.unifier, &ctx.primitives, Some(elem_ty), None); - - let llvm_usize = generator.get_size_type(ctx.ctx); - - let llvm_pndarray_t = ctx.get_llvm_type(generator, ndarray_ty).into_pointer_type(); - let llvm_ndarray_t = llvm_pndarray_t.get_element_type().into_struct_type(); - let llvm_ndarray_data_t = ctx.get_llvm_type(generator, elem_ty).as_basic_type_enum(); - assert!(llvm_ndarray_data_t.is_sized()); - - for i in 0..shape.get_type().len() { - let shape_dim = ctx.builder - .build_extract_value(shape, i, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - - let shape_dim_gez = ctx.builder - .build_int_compare(IntPredicate::SGE, shape_dim, llvm_usize.const_zero(), "") - .unwrap(); - - ctx.make_assert( - generator, - shape_dim_gez, - "0:ValueError", - "negative dimensions not supported", - [None, None, None], - ctx.current_loc, - ); - } - - let ndarray = generator.gen_var_alloc( - ctx, - llvm_ndarray_t.into(), - None, - )?; - let ndarray = NDArrayValue::from_ptr_val(ndarray, llvm_usize, None); - - let num_dims = llvm_usize.const_int(shape.get_type().len() as u64, false); - ndarray.store_ndims(ctx, generator, num_dims); - - let ndarray_num_dims = ndarray.load_ndims(ctx); - ndarray.create_dims(ctx, llvm_usize, ndarray_num_dims); - - for i in 0..shape.get_type().len() { - let ndarray_dim = ndarray - .get_dims() - .ptr_offset(ctx, generator, llvm_usize.const_int(i as u64, true), None); - let shape_dim = ctx.builder.build_extract_value(shape, i, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - - ctx.builder.build_store(ndarray_dim, shape_dim).unwrap(); - } - - let ndarray_dims = ndarray.get_dims().get_ptr(ctx); - let ndarray_num_elems = call_ndarray_calc_size( - generator, - ctx, - ndarray.load_ndims(ctx), - ndarray_dims, - ); - ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); - - Ok(ndarray) -} - -fn ndarray_zero_value<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, -) -> BasicValueEnum<'ctx> { - if [ctx.primitives.int32, ctx.primitives.uint32].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { - ctx.ctx.i32_type().const_zero().into() - } else if [ctx.primitives.int64, ctx.primitives.uint64].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { - ctx.ctx.i64_type().const_zero().into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.float) { - ctx.ctx.f64_type().const_zero().into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) { - ctx.ctx.bool_type().const_zero().into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { - ctx.gen_string(generator, "") - } else { - unreachable!() - } -} - -fn ndarray_one_value<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, -) -> BasicValueEnum<'ctx> { - if [ctx.primitives.int32, ctx.primitives.uint32].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { - let is_signed = ctx.unifier.unioned(elem_ty, ctx.primitives.int32); - ctx.ctx.i32_type().const_int(1, is_signed).into() - } else if [ctx.primitives.int64, ctx.primitives.uint64].iter().any(|ty| ctx.unifier.unioned(elem_ty, *ty)) { - let is_signed = ctx.unifier.unioned(elem_ty, ctx.primitives.int64); - ctx.ctx.i64_type().const_int(1, is_signed).into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.float) { - ctx.ctx.f64_type().const_float(1.0).into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.bool) { - ctx.ctx.bool_type().const_int(1, false).into() - } else if ctx.unifier.unioned(elem_ty, ctx.primitives.str) { - ctx.gen_string(generator, "1") - } else { - unreachable!() - } -} - -/// LLVM-typed implementation for generating the implementation for constructing an `NDArray`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The `shape` parameter used to construct the `NDArray`. -fn call_ndarray_empty_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - shape: ListValue<'ctx>, -) -> Result, String> { - create_ndarray_dyn_shape( - generator, - ctx, - elem_ty, - &shape, - |_, ctx, shape| { - Ok(shape.load_size(ctx, None)) - }, - |generator, ctx, shape, idx| { - Ok(shape.get_data().get(ctx, generator, idx, None).into_int_value()) - }, - ) -} - -/// Generates LLVM IR for populating the entire `NDArray` using a lambda with its flattened index as -/// its input. -fn ndarray_fill_flattened<'ctx, 'a, ValueFn>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, 'a>, - ndarray: NDArrayValue<'ctx>, - value_fn: ValueFn, -) -> Result<(), String> - where - ValueFn: Fn(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, 'a>, IntValue<'ctx>) -> Result, String>, -{ - let llvm_usize = generator.get_size_type(ctx.ctx); - - let ndarray_num_elems = call_ndarray_calc_size( - generator, - ctx, - ndarray.load_ndims(ctx), - ndarray.get_dims().get_ptr(ctx), - ); - - gen_for_callback( - generator, - ctx, - |generator, ctx| { - let i = generator.gen_var_alloc(ctx, llvm_usize.into(), None)?; - ctx.builder.build_store(i, llvm_usize.const_zero()).unwrap(); - - Ok(i) - }, - |_, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - - Ok(ctx.builder.build_int_compare(IntPredicate::ULT, i, ndarray_num_elems, "").unwrap()) - }, - |generator, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let elem = unsafe { - ndarray.get_data().ptr_to_data_flattened_unchecked(ctx, i, None) - }; - - let value = value_fn(generator, ctx, i)?; - ctx.builder.build_store(elem, value).unwrap(); - - Ok(()) - }, - |_, ctx, i_addr| { - let i = ctx.builder - .build_load(i_addr, "") - .map(BasicValueEnum::into_int_value) - .unwrap(); - let i = ctx.builder.build_int_add(i, llvm_usize.const_int(1, true), "").unwrap(); - ctx.builder.build_store(i_addr, i).unwrap(); - - Ok(()) - }, - ) -} - -/// Generates LLVM IR for populating the entire `NDArray` using a lambda with the dimension-indices -/// as its input. -fn ndarray_fill_indexed<'ctx, ValueFn>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - ndarray: NDArrayValue<'ctx>, - value_fn: ValueFn, -) -> Result<(), String> - where - ValueFn: Fn(&mut dyn CodeGenerator, &mut CodeGenContext<'ctx, '_>, PointerValue<'ctx>) -> Result, String>, -{ - ndarray_fill_flattened( - generator, - ctx, - ndarray, - |generator, ctx, idx| { - let indices = call_ndarray_calc_nd_indices( - generator, - ctx, - idx, - ndarray, - ); - - value_fn(generator, ctx, indices) - } - ) -} - -/// LLVM-typed implementation for generating the implementation for `ndarray.zeros`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The `shape` parameter used to construct the `NDArray`. -fn call_ndarray_zeros_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - shape: ListValue<'ctx>, -) -> Result, String> { - let supported_types = [ - ctx.primitives.int32, - ctx.primitives.int64, - ctx.primitives.uint32, - ctx.primitives.uint64, - ctx.primitives.float, - ctx.primitives.bool, - ctx.primitives.str, - ]; - assert!(supported_types.iter().any(|supported_ty| ctx.unifier.unioned(*supported_ty, elem_ty))); - - let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; - ndarray_fill_flattened( - generator, - ctx, - ndarray, - |generator, ctx, _| { - let value = ndarray_zero_value(generator, ctx, elem_ty); - - Ok(value) - } - )?; - - Ok(ndarray) -} - -/// LLVM-typed implementation for generating the implementation for `ndarray.ones`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The `shape` parameter used to construct the `NDArray`. -fn call_ndarray_ones_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - shape: ListValue<'ctx>, -) -> Result, String> { - let supported_types = [ - ctx.primitives.int32, - ctx.primitives.int64, - ctx.primitives.uint32, - ctx.primitives.uint64, - ctx.primitives.float, - ctx.primitives.bool, - ctx.primitives.str, - ]; - assert!(supported_types.iter().any(|supported_ty| ctx.unifier.unioned(*supported_ty, elem_ty))); - - let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; - ndarray_fill_flattened( - generator, - ctx, - ndarray, - |generator, ctx, _| { - let value = ndarray_one_value(generator, ctx, elem_ty); - - Ok(value) - } - )?; - - Ok(ndarray) -} - -/// LLVM-typed implementation for generating the implementation for `ndarray.full`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -/// * `shape` - The `shape` parameter used to construct the `NDArray`. -fn call_ndarray_full_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - shape: ListValue<'ctx>, - fill_value: BasicValueEnum<'ctx>, -) -> Result, String> { - let ndarray = call_ndarray_empty_impl(generator, ctx, elem_ty, shape)?; - ndarray_fill_flattened( - generator, - ctx, - ndarray, - |generator, ctx, _| { - let value = if fill_value.is_pointer_value() { - let llvm_i1 = ctx.ctx.bool_type(); - - let copy = generator.gen_var_alloc(ctx, fill_value.get_type(), None)?; - - call_memcpy_generic( - ctx, - copy, - fill_value.into_pointer_value(), - fill_value.get_type().size_of().map(Into::into).unwrap(), - llvm_i1.const_zero(), - ); - - copy.into() - } else if fill_value.is_int_value() || fill_value.is_float_value() { - fill_value - } else { - unreachable!() - }; - - Ok(value) - } - )?; - - Ok(ndarray) -} - -/// LLVM-typed implementation for generating the implementation for `ndarray.eye`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -fn call_ndarray_eye_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - nrows: IntValue<'ctx>, - ncols: IntValue<'ctx>, - offset: IntValue<'ctx>, -) -> Result, String> { - let llvm_usize = generator.get_size_type(ctx.ctx); - let llvm_usize_2 = llvm_usize.array_type(2); - - let shape_addr = generator.gen_var_alloc(ctx, llvm_usize_2.into(), None)?; - - let shape = ctx.builder.build_load(shape_addr, "") - .map(BasicValueEnum::into_array_value) - .unwrap(); - - let nrows = ctx.builder.build_int_z_extend_or_bit_cast(nrows, llvm_usize, "").unwrap(); - let shape = ctx.builder - .build_insert_value(shape, nrows, 0, "") - .map(AggregateValueEnum::into_array_value) - .unwrap(); - - let ncols = ctx.builder.build_int_z_extend_or_bit_cast(ncols, llvm_usize, "").unwrap(); - let shape = ctx.builder - .build_insert_value(shape, ncols, 1, "") - .map(AggregateValueEnum::into_array_value) - .unwrap(); - - let ndarray = create_ndarray_const_shape(generator, ctx, elem_ty, shape)?; - - ndarray_fill_indexed( - generator, - ctx, - ndarray, - |generator, ctx, indices| { - let row = ctx.build_gep_and_load( - indices, - &[llvm_usize.const_int(0, false)], - None, - ).into_int_value(); - let col = ctx.build_gep_and_load( - indices, - &[llvm_usize.const_int(1, false)], - None, - ).into_int_value(); - - let col_with_offset = ctx.builder - .build_int_add( - col, - ctx.builder.build_int_s_extend_or_bit_cast(offset, llvm_usize, "").unwrap(), - "", - ) - .unwrap(); - let is_on_diag = ctx.builder - .build_int_compare(IntPredicate::EQ, row, col_with_offset, "") - .unwrap(); - - let zero = ndarray_zero_value(generator, ctx, elem_ty); - let one = ndarray_one_value(generator, ctx, elem_ty); - - let value = ctx.builder.build_select(is_on_diag, one, zero, "").unwrap(); - - Ok(value) - }, - )?; - - Ok(ndarray) -} - -/// LLVM-typed implementation for generating the implementation for `ndarray.copy`. -/// -/// * `elem_ty` - The element type of the `NDArray`. -fn ndarray_copy_impl<'ctx>( - generator: &mut dyn CodeGenerator, - ctx: &mut CodeGenContext<'ctx, '_>, - elem_ty: Type, - this: NDArrayValue<'ctx>, -) -> Result, String> { - let llvm_i1 = ctx.ctx.bool_type(); - - let ndarray = create_ndarray_dyn_shape( - generator, - ctx, - elem_ty, - &this, - |_, ctx, shape| { - Ok(shape.load_ndims(ctx)) - }, - |generator, ctx, shape, idx| { - Ok(shape.get_dims().get(ctx, generator, idx, None)) - }, - )?; - - let len = call_ndarray_calc_size( - generator, - ctx, - ndarray.load_ndims(ctx), - ndarray.get_dims().get_ptr(ctx), - ); - let sizeof_ty = ctx.get_llvm_type(generator, elem_ty); - let len_bytes = ctx.builder - .build_int_mul( - len, - sizeof_ty.size_of().unwrap(), - "", - ) - .unwrap(); - - call_memcpy_generic( - ctx, - ndarray.get_data().get_ptr(ctx), - this.get_data().get_ptr(ctx), - len_bytes, - llvm_i1.const_zero(), - ); - - Ok(ndarray) -} - -/// Generates LLVM IR for `ndarray.empty`. -pub fn gen_ndarray_empty<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert_eq!(args.len(), 1); - - let llvm_usize = generator.get_size_type(context.ctx); - let shape_ty = fun.0.args[0].ty; - let shape_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, shape_ty)?; - - call_ndarray_empty_impl( - generator, - context, - context.primitives.float, - ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.zeros`. -pub fn gen_ndarray_zeros<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert_eq!(args.len(), 1); - - let llvm_usize = generator.get_size_type(context.ctx); - let shape_ty = fun.0.args[0].ty; - let shape_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, shape_ty)?; - - call_ndarray_zeros_impl( - generator, - context, - context.primitives.float, - ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.ones`. -pub fn gen_ndarray_ones<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert_eq!(args.len(), 1); - - let llvm_usize = generator.get_size_type(context.ctx); - let shape_ty = fun.0.args[0].ty; - let shape_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, shape_ty)?; - - call_ndarray_ones_impl( - generator, - context, - context.primitives.float, - ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.full`. -pub fn gen_ndarray_full<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert_eq!(args.len(), 2); - - let llvm_usize = generator.get_size_type(context.ctx); - let shape_ty = fun.0.args[0].ty; - let shape_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, shape_ty)?; - let fill_value_ty = fun.0.args[1].ty; - let fill_value_arg = args[1].1.clone() - .to_basic_value_enum(context, generator, fill_value_ty)?; - - call_ndarray_full_impl( - generator, - context, - fill_value_ty, - ListValue::from_ptr_val(shape_arg.into_pointer_value(), llvm_usize, None), - fill_value_arg, - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.eye`. -pub fn gen_ndarray_eye<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert!(matches!(args.len(), 1..=3)); - - let nrows_ty = fun.0.args[0].ty; - let nrows_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, nrows_ty)?; - - let ncols_ty = fun.0.args[1].ty; - let ncols_arg = args.iter() - .find(|arg| arg.0.is_some_and(|name| name == fun.0.args[1].name)) - .map(|arg| arg.1.clone().to_basic_value_enum(context, generator, ncols_ty)) - .unwrap_or_else(|| { - args[0].1.clone().to_basic_value_enum(context, generator, nrows_ty) - })?; - - let offset_ty = fun.0.args[2].ty; - let offset_arg = args.iter() - .find(|arg| arg.0.is_some_and(|name| name == fun.0.args[2].name)) - .map(|arg| arg.1.clone().to_basic_value_enum(context, generator, offset_ty)) - .unwrap_or_else(|| { - Ok(context.gen_symbol_val( - generator, - fun.0.args[2].default_value.as_ref().unwrap(), - offset_ty - )) - })?; - - call_ndarray_eye_impl( - generator, - context, - context.primitives.float, - nrows_arg.into_int_value(), - ncols_arg.into_int_value(), - offset_arg.into_int_value(), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.identity`. -pub fn gen_ndarray_identity<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_none()); - assert_eq!(args.len(), 1); - - let llvm_usize = generator.get_size_type(context.ctx); - - let n_ty = fun.0.args[0].ty; - let n_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, n_ty)?; - - call_ndarray_eye_impl( - generator, - context, - context.primitives.float, - n_arg.into_int_value(), - n_arg.into_int_value(), - llvm_usize.const_zero(), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.copy`. -pub fn gen_ndarray_copy<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - _fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result, String> { - assert!(obj.is_some()); - assert!(args.is_empty()); - - let llvm_usize = generator.get_size_type(context.ctx); - - let this_ty = obj.as_ref().unwrap().0; - let (this_elem_ty, _) = unpack_ndarray_tvars(&mut context.unifier, this_ty); - let this_arg = obj - .as_ref() - .unwrap() - .1 - .clone() - .to_basic_value_enum(context, generator, this_ty)?; - - ndarray_copy_impl( - generator, - context, - this_elem_ty, - NDArrayValue::from_ptr_val(this_arg.into_pointer_value(), llvm_usize, None), - ).map(NDArrayValue::into) -} - -/// Generates LLVM IR for `ndarray.fill`. -pub fn gen_ndarray_fill<'ctx>( - context: &mut CodeGenContext<'ctx, '_>, - obj: &Option<(Type, ValueEnum<'ctx>)>, - fun: (&FunSignature, DefinitionId), - args: &[(Option, ValueEnum<'ctx>)], - generator: &mut dyn CodeGenerator, -) -> Result<(), String> { - assert!(obj.is_some()); - assert_eq!(args.len(), 1); - - let llvm_usize = generator.get_size_type(context.ctx); - - let this_ty = obj.as_ref().unwrap().0; - let this_arg = obj.as_ref().unwrap().1.clone() - .to_basic_value_enum(context, generator, this_ty)? - .into_pointer_value(); - let value_ty = fun.0.args[0].ty; - let value_arg = args[0].1.clone() - .to_basic_value_enum(context, generator, value_ty)?; - - ndarray_fill_flattened( - generator, - context, - NDArrayValue::from_ptr_val(this_arg, llvm_usize, None), - |generator, ctx, _| { - let value = if value_arg.is_pointer_value() { - let llvm_i1 = ctx.ctx.bool_type(); - - let copy = generator.gen_var_alloc(ctx, value_arg.get_type(), None)?; - - call_memcpy_generic( - ctx, - copy, - value_arg.into_pointer_value(), - value_arg.get_type().size_of().map(Into::into).unwrap(), - llvm_i1.const_zero(), - ); - - copy.into() - } else if value_arg.is_int_value() || value_arg.is_float_value() { - value_arg - } else { - unreachable!() - }; - - Ok(value) - } - )?; - - Ok(()) -} diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index c3c1c75..f9eb73f 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -699,7 +699,7 @@ impl Unifier { self.set_a_to_b(a, x); } (TVar { fields: Some(fields), range, is_const_generic: false, .. }, TTuple { ty }) => { - let len = ty.len() as i32; + let len = i32::try_from(ty.len()).unwrap(); for (k, v) in fields { match *k { RecordKey::Int(i) => { diff --git a/nac3standalone/src/basic_symbol_resolver.rs b/nac3standalone/src/basic_symbol_resolver.rs index e483c6d..d7fb1b8 100644 --- a/nac3standalone/src/basic_symbol_resolver.rs +++ b/nac3standalone/src/basic_symbol_resolver.rs @@ -74,7 +74,8 @@ impl SymbolResolver for Resolver { if let Some(id) = str_store.get(s) { *id } else { - let id = str_store.len() as i32; + let id = i32::try_from(str_store.len()) + .expect("Symbol resolver string store size exceeds max capacity (i32::MAX)"); str_store.insert(s.to_string(), id); id } diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index f11acd1..6c4b4ab 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -247,6 +247,8 @@ fn handle_assignment_pattern( } fn main() { + const SIZE_T: u32 = usize::BITS; + let cli = CommandLineArgs::parse(); let CommandLineArgs { file_name, @@ -287,7 +289,6 @@ fn main() { // The default behavior for -O where n>3 defaults to O3 for both Clang and GCC _ => OptimizationLevel::Aggressive, }; - const SIZE_T: u32 = 64; let program = match fs::read_to_string(file_name.clone()) { Ok(program) => program,