Compare commits

...

31 Commits

Author SHA1 Message Date
683daae31e msys2: regenerate packages 2025-02-20 19:01:24 +08:00
b565211df6 msys2: add inkwell hash 2025-02-20 18:48:16 +08:00
1e5fd99a88 flake: add inkwell hash 2025-02-20 18:31:56 +08:00
2df4a5e9bd [core] Update to use custom inkwell
For LLVM 16 support with typed pointers.
2025-02-20 13:29:16 +08:00
b006bdd96b llvm: update to 16, simplify nix files 2025-02-20 13:29:16 +08:00
fffdaf36d3 [meta] Apply clippy suggestions 2025-02-20 11:27:46 +08:00
acb47154dc nac3core: support custom context managers 2025-02-19 22:25:48 +08:00
e917c57339 [core] codegen: Fixup generate_linalg_extern_fn macro
- Use `ident` for `extern_fn` name
- Fixup formatting
2025-02-19 12:48:52 +08:00
eb6f0a1abc [core] codegen/irrt: Migrate compiler builtin functions to IRRT
Saves us from having to manually declare functions and their
corresponding attributes.
2025-02-19 12:14:40 +08:00
af5bbcac11 [core] Bump test-case and insta dependencies 2025-02-19 12:14:40 +08:00
f64320b68e [core] codegen: Refactor IR generation tests to use insta 2025-02-19 12:14:40 +08:00
b988af86bf [core] codegen/types: Create Exception struct type in IR module
Ensures that we don't need to recreate the type every time
`ExceptionType::llvm_type` is called.
2025-02-19 12:14:39 +08:00
4fdf1a37d2 [core] codegen: Refactor memcpy to use build_memcpy 2025-02-19 12:14:04 +08:00
24f6b2d772 [meta] Update dependencies 2025-02-18 12:30:11 +08:00
6265d53ad5 [artiq] Fix intermittent class resolution failures
In the past, modules (and therefore its members) are not added or
analyzed in order of appearance, as it is stored in a HashMap with the
PythonId as its key.

While this never posed an issue in the past, the refactoring performed
in #535 assumed that the classes *are* ordered by appearance, causing
the bug to manifest. Furthermore, this bug will only manifest
iff a base class has a PythonId greater than the derived class,
explaining why the bug only occurs on occasion.

Fix this by using an IndexMap, which preserves the order of insertion
while also performing deduplication.
2025-02-11 17:02:57 +08:00
36d502dc31 [meta] Apply clippy suggestions 2025-02-11 16:52:28 +08:00
82a580c5c6 flake: update ARTIQ source used for PGO 2025-02-10 16:53:35 +08:00
715dc71396 nac3artiq: acquire special python identifiers 2025-02-10 16:42:49 +08:00
064aa0411f [core] codegen: Add Exception{Type,Value} 2025-02-10 11:29:58 +08:00
57552fb2f6 [core] codegen: Add Option{Type,Value} 2025-02-10 11:29:58 +08:00
35e9c5b38e [core] codegen: Add String{Type,Value} 2025-02-10 11:29:58 +08:00
0a761cb263 [core] Use more TupleType constructors 2025-02-10 11:29:58 +08:00
67f42185de [core] codegen/expr: Add concrete ndims value to error message 2025-02-10 11:29:58 +08:00
69542c38a2 [core] codegen: Rename TupleValue::{store,load} -> {insert,extract}
Better matches the underlying operation.
2025-02-10 11:29:55 +08:00
2df22e29f7 [core] codegen: Simplify TupleType::construct 2025-02-10 11:26:45 +08:00
a078481cd2 [meta] Minor simplification for PrimStore extraction 2025-02-10 11:26:45 +08:00
c37c7e8975 [core] codegen/expr: Simplify gen_*_expr_with_values return value
These functions always return `BasicValueEnum` because they operate on
`BasicValueEnum`s, and they also always return a value.
2025-02-10 11:26:45 +08:00
0d8cb909dd [core] codegen/expr: Fix and use gen_unaryop_expr for boolean not ops
While refactoring, I ran into the issue where `!true == true`, which was
caused by the same upper 7-bit of booleans being undefined issue that
was encountered before. It turns out the implementation in
`gen_unaryop_expr` is also inadequate, as `(~v & (i1) 0x1)`` will still
leave upper 7 bits undefined (for whatever reason).

This commit fixes this issue once and for all by using a combination of
`icmp` + `zext` to ensure that the resulting value must be `0 | 1`, and
refactor to use that whenever we need to invert boolean values.
2025-02-10 11:26:45 +08:00
529fa67855 [core] codegen: Add bool_to_int_type to replace bool_to_{i1,i8}
Unifies the implementation for both functions.
2025-02-10 11:26:45 +08:00
f52ba9f151 [core] codegen/irrt: Refactor IRRT to use more create/infer fns 2025-02-10 10:56:24 +08:00
6bcdc3ce00 [core] codegen/extern_fns: Change expansion pattern
Makes more sense to attach the parameter delimiter to the end of each
parameter.
2025-02-10 10:56:22 +08:00
64 changed files with 2624 additions and 1730 deletions

252
Cargo.lock generated
View File

@ -127,9 +127,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.10"
version = "1.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
dependencies = [
"shlex",
]
@ -142,9 +142,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.27"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
dependencies = [
"clap_builder",
"clap_derive",
@ -152,9 +152,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.27"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
dependencies = [
"anstream",
"anstyle",
@ -164,14 +164,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.24"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
@ -312,9 +312,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "equivalent"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
@ -344,6 +344,21 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "function_name"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1ab577a896d09940b5fe12ec5ae71f9d8211fff62c919c03a3750a9901e98a7"
dependencies = [
"function_name-proc-macro",
]
[[package]]
name = "function_name-proc-macro"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673464e1e314dd67a0fd9544abc99e8eb28d0c7e3b69b033bcff9b2d00b87333"
[[package]]
name = "fxhash"
version = "0.2.1"
@ -401,12 +416,6 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.2"
@ -437,16 +446,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.7.1"
@ -454,7 +453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
"hashbrown",
]
[[package]]
@ -466,8 +465,7 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "inkwell"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40fb405537710d51f6bdbc8471365ddd4cd6d3a3c3ad6e0c8291691031ba94b2"
source = "git+https://github.com/Derppening/inkwell?tag=0.5.0_llvm15-typed-ptr#9c70145c6aaa29be79715fc4998df9da67575ecf"
dependencies = [
"either",
"inkwell_internals",
@ -480,25 +478,23 @@ dependencies = [
[[package]]
name = "inkwell_internals"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd28cfd4cfba665d47d31c08a6ba637eed16770abca2eccbbc3ca831fef1e44"
source = "git+https://github.com/Derppening/inkwell?tag=0.5.0_llvm15-typed-ptr#9c70145c6aaa29be79715fc4998df9da67575ecf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
name = "insta"
version = "1.11.0"
version = "1.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da408b722765c64aad796c666b756aa1dda2a6c1b44f98797f2d8ea8f197746f"
checksum = "71c1b125e30d93896b365e156c33dadfffab45ee8400afcbba4752f59de08a86"
dependencies = [
"console",
"linked-hash-map",
"once_cell",
"serde",
"serde_json",
"serde_yaml",
"pin-project",
"similar",
]
@ -600,9 +596,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "llvm-sys"
version = "140.1.3"
version = "160.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3dc78e9857c0231ec11e3bdccf63870493fdc7d0570b0ea7d50bf5df0cb1a0c"
checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4"
dependencies = [
"cc",
"lazy_static",
@ -646,6 +642,7 @@ dependencies = [
name = "nac3artiq"
version = "0.1.0"
dependencies = [
"indexmap",
"itertools",
"nac3core",
"nac3ld",
@ -668,7 +665,8 @@ name = "nac3core"
version = "0.1.0"
dependencies = [
"crossbeam",
"indexmap 2.7.1",
"function_name",
"indexmap",
"indoc",
"inkwell",
"insta",
@ -690,7 +688,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
"trybuild",
]
@ -734,9 +732,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "once_cell"
version = "1.20.2"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "parking_lot"
@ -768,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset",
"indexmap 2.7.1",
"indexmap",
]
[[package]]
@ -778,7 +776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_macros",
"phf_shared 0.11.3",
"phf_shared",
]
[[package]]
@ -788,7 +786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared 0.11.3",
"phf_shared",
]
[[package]]
@ -797,7 +795,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared 0.11.3",
"phf_shared",
"rand",
]
@ -808,19 +806,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
dependencies = [
"phf_generator",
"phf_shared 0.11.3",
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.96",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher 0.3.11",
"syn 2.0.98",
]
[[package]]
@ -829,7 +818,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher 1.0.1",
"siphasher",
]
[[package]]
@ -838,6 +827,26 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "pin-project"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "portable-atomic"
version = "1.10.0"
@ -939,7 +948,7 @@ dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
@ -952,7 +961,7 @@ dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
@ -1102,14 +1111,14 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
name = "serde_json"
version = "1.0.137"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
dependencies = [
"itoa",
"memchr",
@ -1126,18 +1135,6 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
dependencies = [
"indexmap 1.9.3",
"ryu",
"serde",
"yaml-rust",
]
[[package]]
name = "sha3"
version = "0.10.8"
@ -1160,12 +1157,6 @@ version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "siphasher"
version = "1.0.1"
@ -1174,9 +1165,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "smallvec"
version = "1.13.2"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "string-interner"
@ -1184,20 +1175,19 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a3275464d7a9f2d4cac57c89c2ef96a8524dba2864c8d6f82e3980baf136f9b"
dependencies = [
"hashbrown 0.15.2",
"hashbrown",
"serde",
]
[[package]]
name = "string_cache"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe"
dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared 0.10.0",
"phf_shared",
"precomputed-hash",
]
@ -1209,21 +1199,21 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.26.3"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
[[package]]
name = "strum_macros"
version = "0.26.4"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
@ -1233,15 +1223,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.96"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
@ -1262,9 +1251,9 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078"
[[package]]
name = "tempfile"
version = "3.16.0"
version = "3.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
dependencies = [
"cfg-if",
"fastrand",
@ -1295,15 +1284,35 @@ dependencies = [
[[package]]
name = "test-case"
version = "1.2.3"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e5f048404b43e8ae66dce036163515b6057024cf58c6377be501f250bd3c6a"
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
dependencies = [
"test-case-macros",
]
[[package]]
name = "test-case-core"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
"syn 2.0.98",
]
[[package]]
name = "test-case-macros"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
"test-case-core",
]
[[package]]
@ -1323,14 +1332,14 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]
[[package]]
name = "toml"
version = "0.8.19"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
@ -1349,11 +1358,11 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.22"
version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap 2.7.1",
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
@ -1378,9 +1387,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.17.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "unic-char-property"
@ -1436,9 +1445,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.16"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]]
name = "unicode-width"
@ -1610,9 +1619,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.25"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603"
dependencies = [
"memchr",
]
@ -1626,15 +1635,6 @@ dependencies = [
"bitflags",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
@ -1653,5 +1653,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
"syn 2.0.98",
]

View File

@ -13,8 +13,8 @@
llvm-tools-irrt = pkgs.runCommandNoCC "llvm-tools-irrt" {}
''
mkdir -p $out/bin
ln -s ${pkgs.llvmPackages_14.clang-unwrapped}/bin/clang $out/bin/clang-irrt
ln -s ${pkgs.llvmPackages_14.llvm.out}/bin/llvm-as $out/bin/llvm-as-irrt
ln -s ${pkgs.llvmPackages_16.clang-unwrapped}/bin/clang $out/bin/clang-irrt
ln -s ${pkgs.llvmPackages_16.llvm.out}/bin/llvm-as $out/bin/llvm-as-irrt
'';
demo-linalg-stub = pkgs.rustPlatform.buildRustPackage {
name = "demo-linalg-stub";
@ -39,9 +39,12 @@
src = self;
cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"inkwell-0.5.0" = "sha256-Qsqy/fhD/qK0rKBeXetE99vW9G9XAePxlXv0An3Yeuo=";
};
};
passthru.cargoLock = cargoLock;
nativeBuildInputs = [ pkgs.python3 (pkgs.wrapClangMulti pkgs.llvmPackages_14.clang) llvm-tools-irrt pkgs.llvmPackages_14.llvm.out pkgs.llvmPackages_14.bintools llvm-nac3 ];
nativeBuildInputs = [ pkgs.python3 (pkgs.wrapClangMulti pkgs.llvmPackages_16.clang) llvm-tools-irrt pkgs.llvmPackages_16.llvm.out pkgs.llvmPackages_16.bintools llvm-nac3 ];
buildInputs = [ pkgs.python3 llvm-nac3 ];
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ps.scipy ])) ];
checkPhase =
@ -77,7 +80,7 @@
# LLVM PGO support
llvm-nac3-instrumented = pkgs.callPackage ./nix/llvm {
stdenv = pkgs.llvmPackages_14.stdenv;
stdenv = pkgs.llvmPackages_16.stdenv;
extraCmakeFlags = [ "-DLLVM_BUILD_INSTRUMENTED=IR" ];
};
nac3artiq-instrumented = pkgs.python3Packages.toPythonModule (
@ -85,13 +88,13 @@
name = "nac3artiq-instrumented";
src = self;
inherit (nac3artiq) cargoLock;
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_14.bintools llvm-nac3-instrumented ];
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_16.bintools llvm-nac3-instrumented ];
buildInputs = [ pkgs.python3 llvm-nac3-instrumented ];
cargoBuildFlags = [ "--package" "nac3artiq" "--features" "init-llvm-profile" ];
doCheck = false;
configurePhase =
''
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-L${pkgs.llvmPackages_14.compiler-rt}/lib/linux -C link-arg=-lclang_rt.profile-x86_64"
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-L${pkgs.llvmPackages_16.compiler-rt}/lib/linux -C link-arg=-lclang_rt.profile-x86_64"
'';
installPhase =
''
@ -113,14 +116,14 @@
(pkgs.fetchFromGitHub {
owner = "m-labs";
repo = "artiq";
rev = "28c9de3e251daa89a8c9fd79d5ab64a3ec03bac6";
sha256 = "sha256-vAvpbHc5B+1wtG8zqN7j9dQE1ON+i22v+uqA+tw6Gak=";
rev = "554b0749ca5985bf4d006c4f29a05e83de0a226d";
sha256 = "sha256-3eSNHTSlmdzLMcEMIspxqjmjrcQe4aIGqIfRgquUg18=";
})
];
buildInputs = [
(python3-mimalloc.withPackages(ps: [ ps.numpy ps.scipy ps.jsonschema ps.lmdb ps.platformdirs nac3artiq-instrumented ]))
pkgs.llvmPackages_14.llvm.out
pkgs.llvmPackages_14.bintools
pkgs.llvmPackages_16.llvm.out
pkgs.llvmPackages_16.bintools
];
phases = [ "buildPhase" "installPhase" ];
buildPhase =
@ -140,7 +143,7 @@
'';
};
llvm-nac3-pgo = pkgs.callPackage ./nix/llvm {
stdenv = pkgs.llvmPackages_14.stdenv;
stdenv = pkgs.llvmPackages_16.stdenv;
extraCmakeFlags = [ "-DLLVM_PROFDATA_FILE=${nac3artiq-profile}/llvm.profdata" ];
};
nac3artiq-pgo = pkgs.python3Packages.toPythonModule (
@ -148,7 +151,7 @@
name = "nac3artiq-pgo";
src = self;
inherit (nac3artiq) cargoLock;
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_14.bintools llvm-nac3-pgo ];
nativeBuildInputs = [ pkgs.python3 packages.x86_64-linux.llvm-tools-irrt pkgs.llvmPackages_16.bintools llvm-nac3-pgo ];
buildInputs = [ pkgs.python3 llvm-nac3-pgo ];
cargoBuildFlags = [ "--package" "nac3artiq" ];
cargoTestFlags = [ "--package" "nac3ast" "--package" "nac3parser" "--package" "nac3core" "--package" "nac3artiq" ];
@ -169,12 +172,12 @@
buildInputs = with pkgs; [
# build dependencies
packages.x86_64-linux.llvm-nac3
(pkgs.wrapClangMulti llvmPackages_14.clang) llvmPackages_14.llvm.out llvmPackages_14.bintools # for running nac3standalone demos
(pkgs.wrapClangMulti llvmPackages_16.clang) llvmPackages_16.llvm.out llvmPackages_16.bintools # for running nac3standalone demos
packages.x86_64-linux.llvm-tools-irrt
cargo
rustc
# runtime dependencies
lld_14 # for running kernels on the host
lld_16 # for running kernels on the host
(packages.x86_64-linux.python3-mimalloc.withPackages(ps: [ ps.numpy ps.scipy ]))
# development tools
cargo-insta

View File

@ -9,6 +9,7 @@ name = "nac3artiq"
crate-type = ["cdylib"]
[dependencies]
indexmap = "2.7"
itertools = "0.14"
pyo3 = { version = "0.21", features = ["extension-module", "gil-refs"] }
parking_lot = "0.12"

View File

@ -0,0 +1,84 @@
from numpy import int32
from min_artiq import *
@nac3
class PassContextManager:
@kernel
def __init__(self):
pass
@kernel
def __enter__(self):
pass
@kernel
def __exit__(self):
pass
@nac3
class CustomDataContextManager:
a: Kernel[int32]
b: Kernel[int32]
@kernel
def __init__(self, a: int32, b: int32):
self.a = a
self.b = b
@kernel
def __enter__(self):
self.a += 1
print_int32(self.a)
@kernel
def __exit__(self):
self.b += 1
print_int32(self.b)
@nac3
class WithAsContextManager:
a: Kernel[int32]
@kernel
def __init__(self, val: int32):
self.a = val
@kernel
def __enter__(self) -> int32:
print_int32(self.a)
return self.a
@kernel
def __exit__(self):
print_int32(self.a)
@nac3
class CtxMgrTest:
core: KernelInvariant[Core]
def __init__(self):
self.core = Core()
@kernel
def run(self):
x = 0
a = PassContextManager()
with a:
x += 1
h = CustomDataContextManager(1, 2)
with h:
x += h.a + h.b
with WithAsContextManager(15) as num:
x += num
with WithAsContextManager(10) as c, WithAsContextManager(5) as d:
e: int32 = c + d
x += e
print_int32(x)
return
if __name__ == "__main__":
CtxMgrTest().run()

View File

@ -16,7 +16,7 @@ __all__ = [
"rpc", "ms", "us", "ns",
"print_int32", "print_int64",
"Core", "TTLOut",
"parallel", "sequential"
"parallel", "legacy_parallel", "sequential"
]
@ -245,7 +245,7 @@ class Core:
embedding = EmbeddingMap()
if allow_registration:
compiler.analyze(registered_functions, registered_classes, set())
compiler.analyze(registered_functions, registered_classes, special_ids, set())
allow_registration = False
if hasattr(method, "__self__"):
@ -336,4 +336,11 @@ class UnwrapNoneError(Exception):
artiq_builtin = True
parallel = KernelContextManager()
legacy_parallel = KernelContextManager()
sequential = KernelContextManager()
special_ids = {
"parallel": id(parallel),
"legacy_parallel": id(legacy_parallel),
"sequential": id(sequential),
}

View File

@ -12,10 +12,10 @@ use pyo3::{
PyObject, PyResult, Python,
};
use super::{symbol_resolver::InnerResolver, timeline::TimeFns};
use super::{symbol_resolver::InnerResolver, timeline::TimeFns, SpecialPythonId};
use nac3core::{
codegen::{
expr::{destructure_range, gen_call},
expr::{create_fn_and_call, destructure_range, gen_call, infer_and_call_function},
llvm_intrinsics::{call_int_smax, call_memcpy, call_stackrestore, call_stacksave},
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
type_aligned_alloca,
@ -41,7 +41,10 @@ use nac3core::{
numpy::unpack_ndarray_var_tys,
DefinitionId, GenCall,
},
typecheck::typedef::{iter_type_vars, FunSignature, FuncArg, Type, TypeEnum, VarMap},
typecheck::{
type_inferencer::PrimitiveStore,
typedef::{iter_type_vars, FunSignature, FuncArg, Type, TypeEnum, VarMap},
},
};
/// The parallelism mode within a block.
@ -83,6 +86,9 @@ pub struct ArtiqCodeGenerator<'a> {
/// The current parallel context refers to the nearest `with parallel` or `with legacy_parallel`
/// statement, which is used to determine when and how the timeline should be updated.
parallel_mode: ParallelMode,
/// Specially treated python IDs to identify `with parallel` and `with sequential` blocks.
special_ids: SpecialPythonId,
}
impl<'a> ArtiqCodeGenerator<'a> {
@ -90,6 +96,7 @@ impl<'a> ArtiqCodeGenerator<'a> {
name: String,
size_t: IntType<'_>,
timeline: &'a (dyn TimeFns + Sync),
special_ids: SpecialPythonId,
) -> ArtiqCodeGenerator<'a> {
assert!(matches!(size_t.get_bit_width(), 32 | 64));
ArtiqCodeGenerator {
@ -100,6 +107,7 @@ impl<'a> ArtiqCodeGenerator<'a> {
end: None,
timeline,
parallel_mode: ParallelMode::None,
special_ids,
}
}
@ -109,9 +117,10 @@ impl<'a> ArtiqCodeGenerator<'a> {
ctx: &Context,
target_machine: &TargetMachine,
timeline: &'a (dyn TimeFns + Sync),
special_ids: SpecialPythonId,
) -> ArtiqCodeGenerator<'a> {
let llvm_usize = ctx.ptr_sized_int_type(&target_machine.get_target_data(), None);
Self::new(name, llvm_usize, timeline)
Self::new(name, llvm_usize, timeline, special_ids)
}
/// If the generator is currently in a direct-`parallel` block context, emits IR that resets the
@ -257,122 +266,140 @@ impl CodeGenerator for ArtiqCodeGenerator<'_> {
// - If there is a end variable, it indicates that we are (indirectly) inside a
// parallel block, and we should update the max end value.
if let ExprKind::Name { id, ctx: name_ctx } = &item.context_expr.node {
if id == &"parallel".into() || id == &"legacy_parallel".into() {
let old_start = self.start.take();
let old_end = self.end.take();
let old_parallel_mode = self.parallel_mode;
let resolver = ctx.resolver.clone();
if let Some(static_value) =
if let Some((_ptr, static_value, _counter)) = ctx.var_assignment.get(id) {
static_value.clone()
} else if let Some(ValueEnum::Static(val)) =
resolver.get_symbol_value(*id, ctx, self)
{
Some(val)
} else {
None
}
{
let python_id = static_value.get_unique_identifier();
if python_id == self.special_ids.parallel
|| python_id == self.special_ids.legacy_parallel
{
let old_start = self.start.take();
let old_end = self.end.take();
let old_parallel_mode = self.parallel_mode;
let now = if let Some(old_start) = &old_start {
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(
let now = if let Some(old_start) = &old_start {
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(
ctx,
self,
old_start.custom.unwrap(),
)?
} else {
self.timeline.emit_now_mu(ctx)
};
// Emulate variable allocation, as we need to use the CodeGenContext
// HashMap to store our variable due to lifetime limitation
// Note: we should be able to store variables directly if generic
// associative type is used by limiting the lifetime of CodeGenerator to
// the LLVM Context.
// The name is guaranteed to be unique as users cannot use this as variable
// name.
self.start = old_start.clone().map_or_else(
|| {
let start = format!("with-{}-start", self.name_counter).into();
let start_expr = Located {
// location does not matter at this point
location: stmt.location,
node: ExprKind::Name { id: start, ctx: *name_ctx },
custom: Some(ctx.primitives.int64),
};
let start = self
.gen_store_target(ctx, &start_expr, Some("start.addr"))?
.unwrap();
ctx.builder.build_store(start, now).unwrap();
Ok(Some(start_expr)) as Result<_, String>
},
|v| Ok(Some(v)),
)?;
let end = format!("with-{}-end", self.name_counter).into();
let end_expr = Located {
// location does not matter at this point
location: stmt.location,
node: ExprKind::Name { id: end, ctx: *name_ctx },
custom: Some(ctx.primitives.int64),
};
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?.unwrap();
ctx.builder.build_store(end, now).unwrap();
self.end = Some(end_expr);
self.name_counter += 1;
self.parallel_mode = if python_id == self.special_ids.parallel {
ParallelMode::Deep
} else if python_id == self.special_ids.legacy_parallel {
ParallelMode::Legacy
} else {
unreachable!()
};
self.gen_block(ctx, body.iter())?;
let current = ctx.builder.get_insert_block().unwrap();
// if the current block is terminated, move before the terminator
// we want to set the timeline before reaching the terminator
// TODO: This may be unsound if there are multiple exit paths in the
// block... e.g.
// if ...:
// return
// Perhaps we can fix this by using actual with block?
let reset_position = if let Some(terminator) = current.get_terminator() {
ctx.builder.position_before(&terminator);
true
} else {
false
};
// set duration
let end_expr = self.end.take().unwrap();
let end_val = self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum(
ctx,
self,
old_start.custom.unwrap(),
)?
} else {
self.timeline.emit_now_mu(ctx)
};
end_expr.custom.unwrap(),
)?;
// Emulate variable allocation, as we need to use the CodeGenContext
// HashMap to store our variable due to lifetime limitation
// Note: we should be able to store variables directly if generic
// associative type is used by limiting the lifetime of CodeGenerator to
// the LLVM Context.
// The name is guaranteed to be unique as users cannot use this as variable
// name.
self.start = old_start.clone().map_or_else(
|| {
let start = format!("with-{}-start", self.name_counter).into();
let start_expr = Located {
// location does not matter at this point
location: stmt.location,
node: ExprKind::Name { id: start, ctx: *name_ctx },
custom: Some(ctx.primitives.int64),
};
let start = self
.gen_store_target(ctx, &start_expr, Some("start.addr"))?
.unwrap();
ctx.builder.build_store(start, now).unwrap();
Ok(Some(start_expr)) as Result<_, String>
},
|v| Ok(Some(v)),
)?;
let end = format!("with-{}-end", self.name_counter).into();
let end_expr = Located {
// location does not matter at this point
location: stmt.location,
node: ExprKind::Name { id: end, ctx: *name_ctx },
custom: Some(ctx.primitives.int64),
};
let end = self.gen_store_target(ctx, &end_expr, Some("end.addr"))?.unwrap();
ctx.builder.build_store(end, now).unwrap();
self.end = Some(end_expr);
self.name_counter += 1;
self.parallel_mode = match id.to_string().as_str() {
"parallel" => ParallelMode::Deep,
"legacy_parallel" => ParallelMode::Legacy,
_ => unreachable!(),
};
// inside a sequential block
if old_start.is_none() {
self.timeline.emit_at_mu(ctx, end_val);
}
self.gen_block(ctx, body.iter())?;
// inside a parallel block, should update the outer max now_mu
self.timeline_update_end_max(ctx, old_end.clone(), Some("outer.end"))?;
let current = ctx.builder.get_insert_block().unwrap();
self.parallel_mode = old_parallel_mode;
self.end = old_end;
self.start = old_start;
// if the current block is terminated, move before the terminator
// we want to set the timeline before reaching the terminator
// TODO: This may be unsound if there are multiple exit paths in the
// block... e.g.
// if ...:
// return
// Perhaps we can fix this by using actual with block?
let reset_position = if let Some(terminator) = current.get_terminator() {
ctx.builder.position_before(&terminator);
true
} else {
false
};
if reset_position {
ctx.builder.position_at_end(current);
}
// set duration
let end_expr = self.end.take().unwrap();
let end_val = self.gen_expr(ctx, &end_expr)?.unwrap().to_basic_value_enum(
ctx,
self,
end_expr.custom.unwrap(),
)?;
return Ok(());
} else if python_id == self.special_ids.sequential {
// For deep parallel, temporarily take away start to avoid function calls in
// the block from resetting the timeline.
// This does not affect legacy parallel, as the timeline will be reset after
// this block finishes execution.
let start = self.start.take();
self.gen_block(ctx, body.iter())?;
self.start = start;
// inside a sequential block
if old_start.is_none() {
self.timeline.emit_at_mu(ctx, end_val);
// Reset the timeline when we are exiting the sequential block
// Legacy parallel does not need this, since it will be reset after codegen
// for this statement is completed
if self.parallel_mode == ParallelMode::Deep {
self.timeline_reset_start(ctx)?;
}
return Ok(());
}
// inside a parallel block, should update the outer max now_mu
self.timeline_update_end_max(ctx, old_end.clone(), Some("outer.end"))?;
self.parallel_mode = old_parallel_mode;
self.end = old_end;
self.start = old_start;
if reset_position {
ctx.builder.position_at_end(current);
}
return Ok(());
} else if id == &"sequential".into() {
// For deep parallel, temporarily take away start to avoid function calls in
// the block from resetting the timeline.
// This does not affect legacy parallel, as the timeline will be reset after
// this block finishes execution.
let start = self.start.take();
self.gen_block(ctx, body.iter())?;
self.start = start;
// Reset the timeline when we are exiting the sequential block
// Legacy parallel does not need this, since it will be reset after codegen
// for this statement is completed
if self.parallel_mode == ParallelMode::Deep {
self.timeline_reset_start(ctx)?;
}
return Ok(());
}
}
}
@ -389,12 +416,7 @@ fn gen_rpc_tag(
) -> Result<(), String> {
use nac3core::typecheck::typedef::TypeEnum::*;
let int32 = ctx.primitives.int32;
let int64 = ctx.primitives.int64;
let float = ctx.primitives.float;
let bool = ctx.primitives.bool;
let str = ctx.primitives.str;
let none = ctx.primitives.none;
let PrimitiveStore { int32, int64, float, bool, str, none, .. } = ctx.primitives;
if ctx.unifier.unioned(ty, int32) {
buffer.push(b'i');
@ -470,7 +492,6 @@ fn format_rpc_arg<'ctx>(
// NAC3: NDArray = { usize, usize*, T* }
// libproto_artiq: NDArray = [data[..], dim_sz[..]]
let llvm_i1 = ctx.ctx.bool_type();
let llvm_usize = ctx.get_size_type();
let (elem_ty, ndims) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty);
@ -488,11 +509,11 @@ fn format_rpc_arg<'ctx>(
let sizeof_usize = llvm_usize.size_of();
let sizeof_usize =
ctx.builder.build_int_z_extend_or_bit_cast(sizeof_usize, llvm_usize, "").unwrap();
ctx.builder.build_int_truncate_or_bit_cast(sizeof_usize, llvm_usize, "").unwrap();
let sizeof_pdata = dtype.ptr_type(AddressSpace::default()).size_of();
let sizeof_pdata =
ctx.builder.build_int_z_extend_or_bit_cast(sizeof_pdata, llvm_usize, "").unwrap();
ctx.builder.build_int_truncate_or_bit_cast(sizeof_pdata, llvm_usize, "").unwrap();
let sizeof_buf_shape = ctx.builder.build_int_mul(sizeof_usize, ndims, "").unwrap();
let sizeof_buf = ctx.builder.build_int_add(sizeof_buf_shape, sizeof_pdata, "").unwrap();
@ -507,13 +528,13 @@ fn format_rpc_arg<'ctx>(
// Write to `buf->data`
let carray_data = carray.load_data(ctx);
let carray_data = ctx.builder.build_pointer_cast(carray_data, llvm_pi8, "").unwrap();
call_memcpy(ctx, buf_data, carray_data, sizeof_pdata, llvm_i1.const_zero());
call_memcpy(ctx, buf_data, carray_data, sizeof_pdata);
// Write to `buf->shape`
let carray_shape = ndarray.shape().base_ptr(ctx, generator);
let carray_shape_i8 =
ctx.builder.build_pointer_cast(carray_shape, llvm_pi8, "").unwrap();
call_memcpy(ctx, buf_shape, carray_shape_i8, sizeof_buf_shape, llvm_i1.const_zero());
call_memcpy(ctx, buf_shape, carray_shape_i8, sizeof_buf_shape);
buf.base_ptr(ctx, generator)
}
@ -914,47 +935,14 @@ fn rpc_codegen_callback_fn<'ctx>(
}
// call
if is_async {
let rpc_send_async = ctx.module.get_function("rpc_send_async").unwrap_or_else(|| {
ctx.module.add_function(
"rpc_send_async",
ctx.ctx.void_type().fn_type(
&[
int32.into(),
tag_ptr_type.ptr_type(AddressSpace::default()).into(),
ptr_type.ptr_type(AddressSpace::default()).into(),
],
false,
),
None,
)
});
ctx.builder
.build_call(
rpc_send_async,
&[service_id.into(), tag_ptr.into(), args_ptr.into()],
"rpc.send",
)
.unwrap();
} else {
let rpc_send = ctx.module.get_function("rpc_send").unwrap_or_else(|| {
ctx.module.add_function(
"rpc_send",
ctx.ctx.void_type().fn_type(
&[
int32.into(),
tag_ptr_type.ptr_type(AddressSpace::default()).into(),
ptr_type.ptr_type(AddressSpace::default()).into(),
],
false,
),
None,
)
});
ctx.builder
.build_call(rpc_send, &[service_id.into(), tag_ptr.into(), args_ptr.into()], "rpc.send")
.unwrap();
}
infer_and_call_function(
ctx,
if is_async { "rpc_send_async" } else { "rpc_send" },
None,
&[service_id.into(), tag_ptr.into(), args_ptr.into()],
Some("rpc.send"),
None,
);
// reclaim stack space used by arguments
call_stackrestore(ctx, stackptr);
@ -1168,29 +1156,22 @@ fn polymorphic_print<'ctx>(
debug_assert!(!fmt.is_empty());
debug_assert_eq!(fmt.as_bytes().last().unwrap(), &0u8);
let fn_name = if as_rtio { "rtio_log" } else { "core_log" };
let print_fn = ctx.module.get_function(fn_name).unwrap_or_else(|| {
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
let fn_t = if as_rtio {
let llvm_void = ctx.ctx.void_type();
llvm_void.fn_type(&[llvm_pi8.into()], true)
} else {
let llvm_i32 = ctx.ctx.i32_type();
llvm_i32.fn_type(&[llvm_pi8.into()], true)
};
ctx.module.add_function(fn_name, fn_t, None)
});
let llvm_i32 = ctx.ctx.i32_type();
let llvm_pi8 = ctx.ctx.i8_type().ptr_type(AddressSpace::default());
let fmt = ctx.gen_string(generator, fmt);
let fmt = unsafe { fmt.get_field_at_index_unchecked(0) }.into_pointer_value();
ctx.builder
.build_call(
print_fn,
&once(fmt.into()).chain(args).map(BasicValueEnum::into).collect_vec(),
"",
)
.unwrap();
create_fn_and_call(
ctx,
if as_rtio { "rtio_log" } else { "core_log" },
if as_rtio { None } else { Some(llvm_i32.into()) },
&[llvm_pi8.into()],
&once(fmt.into()).chain(args).map(BasicValueEnum::into).collect_vec(),
true,
None,
None,
);
};
let llvm_i32 = ctx.ctx.i32_type();

View File

@ -19,6 +19,7 @@ use std::{
sync::Arc,
};
use indexmap::IndexMap;
use itertools::Itertools;
use parking_lot::{Mutex, RwLock};
use pyo3::{
@ -162,6 +163,13 @@ pub struct PrimitivePythonId {
module: u64,
}
#[derive(Clone, Default)]
pub struct SpecialPythonId {
parallel: u64,
legacy_parallel: u64,
sequential: u64,
}
type TopLevelComponent = (Stmt, String, PyObject);
// TopLevelComposer is unsendable as it holds the unification table, which is
@ -179,6 +187,7 @@ struct Nac3 {
string_store: Arc<RwLock<HashMap<String, i32>>>,
exception_ids: Arc<RwLock<HashMap<usize, usize>>>,
deferred_eval_store: DeferredEvaluationStore,
special_ids: SpecialPythonId,
/// LLVM-related options for code generation.
llvm_options: CodeGenLLVMOptions,
}
@ -797,6 +806,7 @@ impl Nac3 {
&context,
&self.get_llvm_target_machine(),
self.time_fns,
self.special_ids.clone(),
))
})
.collect();
@ -813,6 +823,7 @@ impl Nac3 {
&context,
&self.get_llvm_target_machine(),
self.time_fns,
self.special_ids.clone(),
);
let module = context.create_module("main");
let target_machine = self.llvm_options.create_target_machine().unwrap();
@ -1192,6 +1203,7 @@ impl Nac3 {
string_store: Arc::new(string_store.into()),
exception_ids: Arc::default(),
deferred_eval_store: DeferredEvaluationStore::new(),
special_ids: SpecialPythonId::default(),
llvm_options: CodeGenLLVMOptions {
opt_level: OptimizationLevel::Default,
target: isa.get_llvm_target_options(),
@ -1203,11 +1215,12 @@ impl Nac3 {
&mut self,
functions: &PySet,
classes: &PySet,
special_ids: &PyDict,
content_modules: &PySet,
) -> PyResult<()> {
let (modules, class_ids) =
Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> {
let mut modules: HashMap<u64, PyObject> = HashMap::new();
Python::with_gil(|py| -> PyResult<(IndexMap<u64, PyObject>, HashSet<u64>)> {
let mut modules: IndexMap<u64, PyObject> = IndexMap::new();
let mut class_ids: HashSet<u64> = HashSet::new();
let id_fn = PyModule::import(py, "builtins")?.getattr("id")?;
@ -1236,6 +1249,25 @@ impl Nac3 {
for module in modules.into_values() {
self.register_module(&module, &class_ids)?;
}
self.special_ids = SpecialPythonId {
parallel: special_ids.get_item("parallel").ok().flatten().unwrap().extract().unwrap(),
legacy_parallel: special_ids
.get_item("legacy_parallel")
.ok()
.flatten()
.unwrap()
.extract()
.unwrap(),
sequential: special_ids
.get_item("sequential")
.ok()
.flatten()
.unwrap()
.extract()
.unwrap(),
};
Ok(())
}

View File

@ -1,11 +1,6 @@
use itertools::Either;
use nac3core::{
codegen::CodeGenContext,
inkwell::{
values::{BasicValueEnum, CallSiteValue},
AddressSpace, AtomicOrdering,
},
codegen::{expr::infer_and_call_function, CodeGenContext},
inkwell::{values::BasicValueEnum, AddressSpace, AtomicOrdering},
};
/// Functions for manipulating the timeline.
@ -288,36 +283,27 @@ pub struct ExternTimeFns {}
impl TimeFns for ExternTimeFns {
fn emit_now_mu<'ctx>(&self, ctx: &mut CodeGenContext<'ctx, '_>) -> BasicValueEnum<'ctx> {
let now_mu = ctx.module.get_function("now_mu").unwrap_or_else(|| {
ctx.module.add_function("now_mu", ctx.ctx.i64_type().fn_type(&[], false), None)
});
ctx.builder
.build_call(now_mu, &[], "now_mu")
.map(CallSiteValue::try_as_basic_value)
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
"now_mu",
Some(ctx.ctx.i64_type().into()),
&[],
Some("now_mu"),
None,
)
.unwrap()
}
fn emit_at_mu<'ctx>(&self, ctx: &mut CodeGenContext<'ctx, '_>, t: BasicValueEnum<'ctx>) {
let at_mu = ctx.module.get_function("at_mu").unwrap_or_else(|| {
ctx.module.add_function(
"at_mu",
ctx.ctx.void_type().fn_type(&[ctx.ctx.i64_type().into()], false),
None,
)
});
ctx.builder.build_call(at_mu, &[t.into()], "at_mu").unwrap();
assert_eq!(t.get_type(), ctx.ctx.i64_type().into());
infer_and_call_function(ctx, "at_mu", None, &[t], Some("at_mu"), None);
}
fn emit_delay_mu<'ctx>(&self, ctx: &mut CodeGenContext<'ctx, '_>, dt: BasicValueEnum<'ctx>) {
let delay_mu = ctx.module.get_function("delay_mu").unwrap_or_else(|| {
ctx.module.add_function(
"delay_mu",
ctx.ctx.void_type().fn_type(&[ctx.ctx.i64_type().into()], false),
None,
)
});
ctx.builder.build_call(delay_mu, &[dt.into()], "delay_mu").unwrap();
assert_eq!(dt.get_type(), ctx.ctx.i64_type().into());
infer_and_call_function(ctx, "delay_mu", None, &[dt], Some("delay_mu"), None);
}
}

View File

@ -16,18 +16,20 @@ indexmap = "2.7"
parking_lot = "0.12"
nac3core_derive = { path = "nac3core_derive", optional = true }
nac3parser = { path = "../nac3parser" }
strum = "0.26"
strum_macros = "0.26"
strum = "0.27"
strum_macros = "0.27"
[dependencies.inkwell]
version = "0.5"
git = "https://github.com/Derppening/inkwell"
tag = "0.5.0_llvm15-typed-ptr"
default-features = false
features = ["llvm14-0-prefer-dynamic", "target-x86", "target-arm", "target-riscv", "no-libffi-linking"]
features = ["llvm16-0-prefer-dynamic", "target-x86", "target-arm", "target-riscv", "no-libffi-linking", "typed-pointers"]
[dev-dependencies]
test-case = "1.2.0"
test-case = "3.3"
indoc = "2.0"
insta = "=1.11.0"
insta = "1.42"
function_name = "0.3"
[build-dependencies]
regex = "1.11"

View File

@ -28,6 +28,8 @@ fn main() {
"-fno-exceptions",
"-fno-rtti",
"-emit-llvm",
"-Xclang",
"-no-opaque-pointers",
"-S",
"-Wall",
"-Wextra",
@ -100,6 +102,7 @@ fn main() {
let mut llvm_as = Command::new("llvm-as-irrt")
.stdin(Stdio::piped())
.arg("-opaque-pointers=0")
.arg("-o")
.arg(out_dir.join("irrt.bc"))
.spawn()

View File

@ -1,3 +1,4 @@
#include "irrt/cc-builtins.hpp"
#include "irrt/exception.hpp"
#include "irrt/list.hpp"
#include "irrt/math.hpp"

View File

@ -0,0 +1,30 @@
#pragma once
extern "C" {
#define DEF_builtin_unary(RET, NAME, TY) \
RET __nac3_##NAME(TY v) { return __builtin_##NAME(v); }
#define DEF_builtin_binary(RET, NAME, TY1, TY2) \
RET __nac3_##NAME(TY1 v1, TY2 v2) { return __builtin_##NAME(v1, v2); }
DEF_builtin_unary(bool, isinf, double);
DEF_builtin_unary(bool, isnan, double);
DEF_builtin_unary(double, tan, double);
DEF_builtin_unary(double, asin, double);
DEF_builtin_unary(double, acos, double);
DEF_builtin_unary(double, atan, double);
DEF_builtin_unary(double, sinh, double);
DEF_builtin_unary(double, cosh, double);
DEF_builtin_unary(double, tanh, double);
DEF_builtin_unary(double, asinh, double);
DEF_builtin_unary(double, acosh, double);
DEF_builtin_unary(double, atanh, double);
DEF_builtin_unary(double, expm1, double);
DEF_builtin_unary(double, cbrt, double);
DEF_builtin_unary(double, erf, double);
DEF_builtin_unary(double, erfc, double);
DEF_builtin_binary(double, atan2, double, double);
DEF_builtin_binary(double, hypot, double, double);
DEF_builtin_binary(double, nextafter, double, double);
DEF_builtin_binary(double, ldexp, double, int);
}

View File

@ -34,16 +34,6 @@ DEF_nac3_int_exp_(int64_t);
DEF_nac3_int_exp_(uint32_t);
DEF_nac3_int_exp_(uint64_t);
int32_t __nac3_isinf(double x) {
return __builtin_isinf(x);
}
int32_t __nac3_isnan(double x) {
return __builtin_isnan(x);
}
double tgamma(double arg);
double __nac3_gamma(double z) {
// Handling for denormals
// | x | Python gamma(x) | C tgamma(x) |
@ -59,14 +49,12 @@ double __nac3_gamma(double z) {
return z;
}
double v = tgamma(z);
double v = __builtin_tgamma(z);
// (4)-(5)
return __builtin_isinf(v) || __builtin_isnan(v) ? __builtin_inf() : v;
}
double lgamma(double arg);
double __nac3_gammaln(double x) {
// libm's handling of value overflows differs from scipy:
// - scipy: gammaln(-inf) -> -inf
@ -76,7 +64,7 @@ double __nac3_gammaln(double x) {
return x;
}
return lgamma(x);
return __builtin_lgamma(x);
}
double j0(double x);

View File

@ -1194,7 +1194,7 @@ macro_rules! create_helper_call_numpy_unary_elementwise_float_to_bool {
BasicValueEnum::FloatValue(n) => {
debug_assert!(ctx.unifier.unioned(n_ty, ctx.primitives.float));
let ret = $on_scalar(generator, ctx, n);
let ret = $on_scalar(ctx, n, Option::<&str>::None);
Some(generator.bool_to_i8(ctx, ret).into())
}
_ => None,
@ -1263,55 +1263,55 @@ create_helper_call_numpy_unary_elementwise_float_to_float!(
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_tan,
"np_tan",
extern_fns::call_tan
irrt::call_tan
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arcsin,
"np_arcsin",
extern_fns::call_asin
irrt::call_asin
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arccos,
"np_arccos",
extern_fns::call_acos
irrt::call_acos
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arctan,
"np_arctan",
extern_fns::call_atan
irrt::call_atan
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_sinh,
"np_sinh",
extern_fns::call_sinh
irrt::call_sinh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_cosh,
"np_cosh",
extern_fns::call_cosh
irrt::call_cosh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_tanh,
"np_tanh",
extern_fns::call_tanh
irrt::call_tanh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arcsinh,
"np_arcsinh",
extern_fns::call_asinh
irrt::call_asinh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arccosh,
"np_arccosh",
extern_fns::call_acosh
irrt::call_acosh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_arctanh,
"np_arctanh",
extern_fns::call_atanh
irrt::call_atanh
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
@ -1327,7 +1327,7 @@ create_helper_call_numpy_unary_elementwise_float_to_float!(
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_expm1,
"np_expm1",
extern_fns::call_expm1
irrt::call_expm1
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
@ -1354,7 +1354,7 @@ create_helper_call_numpy_unary_elementwise_float_to_float!(
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_numpy_cbrt,
"np_cbrt",
extern_fns::call_cbrt
irrt::call_cbrt
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
@ -1371,12 +1371,12 @@ create_helper_call_numpy_unary_elementwise_float_to_float!(
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_scipy_special_erf,
"sp_spec_erf",
extern_fns::call_erf
irrt::call_erf
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_scipy_special_erfc,
"sp_spec_erfc",
extern_fns::call_erfc
irrt::call_erfc
);
create_helper_call_numpy_unary_elementwise_float_to_float!(
call_scipy_special_gamma,
@ -1422,7 +1422,7 @@ pub fn call_numpy_arctan2<'ctx, G: CodeGenerator + ?Sized>(
match (x1_scalar, x2_scalar) {
(BasicValueEnum::FloatValue(x1), BasicValueEnum::FloatValue(x2)) => {
Ok(extern_fns::call_atan2(ctx, x1, x2, None).into())
Ok(irrt::call_atan2(ctx, x1, x2, None).into())
}
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
}
@ -1560,7 +1560,7 @@ pub fn call_numpy_ldexp<'ctx, G: CodeGenerator + ?Sized>(
(BasicValueEnum::FloatValue(x1_scalar), BasicValueEnum::IntValue(x2_scalar)) => {
debug_assert_eq!(x1.get_dtype(), ctx.ctx.f64_type().into());
debug_assert_eq!(x2.get_dtype(), ctx.ctx.i32_type().into());
Ok(extern_fns::call_ldexp(ctx, x1_scalar, x2_scalar, None).into())
Ok(irrt::call_ldexp(ctx, x1_scalar, x2_scalar, None).into())
}
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
}
@ -1594,7 +1594,7 @@ pub fn call_numpy_hypot<'ctx, G: CodeGenerator + ?Sized>(
match (x1_scalar, x2_scalar) {
(BasicValueEnum::FloatValue(x1), BasicValueEnum::FloatValue(x2)) => {
Ok(extern_fns::call_hypot(ctx, x1, x2, None).into())
Ok(irrt::call_hypot(ctx, x1, x2, None).into())
}
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
}
@ -1628,7 +1628,7 @@ pub fn call_numpy_nextafter<'ctx, G: CodeGenerator + ?Sized>(
match (x1_scalar, x2_scalar) {
(BasicValueEnum::FloatValue(x1), BasicValueEnum::FloatValue(x2)) => {
Ok(extern_fns::call_nextafter(ctx, x1, x2, None).into())
Ok(irrt::call_nextafter(ctx, x1, x2, None).into())
}
_ => unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]),
}

View File

@ -32,7 +32,9 @@ use super::{
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
gen_var,
},
types::{ndarray::NDArrayType, ListType, RangeType},
types::{
ndarray::NDArrayType, ExceptionType, ListType, OptionType, RangeType, StringType, TupleType,
},
values::{
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
@ -43,7 +45,7 @@ use super::{
use crate::{
symbol_resolver::{SymbolValue, ValueEnum},
toplevel::{
helper::{arraylike_flatten_element_type, PrimDef},
helper::{arraylike_flatten_element_type, extract_ndims, PrimDef},
numpy::unpack_ndarray_var_tys,
DefinitionId, TopLevelDef,
},
@ -168,65 +170,27 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
SymbolValue::Bool(v) => self.ctx.i8_type().const_int(u64::from(*v), true).into(),
SymbolValue::Double(v) => self.ctx.f64_type().const_float(*v).into(),
SymbolValue::Str(v) => {
let str_ptr = self
.builder
.build_global_string_ptr(v, "const")
.map(|v| v.as_pointer_value().into())
.unwrap();
let size = self.get_size_type().const_int(v.len() as u64, false);
let ty = self.get_llvm_type(generator, self.primitives.str).into_struct_type();
ty.const_named_struct(&[str_ptr, size.into()]).into()
StringType::new(self).construct_constant(self, v, None).as_abi_value(self).into()
}
SymbolValue::Tuple(ls) => {
let vals = ls.iter().map(|v| self.gen_symbol_val(generator, v, ty)).collect_vec();
let fields = vals.iter().map(BasicValueEnum::get_type).collect_vec();
let ty = self.ctx.struct_type(&fields, false);
let ptr = gen_var(self, ty.into(), Some("tuple")).unwrap();
let zero = self.ctx.i32_type().const_zero();
unsafe {
for (i, val) in vals.into_iter().enumerate() {
let p = self
.builder
.build_in_bounds_gep(
ptr,
&[zero, self.ctx.i32_type().const_int(i as u64, false)],
"elemptr",
)
.unwrap();
self.builder.build_store(p, val).unwrap();
}
}
self.builder.build_load(ptr, "tup_val").unwrap()
TupleType::new(self, &fields)
.construct_from_objects(self, vals, Some("tup_val"))
.as_abi_value(self)
.into()
}
SymbolValue::OptionSome(v) => {
let ty = match self.unifier.get_ty_immutable(ty).as_ref() {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == self.primitives.option.obj_id(&self.unifier).unwrap() =>
{
*params.iter().next().unwrap().1
}
_ => codegen_unreachable!(self, "must be option type"),
};
let val = self.gen_symbol_val(generator, v, ty);
let ptr = generator
.gen_var_alloc(self, val.get_type(), Some("default_opt_some"))
.unwrap();
self.builder.build_store(ptr, val).unwrap();
ptr.into()
}
SymbolValue::OptionNone => {
let ty = match self.unifier.get_ty_immutable(ty).as_ref() {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == self.primitives.option.obj_id(&self.unifier).unwrap() =>
{
*params.iter().next().unwrap().1
}
_ => codegen_unreachable!(self, "must be option type"),
};
let actual_ptr_type =
self.get_llvm_type(generator, ty).ptr_type(AddressSpace::default());
actual_ptr_type.const_null().into()
OptionType::from_unifier_type(generator, self, ty)
.construct_some_value(generator, self, &val, None)
.as_abi_value(self)
.into()
}
SymbolValue::OptionNone => OptionType::from_unifier_type(generator, self, ty)
.construct_empty(generator, self, None)
.as_abi_value(self)
.into(),
}
}
@ -321,15 +285,10 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
if let Some(v) = self.const_strings.get(v) {
Some(*v)
} else {
let str_ptr = self
.builder
.build_global_string_ptr(v, "const")
.map(|v| v.as_pointer_value().into())
.unwrap();
let size = self.get_size_type().const_int(v.len() as u64, false);
let ty = self.get_llvm_type(generator, self.primitives.str);
let val =
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
let val = StringType::new(self)
.construct_constant(self, v, None)
.as_abi_value(self)
.into();
self.const_strings.insert(v.to_string(), val);
Some(val)
}
@ -619,42 +578,35 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
params: [Option<IntValue<'ctx>>; 3],
loc: Location,
) {
let llvm_i32 = self.ctx.i32_type();
let llvm_i64 = self.ctx.i64_type();
let llvm_exn = ExceptionType::get_instance(generator, self);
let zelf = if let Some(exception_val) = self.exception_val {
exception_val
llvm_exn.map_pointer_value(exception_val, Some("exn"))
} else {
let ty = self.get_llvm_type(generator, self.primitives.exception).into_pointer_type();
let zelf_ty: BasicTypeEnum = ty.get_element_type().into_struct_type().into();
let zelf = generator.gen_var_alloc(self, zelf_ty, Some("exn")).unwrap();
*self.exception_val.insert(zelf)
let zelf = llvm_exn.alloca_var(generator, self, Some("exn"));
self.exception_val = Some(zelf.as_abi_value(self));
zelf
};
let int32 = self.ctx.i32_type();
let zero = int32.const_zero();
unsafe {
let id_ptr = self.builder.build_in_bounds_gep(zelf, &[zero, zero], "exn.id").unwrap();
let id = self.resolver.get_string_id(name);
self.builder.build_store(id_ptr, int32.const_int(id as u64, false)).unwrap();
let ptr = self
.builder
.build_in_bounds_gep(zelf, &[zero, int32.const_int(5, false)], "exn.msg")
.unwrap();
self.builder.build_store(ptr, msg).unwrap();
let i64_zero = self.ctx.i64_type().const_zero();
for (i, attr_ind) in [6, 7, 8].iter().enumerate() {
let ptr = self
.builder
.build_in_bounds_gep(
zelf,
&[zero, int32.const_int(*attr_ind, false)],
"exn.param",
)
.unwrap();
let val = params[i].map_or(i64_zero, |v| {
self.builder.build_int_s_extend(v, self.ctx.i64_type(), "sext").unwrap()
});
self.builder.build_store(ptr, val).unwrap();
}
}
gen_raise(generator, self, Some(&zelf.into()), loc);
let id = self.resolver.get_string_id(name);
zelf.store_name(self, llvm_i32.const_int(id as u64, false));
zelf.store_message(self, msg.into_struct_value());
zelf.store_params(
self,
params
.iter()
.map(|p| {
p.map_or(llvm_i64.const_zero(), |v| {
self.builder.build_int_s_extend(v, self.ctx.i64_type(), "sext").unwrap()
})
})
.collect_array()
.as_ref()
.unwrap(),
);
gen_raise(generator, self, Some(&zelf), loc);
}
pub fn make_assert<G: CodeGenerator + ?Sized>(
@ -1319,7 +1271,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
op: Binop,
right: (&Option<Type>, BasicValueEnum<'ctx>),
loc: Location,
) -> Result<Option<ValueEnum<'ctx>>, String> {
) -> Result<BasicValueEnum<'ctx>, String> {
let (left_ty, left_val) = left;
let (right_ty, right_val) = right;
@ -1330,14 +1282,14 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
// which would be unchanged until further unification, which we would never do
// when doing code generation for function instances
if ty1 == ty2 && [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1) {
Ok(Some(ctx.gen_int_ops(generator, op.base, left_val, right_val, true).into()))
Ok(ctx.gen_int_ops(generator, op.base, left_val, right_val, true))
} else if ty1 == ty2 && [ctx.primitives.uint32, ctx.primitives.uint64].contains(&ty1) {
Ok(Some(ctx.gen_int_ops(generator, op.base, left_val, right_val, false).into()))
Ok(ctx.gen_int_ops(generator, op.base, left_val, right_val, false))
} else if [Operator::LShift, Operator::RShift].contains(&op.base) {
let signed = [ctx.primitives.int32, ctx.primitives.int64].contains(&ty1);
Ok(Some(ctx.gen_int_ops(generator, op.base, left_val, right_val, signed).into()))
Ok(ctx.gen_int_ops(generator, op.base, left_val, right_val, signed))
} else if ty1 == ty2 && ctx.primitives.float == ty1 {
Ok(Some(ctx.gen_float_ops(op.base, left_val, right_val).into()))
Ok(ctx.gen_float_ops(op.base, left_val, right_val))
} else if ty1 == ctx.primitives.float && ty2 == ctx.primitives.int32 {
// Pow is the only operator that would pass typecheck between float and int
assert_eq!(op.base, Operator::Pow);
@ -1347,7 +1299,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
right_val.into_int_value(),
Some("f_pow_i"),
);
Ok(Some(res.into()))
Ok(res.into())
} else if ty1.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
|| ty2.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::List.id())
{
@ -1377,7 +1329,10 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
debug_assert!(ctx.unifier.unioned(elem_ty1, elem_ty2));
let llvm_elem_ty = ctx.get_llvm_type(generator, elem_ty1);
let sizeof_elem = llvm_elem_ty.size_of().unwrap();
let sizeof_elem = ctx
.builder
.build_int_truncate_or_bit_cast(llvm_elem_ty.size_of().unwrap(), llvm_usize, "")
.unwrap();
let lhs =
ListValue::from_pointer_value(left_val.into_pointer_value(), llvm_usize, None);
@ -1392,34 +1347,14 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
let new_list =
ListType::new(ctx, &llvm_elem_ty).construct(generator, ctx, size, None);
let lhs_size = ctx
.builder
.build_int_z_extend_or_bit_cast(
lhs.load_size(ctx, None),
sizeof_elem.get_type(),
"",
)
.unwrap();
let lhs_size = lhs.load_size(ctx, None);
let lhs_len = ctx.builder.build_int_mul(lhs_size, sizeof_elem, "").unwrap();
let rhs_size = ctx
.builder
.build_int_z_extend_or_bit_cast(
rhs.load_size(ctx, None),
sizeof_elem.get_type(),
"",
)
.unwrap();
let rhs_size = rhs.load_size(ctx, None);
let rhs_len = ctx.builder.build_int_mul(rhs_size, sizeof_elem, "").unwrap();
let list_ptr = new_list.data().base_ptr(ctx, generator);
call_memcpy_generic(
ctx,
list_ptr,
lhs.data().base_ptr(ctx, generator),
lhs_len,
ctx.ctx.bool_type().const_zero(),
);
call_memcpy_generic(ctx, list_ptr, lhs.data().base_ptr(ctx, generator), lhs_len);
let list_ptr = unsafe {
new_list.data().ptr_offset_unchecked(
@ -1429,15 +1364,9 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
None,
)
};
call_memcpy_generic(
ctx,
list_ptr,
rhs.data().base_ptr(ctx, generator),
rhs_len,
ctx.ctx.bool_type().const_zero(),
);
call_memcpy_generic(ctx, list_ptr, rhs.data().base_ptr(ctx, generator), rhs_len);
Ok(Some(new_list.as_abi_value(ctx).into()))
Ok(new_list.as_abi_value(ctx).into())
}
Operator::Mult => {
@ -1475,7 +1404,10 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
let int_val = call_int_smax(ctx, int_val, llvm_usize.const_zero(), None);
let elem_llvm_ty = ctx.get_llvm_type(generator, elem_ty);
let sizeof_elem = elem_llvm_ty.size_of().unwrap();
let sizeof_elem = ctx
.builder
.build_int_truncate_or_bit_cast(elem_llvm_ty.size_of().unwrap(), llvm_usize, "")
.unwrap();
let new_list = ListType::new(ctx, &elem_llvm_ty).construct(
generator,
@ -1499,14 +1431,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
new_list.data().ptr_offset_unchecked(ctx, generator, &offset, None)
};
let list_size = ctx
.builder
.build_int_z_extend_or_bit_cast(
list_val.load_size(ctx, None),
sizeof_elem.get_type(),
"",
)
.unwrap();
let list_size = list_val.load_size(ctx, None);
let memcpy_sz =
ctx.builder.build_int_mul(list_size, sizeof_elem, "").unwrap();
@ -1516,7 +1441,6 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
ptr,
list_val.data().base_ptr(ctx, generator),
memcpy_sz,
ctx.ctx.bool_type().const_zero(),
);
Ok(())
@ -1524,7 +1448,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
llvm_usize.const_int(1, false),
)?;
Ok(Some(new_list.as_abi_value(ctx).into()))
Ok(new_list.as_abi_value(ctx).into())
}
_ => todo!("Operator not supported"),
@ -1563,7 +1487,7 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
let result = left
.matmul(generator, ctx, ty1, (ty2, right), (common_dtype, out))
.split_unsized(generator, ctx);
Ok(Some(result.to_basic_value_enum().into()))
Ok(result.to_basic_value_enum())
} else {
// For other operations, they are all elementwise operations.
@ -1594,14 +1518,12 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
op,
(&Some(ty2_dtype), right_value),
ctx.current_loc,
)?
.unwrap()
.to_basic_value_enum(ctx, generator, common_dtype)?;
)?;
Ok(result)
})
.unwrap();
Ok(Some(result.as_abi_value(ctx).into()))
Ok(result.as_abi_value(ctx).into())
}
} else {
let left_ty_enum = ctx.unifier.get_ty_immutable(left_ty.unwrap());
@ -1650,7 +1572,8 @@ pub fn gen_binop_expr_with_values<'ctx, G: CodeGenerator>(
(&signature, fun_id),
vec![(None, right_val.into())],
)
.map(|f| f.map(Into::into))
.map(Option::unwrap)
.map(BasicValueEnum::into)
}
}
@ -1688,6 +1611,7 @@ pub fn gen_binop_expr<'ctx, G: CodeGenerator>(
(&right.custom, right_val),
loc,
)
.map(|res| Some(res.into()))
}
/// Generates LLVM IR for a unary operator expression using the [`Type`] and
@ -1697,18 +1621,19 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
ctx: &mut CodeGenContext<'ctx, '_>,
op: ast::Unaryop,
operand: (&Option<Type>, BasicValueEnum<'ctx>),
) -> Result<Option<ValueEnum<'ctx>>, String> {
) -> Result<BasicValueEnum<'ctx>, String> {
let (ty, val) = operand;
let ty = ctx.unifier.get_representative(ty.unwrap());
Ok(Some(if ty == ctx.primitives.bool {
Ok(if ty == ctx.primitives.bool {
let val = val.into_int_value();
if op == ast::Unaryop::Not {
let not = ctx.builder.build_not(val, "not").unwrap();
let not_bool =
ctx.builder.build_and(not, not.get_type().const_int(1, false), "").unwrap();
let not = ctx
.builder
.build_int_compare(IntPredicate::EQ, val, val.get_type().const_zero(), "not")
.unwrap();
not_bool.into()
generator.bool_to_int_type(ctx, not, val.get_type()).into()
} else {
let llvm_i32 = ctx.ctx.i32_type();
@ -1721,7 +1646,6 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
ctx.builder.build_int_z_extend(val, llvm_i32, "").map(Into::into).unwrap(),
),
)?
.unwrap()
}
} else if [
ctx.primitives.int32,
@ -1775,10 +1699,13 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
if op == ast::Unaryop::Invert {
ast::Unaryop::Not
} else {
let ndims = extract_ndims(&ctx.unifier, ty);
codegen_unreachable!(
ctx,
"ufunc {} not supported for ndarray[bool, N]",
"ufunc {} not supported for ndarray[bool, {}]",
op.op_info().method_name,
ndims,
)
}
} else {
@ -1790,16 +1717,14 @@ pub fn gen_unaryop_expr_with_values<'ctx, G: CodeGenerator>(
ctx,
NDArrayOut::NewNDArray { dtype: ndarray.get_type().element_type() },
|generator, ctx, scalar| {
gen_unaryop_expr_with_values(generator, ctx, op, (&Some(ndarray_dtype), scalar))?
.map(|val| val.to_basic_value_enum(ctx, generator, ndarray_dtype))
.unwrap()
gen_unaryop_expr_with_values(generator, ctx, op, (&Some(ndarray_dtype), scalar))
},
)?;
mapped_ndarray.as_abi_value(ctx).into()
} else {
unimplemented!()
}))
})
}
/// Generates LLVM IR for a unary operator expression.
@ -1819,6 +1744,7 @@ pub fn gen_unaryop_expr<'ctx, G: CodeGenerator>(
};
gen_unaryop_expr_with_values(generator, ctx, op, (&operand.custom, val))
.map(|res| Some(res.into()))
}
/// Generates LLVM IR for a comparison operator expression using the [`Type`] and
@ -1829,7 +1755,7 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
left: (Option<Type>, BasicValueEnum<'ctx>),
ops: &[ast::Cmpop],
comparators: &[(Option<Type>, BasicValueEnum<'ctx>)],
) -> Result<Option<ValueEnum<'ctx>>, String> {
) -> Result<BasicValueEnum<'ctx>, String> {
debug_assert_eq!(comparators.len(), ops.len());
if comparators.len() == 1 {
@ -1871,19 +1797,13 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
(Some(left_ty_dtype), left_scalar),
&[op],
&[(Some(right_ty_dtype), right_scalar)],
)?
.unwrap()
.to_basic_value_enum(
ctx,
generator,
ctx.primitives.bool,
)?;
Ok(generator.bool_to_i8(ctx, val.into_int_value()).into())
},
)?;
return Ok(Some(result_ndarray.as_abi_value(ctx).into()));
return Ok(result_ndarray.as_abi_value(ctx).into());
}
}
@ -1967,41 +1887,19 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
} else if left_ty == ctx.primitives.str {
assert!(ctx.unifier.unioned(left_ty, right_ty));
let lhs = lhs.into_struct_value();
let rhs = rhs.into_struct_value();
let llvm_str = StringType::new(ctx);
let llvm_i32 = ctx.ctx.i32_type();
let llvm_usize = ctx.get_size_type();
let lhs = llvm_str.map_struct_value(lhs.into_struct_value(), None);
let rhs = llvm_str.map_struct_value(rhs.into_struct_value(), None);
let plhs = generator.gen_var_alloc(ctx, lhs.get_type().into(), None).unwrap();
ctx.builder.build_store(plhs, lhs).unwrap();
let prhs = generator.gen_var_alloc(ctx, lhs.get_type().into(), None).unwrap();
ctx.builder.build_store(prhs, rhs).unwrap();
let lhs_ptr = ctx.build_in_bounds_gep_and_load(
plhs,
&[llvm_usize.const_zero(), llvm_i32.const_zero()],
None,
).into_pointer_value();
let lhs_len = ctx.build_in_bounds_gep_and_load(
plhs,
&[llvm_usize.const_zero(), llvm_i32.const_int(1, false)],
None,
).into_int_value();
let rhs_ptr = ctx.build_in_bounds_gep_and_load(
prhs,
&[llvm_usize.const_zero(), llvm_i32.const_zero()],
None,
).into_pointer_value();
let rhs_len = ctx.build_in_bounds_gep_and_load(
prhs,
&[llvm_usize.const_zero(), llvm_i32.const_int(1, false)],
None,
).into_int_value();
let result = call_string_eq(ctx, lhs_ptr, lhs_len, rhs_ptr, rhs_len);
let result = call_string_eq(ctx, lhs, rhs);
if *op == Cmpop::NotEq {
ctx.builder.build_not(result, "").unwrap()
gen_unaryop_expr_with_values(
generator,
ctx,
Unaryop::Not,
(&Some(ctx.primitives.bool), result.into()),
)?.into_int_value()
} else {
result
}
@ -2104,9 +2002,6 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
&[Cmpop::Eq],
&[(Some(right_elem_ty), right)],
)?
.unwrap()
.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
.unwrap()
.into_int_value();
gen_if_callback(
@ -2155,8 +2050,6 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
Unaryop::Not,
(&Some(ctx.primitives.bool), acc.into()),
)?
.unwrap()
.to_basic_value_enum(ctx, generator, ctx.primitives.bool)?
.into_int_value()
} else {
acc
@ -2244,11 +2137,6 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
&[op],
&[(Some(right_ty), right_elem)],
)
.transpose()
.unwrap()
.and_then(|v| {
v.to_basic_value_enum(ctx, generator, ctx.primitives.bool)
})
.map(BasicValueEnum::into_int_value)?;
Ok(ctx.builder.build_not(
@ -2285,7 +2173,12 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
// Invert the final value if __ne__
if *op == Cmpop::NotEq {
ctx.builder.build_not(cmp_phi, "").unwrap()
gen_unaryop_expr_with_values(
generator,
ctx,
Unaryop::Not,
(&Some(ctx.primitives.bool), cmp_phi.into()),
)?.into_int_value()
} else {
cmp_phi
}
@ -2310,12 +2203,9 @@ pub fn gen_cmpop_expr_with_values<'ctx, G: CodeGenerator>(
};
Ok(prev?.map(|v| ctx.builder.build_and(v, current, "cmp").unwrap()).or(Some(current)))
})?;
})?.unwrap();
Ok(Some(match cmp_val {
Some(v) => v.into(),
None => return Ok(None),
}))
Ok(cmp_val.into())
}
/// Generates LLVM IR for a comparison operator expression.
@ -2362,6 +2252,7 @@ pub fn gen_cmpop_expr<'ctx, G: CodeGenerator>(
ops,
comparator_vals.as_slice(),
)
.map(|res| Some(res.into()))
}
/// See [`CodeGenerator::gen_expr`].
@ -2391,16 +2282,13 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
const_val.into()
}
ExprKind::Name { id, .. } if id == &"none".into() => {
match (
ctx.unifier.get_ty(expr.custom.unwrap()).as_ref(),
ctx.unifier.get_ty(ctx.primitives.option).as_ref(),
) {
(TypeEnum::TObj { obj_id, params, .. }, TypeEnum::TObj { obj_id: opt_id, .. })
if *obj_id == *opt_id =>
match &*ctx.unifier.get_ty(expr.custom.unwrap()) {
TypeEnum::TObj { obj_id, .. }
if *obj_id == ctx.primitives.option.obj_id(&ctx.unifier).unwrap() =>
{
ctx.get_llvm_type(generator, *params.iter().next().unwrap().1)
.ptr_type(AddressSpace::default())
.const_null()
OptionType::from_unifier_type(generator, ctx, expr.custom.unwrap())
.construct_empty(generator, ctx, None)
.as_abi_value(ctx)
.into()
}
_ => codegen_unreachable!(ctx, "must be option type"),
@ -2885,8 +2773,12 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
};
}
ValueEnum::Dynamic(BasicValueEnum::PointerValue(ptr)) => {
let not_null =
ctx.builder.build_is_not_null(ptr, "unwrap_not_null").unwrap();
let option = OptionType::from_pointer_type(
ptr.get_type(),
ctx.get_size_type(),
)
.map_pointer_value(ptr, None);
let not_null = option.is_some(ctx);
ctx.make_assert(
generator,
not_null,
@ -2895,12 +2787,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
[None, None, None],
expr.location,
);
return Ok(Some(
ctx.builder
.build_load(ptr, "unwrap_some_load")
.map(Into::into)
.unwrap(),
));
return Ok(Some(unsafe { option.load(ctx).into() }));
}
ValueEnum::Dynamic(_) => {
codegen_unreachable!(ctx, "option must be static or ptr")

View File

@ -1,10 +1,9 @@
use inkwell::{
attributes::{Attribute, AttributeLoc},
values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue},
values::{BasicValueEnum, FloatValue},
};
use itertools::Either;
use super::CodeGenContext;
use super::{expr::infer_and_call_function, CodeGenContext};
/// Macro to generate extern function
/// Both function return type and function parameter type are `FloatValue`
@ -37,8 +36,8 @@ macro_rules! generate_extern_fn {
($fn_name:ident, $extern_fn:literal $(,$args:ident)* $(,$attributes:literal)*) => {
#[doc = concat!("Invokes the [`", stringify!($extern_fn), "`](https://en.cppreference.com/w/c/numeric/math/", stringify!($llvm_name), ") function." )]
pub fn $fn_name<'ctx>(
ctx: &CodeGenContext<'ctx, '_>
$(,$args: FloatValue<'ctx>)*,
ctx: &CodeGenContext<'ctx, '_>,
$($args: FloatValue<'ctx>,)*
name: Option<&str>,
) -> FloatValue<'ctx> {
const FN_NAME: &str = $extern_fn;
@ -46,99 +45,35 @@ macro_rules! generate_extern_fn {
let llvm_f64 = ctx.ctx.f64_type();
$(debug_assert_eq!($args.get_type(), llvm_f64);)*
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
let fn_type = llvm_f64.fn_type(&[$($args.get_type().into()),*], false);
let func = ctx.module.add_function(FN_NAME, fn_type, None);
for attr in [$($attributes),*] {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
);
}
func
});
ctx.builder
.build_call(extern_fn, &[$($args.into()),*], name.unwrap_or_default())
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_float_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
FN_NAME,
Some(llvm_f64.into()),
&[$($args.into()),*],
name,
Some(&|func| {
for attr in [$($attributes),*] {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
);
}
})
)
.map(BasicValueEnum::into_float_value)
.unwrap()
}
};
}
generate_extern_fn!("unary", call_tan, "tan");
generate_extern_fn!("unary", call_asin, "asin");
generate_extern_fn!("unary", call_acos, "acos");
generate_extern_fn!("unary", call_atan, "atan");
generate_extern_fn!("unary", call_sinh, "sinh");
generate_extern_fn!("unary", call_cosh, "cosh");
generate_extern_fn!("unary", call_tanh, "tanh");
generate_extern_fn!("unary", call_asinh, "asinh");
generate_extern_fn!("unary", call_acosh, "acosh");
generate_extern_fn!("unary", call_atanh, "atanh");
generate_extern_fn!("unary", call_expm1, "expm1");
generate_extern_fn!(
"unary",
call_cbrt,
"cbrt",
"mustprogress",
"nofree",
"nosync",
"nounwind",
"readonly",
"willreturn"
);
generate_extern_fn!("unary", call_erf, "erf", "nounwind");
generate_extern_fn!("unary", call_erfc, "erfc", "nounwind");
generate_extern_fn!("unary", call_j1, "j1", "nounwind");
generate_extern_fn!("binary", call_atan2, "atan2");
generate_extern_fn!("binary", call_hypot, "hypot", "nounwind");
generate_extern_fn!("binary", call_nextafter, "nextafter", "nounwind");
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
pub fn call_ldexp<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
arg: FloatValue<'ctx>,
exp: IntValue<'ctx>,
name: Option<&str>,
) -> FloatValue<'ctx> {
const FN_NAME: &str = "ldexp";
let llvm_f64 = ctx.ctx.f64_type();
let llvm_i32 = ctx.ctx.i32_type();
debug_assert_eq!(arg.get_type(), llvm_f64);
debug_assert_eq!(exp.get_type(), llvm_i32);
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
let fn_type = llvm_f64.fn_type(&[llvm_f64.into(), llvm_i32.into()], false);
let func = ctx.module.add_function(FN_NAME, fn_type, None);
for attr in ["mustprogress", "nofree", "nounwind", "willreturn"] {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
);
}
func
});
ctx.builder
.build_call(extern_fn, &[arg.into(), exp.into()], name.unwrap_or_default())
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_float_value))
.map(Either::unwrap_left)
.unwrap()
}
/// Macro to generate `np_linalg` and `sp_linalg` functions
/// The function takes as input `NDArray` and returns ()
///
/// Arguments:
/// * `$fn_name:ident`: The identifier of the rust function to be generated
/// * `$extern_fn:literal`: Name of underlying extern function
/// * `$extern_fn:ident`: Name of underlying extern function
/// * (2/3/4): Number of `NDArray` that function takes as input
///
/// Note:
@ -146,48 +81,51 @@ pub fn call_ldexp<'ctx>(
/// It is the responsibility of caller to ensure that output `NDArray` is properly allocated on stack
/// The function changes the content of the output `NDArray` in-place
macro_rules! generate_linalg_extern_fn {
($fn_name:ident, $extern_fn:literal, 2) => {
($fn_name:ident, $extern_fn:ident, 2) => {
generate_linalg_extern_fn!($fn_name, $extern_fn, mat1, mat2);
};
($fn_name:ident, $extern_fn:literal, 3) => {
($fn_name:ident, $extern_fn:ident, 3) => {
generate_linalg_extern_fn!($fn_name, $extern_fn, mat1, mat2, mat3);
};
($fn_name:ident, $extern_fn:literal, 4) => {
($fn_name:ident, $extern_fn:ident, 4) => {
generate_linalg_extern_fn!($fn_name, $extern_fn, mat1, mat2, mat3, mat4);
};
($fn_name:ident, $extern_fn:literal $(,$input_matrix:ident)*) => {
#[doc = concat!("Invokes the linalg `", stringify!($extern_fn), " function." )]
($fn_name:ident, $extern_fn:ident $(,$input_matrix:ident)*) => {
#[doc = concat!("Invokes the linalg `", stringify!($extern_fn), "` function." )]
pub fn $fn_name<'ctx>(
ctx: &mut CodeGenContext<'ctx, '_>
$(,$input_matrix: BasicValueEnum<'ctx>)*,
ctx: &mut CodeGenContext<'ctx, '_>,
$($input_matrix: BasicValueEnum<'ctx>,)*
name: Option<&str>,
){
const FN_NAME: &str = $extern_fn;
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
let fn_type = ctx.ctx.void_type().fn_type(&[$($input_matrix.get_type().into()),*], false);
) {
const FN_NAME: &str = stringify!($extern_fn);
let func = ctx.module.add_function(FN_NAME, fn_type, None);
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
infer_and_call_function(
ctx,
FN_NAME,
None,
&[$($input_matrix.into(),)*],
name,
Some(&|func| {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
);
}
func
});
ctx.builder.build_call(extern_fn, &[$($input_matrix.into(),)*], name.unwrap_or_default()).unwrap();
ctx.ctx.create_enum_attribute(
Attribute::get_named_enum_kind_id("nounwind"),
0,
),
)
}),
);
}
};
}
generate_linalg_extern_fn!(call_np_linalg_cholesky, "np_linalg_cholesky", 2);
generate_linalg_extern_fn!(call_np_linalg_qr, "np_linalg_qr", 3);
generate_linalg_extern_fn!(call_np_linalg_svd, "np_linalg_svd", 4);
generate_linalg_extern_fn!(call_np_linalg_inv, "np_linalg_inv", 2);
generate_linalg_extern_fn!(call_np_linalg_pinv, "np_linalg_pinv", 2);
generate_linalg_extern_fn!(call_np_linalg_matrix_power, "np_linalg_matrix_power", 3);
generate_linalg_extern_fn!(call_np_linalg_det, "np_linalg_det", 2);
generate_linalg_extern_fn!(call_sp_linalg_lu, "sp_linalg_lu", 3);
generate_linalg_extern_fn!(call_sp_linalg_schur, "sp_linalg_schur", 3);
generate_linalg_extern_fn!(call_sp_linalg_hessenberg, "sp_linalg_hessenberg", 3);
generate_linalg_extern_fn!(call_np_linalg_cholesky, np_linalg_cholesky, 2);
generate_linalg_extern_fn!(call_np_linalg_qr, np_linalg_qr, 3);
generate_linalg_extern_fn!(call_np_linalg_svd, np_linalg_svd, 4);
generate_linalg_extern_fn!(call_np_linalg_inv, np_linalg_inv, 2);
generate_linalg_extern_fn!(call_np_linalg_pinv, np_linalg_pinv, 2);
generate_linalg_extern_fn!(call_np_linalg_matrix_power, np_linalg_matrix_power, 3);
generate_linalg_extern_fn!(call_np_linalg_det, np_linalg_det, 2);
generate_linalg_extern_fn!(call_sp_linalg_lu, sp_linalg_lu, 3);
generate_linalg_extern_fn!(call_sp_linalg_schur, sp_linalg_schur, 3);
generate_linalg_extern_fn!(call_sp_linalg_hessenberg, sp_linalg_hessenberg, 3);

View File

@ -7,7 +7,7 @@ use inkwell::{
use nac3parser::ast::{Expr, Stmt, StrRef};
use super::{bool_to_i1, bool_to_i8, expr::*, stmt::*, values::ArraySliceValue, CodeGenContext};
use super::{bool_to_int_type, expr::*, stmt::*, values::ArraySliceValue, CodeGenContext};
use crate::{
symbol_resolver::ValueEnum,
toplevel::{DefinitionId, TopLevelDef},
@ -248,22 +248,32 @@ pub trait CodeGenerator {
gen_block(self, ctx, stmts)
}
/// See [`bool_to_i1`].
/// Converts the value of a boolean-like value `bool_value` into an `i1`.
fn bool_to_i1<'ctx>(
&self,
ctx: &CodeGenContext<'ctx, '_>,
bool_value: IntValue<'ctx>,
) -> IntValue<'ctx> {
bool_to_i1(&ctx.builder, bool_value)
self.bool_to_int_type(ctx, bool_value, ctx.ctx.bool_type())
}
/// See [`bool_to_i8`].
/// Converts the value of a boolean-like value `bool_value` into an `i8`.
fn bool_to_i8<'ctx>(
&self,
ctx: &CodeGenContext<'ctx, '_>,
bool_value: IntValue<'ctx>,
) -> IntValue<'ctx> {
bool_to_i8(&ctx.builder, ctx.ctx, bool_value)
self.bool_to_int_type(ctx, bool_value, ctx.ctx.i8_type())
}
/// See [`bool_to_int_type`].
fn bool_to_int_type<'ctx>(
&self,
ctx: &CodeGenContext<'ctx, '_>,
bool_value: IntValue<'ctx>,
ty: IntType<'ctx>,
) -> IntValue<'ctx> {
bool_to_int_type(&ctx.builder, bool_value, ty)
}
}

View File

@ -0,0 +1,130 @@
use inkwell::{
attributes::{Attribute, AttributeLoc},
values::{BasicValueEnum, FloatValue, IntValue},
};
use crate::codegen::{expr::infer_and_call_function, CodeGenContext};
/// Generates a call to [`isinf`](https://en.cppreference.com/w/c/numeric/math/isinf) in IR. Returns
/// an `i1` representing the result.
pub fn call_isinf<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
v: FloatValue<'ctx>,
name: Option<&str>,
) -> IntValue<'ctx> {
let llvm_i1 = ctx.ctx.bool_type();
let llvm_f64 = ctx.ctx.f64_type();
assert_eq!(v.get_type(), llvm_f64);
infer_and_call_function(ctx, "__nac3_isinf", Some(llvm_i1.into()), &[v.into()], name, None)
.map(BasicValueEnum::into_int_value)
.unwrap()
}
/// Generates a call to [`isnan`](https://en.cppreference.com/w/c/numeric/math/isnan) in IR. Returns
/// an `i1` representing the result.
pub fn call_isnan<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
v: FloatValue<'ctx>,
name: Option<&str>,
) -> IntValue<'ctx> {
let llvm_i1 = ctx.ctx.bool_type();
let llvm_f64 = ctx.ctx.f64_type();
assert_eq!(v.get_type(), llvm_f64);
infer_and_call_function(ctx, "__nac3_isnan", Some(llvm_i1.into()), &[v.into()], name, None)
.map(BasicValueEnum::into_int_value)
.unwrap()
}
/// Macro to generate N-ary functions accepting an arbitrary number of `f64` as arguments and
/// returning `f64`.
///
/// Arguments:
///
/// - `$fn_name:ident`: The name of the Rust function to be generated.
/// - `$builtin_fn:ident`: The name of the builtin function to be invoked in the body of the
/// generated function. The corresponding function in IRRT must be prefixed with `__nac3_`.
/// - `$(,$args:ident)*`: The parameter name(s) to the IRRT function.
macro_rules! generate_f64_nary_fn {
($fn_name:ident, $builtin_fn:ident $(,$args:ident)* $(,)?) => {
#[doc = concat!("Generates a call to [`", stringify!($builtin_fn), "`](https://en.cppreference.com/w/c/numeric/math/", stringify!($builtin_fn), ") in IR." )]
pub fn $fn_name<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
$($args: FloatValue<'ctx>,)*
name: Option<&str>,
) -> FloatValue<'ctx> {
const FN_NAME: &str = concat!("__nac3_", stringify!($builtin_fn));
let llvm_f64 = ctx.ctx.f64_type();
$(debug_assert_eq!($args.get_type(), llvm_f64);)*
infer_and_call_function(
ctx,
FN_NAME,
Some(llvm_f64.into()),
&[$($args.into()),*],
name,
Some(&|func| {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0)
);
}),
)
.map(BasicValueEnum::into_float_value)
.unwrap()
}
};
}
generate_f64_nary_fn!(call_tan, tan, arg);
generate_f64_nary_fn!(call_asin, asin, arg);
generate_f64_nary_fn!(call_acos, acos, arg);
generate_f64_nary_fn!(call_atan, atan, arg);
generate_f64_nary_fn!(call_sinh, sinh, arg);
generate_f64_nary_fn!(call_cosh, cosh, arg);
generate_f64_nary_fn!(call_tanh, tanh, arg);
generate_f64_nary_fn!(call_asinh, asinh, arg);
generate_f64_nary_fn!(call_acosh, acosh, arg);
generate_f64_nary_fn!(call_atanh, atanh, arg);
generate_f64_nary_fn!(call_expm1, expm1, arg);
generate_f64_nary_fn!(call_cbrt, cbrt, arg);
generate_f64_nary_fn!(call_erf, erf, arg);
generate_f64_nary_fn!(call_erfc, erfc, arg);
generate_f64_nary_fn!(call_atan2, atan2, y, x);
generate_f64_nary_fn!(call_hypot, hypot, x, y);
generate_f64_nary_fn!(call_nextafter, nextafter, from, to);
/// Invokes the [`ldexp`](https://en.cppreference.com/w/c/numeric/math/ldexp) function.
pub fn call_ldexp<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
arg: FloatValue<'ctx>,
exp: IntValue<'ctx>,
name: Option<&str>,
) -> FloatValue<'ctx> {
const FN_NAME: &str = "__nac3_ldexp";
let llvm_f64 = ctx.ctx.f64_type();
let llvm_i32 = ctx.ctx.i32_type();
debug_assert_eq!(arg.get_type(), llvm_f64);
debug_assert_eq!(exp.get_type(), llvm_i32);
infer_and_call_function(
ctx,
FN_NAME,
Some(llvm_f64.into()),
&[arg.into(), exp.into()],
name,
Some(&|func| {
func.add_attribute(
AttributeLoc::Function,
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id("nounwind"), 0),
);
}),
)
.map(BasicValueEnum::into_float_value)
.unwrap()
}

View File

@ -1,13 +1,14 @@
use inkwell::{
types::BasicTypeEnum,
values::{BasicValueEnum, CallSiteValue, IntValue},
values::{BasicValueEnum, IntValue},
AddressSpace, IntPredicate,
};
use itertools::Either;
use super::calculate_len_for_slice_range;
use crate::codegen::{
expr::infer_and_call_function,
macros::codegen_unreachable,
stmt::gen_if_callback,
values::{ArrayLikeValue, ListValue},
CodeGenContext, CodeGenerator,
};
@ -36,25 +37,6 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>(
assert_eq!(src_idx.2.get_type(), llvm_i32);
let (fun_symbol, elem_ptr_type) = ("__nac3_list_slice_assign_var_size", llvm_pi8);
let slice_assign_fun = {
let ty_vec = vec![
llvm_i32.into(), // dest start idx
llvm_i32.into(), // dest end idx
llvm_i32.into(), // dest step
elem_ptr_type.into(), // dest arr ptr
llvm_i32.into(), // dest arr len
llvm_i32.into(), // src start idx
llvm_i32.into(), // src end idx
llvm_i32.into(), // src step
elem_ptr_type.into(), // src arr ptr
llvm_i32.into(), // src arr len
llvm_i32.into(), // size
];
ctx.module.get_function(fun_symbol).unwrap_or_else(|| {
let fn_t = llvm_i32.fn_type(ty_vec.as_slice(), false);
ctx.module.add_function(fun_symbol, fn_t, None)
})
};
let zero = llvm_i32.const_zero();
let one = llvm_i32.const_int(1, false);
@ -127,7 +109,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>(
);
let new_len = {
let args = vec![
let args = [
dest_idx.0.into(), // dest start idx
dest_idx.1.into(), // dest end idx
dest_idx.2.into(), // dest step
@ -150,25 +132,35 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>(
}
.into(),
];
ctx.builder
.build_call(slice_assign_fun, args.as_slice(), "slice_assign")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
fun_symbol,
Some(llvm_i32.into()),
&args,
Some("slice_assign"),
None,
)
.map(BasicValueEnum::into_int_value)
.unwrap()
};
// update length
let need_update =
ctx.builder.build_int_compare(IntPredicate::NE, new_len, dest_len, "need_update").unwrap();
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
let update_bb = ctx.ctx.append_basic_block(current, "update");
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
ctx.builder.build_conditional_branch(need_update, update_bb, cont_bb).unwrap();
ctx.builder.position_at_end(update_bb);
let new_len =
ctx.builder.build_int_z_extend_or_bit_cast(new_len, llvm_usize, "new_len").unwrap();
dest_arr.store_size(ctx, new_len);
ctx.builder.build_unconditional_branch(cont_bb).unwrap();
ctx.builder.position_at_end(cont_bb);
gen_if_callback(
generator,
ctx,
|_, ctx| {
Ok(ctx
.builder
.build_int_compare(IntPredicate::NE, new_len, dest_len, "need_update")
.unwrap())
},
|_, ctx| {
let new_len =
ctx.builder.build_int_z_extend_or_bit_cast(new_len, llvm_usize, "new_len").unwrap();
dest_arr.store_size(ctx, new_len);
Ok(())
},
|_, _| Ok(()),
)
.unwrap();
}

View File

@ -1,10 +1,10 @@
use inkwell::{
values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue},
values::{BasicValueEnum, FloatValue, IntValue},
IntPredicate,
};
use itertools::Either;
use crate::codegen::{
expr::infer_and_call_function,
macros::codegen_unreachable,
{CodeGenContext, CodeGenerator},
};
@ -18,18 +18,16 @@ pub fn integer_power<'ctx, G: CodeGenerator + ?Sized>(
exp: IntValue<'ctx>,
signed: bool,
) -> IntValue<'ctx> {
let symbol = match (base.get_type().get_bit_width(), exp.get_type().get_bit_width(), signed) {
let base_type = base.get_type();
let symbol = match (base_type.get_bit_width(), exp.get_type().get_bit_width(), signed) {
(32, 32, true) => "__nac3_int_exp_int32_t",
(64, 64, true) => "__nac3_int_exp_int64_t",
(32, 32, false) => "__nac3_int_exp_uint32_t",
(64, 64, false) => "__nac3_int_exp_uint64_t",
_ => codegen_unreachable!(ctx),
};
let base_type = base.get_type();
let pow_fun = ctx.module.get_function(symbol).unwrap_or_else(|| {
let fn_type = base_type.fn_type(&[base_type.into(), base_type.into()], false);
ctx.module.add_function(symbol, fn_type, None)
});
// throw exception when exp < 0
let ge_zero = ctx
.builder
@ -48,66 +46,17 @@ pub fn integer_power<'ctx, G: CodeGenerator + ?Sized>(
[None, None, None],
ctx.current_loc,
);
ctx.builder
.build_call(pow_fun, &[base.into(), exp.into()], "call_int_pow")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap()
}
/// Generates a call to `isinf` in IR. Returns an `i1` representing the result.
pub fn call_isinf<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>,
v: FloatValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_i32 = ctx.ctx.i32_type();
let llvm_f64 = ctx.ctx.f64_type();
assert_eq!(v.get_type(), llvm_f64);
let intrinsic_fn = ctx.module.get_function("__nac3_isinf").unwrap_or_else(|| {
let fn_type = llvm_i32.fn_type(&[llvm_f64.into()], false);
ctx.module.add_function("__nac3_isinf", fn_type, None)
});
let ret = ctx
.builder
.build_call(intrinsic_fn, &[v.into()], "isinf")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap();
generator.bool_to_i1(ctx, ret)
}
/// Generates a call to `isnan` in IR. Returns an `i1` representing the result.
pub fn call_isnan<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>,
v: FloatValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_i32 = ctx.ctx.i32_type();
let llvm_f64 = ctx.ctx.f64_type();
assert_eq!(v.get_type(), llvm_f64);
let intrinsic_fn = ctx.module.get_function("__nac3_isnan").unwrap_or_else(|| {
let fn_type = llvm_i32.fn_type(&[llvm_f64.into()], false);
ctx.module.add_function("__nac3_isnan", fn_type, None)
});
let ret = ctx
.builder
.build_call(intrinsic_fn, &[v.into()], "isnan")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap();
generator.bool_to_i1(ctx, ret)
infer_and_call_function(
ctx,
symbol,
Some(base_type.into()),
&[base.into(), exp.into()],
Some("call_int_pow"),
None,
)
.map(BasicValueEnum::into_int_value)
.unwrap()
}
/// Generates a call to `gamma` in IR. Returns an `f64` representing the result.
@ -116,17 +65,16 @@ pub fn call_gamma<'ctx>(ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>) ->
assert_eq!(v.get_type(), llvm_f64);
let intrinsic_fn = ctx.module.get_function("__nac3_gamma").unwrap_or_else(|| {
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
ctx.module.add_function("__nac3_gamma", fn_type, None)
});
ctx.builder
.build_call(intrinsic_fn, &[v.into()], "gamma")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_float_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
"__nac3_gamma",
Some(llvm_f64.into()),
&[v.into()],
Some("gamma"),
None,
)
.map(BasicValueEnum::into_float_value)
.unwrap()
}
/// Generates a call to `gammaln` in IR. Returns an `f64` representing the result.
@ -135,17 +83,16 @@ pub fn call_gammaln<'ctx>(ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>) -
assert_eq!(v.get_type(), llvm_f64);
let intrinsic_fn = ctx.module.get_function("__nac3_gammaln").unwrap_or_else(|| {
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
ctx.module.add_function("__nac3_gammaln", fn_type, None)
});
ctx.builder
.build_call(intrinsic_fn, &[v.into()], "gammaln")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_float_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
"__nac3_gammaln",
Some(llvm_f64.into()),
&[v.into()],
Some("gammaln"),
None,
)
.map(BasicValueEnum::into_float_value)
.unwrap()
}
/// Generates a call to `j0` in IR. Returns an `f64` representing the result.
@ -154,15 +101,7 @@ pub fn call_j0<'ctx>(ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>) -> Flo
assert_eq!(v.get_type(), llvm_f64);
let intrinsic_fn = ctx.module.get_function("__nac3_j0").unwrap_or_else(|| {
let fn_type = llvm_f64.fn_type(&[llvm_f64.into()], false);
ctx.module.add_function("__nac3_j0", fn_type, None)
});
ctx.builder
.build_call(intrinsic_fn, &[v.into()], "j0")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_float_value))
.map(Either::unwrap_left)
infer_and_call_function(ctx, "__nac3_j0", Some(llvm_f64.into()), &[v.into()], Some("j0"), None)
.map(BasicValueEnum::into_float_value)
.unwrap()
}

View File

@ -11,12 +11,14 @@ use nac3parser::ast::Expr;
use super::{CodeGenContext, CodeGenerator};
use crate::{symbol_resolver::SymbolResolver, typecheck::typedef::Type};
pub use cc_builtins::*;
pub use list::*;
pub use math::*;
pub use range::*;
pub use slice::*;
pub use string::*;
mod cc_builtins;
mod list;
mod math;
pub mod ndarray;

View File

@ -1,13 +1,11 @@
use inkwell::{
types::BasicTypeEnum,
values::{BasicValueEnum, IntValue, PointerValue},
AddressSpace,
};
use crate::codegen::{
expr::{create_and_call_function, infer_and_call_function},
expr::infer_and_call_function,
irrt::get_usize_dependent_function_name,
types::ProxyType,
values::{ndarray::NDArrayValue, ProxyValue, TypedArrayLikeAccessor},
CodeGenContext, CodeGenerator,
};
@ -21,24 +19,17 @@ pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator +
shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
) {
let llvm_usize = ctx.get_size_type();
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
assert_eq!(
BasicTypeEnum::try_from(shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(shape.element_type(ctx, generator), llvm_usize.into());
let name =
get_usize_dependent_function_name(ctx, "__nac3_ndarray_util_assert_shape_no_negative");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_usize.into()),
&[
(llvm_usize.into(), shape.size(ctx, generator).into()),
(llvm_pusize.into(), shape.base_ptr(ctx, generator).into()),
],
&[shape.size(ctx, generator).into(), shape.base_ptr(ctx, generator).into()],
None,
None,
);
@ -55,29 +46,22 @@ pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator +
output_shape: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
) {
let llvm_usize = ctx.get_size_type();
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
assert_eq!(
BasicTypeEnum::try_from(ndarray_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(
BasicTypeEnum::try_from(output_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(ndarray_shape.element_type(ctx, generator), llvm_usize.into());
assert_eq!(output_shape.element_type(ctx, generator), llvm_usize.into());
let name =
get_usize_dependent_function_name(ctx, "__nac3_ndarray_util_assert_output_shape_same");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_usize.into()),
&[
(llvm_usize.into(), ndarray_shape.size(ctx, generator).into()),
(llvm_pusize.into(), ndarray_shape.base_ptr(ctx, generator).into()),
(llvm_usize.into(), output_shape.size(ctx, generator).into()),
(llvm_pusize.into(), output_shape.base_ptr(ctx, generator).into()),
ndarray_shape.size(ctx, generator).into(),
ndarray_shape.base_ptr(ctx, generator).into(),
output_shape.size(ctx, generator).into(),
output_shape.base_ptr(ctx, generator).into(),
],
None,
None,
@ -93,15 +77,14 @@ pub fn call_nac3_ndarray_size<'ctx>(
ndarray: NDArrayValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_usize = ctx.get_size_type();
let llvm_ndarray = ndarray.get_type();
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_size");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_usize.into()),
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
&[ndarray.as_abi_value(ctx).into()],
Some("size"),
None,
)
@ -118,15 +101,14 @@ pub fn call_nac3_ndarray_nbytes<'ctx>(
ndarray: NDArrayValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_usize = ctx.get_size_type();
let llvm_ndarray = ndarray.get_type();
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_nbytes");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_usize.into()),
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
&[ndarray.as_abi_value(ctx).into()],
Some("nbytes"),
None,
)
@ -143,15 +125,14 @@ pub fn call_nac3_ndarray_len<'ctx>(
ndarray: NDArrayValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_usize = ctx.get_size_type();
let llvm_ndarray = ndarray.get_type();
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_len");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_usize.into()),
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
&[ndarray.as_abi_value(ctx).into()],
Some("len"),
None,
)
@ -167,15 +148,14 @@ pub fn call_nac3_ndarray_is_c_contiguous<'ctx>(
ndarray: NDArrayValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_i1 = ctx.ctx.bool_type();
let llvm_ndarray = ndarray.get_type();
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_is_c_contiguous");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_i1.into()),
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
&[ndarray.as_abi_value(ctx).into()],
Some("is_c_contiguous"),
None,
)
@ -194,20 +174,16 @@ pub fn call_nac3_ndarray_get_nth_pelement<'ctx>(
let llvm_i8 = ctx.ctx.i8_type();
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
let llvm_usize = ctx.get_size_type();
let llvm_ndarray = ndarray.get_type();
assert_eq!(index.get_type(), llvm_usize);
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_get_nth_pelement");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_pi8.into()),
&[
(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
(llvm_usize.into(), index.into()),
],
&[ndarray.as_abi_value(ctx).into(), index.into()],
Some("pelement"),
None,
)
@ -229,24 +205,16 @@ pub fn call_nac3_ndarray_get_pelement_by_indices<'ctx, G: CodeGenerator + ?Sized
let llvm_i8 = ctx.ctx.i8_type();
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
let llvm_usize = ctx.get_size_type();
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
let llvm_ndarray = ndarray.get_type();
assert_eq!(
BasicTypeEnum::try_from(indices.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(indices.element_type(ctx, generator), llvm_usize.into());
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_get_pelement_by_indices");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
Some(llvm_pi8.into()),
&[
(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
],
&[ndarray.as_abi_value(ctx).into(), indices.base_ptr(ctx, generator).into()],
Some("pelement"),
None,
)
@ -261,18 +229,9 @@ pub fn call_nac3_ndarray_set_strides_by_shape<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
ndarray: NDArrayValue<'ctx>,
) {
let llvm_ndarray = ndarray.get_type();
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_set_strides_by_shape");
create_and_call_function(
ctx,
&name,
None,
&[(llvm_ndarray.as_abi_type().into(), ndarray.as_abi_value(ctx).into())],
None,
None,
);
infer_and_call_function(ctx, &name, None, &[ndarray.as_abi_value(ctx).into()], None, None);
}
/// Generates a call to `__nac3_ndarray_copy_data`.

View File

@ -1,13 +1,8 @@
use inkwell::{
types::BasicTypeEnum,
values::{BasicValueEnum, IntValue},
AddressSpace,
};
use inkwell::values::{BasicValueEnum, IntValue};
use crate::codegen::{
expr::{create_and_call_function, infer_and_call_function},
expr::infer_and_call_function,
irrt::get_usize_dependent_function_name,
types::ProxyType,
values::{
ndarray::{NDArrayValue, NDIterValue},
ProxyValue, TypedArrayLikeAccessor,
@ -26,23 +21,19 @@ pub fn call_nac3_nditer_initialize<'ctx, G: CodeGenerator + ?Sized>(
indices: &impl TypedArrayLikeAccessor<'ctx, G, IntValue<'ctx>>,
) {
let llvm_usize = ctx.get_size_type();
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
assert_eq!(
BasicTypeEnum::try_from(indices.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(indices.element_type(ctx, generator), llvm_usize.into());
let name = get_usize_dependent_function_name(ctx, "__nac3_nditer_initialize");
create_and_call_function(
infer_and_call_function(
ctx,
&name,
None,
&[
(iter.get_type().as_abi_type().into(), iter.as_abi_value(ctx).into()),
(ndarray.get_type().as_abi_type().into(), ndarray.as_abi_value(ctx).into()),
(llvm_pusize.into(), indices.base_ptr(ctx, generator).into()),
iter.as_abi_value(ctx).into(),
ndarray.as_abi_value(ctx).into(),
indices.base_ptr(ctx, generator).into(),
],
None,
None,

View File

@ -1,4 +1,4 @@
use inkwell::{types::BasicTypeEnum, values::IntValue};
use inkwell::values::IntValue;
use crate::codegen::{
expr::infer_and_call_function, irrt::get_usize_dependent_function_name,
@ -22,26 +22,12 @@ pub fn call_nac3_ndarray_matmul_calculate_shapes<'ctx, G: CodeGenerator + ?Sized
) {
let llvm_usize = ctx.get_size_type();
assert_eq!(
BasicTypeEnum::try_from(a_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(
BasicTypeEnum::try_from(b_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(
BasicTypeEnum::try_from(new_a_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(
BasicTypeEnum::try_from(new_b_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(
BasicTypeEnum::try_from(dst_shape.element_type(ctx, generator)).unwrap(),
llvm_usize.into()
);
assert_eq!(a_shape.element_type(ctx, generator), llvm_usize.into());
assert_eq!(b_shape.element_type(ctx, generator), llvm_usize.into());
assert_eq!(final_ndims.get_type(), llvm_usize);
assert_eq!(new_a_shape.element_type(ctx, generator), llvm_usize.into());
assert_eq!(new_b_shape.element_type(ctx, generator), llvm_usize.into());
assert_eq!(dst_shape.element_type(ctx, generator), llvm_usize.into());
let name = get_usize_dependent_function_name(ctx, "__nac3_ndarray_matmul_calculate_shapes");

View File

@ -1,10 +1,9 @@
use inkwell::{
values::{BasicValueEnum, CallSiteValue, IntValue},
values::{BasicValueEnum, IntValue},
IntPredicate,
};
use itertools::Either;
use crate::codegen::{CodeGenContext, CodeGenerator};
use crate::codegen::{expr::infer_and_call_function, CodeGenContext, CodeGenerator};
/// Invokes the `__nac3_range_slice_len` in IRRT.
///
@ -23,16 +22,10 @@ pub fn calculate_len_for_slice_range<'ctx, G: CodeGenerator + ?Sized>(
const SYMBOL: &str = "__nac3_range_slice_len";
let llvm_i32 = ctx.ctx.i32_type();
assert_eq!(start.get_type(), llvm_i32);
assert_eq!(end.get_type(), llvm_i32);
assert_eq!(step.get_type(), llvm_i32);
let len_func = ctx.module.get_function(SYMBOL).unwrap_or_else(|| {
let fn_t = llvm_i32.fn_type(&[llvm_i32.into(), llvm_i32.into(), llvm_i32.into()], false);
ctx.module.add_function(SYMBOL, fn_t, None)
});
// assert step != 0, throw exception if not
let not_zero = ctx
.builder
@ -47,10 +40,14 @@ pub fn calculate_len_for_slice_range<'ctx, G: CodeGenerator + ?Sized>(
ctx.current_loc,
);
ctx.builder
.build_call(len_func, &[start.into(), end.into(), step.into()], "calc_len")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
SYMBOL,
Some(llvm_i32.into()),
&[start.into(), end.into(), step.into()],
Some("calc_len"),
None,
)
.map(BasicValueEnum::into_int_value)
.unwrap()
}

View File

@ -1,10 +1,9 @@
use inkwell::values::{BasicValueEnum, CallSiteValue, IntValue};
use itertools::Either;
use inkwell::values::{BasicValueEnum, IntValue};
use nac3parser::ast::Expr;
use crate::{
codegen::{CodeGenContext, CodeGenerator},
codegen::{expr::infer_and_call_function, CodeGenContext, CodeGenerator},
typecheck::typedef::Type,
};
@ -17,23 +16,26 @@ pub fn handle_slice_index_bound<'ctx, G: CodeGenerator>(
length: IntValue<'ctx>,
) -> Result<Option<IntValue<'ctx>>, String> {
const SYMBOL: &str = "__nac3_slice_index_bound";
let func = ctx.module.get_function(SYMBOL).unwrap_or_else(|| {
let i32_t = ctx.ctx.i32_type();
let fn_t = i32_t.fn_type(&[i32_t.into(), i32_t.into()], false);
ctx.module.add_function(SYMBOL, fn_t, None)
});
let llvm_i32 = ctx.ctx.i32_type();
assert_eq!(length.get_type(), llvm_i32);
let i = if let Some(v) = generator.gen_expr(ctx, i)? {
v.to_basic_value_enum(ctx, generator, i.custom.unwrap())?
} else {
return Ok(None);
};
Ok(Some(
ctx.builder
.build_call(func, &[i.into(), length.into()], "bounded_ind")
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap(),
infer_and_call_function(
ctx,
SYMBOL,
Some(llvm_i32.into()),
&[i, length.into()],
Some("bounded_ind"),
None,
)
.map(BasicValueEnum::into_int_value)
.unwrap(),
))
}

View File

@ -1,45 +1,31 @@
use inkwell::values::{BasicValueEnum, CallSiteValue, IntValue, PointerValue};
use itertools::Either;
use inkwell::values::{BasicValueEnum, IntValue};
use super::get_usize_dependent_function_name;
use crate::codegen::CodeGenContext;
use crate::codegen::{expr::infer_and_call_function, values::StringValue, CodeGenContext};
/// Generates a call to string equality comparison. Returns an `i1` representing whether the strings are equal.
pub fn call_string_eq<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
str1_ptr: PointerValue<'ctx>,
str1_len: IntValue<'ctx>,
str2_ptr: PointerValue<'ctx>,
str2_len: IntValue<'ctx>,
str1: StringValue<'ctx>,
str2: StringValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_i1 = ctx.ctx.bool_type();
let func_name = get_usize_dependent_function_name(ctx, "nac3_str_eq");
let func = ctx.module.get_function(&func_name).unwrap_or_else(|| {
ctx.module.add_function(
&func_name,
llvm_i1.fn_type(
&[
str1_ptr.get_type().into(),
str1_len.get_type().into(),
str2_ptr.get_type().into(),
str2_len.get_type().into(),
],
false,
),
None,
)
});
ctx.builder
.build_call(
func,
&[str1_ptr.into(), str1_len.into(), str2_ptr.into(), str2_len.into()],
"str_eq_call",
)
.map(CallSiteValue::try_as_basic_value)
.map(|v| v.map_left(BasicValueEnum::into_int_value))
.map(Either::unwrap_left)
.unwrap()
infer_and_call_function(
ctx,
&func_name,
Some(llvm_i1.into()),
&[
str1.extract_ptr(ctx).into(),
str1.extract_len(ctx).into(),
str2.extract_ptr(ctx).into(),
str2.extract_len(ctx).into(),
],
Some("str_eq_call"),
None,
)
.map(BasicValueEnum::into_int_value)
.unwrap()
}

View File

@ -98,41 +98,29 @@ pub fn call_stackrestore<'ctx>(ctx: &CodeGenContext<'ctx, '_>, ptr: PointerValue
/// * `dest` - The pointer to the destination. Must be a pointer to an integer type.
/// * `src` - The pointer to the source. Must be a pointer to an integer type.
/// * `len` - The number of bytes to copy.
/// * `is_volatile` - Whether the `memcpy` operation should be `volatile`.
pub fn call_memcpy<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
dest: PointerValue<'ctx>,
src: PointerValue<'ctx>,
len: IntValue<'ctx>,
is_volatile: IntValue<'ctx>,
) {
const FN_NAME: &str = "llvm.memcpy";
debug_assert!(dest.get_type().get_element_type().is_int_type());
debug_assert!(src.get_type().get_element_type().is_int_type());
debug_assert_eq!(
dest.get_type().get_element_type().into_int_type().get_bit_width(),
src.get_type().get_element_type().into_int_type().get_bit_width(),
);
debug_assert!(matches!(len.get_type().get_bit_width(), 32 | 64));
debug_assert_eq!(is_volatile.get_type().get_bit_width(), 1);
debug_assert_eq!(len.get_type(), ctx.get_size_type());
let llvm_dest_t = dest.get_type();
let llvm_src_t = src.get_type();
let llvm_len_t = len.get_type();
let intrinsic_fn = Intrinsic::find(FN_NAME)
.and_then(|intrinsic| {
intrinsic.get_declaration(
&ctx.module,
&[llvm_dest_t.into(), llvm_src_t.into(), llvm_len_t.into()],
)
})
.unwrap();
let target_data =
ctx.registry.llvm_options.create_target_machine().map(|tm| tm.get_target_data()).unwrap();
let dest_alignment = target_data.get_abi_alignment(&llvm_dest_t);
let src_alignment = target_data.get_abi_alignment(&llvm_src_t);
ctx.builder
.build_call(intrinsic_fn, &[dest.into(), src.into(), len.into(), is_volatile.into()], "")
.unwrap();
ctx.builder.build_memcpy(dest, dest_alignment, src, src_alignment, len).unwrap();
}
/// Invokes the `llvm.memcpy` intrinsic.
@ -144,7 +132,6 @@ pub fn call_memcpy_generic<'ctx>(
dest: PointerValue<'ctx>,
src: PointerValue<'ctx>,
len: IntValue<'ctx>,
is_volatile: IntValue<'ctx>,
) {
let llvm_i8 = ctx.ctx.i8_type();
let llvm_p0i8 = llvm_i8.ptr_type(AddressSpace::default());
@ -169,7 +156,7 @@ pub fn call_memcpy_generic<'ctx>(
.unwrap()
};
call_memcpy(ctx, dest, src, len, is_volatile);
call_memcpy(ctx, dest, src, len);
}
/// Invokes the `llvm.memcpy` intrinsic.
@ -183,11 +170,10 @@ pub fn call_memcpy_generic_array<'ctx>(
dest: PointerValue<'ctx>,
src: PointerValue<'ctx>,
len: IntValue<'ctx>,
is_volatile: IntValue<'ctx>,
) {
let llvm_i8 = ctx.ctx.i8_type();
let llvm_p0i8 = llvm_i8.ptr_type(AddressSpace::default());
let llvm_sizeof_expr_t = llvm_i8.size_of().get_type();
let llvm_usize = ctx.get_size_type();
let dest_elem_t = dest.get_type().get_element_type();
let src_elem_t = src.get_type().get_element_type();
@ -209,10 +195,13 @@ pub fn call_memcpy_generic_array<'ctx>(
.unwrap()
};
let len = ctx.builder.build_int_z_extend_or_bit_cast(len, llvm_sizeof_expr_t, "").unwrap();
let len = ctx.builder.build_int_mul(len, src_elem_t.size_of().unwrap(), "").unwrap();
let sizeof_elem = ctx
.builder
.build_int_truncate_or_bit_cast(src_elem_t.size_of().unwrap(), llvm_usize, "")
.unwrap();
let len = ctx.builder.build_int_mul(len, sizeof_elem, "").unwrap();
call_memcpy(ctx, dest, src, len, is_volatile);
call_memcpy(ctx, dest, src, len);
}
/// Macro to find and generate build call for llvm intrinsic (body of llvm intrinsic function)

View File

@ -43,7 +43,10 @@ use crate::{
};
use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore};
pub use generator::{CodeGenerator, DefaultCodeGenerator};
use types::{ndarray::NDArrayType, ListType, ProxyType, RangeType, TupleType};
use types::{
ndarray::NDArrayType, ExceptionType, ListType, OptionType, ProxyType, RangeType, StringType,
TupleType,
};
pub mod builtin_fns;
pub mod concrete_type;
@ -538,7 +541,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
if PrimDef::contains_id(*obj_id) {
return match &*unifier.get_ty_immutable(ty) {
TObj { obj_id, params, .. } if *obj_id == PrimDef::Option.id() => {
get_llvm_type(
let element_type = get_llvm_type(
ctx,
module,
generator,
@ -546,9 +549,9 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
top_level,
type_cache,
*params.iter().next().unwrap().1,
)
.ptr_type(AddressSpace::default())
.into()
);
OptionType::new_with_generator(generator, ctx, &element_type).as_abi_type().into()
}
TObj { obj_id, params, .. } if *obj_id == PrimDef::List.id() => {
@ -786,34 +789,11 @@ pub fn gen_func_impl<
(primitives.float, context.f64_type().into()),
(primitives.bool, context.i8_type().into()),
(primitives.str, {
let name = "str";
match module.get_struct_type(name) {
None => {
let str_type = context.opaque_struct_type("str");
let fields = [
context.i8_type().ptr_type(AddressSpace::default()).into(),
generator.get_size_type(context).into(),
];
str_type.set_body(&fields, false);
str_type.into()
}
Some(t) => t.as_basic_type_enum(),
}
StringType::new_with_generator(generator, context).as_abi_type().into()
}),
(primitives.range, RangeType::new_with_generator(generator, context).as_abi_type().into()),
(primitives.exception, {
let name = "Exception";
if let Some(t) = module.get_struct_type(name) {
t.ptr_type(AddressSpace::default()).as_basic_type_enum()
} else {
let exception = context.opaque_struct_type("Exception");
let int32 = context.i32_type().into();
let int64 = context.i64_type().into();
let str_ty = module.get_struct_type("str").unwrap().as_basic_type_enum();
let fields = [int32, str_ty, int32, int32, str_ty, str_ty, int64, int64, int64];
exception.set_body(&fields, false);
exception.ptr_type(AddressSpace::default()).as_basic_type_enum()
}
ExceptionType::new_with_generator(generator, context).as_abi_type().into()
}),
]
.iter()
@ -933,7 +913,7 @@ pub fn gen_func_impl<
let param_val = param.into_int_value();
if expected_ty.get_bit_width() == 8 && param_val.get_type().get_bit_width() == 1 {
bool_to_i8(&builder, context, param_val)
bool_to_int_type(&builder, param_val, context.i8_type())
} else {
param_val
}
@ -1103,43 +1083,29 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
})
}
/// Converts the value of a boolean-like value `bool_value` into an `i1`.
fn bool_to_i1<'ctx>(builder: &Builder<'ctx>, bool_value: IntValue<'ctx>) -> IntValue<'ctx> {
if bool_value.get_type().get_bit_width() == 1 {
bool_value
} else {
builder
.build_int_compare(
IntPredicate::NE,
bool_value,
bool_value.get_type().const_zero(),
"tobool",
)
.unwrap()
}
}
/// Converts the value of a boolean-like value `bool_value` into an `i8`.
fn bool_to_i8<'ctx>(
/// Converts the value of a boolean-like value `value` into an arbitrary [`IntType`].
///
/// This has the same semantics as `(ty)(value != 0)` in C.
///
/// The returned value is guaranteed to either be `0` or `1`, except for `ty == i1` where only the
/// least-significant bit would be guaranteed to be `0` or `1`.
fn bool_to_int_type<'ctx>(
builder: &Builder<'ctx>,
ctx: &'ctx Context,
bool_value: IntValue<'ctx>,
value: IntValue<'ctx>,
ty: IntType<'ctx>,
) -> IntValue<'ctx> {
let value_bits = bool_value.get_type().get_bit_width();
match value_bits {
8 => bool_value,
1 => builder.build_int_z_extend(bool_value, ctx.i8_type(), "frombool").unwrap(),
_ => bool_to_i8(
// i1 -> i1 : %value ; no-op
// i1 -> i<N> : zext i1 %value to i<N> ; guaranteed to be 0 or 1 - see docs
// i<M> -> i<N>: zext i1 (icmp eq i<M> %value, 0) to i<N> ; same as i<M> -> i1 -> i<N>
match (value.get_type().get_bit_width(), ty.get_bit_width()) {
(1, 1) => value,
(1, _) => builder.build_int_z_extend(value, ty, "frombool").unwrap(),
_ => bool_to_int_type(
builder,
ctx,
builder
.build_int_compare(
IntPredicate::NE,
bool_value,
bool_value.get_type().const_zero(),
"",
)
.build_int_compare(IntPredicate::NE, value, value.get_type().const_zero(), "tobool")
.unwrap(),
ty,
),
}
}

View File

@ -0,0 +1,36 @@
---
source: nac3core/src/codegen/test.rs
expression: "module.print_to_string().to_str().map(str::trim).unwrap()"
---
; ModuleID = 'test'
source_filename = "test"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define i32 @testing(i32 %0, i32 %1) local_unnamed_addr #0 !dbg !4 {
init:
%add = add i32 %1, %0, !dbg !9
%cmp = icmp eq i32 %add, 1, !dbg !10
%. = select i1 %cmp, i32 %0, i32 0, !dbg !11
ret i32 %., !dbg !12
}
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 2, !"Dwarf Version", i32 4}
!2 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: "NAC3", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !DIFile(filename: "unknown", directory: "")
!4 = distinct !DISubprogram(name: "testing", linkageName: "testing", scope: null, file: !3, line: 1, type: !5, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !8)
!5 = !DISubroutineType(flags: DIFlagPublic, types: !6)
!6 = !{!7}
!7 = !DIBasicType(name: "_", flags: DIFlagPublic)
!8 = !{}
!9 = !DILocation(line: 1, column: 9, scope: !4)
!10 = !DILocation(line: 2, column: 15, scope: !4)
!11 = !DILocation(line: 2, scope: !4)
!12 = !DILocation(line: 3, column: 8, scope: !4)

View File

@ -0,0 +1,42 @@
---
source: nac3core/src/codegen/test.rs
expression: "module.print_to_string().to_str().map(str::trim).unwrap()"
---
; ModuleID = 'test'
source_filename = "test"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define i32 @testing(i32 %0) local_unnamed_addr #0 !dbg !5 {
init:
%add.i = shl i32 %0, 1, !dbg !10
%mul = add i32 %add.i, 2, !dbg !10
ret i32 %mul, !dbg !10
}
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
define i32 @foo.0(i32 %0) local_unnamed_addr #0 !dbg !11 {
init:
%add = add i32 %0, 1, !dbg !12
ret i32 %add, !dbg !12
}
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2, !4}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 2, !"Dwarf Version", i32 4}
!2 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: "NAC3", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !DIFile(filename: "unknown", directory: "")
!4 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: "NAC3", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!5 = distinct !DISubprogram(name: "testing", linkageName: "testing", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !9)
!6 = !DISubroutineType(flags: DIFlagPublic, types: !7)
!7 = !{!8}
!8 = !DIBasicType(name: "_", flags: DIFlagPublic)
!9 = !{}
!10 = !DILocation(line: 2, column: 12, scope: !5)
!11 = distinct !DISubprogram(name: "foo.0", linkageName: "foo.0", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, retainedNodes: !9)
!12 = !DILocation(line: 1, column: 12, scope: !11)

View File

@ -17,10 +17,10 @@ use super::{
gen_in_range_check,
irrt::{handle_slice_indices, list_slice_assignment},
macros::codegen_unreachable,
types::{ndarray::NDArrayType, RangeType},
types::{ndarray::NDArrayType, ExceptionType, RangeType},
values::{
ndarray::{RustNDIndex, ScalarOrNDArray},
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue,
ArrayLikeIndexer, ArraySliceValue, ExceptionValue, ListValue, ProxyValue,
},
CodeGenContext, CodeGenerator,
};
@ -1337,43 +1337,19 @@ pub fn exn_constructor<'ctx>(
pub fn gen_raise<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
exception: Option<&BasicValueEnum<'ctx>>,
exception: Option<&ExceptionValue<'ctx>>,
loc: Location,
) {
if let Some(exception) = exception {
unsafe {
let int32 = ctx.ctx.i32_type();
let zero = int32.const_zero();
let exception = exception.into_pointer_value();
let file_ptr = ctx
.builder
.build_in_bounds_gep(exception, &[zero, int32.const_int(1, false)], "file_ptr")
.unwrap();
let filename = ctx.gen_string(generator, loc.file.0);
ctx.builder.build_store(file_ptr, filename).unwrap();
let row_ptr = ctx
.builder
.build_in_bounds_gep(exception, &[zero, int32.const_int(2, false)], "row_ptr")
.unwrap();
ctx.builder.build_store(row_ptr, int32.const_int(loc.row as u64, false)).unwrap();
let col_ptr = ctx
.builder
.build_in_bounds_gep(exception, &[zero, int32.const_int(3, false)], "col_ptr")
.unwrap();
ctx.builder.build_store(col_ptr, int32.const_int(loc.column as u64, false)).unwrap();
exception.store_location(generator, ctx, loc);
let current_fun = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
let fun_name = ctx.gen_string(generator, current_fun.get_name().to_str().unwrap());
let name_ptr = ctx
.builder
.build_in_bounds_gep(exception, &[zero, int32.const_int(4, false)], "name_ptr")
.unwrap();
ctx.builder.build_store(name_ptr, fun_name).unwrap();
}
let current_fun = ctx.builder.get_insert_block().and_then(BasicBlock::get_parent).unwrap();
let fun_name = ctx.gen_string(generator, current_fun.get_name().to_str().unwrap());
exception.store_func(ctx, fun_name);
let raise = get_builtins(generator, ctx, "__nac3_raise");
let exception = *exception;
ctx.build_call_or_invoke(raise, &[exception], "raise");
ctx.build_call_or_invoke(raise, &[exception.as_abi_value(ctx).into()], "raise");
} else {
let resume = get_builtins(generator, ctx, "__nac3_resume");
ctx.build_call_or_invoke(resume, &[], "resume");
@ -1712,13 +1688,259 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
}
/// See [`CodeGenerator::gen_with`].
pub fn gen_with<G: CodeGenerator>(
_: &mut G,
_: &mut CodeGenContext<'_, '_>,
pub fn gen_with<'ctx, 'a, G: CodeGenerator>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, 'a>,
stmt: &Stmt<Option<Type>>,
) -> Result<(), String> {
// TODO: Implement with statement after finishing exceptions
Err(format!("With statement with custom types is not yet supported (at {})", stmt.location))
let StmtKind::With { items, body, .. } = &stmt.node else { codegen_unreachable!(ctx) };
let mut exits = vec![];
let mut enters = vec![];
// prepare enters and exits
for item in items {
// evaluate the expression first
let expr_ty = item.context_expr.custom.unwrap();
let expr = generator.gen_expr(ctx, &item.context_expr)?.unwrap();
// get the __enter__ method signature and ID
let TypeEnum::TObj { obj_id, fields, .. } = &*ctx.unifier.get_ty(expr_ty) else {
codegen_unreachable!(ctx)
};
let top_level_defs = ctx.top_level.definitions.read();
let def = top_level_defs[obj_id.0].read();
let TopLevelDef::Class { methods, .. } = &*def else { codegen_unreachable!(ctx) };
let enter_fun_id = methods
.iter()
.find(|method| method.0 == "__enter__".into())
.map(|method| method.2)
.unwrap();
let enter = fields.get(&"__enter__".into()).copied().unwrap();
let TypeEnum::TFunc(enter_signature) = &*ctx.unifier.get_ty(enter.0) else {
codegen_unreachable!(ctx)
};
enters.push((
expr_ty,
expr.clone(),
enter_signature.clone(),
enter_fun_id,
item.optional_vars.clone(),
));
// save __exit__() data to be called later in final stage
let exit_fun_id = methods
.iter()
.find(|method| method.0 == "__exit__".into())
.map(|method| method.2)
.unwrap();
let exit = fields.get(&"__exit__".into()).copied().unwrap();
let TypeEnum::TFunc(exit_signature) = &*ctx.unifier.get_ty(exit.0) else {
codegen_unreachable!(ctx)
};
// stack the exits as the exit order is opposite of enter
// would be best to reuse try...finally but re-building Stmt vec seems infeasible
exits.push((expr_ty, expr, exit_signature.clone(), exit_fun_id));
}
let body_gen_lambda = |ctx: &mut CodeGenContext<'ctx, 'a>,
generator: &mut G|
-> Result<(), String> {
for enter in &enters {
// call __enter__()
let enter_ret = generator.gen_call(
ctx,
Some((enter.0, enter.1.clone())),
(&enter.2, enter.3),
Vec::default(),
)?;
// deal with assignments (`as`)
if let Some(optional_vars) = &enter.4 {
generator.gen_assign(ctx, optional_vars, enter_ret.unwrap().into(), enter.2.ret)?;
}
}
// generate the `with` body
generator.gen_block(ctx, body.iter())
};
let exit_gen_lambda =
|ctx: &mut CodeGenContext<'ctx, 'a>, generator: &mut G| -> Result<(), String> {
// call __exit__()s in the reverse order
for exit in exits.iter().rev() {
generator.gen_call(
ctx,
Some((exit.0, exit.1.clone())),
(&exit.2, exit.3),
Vec::default(),
)?;
}
Ok(())
};
// copied and trimmed from gen_try, to cover try (setup, enter)..finally (exit)
let personality_symbol = ctx.top_level.personality_symbol.as_ref().unwrap();
let personality = ctx.module.get_function(personality_symbol).unwrap_or_else(|| {
let ty = ctx.ctx.i32_type().fn_type(&[], true);
ctx.module.add_function(personality_symbol, ty, None)
});
let exception_type = ctx.get_llvm_type(generator, ctx.primitives.exception);
let ptr_type = ctx.ctx.i8_type().ptr_type(inkwell::AddressSpace::default());
let current_block = ctx.builder.get_insert_block().unwrap();
let current_fun = current_block.get_parent().unwrap();
let landingpad = ctx.ctx.append_basic_block(current_fun, "with.landingpad");
let dispatcher = ctx.ctx.append_basic_block(current_fun, "with.dispatch");
let dispatcher_end = dispatcher;
ctx.builder.position_at_end(dispatcher);
let exn = ctx.builder.build_phi(exception_type, "exn").unwrap();
ctx.builder.position_at_end(current_block);
let mut old_loop_target = None;
let final_state =
generator.gen_var_alloc(ctx, ptr_type.into(), Some("with.final_state.addr"))?;
let mut final_data = Some((final_state, Vec::new(), Vec::new()));
if let Some((continue_target, break_target)) = ctx.loop_target {
let break_proxy = ctx.ctx.append_basic_block(current_fun, "with.break");
let continue_proxy = ctx.ctx.append_basic_block(current_fun, "with.continue");
final_proxy(ctx, break_target, break_proxy, final_data.as_mut().unwrap());
final_proxy(ctx, continue_target, continue_proxy, final_data.as_mut().unwrap());
old_loop_target = ctx.loop_target.replace((continue_proxy, break_proxy));
}
let return_proxy = ctx.ctx.append_basic_block(current_fun, "with.return");
if let Some(return_target) = ctx.return_target {
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
} else {
let return_target = ctx.ctx.append_basic_block(current_fun, "with.return_target");
ctx.builder.position_at_end(return_target);
let return_value = ctx.return_buffer.map(|v| ctx.builder.build_load(v, "$ret").unwrap());
ctx.builder.build_return(return_value.as_ref().map(|v| v as &dyn BasicValue)).unwrap();
ctx.builder.position_at_end(current_block);
final_proxy(ctx, return_target, return_proxy, final_data.as_mut().unwrap());
}
let old_return = ctx.return_target.replace(return_proxy);
let cleanup = ctx.ctx.append_basic_block(current_fun, "with.cleanup");
// replace unwind target, clauses stay the same
let old_unwind = ctx.unwind_target.replace(landingpad);
body_gen_lambda(ctx, generator)?;
let body = ctx.builder.get_insert_block().unwrap();
// reset old_unwind
ctx.unwind_target = old_unwind;
ctx.return_target = old_return;
ctx.loop_target = old_loop_target.or(ctx.loop_target).take();
let final_landingpad = ctx.ctx.append_basic_block(current_fun, "with.catch.final");
ctx.builder.position_at_end(final_landingpad);
ctx.builder
.build_landing_pad(
ctx.ctx.struct_type(&[ptr_type.into(), exception_type], false),
personality,
&[],
true,
"with.catch.final",
)
.unwrap();
ctx.builder.build_unconditional_branch(cleanup).unwrap();
ctx.builder.position_at_end(body);
let old_unwind = ctx.unwind_target.replace(final_landingpad);
let mut final_proxy_lambda =
|ctx: &mut CodeGenContext<'ctx, 'a>, target: BasicBlock<'ctx>, block: BasicBlock<'ctx>| {
final_proxy(ctx, target, block, final_data.as_mut().unwrap());
};
let redirect = &mut final_proxy_lambda
as &mut dyn FnMut(&mut CodeGenContext<'ctx, 'a>, BasicBlock<'ctx>, BasicBlock<'ctx>);
let resume = get_builtins(generator, ctx, "__nac3_resume");
let end_catch = get_builtins(generator, ctx, "__nac3_end_catch");
if let Some((continue_target, break_target)) = ctx.loop_target.take() {
let break_proxy = ctx.ctx.append_basic_block(current_fun, "with.break");
let continue_proxy = ctx.ctx.append_basic_block(current_fun, "with.continue");
ctx.builder.position_at_end(break_proxy);
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
ctx.builder.position_at_end(continue_proxy);
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
ctx.builder.position_at_end(body);
redirect(ctx, break_target, break_proxy);
redirect(ctx, continue_target, continue_proxy);
ctx.loop_target = Some((continue_proxy, break_proxy));
old_loop_target = Some((continue_target, break_target));
}
let return_proxy = ctx.ctx.append_basic_block(current_fun, "with.return");
ctx.builder.position_at_end(return_proxy);
ctx.builder.build_call(end_catch, &[], "end_catch").unwrap();
let return_target = ctx.return_target.take().unwrap_or_else(|| {
let doreturn = ctx.ctx.append_basic_block(current_fun, "with.doreturn");
ctx.builder.position_at_end(doreturn);
let return_value = ctx.return_buffer.map(|v| ctx.builder.build_load(v, "$ret").unwrap());
ctx.builder.build_return(return_value.as_ref().map(|v| v as &dyn BasicValue)).unwrap();
doreturn
});
redirect(ctx, return_target, return_proxy);
ctx.return_target = Some(return_proxy);
let old_return = Some(return_target);
ctx.unwind_target = old_unwind;
ctx.loop_target = old_loop_target.or(ctx.loop_target).take();
ctx.return_target = old_return;
ctx.builder.position_at_end(landingpad);
let landingpad_value = ctx
.builder
.build_landing_pad(
ctx.ctx.struct_type(&[ptr_type.into(), exception_type], false),
personality,
&Vec::new(),
true,
"try.landingpad",
)
.map(BasicValueEnum::into_struct_value)
.unwrap();
let exn_val = ctx.builder.build_extract_value(landingpad_value, 1, "exn").unwrap();
ctx.builder.build_unconditional_branch(dispatcher).unwrap();
exn.add_incoming(&[(&exn_val, landingpad)]);
if dispatcher_end.get_terminator().is_none() {
ctx.builder.position_at_end(dispatcher_end);
ctx.builder.build_unconditional_branch(cleanup).unwrap();
}
// exception path
ctx.builder.position_at_end(cleanup);
exit_gen_lambda(ctx, generator)?;
ctx.build_call_or_invoke(resume, &[], "resume");
ctx.builder.build_unreachable().unwrap();
// normal path
let (final_state, mut final_targets, final_paths) = final_data.unwrap();
let tail = ctx.ctx.append_basic_block(current_fun, "with.tail");
final_targets.push(tail);
let finalizer = ctx.ctx.append_basic_block(current_fun, "with.exits");
ctx.builder.position_at_end(finalizer);
exit_gen_lambda(ctx, generator)?;
let dest = ctx.builder.build_load(final_state, "final_dest").unwrap();
ctx.builder.build_indirect_branch(dest, &final_targets).unwrap();
for block in &final_paths {
if block.get_terminator().is_none() {
ctx.builder.position_at_end(*block);
ctx.builder.build_unconditional_branch(finalizer).unwrap();
}
}
for block in &[body] {
if block.get_terminator().is_none() {
ctx.builder.position_at_end(*block);
unsafe {
ctx.builder.build_store(final_state, tail.get_address().unwrap()).unwrap();
}
ctx.builder.build_unconditional_branch(finalizer).unwrap();
}
}
ctx.builder.position_at_end(tail);
Ok(())
}
/// Generates IR for a `return` statement.
@ -1860,6 +2082,8 @@ pub fn gen_stmt<G: CodeGenerator>(
} else {
return Ok(());
};
let exc = ExceptionType::get_instance(generator, ctx)
.map_pointer_value(exc.into_pointer_value(), None);
gen_raise(generator, ctx, Some(&exc), stmt.location);
} else {
gen_raise(generator, ctx, None, stmt.location);

View File

@ -3,6 +3,7 @@ use std::{
sync::Arc,
};
use function_name::named;
use indexmap::IndexMap;
use indoc::indoc;
use inkwell::{
@ -89,6 +90,7 @@ impl SymbolResolver for Resolver {
}
#[test]
#[named]
fn test_primitives() {
let source = indoc! { "
c = a + b
@ -181,60 +183,10 @@ fn test_primitives() {
id: 0,
};
let f = Arc::new(WithCall::new(Box::new(|module| {
// the following IR is equivalent to
// ```
// ; ModuleID = 'test.ll'
// source_filename = "test"
//
// ; Function Attrs: norecurse nounwind readnone
// define i32 @testing(i32 %0, i32 %1) local_unnamed_addr #0 {
// init:
// %add = add i32 %1, %0
// %cmp = icmp eq i32 %add, 1
// %ifexpr = select i1 %cmp, i32 %0, i32 0
// ret i32 %ifexpr
// }
//
// attributes #0 = { norecurse nounwind readnone }
// ```
// after O2 optimization
let expected = indoc! {"
; ModuleID = 'test'
source_filename = \"test\"
target datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"
target triple = \"x86_64-unknown-linux-gnu\"
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
define i32 @testing(i32 %0, i32 %1) local_unnamed_addr #0 !dbg !4 {
init:
%add = add i32 %1, %0, !dbg !9
%cmp = icmp eq i32 %add, 1, !dbg !10
%. = select i1 %cmp, i32 %0, i32 0, !dbg !11
ret i32 %., !dbg !12
}
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn }
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}
!0 = !{i32 2, !\"Debug Info Version\", i32 3}
!1 = !{i32 2, !\"Dwarf Version\", i32 4}
!2 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: \"NAC3\", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !DIFile(filename: \"unknown\", directory: \"\")
!4 = distinct !DISubprogram(name: \"testing\", linkageName: \"testing\", scope: null, file: !3, line: 1, type: !5, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !8)
!5 = !DISubroutineType(flags: DIFlagPublic, types: !6)
!6 = !{!7}
!7 = !DIBasicType(name: \"_\", flags: DIFlagPublic)
!8 = !{}
!9 = !DILocation(line: 1, column: 9, scope: !4)
!10 = !DILocation(line: 2, column: 15, scope: !4)
!11 = !DILocation(line: 0, scope: !4)
!12 = !DILocation(line: 3, column: 8, scope: !4)
"}
.trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
insta::assert_snapshot!(
function_name!(),
module.print_to_string().to_str().map(str::trim).unwrap()
);
})));
Target::initialize_all(&InitializationConfig::default());
@ -249,6 +201,7 @@ fn test_primitives() {
}
#[test]
#[named]
fn test_simple_call() {
let source_1 = indoc! { "
a = foo(a)
@ -383,48 +336,10 @@ fn test_simple_call() {
id: 0,
};
let f = Arc::new(WithCall::new(Box::new(|module| {
let expected = indoc! {"
; ModuleID = 'test'
source_filename = \"test\"
target datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"
target triple = \"x86_64-unknown-linux-gnu\"
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
define i32 @testing(i32 %0) local_unnamed_addr #0 !dbg !5 {
init:
%add.i = shl i32 %0, 1, !dbg !10
%mul = add i32 %add.i, 2, !dbg !10
ret i32 %mul, !dbg !10
}
; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
define i32 @foo.0(i32 %0) local_unnamed_addr #0 !dbg !11 {
init:
%add = add i32 %0, 1, !dbg !12
ret i32 %add, !dbg !12
}
attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn }
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2, !4}
!0 = !{i32 2, !\"Debug Info Version\", i32 3}
!1 = !{i32 2, !\"Dwarf Version\", i32 4}
!2 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: \"NAC3\", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !DIFile(filename: \"unknown\", directory: \"\")
!4 = distinct !DICompileUnit(language: DW_LANG_Python, file: !3, producer: \"NAC3\", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!5 = distinct !DISubprogram(name: \"testing\", linkageName: \"testing\", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !9)
!6 = !DISubroutineType(flags: DIFlagPublic, types: !7)
!7 = !{!8}
!8 = !DIBasicType(name: \"_\", flags: DIFlagPublic)
!9 = !{}
!10 = !DILocation(line: 2, column: 12, scope: !5)
!11 = distinct !DISubprogram(name: \"foo.0\", linkageName: \"foo.0\", scope: null, file: !3, line: 1, type: !6, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, retainedNodes: !9)
!12 = !DILocation(line: 1, column: 12, scope: !11)
"}
.trim();
assert_eq!(expected, module.print_to_string().to_str().unwrap().trim());
insta::assert_snapshot!(
function_name!(),
module.print_to_string().to_str().map(str::trim).unwrap()
);
})));
Target::initialize_all(&InitializationConfig::default());

View File

@ -0,0 +1,264 @@
use inkwell::{
context::{AsContextRef, Context},
types::{AnyTypeEnum, BasicType, BasicTypeEnum, IntType, PointerType, StructType},
values::{IntValue, PointerValue, StructValue},
AddressSpace,
};
use itertools::Itertools;
use nac3core_derive::StructFields;
use super::{
structure::{check_struct_type_matches_fields, StructField, StructFields, StructProxyType},
ProxyType,
};
use crate::{
codegen::{values::ExceptionValue, CodeGenContext, CodeGenerator},
typecheck::typedef::{Type, TypeEnum},
};
/// Proxy type for an `Exception` in LLVM.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ExceptionType<'ctx> {
ty: PointerType<'ctx>,
llvm_usize: IntType<'ctx>,
}
#[derive(PartialEq, Eq, Clone, Copy, StructFields)]
pub struct ExceptionStructFields<'ctx> {
/// The ID of the exception name.
#[value_type(i32_type())]
pub name: StructField<'ctx, IntValue<'ctx>>,
/// The file where the exception originated from.
#[value_type(get_struct_type("str").unwrap())]
pub file: StructField<'ctx, StructValue<'ctx>>,
/// The line number where the exception originated from.
#[value_type(i32_type())]
pub line: StructField<'ctx, IntValue<'ctx>>,
/// The column number where the exception originated from.
#[value_type(i32_type())]
pub col: StructField<'ctx, IntValue<'ctx>>,
/// The function name where the exception originated from.
#[value_type(get_struct_type("str").unwrap())]
pub func: StructField<'ctx, StructValue<'ctx>>,
/// The exception message.
#[value_type(get_struct_type("str").unwrap())]
pub message: StructField<'ctx, StructValue<'ctx>>,
#[value_type(i64_type())]
pub param0: StructField<'ctx, IntValue<'ctx>>,
#[value_type(i64_type())]
pub param1: StructField<'ctx, IntValue<'ctx>>,
#[value_type(i64_type())]
pub param2: StructField<'ctx, IntValue<'ctx>>,
}
impl<'ctx> ExceptionType<'ctx> {
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
#[must_use]
fn fields(
ctx: impl AsContextRef<'ctx>,
llvm_usize: IntType<'ctx>,
) -> ExceptionStructFields<'ctx> {
ExceptionStructFields::new(ctx, llvm_usize)
}
/// Creates an LLVM type corresponding to the expected structure of an `Exception`.
#[must_use]
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> {
const NAME: &str = "Exception";
assert!(ctx.get_struct_type("str").is_some());
if let Some(t) = ctx.get_struct_type(NAME) {
t.ptr_type(AddressSpace::default())
} else {
let exn_ty = ctx.opaque_struct_type(NAME);
let field_tys =
Self::fields(ctx, llvm_usize).into_iter().map(|field| field.1).collect_vec();
exn_ty.set_body(&field_tys, false);
exn_ty.ptr_type(AddressSpace::default())
}
}
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
let llvm_str = Self::llvm_type(ctx, llvm_usize);
Self { ty: llvm_str, llvm_usize }
}
/// Creates an instance of [`ExceptionType`].
#[must_use]
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
Self::new_impl(ctx.ctx, ctx.get_size_type())
}
/// Creates an instance of [`ExceptionType`].
#[must_use]
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
generator: &G,
ctx: &'ctx Context,
) -> Self {
Self::new_impl(ctx, generator.get_size_type(ctx))
}
/// Creates an [`ExceptionType`] from a [unifier type][Type].
#[must_use]
pub fn from_unifier_type(ctx: &mut CodeGenContext<'ctx, '_>, ty: Type) -> Self {
// Check unifier type
assert!(
matches!(&*ctx.unifier.get_ty_immutable(ty), TypeEnum::TObj { obj_id, .. } if *obj_id == ctx.primitives.exception.obj_id(&ctx.unifier).unwrap())
);
Self::new_impl(ctx.ctx, ctx.get_size_type())
}
/// Creates an [`ExceptionType`] from a [`StructType`] representing an `Exception`.
#[must_use]
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
Self::from_pointer_type(ty.ptr_type(AddressSpace::default()), llvm_usize)
}
/// Creates an [`ExceptionType`] from a [`PointerType`] representing an `Exception`.
#[must_use]
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
Self { ty: ptr_ty, llvm_usize }
}
/// Returns an instance of [`ExceptionType`] by obtaining the LLVM representation of the builtin
/// `Exception` type.
#[must_use]
pub fn get_instance<G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
) -> Self {
Self::from_pointer_type(
ctx.get_llvm_type(generator, ctx.primitives.exception).into_pointer_type(),
ctx.get_size_type(),
)
}
/// Allocates an instance of [`ExceptionValue`] as if by calling `alloca` on the base type.
///
/// See [`ProxyType::raw_alloca`].
#[must_use]
pub fn alloca(
&self,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
self.raw_alloca(ctx, name),
self.llvm_usize,
name,
)
}
/// Allocates an instance of [`ExceptionValue`] as if by calling `alloca` on the base type.
///
/// See [`ProxyType::raw_alloca_var`].
#[must_use]
pub fn alloca_var<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
self.raw_alloca_var(generator, ctx, name),
self.llvm_usize,
name,
)
}
/// Converts an existing value into a [`ExceptionValue`].
#[must_use]
pub fn map_struct_value<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
value: StructValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_struct_value(
generator,
ctx,
value,
self.llvm_usize,
name,
)
}
/// Converts an existing value into a [`ExceptionValue`].
#[must_use]
pub fn map_pointer_value(
&self,
value: PointerValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
}
}
impl<'ctx> ProxyType<'ctx> for ExceptionType<'ctx> {
type ABI = PointerType<'ctx>;
type Base = PointerType<'ctx>;
type Value = ExceptionValue<'ctx>;
fn is_representable(
llvm_ty: impl BasicType<'ctx>,
llvm_usize: IntType<'ctx>,
) -> Result<(), String> {
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
Self::has_same_repr(ty, llvm_usize)
} else {
Err(format!("Expected pointer type, got {llvm_ty:?}"))
}
}
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
let ctx = ty.get_context();
let llvm_ty = ty.get_element_type();
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
};
check_struct_type_matches_fields(Self::fields(ctx, llvm_usize), llvm_ty, "exception", &[])
}
fn alloca_type(&self) -> impl BasicType<'ctx> {
self.as_abi_type().get_element_type().into_struct_type()
}
fn as_base_type(&self) -> Self::Base {
self.ty
}
fn as_abi_type(&self) -> Self::ABI {
self.as_base_type()
}
}
impl<'ctx> StructProxyType<'ctx> for ExceptionType<'ctx> {
type StructFields = ExceptionStructFields<'ctx>;
fn get_fields(&self) -> Self::StructFields {
Self::fields(self.ty.get_context(), self.llvm_usize)
}
}
impl<'ctx> From<ExceptionType<'ctx>> for PointerType<'ctx> {
fn from(value: ExceptionType<'ctx>) -> Self {
value.as_base_type()
}
}

View File

@ -25,13 +25,19 @@ use super::{
values::{ArraySliceValue, ProxyValue},
{CodeGenContext, CodeGenerator},
};
pub use exception::*;
pub use list::*;
pub use option::*;
pub use range::*;
pub use string::*;
pub use tuple::*;
mod exception;
mod list;
pub mod ndarray;
mod option;
mod range;
mod string;
pub mod structure;
mod tuple;
pub mod utils;

View File

@ -0,0 +1,188 @@
use inkwell::{
context::Context,
types::{BasicType, BasicTypeEnum, IntType, PointerType},
values::{BasicValue, BasicValueEnum, PointerValue},
AddressSpace,
};
use super::ProxyType;
use crate::{
codegen::{values::OptionValue, CodeGenContext, CodeGenerator},
typecheck::typedef::{iter_type_vars, Type, TypeEnum},
};
/// Proxy type for an `Option` type in LLVM.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct OptionType<'ctx> {
ty: PointerType<'ctx>,
llvm_usize: IntType<'ctx>,
}
impl<'ctx> OptionType<'ctx> {
/// Creates an LLVM type corresponding to the expected structure of an `Option`.
#[must_use]
fn llvm_type(element_type: &impl BasicType<'ctx>) -> PointerType<'ctx> {
element_type.ptr_type(AddressSpace::default())
}
fn new_impl(element_type: &impl BasicType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
let llvm_option = Self::llvm_type(element_type);
Self { ty: llvm_option, llvm_usize }
}
/// Creates an instance of [`OptionType`].
#[must_use]
pub fn new(ctx: &CodeGenContext<'ctx, '_>, element_type: &impl BasicType<'ctx>) -> Self {
Self::new_impl(element_type, ctx.get_size_type())
}
/// Creates an instance of [`OptionType`].
#[must_use]
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
generator: &G,
ctx: &'ctx Context,
element_type: &impl BasicType<'ctx>,
) -> Self {
Self::new_impl(element_type, generator.get_size_type(ctx))
}
/// Creates an [`OptionType`] from a [unifier type][Type].
#[must_use]
pub fn from_unifier_type<G: CodeGenerator + ?Sized>(
generator: &G,
ctx: &mut CodeGenContext<'ctx, '_>,
ty: Type,
) -> Self {
// Check unifier type and extract `element_type`
let elem_type = match &*ctx.unifier.get_ty_immutable(ty) {
TypeEnum::TObj { obj_id, params, .. }
if *obj_id == ctx.primitives.option.obj_id(&ctx.unifier).unwrap() =>
{
iter_type_vars(params).next().unwrap().ty
}
_ => panic!("Expected `option` type, but got {}", ctx.unifier.stringify(ty)),
};
let llvm_usize = ctx.get_size_type();
let llvm_elem_type = ctx.get_llvm_type(generator, elem_type);
Self::new_impl(&llvm_elem_type, llvm_usize)
}
/// Creates an [`OptionType`] from a [`PointerType`].
#[must_use]
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
Self { ty: ptr_ty, llvm_usize }
}
/// Returns the element type of this `Option` type.
#[must_use]
pub fn element_type(&self) -> BasicTypeEnum<'ctx> {
BasicTypeEnum::try_from(self.ty.get_element_type()).unwrap()
}
/// Allocates an [`OptionValue`] on the stack.
///
/// The returned value will be `Some(v)` if [`value` contains a value][Option::is_some],
/// otherwise `none` will be returned.
#[must_use]
pub fn construct<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
value: Option<BasicValueEnum<'ctx>>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
let ptr = if let Some(v) = value {
let pvar = self.raw_alloca_var(generator, ctx, name);
ctx.builder.build_store(pvar, v).unwrap();
pvar
} else {
self.ty.const_null()
};
self.map_pointer_value(ptr, name)
}
/// Allocates an [`OptionValue`] on the stack.
///
/// The returned value will always be `none`.
#[must_use]
pub fn construct_empty<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
self.construct(generator, ctx, None, name)
}
/// Allocates an [`OptionValue`] on the stack.
///
/// The returned value will be set to `Some(value)`.
#[must_use]
pub fn construct_some_value<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
value: &impl BasicValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
self.construct(generator, ctx, Some(value.as_basic_value_enum()), name)
}
/// Converts an existing value into a [`OptionValue`].
#[must_use]
pub fn map_pointer_value(
&self,
value: PointerValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
}
}
impl<'ctx> ProxyType<'ctx> for OptionType<'ctx> {
type ABI = PointerType<'ctx>;
type Base = PointerType<'ctx>;
type Value = OptionValue<'ctx>;
fn is_representable(
llvm_ty: impl BasicType<'ctx>,
llvm_usize: IntType<'ctx>,
) -> Result<(), String> {
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
Self::has_same_repr(ty, llvm_usize)
} else {
Err(format!("Expected pointer type, got {llvm_ty:?}"))
}
}
fn has_same_repr(ty: Self::Base, _: IntType<'ctx>) -> Result<(), String> {
BasicTypeEnum::try_from(ty.get_element_type())
.map_err(|()| format!("Expected `ty` to be a BasicTypeEnum, got {ty}"))?;
Ok(())
}
fn alloca_type(&self) -> impl BasicType<'ctx> {
self.element_type()
}
fn as_base_type(&self) -> Self::Base {
self.ty
}
fn as_abi_type(&self) -> Self::ABI {
self.as_base_type()
}
}
impl<'ctx> From<OptionType<'ctx>> for PointerType<'ctx> {
fn from(value: OptionType<'ctx>) -> Self {
value.as_base_type()
}
}

View File

@ -0,0 +1,177 @@
use inkwell::{
context::Context,
types::{BasicType, BasicTypeEnum, IntType, PointerType, StructType},
values::{GlobalValue, IntValue, PointerValue, StructValue},
AddressSpace,
};
use itertools::Itertools;
use nac3core_derive::StructFields;
use super::{
structure::{check_struct_type_matches_fields, StructField, StructFields},
ProxyType,
};
use crate::codegen::{values::StringValue, CodeGenContext, CodeGenerator};
/// Proxy type for a `str` type in LLVM.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct StringType<'ctx> {
ty: StructType<'ctx>,
llvm_usize: IntType<'ctx>,
}
#[derive(PartialEq, Eq, Clone, Copy, StructFields)]
pub struct StringStructFields<'ctx> {
/// Pointer to the first character of the string.
#[value_type(i8_type().ptr_type(AddressSpace::default()))]
pub ptr: StructField<'ctx, PointerValue<'ctx>>,
/// Length of the string.
#[value_type(usize)]
pub len: StructField<'ctx, IntValue<'ctx>>,
}
impl<'ctx> StringType<'ctx> {
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
#[must_use]
fn fields(llvm_usize: IntType<'ctx>) -> StringStructFields<'ctx> {
StringStructFields::new(llvm_usize.get_context(), llvm_usize)
}
/// Creates an LLVM type corresponding to the expected structure of a `str`.
#[must_use]
fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> StructType<'ctx> {
const NAME: &str = "str";
if let Some(t) = ctx.get_struct_type(NAME) {
t
} else {
let str_ty = ctx.opaque_struct_type(NAME);
let field_tys = Self::fields(llvm_usize).into_iter().map(|field| field.1).collect_vec();
str_ty.set_body(&field_tys, false);
str_ty
}
}
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
let llvm_str = Self::llvm_type(ctx, llvm_usize);
Self { ty: llvm_str, llvm_usize }
}
/// Creates an instance of [`StringType`].
#[must_use]
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
Self::new_impl(ctx.ctx, ctx.get_size_type())
}
/// Creates an instance of [`StringType`].
#[must_use]
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
generator: &G,
ctx: &'ctx Context,
) -> Self {
Self::new_impl(ctx, generator.get_size_type(ctx))
}
/// Creates an [`StringType`] from a [`StructType`] representing a `str`.
#[must_use]
pub fn from_struct_type(ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
debug_assert!(Self::has_same_repr(ty, llvm_usize).is_ok());
Self { ty, llvm_usize }
}
/// Creates an [`StringType`] from a [`PointerType`] representing a `str`.
#[must_use]
pub fn from_pointer_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
Self::from_struct_type(ptr_ty.get_element_type().into_struct_type(), llvm_usize)
}
/// Returns the fields present in this [`StringType`].
#[must_use]
pub fn get_fields(&self) -> StringStructFields<'ctx> {
Self::fields(self.llvm_usize)
}
/// Constructs a global constant string.
#[must_use]
pub fn construct_constant(
&self,
ctx: &CodeGenContext<'ctx, '_>,
v: &str,
name: Option<&'ctx str>,
) -> StringValue<'ctx> {
let str_ptr = ctx
.builder
.build_global_string_ptr(v, "const")
.map(GlobalValue::as_pointer_value)
.unwrap();
let size = ctx.get_size_type().const_int(v.len() as u64, false);
self.map_struct_value(
self.as_abi_type().const_named_struct(&[str_ptr.into(), size.into()]),
name,
)
}
/// Converts an existing value into a [`StringValue`].
#[must_use]
pub fn map_struct_value(
&self,
value: StructValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_struct_value(value, self.llvm_usize, name)
}
/// Converts an existing value into a [`StringValue`].
#[must_use]
pub fn map_pointer_value(
&self,
ctx: &CodeGenContext<'ctx, '_>,
value: PointerValue<'ctx>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(ctx, value, self.llvm_usize, name)
}
}
impl<'ctx> ProxyType<'ctx> for StringType<'ctx> {
type ABI = StructType<'ctx>;
type Base = StructType<'ctx>;
type Value = StringValue<'ctx>;
fn is_representable(
llvm_ty: impl BasicType<'ctx>,
llvm_usize: IntType<'ctx>,
) -> Result<(), String> {
if let BasicTypeEnum::StructType(ty) = llvm_ty.as_basic_type_enum() {
Self::has_same_repr(ty, llvm_usize)
} else {
Err(format!("Expected structure type, got {llvm_ty:?}"))
}
}
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
check_struct_type_matches_fields(Self::fields(llvm_usize), ty, "str", &[])
}
fn alloca_type(&self) -> impl BasicType<'ctx> {
self.as_abi_type()
}
fn as_base_type(&self) -> Self::Base {
self.ty
}
fn as_abi_type(&self) -> Self::ABI {
self.as_base_type()
}
}
impl<'ctx> From<StringType<'ctx>> for StructType<'ctx> {
fn from(value: StringType<'ctx>) -> Self {
value.as_base_type()
}
}

View File

@ -115,15 +115,8 @@ impl<'ctx> TupleType<'ctx> {
/// Constructs a [`TupleValue`] from this type by zero-initializing the tuple value.
#[must_use]
pub fn construct(
&self,
ctx: &CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
self.map_struct_value(
Self::llvm_type(ctx.ctx, &self.ty.get_field_types()).const_zero(),
name,
)
pub fn construct(&self, name: Option<&'ctx str>) -> <Self as ProxyType<'ctx>>::Value {
self.map_struct_value(self.as_abi_type().const_zero(), name)
}
/// Constructs a [`TupleValue`] from `objects`. The resulting tuple preserves the order of
@ -143,9 +136,9 @@ impl<'ctx> TupleType<'ctx> {
.enumerate()
.all(|(i, v)| { v.get_type() == unsafe { self.type_at_index_unchecked(i as u32) } }));
let mut value = self.construct(ctx, name);
let mut value = self.construct(name);
for (i, val) in values.into_iter().enumerate() {
value.store_element(ctx, i as u32, val);
value.insert_element(ctx, i as u32, val);
}
value

View File

@ -0,0 +1,188 @@
use inkwell::{
types::IntType,
values::{IntValue, PointerValue, StructValue},
};
use itertools::Itertools;
use nac3parser::ast::Location;
use super::{structure::StructProxyValue, ProxyValue, StringValue};
use crate::codegen::{
types::{
structure::{StructField, StructProxyType},
ExceptionType,
},
CodeGenContext, CodeGenerator,
};
/// Proxy type for accessing an `Exception` value in LLVM.
#[derive(Copy, Clone)]
pub struct ExceptionValue<'ctx> {
value: PointerValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
}
impl<'ctx> ExceptionValue<'ctx> {
/// Creates an [`ExceptionValue`] from a [`StructValue`].
#[must_use]
pub fn from_struct_value<G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
val: StructValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
) -> Self {
let pval = generator
.gen_var_alloc(
ctx,
val.get_type().into(),
name.map(|name| format!("{name}.addr")).as_deref(),
)
.unwrap();
ctx.builder.build_store(pval, val).unwrap();
Self::from_pointer_value(pval, llvm_usize, name)
}
/// Creates an [`ExceptionValue`] from a [`PointerValue`].
#[must_use]
pub fn from_pointer_value(
ptr: PointerValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
) -> Self {
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
Self { value: ptr, llvm_usize, name }
}
fn name_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().name
}
/// Stores the ID of the exception name into this instance.
pub fn store_name(&self, ctx: &CodeGenContext<'ctx, '_>, name: IntValue<'ctx>) {
debug_assert_eq!(name.get_type(), ctx.ctx.i32_type());
self.name_field().store(ctx, self.value, name, self.name);
}
fn file_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
self.get_type().get_fields().file
}
/// Stores the file name of the exception source into this instance.
pub fn store_file(&self, ctx: &CodeGenContext<'ctx, '_>, file: StructValue<'ctx>) {
debug_assert!(StringValue::is_instance(file, self.llvm_usize).is_ok());
self.file_field().store(ctx, self.value, file, self.name);
}
fn line_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().line
}
fn col_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().col
}
/// Stores the [location][Location] of the exception source into this instance.
pub fn store_location<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
location: Location,
) {
let llvm_i32 = ctx.ctx.i32_type();
let filename = ctx.gen_string(generator, location.file.0);
self.store_file(ctx, filename);
self.line_field().store(
ctx,
self.value,
llvm_i32.const_int(location.row as u64, false),
self.name,
);
self.col_field().store(
ctx,
self.value,
llvm_i32.const_int(location.column as u64, false),
self.name,
);
}
fn func_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
self.get_type().get_fields().func
}
/// Stores the function name of the exception source into this instance.
pub fn store_func(&self, ctx: &CodeGenContext<'ctx, '_>, func: StructValue<'ctx>) {
debug_assert!(StringValue::is_instance(func, self.llvm_usize).is_ok());
self.func_field().store(ctx, self.value, func, self.name);
}
fn message_field(&self) -> StructField<'ctx, StructValue<'ctx>> {
self.get_type().get_fields().message
}
/// Stores the exception message into this instance.
pub fn store_message(&self, ctx: &CodeGenContext<'ctx, '_>, message: StructValue<'ctx>) {
debug_assert!(StringValue::is_instance(message, self.llvm_usize).is_ok());
self.message_field().store(ctx, self.value, message, self.name);
}
fn param0_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().param0
}
fn param1_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().param1
}
fn param2_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().param2
}
/// Stores the parameters of the exception into this instance.
///
/// If the parameter does not exist, pass `i64 0` in the parameter slot.
pub fn store_params(&self, ctx: &CodeGenContext<'ctx, '_>, params: &[IntValue<'ctx>; 3]) {
debug_assert!(params.iter().all(|p| p.get_type() == ctx.ctx.i64_type()));
[self.param0_field(), self.param1_field(), self.param2_field()]
.into_iter()
.zip_eq(params)
.for_each(|(field, param)| {
field.store(ctx, self.value, *param, self.name);
});
}
}
impl<'ctx> ProxyValue<'ctx> for ExceptionValue<'ctx> {
type ABI = PointerValue<'ctx>;
type Base = PointerValue<'ctx>;
type Type = ExceptionType<'ctx>;
fn get_type(&self) -> Self::Type {
Self::Type::from_pointer_type(self.value.get_type(), self.llvm_usize)
}
fn as_base_value(&self) -> Self::Base {
self.value
}
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
self.as_base_value()
}
}
impl<'ctx> StructProxyValue<'ctx> for ExceptionValue<'ctx> {}
impl<'ctx> From<ExceptionValue<'ctx>> for PointerValue<'ctx> {
fn from(value: ExceptionValue<'ctx>) -> Self {
value.as_base_value()
}
}

View File

@ -2,14 +2,20 @@ use inkwell::{types::IntType, values::BasicValue};
use super::{types::ProxyType, CodeGenContext};
pub use array::*;
pub use exception::*;
pub use list::*;
pub use option::*;
pub use range::*;
pub use string::*;
pub use tuple::*;
mod array;
mod exception;
mod list;
pub mod ndarray;
mod option;
mod range;
mod string;
pub mod structure;
mod tuple;
pub mod utils;

View File

@ -213,9 +213,7 @@ fn matmul_at_least_2d<'ctx, G: CodeGenerator>(
Binop::normal(Operator::Mult),
(&Some(rhs_dtype), b_kj),
ctx.current_loc,
)?
.unwrap()
.to_basic_value_enum(ctx, generator, dst_dtype)?;
)?;
// dst_[...]ij += x
let dst_ij = ctx.builder.build_load(pdst_ij, "").unwrap();
@ -226,9 +224,7 @@ fn matmul_at_least_2d<'ctx, G: CodeGenerator>(
Binop::normal(Operator::Add),
(&Some(dst_dtype), x),
ctx.current_loc,
)?
.unwrap()
.to_basic_value_enum(ctx, generator, dst_dtype)?;
)?;
ctx.builder.build_store(pdst_ij, dst_ij).unwrap();
Ok(())

View File

@ -226,13 +226,7 @@ impl<'ctx> NDArrayValue<'ctx> {
) {
let num_items = self.load_ndims(ctx);
call_memcpy_generic_array(
ctx,
self.shape().base_ptr(ctx, generator),
shape,
num_items,
ctx.ctx.bool_type().const_zero(),
);
call_memcpy_generic_array(ctx, self.shape().base_ptr(ctx, generator), shape, num_items);
}
/// Copy shape dimensions from an ndarray.
@ -258,13 +252,7 @@ impl<'ctx> NDArrayValue<'ctx> {
) {
let num_items = self.load_ndims(ctx);
call_memcpy_generic_array(
ctx,
self.strides().base_ptr(ctx, generator),
strides,
num_items,
ctx.ctx.bool_type().const_zero(),
);
call_memcpy_generic_array(ctx, self.strides().base_ptr(ctx, generator), strides, num_items);
}
/// Copy strides dimensions from an ndarray.

View File

@ -106,7 +106,7 @@ pub fn parse_numpy_int_sequence<'ctx, G: CodeGenerator + ?Sized>(
for i in 0..input_seq.get_type().num_elements() {
// Get the i-th element off of the tuple and load it into `result`.
let int = input_seq.load_element(ctx, i).into_int_value();
let int = input_seq.extract_element(ctx, i).into_int_value();
let int = ctx.builder.build_int_s_extend_or_bit_cast(int, llvm_usize, "").unwrap();
unsafe {

View File

@ -0,0 +1,75 @@
use inkwell::{
types::IntType,
values::{BasicValueEnum, IntValue, PointerValue},
};
use super::ProxyValue;
use crate::codegen::{types::OptionType, CodeGenContext};
/// Proxy type for accessing a `Option` value in LLVM.
#[derive(Copy, Clone)]
pub struct OptionValue<'ctx> {
value: PointerValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
}
impl<'ctx> OptionValue<'ctx> {
/// Creates an [`OptionValue`] from a [`PointerValue`].
#[must_use]
pub fn from_pointer_value(
ptr: PointerValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
) -> Self {
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
Self { value: ptr, llvm_usize, name }
}
/// Returns an `i1` indicating if this `Option` instance does not hold a value.
#[must_use]
pub fn is_none(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
ctx.builder.build_is_null(self.value, "").unwrap()
}
/// Returns an `i1` indicating if this `Option` instance contains a value.
#[must_use]
pub fn is_some(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
ctx.builder.build_is_not_null(self.value, "").unwrap()
}
/// Loads the value present in this `Option` instance.
///
/// # Safety
///
/// The caller must ensure that this `option` value [contains a value][Self::is_some].
#[must_use]
pub unsafe fn load(&self, ctx: &CodeGenContext<'ctx, '_>) -> BasicValueEnum<'ctx> {
ctx.builder.build_load(self.value, "").unwrap()
}
}
impl<'ctx> ProxyValue<'ctx> for OptionValue<'ctx> {
type ABI = PointerValue<'ctx>;
type Base = PointerValue<'ctx>;
type Type = OptionType<'ctx>;
fn get_type(&self) -> Self::Type {
Self::Type::from_pointer_type(self.value.get_type(), self.llvm_usize)
}
fn as_base_value(&self) -> Self::Base {
self.value
}
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
self.as_base_value()
}
}
impl<'ctx> From<OptionValue<'ctx>> for PointerValue<'ctx> {
fn from(value: OptionValue<'ctx>) -> Self {
value.as_base_value()
}
}

View File

@ -0,0 +1,87 @@
use inkwell::{
types::IntType,
values::{BasicValueEnum, IntValue, PointerValue, StructValue},
};
use crate::codegen::{
types::{structure::StructField, StringType},
values::ProxyValue,
CodeGenContext,
};
/// Proxy type for accessing a `str` value in LLVM.
#[derive(Copy, Clone)]
pub struct StringValue<'ctx> {
value: StructValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
}
impl<'ctx> StringValue<'ctx> {
/// Creates an [`StringValue`] from a [`StructValue`].
#[must_use]
pub fn from_struct_value(
val: StructValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
) -> Self {
debug_assert!(Self::is_instance(val, llvm_usize).is_ok());
Self { value: val, llvm_usize, name }
}
/// Creates an [`StringValue`] from a [`PointerValue`].
#[must_use]
pub fn from_pointer_value(
ctx: &CodeGenContext<'ctx, '_>,
ptr: PointerValue<'ctx>,
llvm_usize: IntType<'ctx>,
name: Option<&'ctx str>,
) -> Self {
let val = ctx.builder.build_load(ptr, "").map(BasicValueEnum::into_struct_value).unwrap();
Self::from_struct_value(val, llvm_usize, name)
}
fn ptr_field(&self) -> StructField<'ctx, PointerValue<'ctx>> {
self.get_type().get_fields().ptr
}
/// Returns the pointer to the beginning of the string.
pub fn extract_ptr(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
self.ptr_field().extract_value(ctx, self.value)
}
fn len_field(&self) -> StructField<'ctx, IntValue<'ctx>> {
self.get_type().get_fields().len
}
/// Returns the length of the string.
pub fn extract_len(&self, ctx: &CodeGenContext<'ctx, '_>) -> IntValue<'ctx> {
self.len_field().extract_value(ctx, self.value)
}
}
impl<'ctx> ProxyValue<'ctx> for StringValue<'ctx> {
type ABI = StructValue<'ctx>;
type Base = StructValue<'ctx>;
type Type = StringType<'ctx>;
fn get_type(&self) -> Self::Type {
Self::Type::from_struct_type(self.value.get_type(), self.llvm_usize)
}
fn as_base_value(&self) -> Self::Base {
self.value
}
fn as_abi_value(&self, _: &CodeGenContext<'ctx, '_>) -> Self::ABI {
self.as_base_value()
}
}
impl<'ctx> From<StringValue<'ctx>> for StructValue<'ctx> {
fn from(value: StringValue<'ctx>) -> Self {
value.as_base_value()
}
}

View File

@ -45,7 +45,7 @@ impl<'ctx> TupleValue<'ctx> {
}
/// Stores a value into the tuple element at the given `index`.
pub fn store_element(
pub fn insert_element(
&mut self,
ctx: &CodeGenContext<'ctx, '_>,
index: u32,
@ -63,7 +63,11 @@ impl<'ctx> TupleValue<'ctx> {
}
/// Loads a value from the tuple element at the given `index`.
pub fn load_element(&self, ctx: &CodeGenContext<'ctx, '_>, index: u32) -> BasicValueEnum<'ctx> {
pub fn extract_element(
&self,
ctx: &CodeGenContext<'ctx, '_>,
index: u32,
) -> BasicValueEnum<'ctx> {
ctx.builder
.build_extract_value(
self.value,

View File

@ -36,9 +36,7 @@ pub fn get_exn_constructor(
unifier: &mut Unifier,
primitives: &PrimitiveStore,
) -> (TopLevelDef, TopLevelDef, Type, Type) {
let int32 = primitives.int32;
let int64 = primitives.int64;
let string = primitives.str;
let PrimitiveStore { int32, int64, str: string, .. } = *primitives;
let exception_fields = make_exception_fields(int32, int64, string);
let exn_cons_args = vec![
FuncArg {

View File

@ -1521,8 +1521,7 @@ impl TopLevelComposer {
.any(|ann| matches!(ann, TypeAnnotation::CustomClass { id, .. } if id.0 == 7))
{
// create constructor for these classes
let string = primitives_ty.str;
let int64 = primitives_ty.int64;
let PrimitiveStore { str: string, int64, .. } = *primitives_ty;
let signature = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![
FuncArg {

View File

@ -247,7 +247,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&[];
&[],
"simple class compose";
"simple class compose"
)]
#[test_case(
@ -269,7 +270,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&[];
&[],
"generic class";
"generic class"
)]
#[test_case(
@ -298,7 +300,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&[];
&[],
"list tuple generic";
"list tuple generic"
)]
#[test_case(
@ -323,7 +326,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&[];
&[],
"self1";
"self1"
)]
#[test_case(
@ -357,7 +361,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&[];
&[],
"inheritance_override";
"inheritance_override"
)]
#[test_case(
@ -370,7 +375,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["application of type vars to generic class is not currently supported (at unknown:4:24)"];
&["application of type vars to generic class is not currently supported (at unknown:4:24)"],
"err no type var in generic app";
"err no type var in generic app"
)]
#[test_case(
@ -386,7 +392,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["NameError: name 'B' is not defined (at unknown:1:9)"];
&["NameError: name 'B' is not defined (at unknown:1:9)"],
"cyclic1";
"cyclic1"
)]
#[test_case(
@ -407,7 +414,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"},
],
&["NameError: name 'C' is not defined (at unknown:1:25)"];
&["NameError: name 'C' is not defined (at unknown:1:25)"],
"cyclic2";
"cyclic2"
)]
#[test_case(
@ -417,7 +425,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["5: Class {\nname: \"A\",\ndef_id: DefinitionId(5),\nancestors: [CustomClassKind { id: DefinitionId(5), params: [] }],\nfields: [],\nmethods: [],\ntype_vars: []\n}"];
&["5: Class {\nname: \"A\",\ndef_id: DefinitionId(5),\nancestors: [CustomClassKind { id: DefinitionId(5), params: [] }],\nfields: [],\nmethods: [],\ntype_vars: []\n}"],
"simple pass in class";
"simple pass in class"
)]
#[test_case(
@ -426,7 +435,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
def __init__():
pass
"}],
&["__init__ method must have a `self` parameter (at unknown:2:5)"];
&["__init__ method must have a `self` parameter (at unknown:2:5)"],
"err no self_1";
"err no self_1"
)]
#[test_case(
@ -448,7 +458,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
"}
],
&["a class definition can only have at most one base class declaration and one generic declaration (at unknown:1:24)"];
&["a class definition can only have at most one base class declaration and one generic declaration (at unknown:1:24)"],
"err multiple inheritance";
"err multiple inheritance"
)]
#[test_case(
@ -473,7 +484,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["method fun has same name as ancestors' method, but incompatible type"];
&["method fun has same name as ancestors' method, but incompatible type"],
"err_incompatible_inheritance_method";
"err_incompatible_inheritance_method"
)]
#[test_case(
@ -499,7 +511,8 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["field `a` has already declared in the ancestor classes"];
&["field `a` has already declared in the ancestor classes"],
"err_incompatible_inheritance_field";
"err_incompatible_inheritance_field"
)]
#[test_case(
@ -516,10 +529,13 @@ fn test_simple_function_analyze(source: &[&str], tys: &[&str], names: &[&str]) {
pass
"}
],
&["duplicate definition of class `A` (at unknown:1:1)"];
&["duplicate definition of class `A` (at unknown:1:1)"],
"class same name";
"class same name"
)]
fn test_analyze(source: &[&str], res: &[&str]) {
// case_name param is required for insta to distinguish different test_case
// See https://github.com/frondeus/test-case/issues/37
fn test_analyze(source: &[&str], res: &[&str], case_name: &str) {
let print = false;
let mut composer =
TopLevelComposer::new(Vec::new(), Vec::new(), ComposerConfig::default(), 64).0;
@ -572,7 +588,9 @@ fn test_analyze(source: &[&str], res: &[&str]) {
let def = &*def.read();
res_vec.push(format!("{}\n", def.to_string(composer.unifier.borrow_mut())));
}
insta::assert_debug_snapshot!(res_vec);
insta::with_settings!({ snapshot_suffix => case_name.replace(' ', "_") }, {
insta::assert_debug_snapshot!(res_vec);
});
}
}

View File

@ -21,4 +21,4 @@ phf = { version = "0.11", features = ["macros"] }
ahash = "0.8"
[dev-dependencies]
insta = "=1.11.0"
insta = "1.42"

View File

@ -1,35 +0,0 @@
From 5c571082fdaf61f6df19d9b7137dc26d71334058 Mon Sep 17 00:00:00 2001
From: Natanael Copa <ncopa@alpinelinux.org>
Date: Thu, 18 Feb 2016 10:33:04 +0100
Subject: [PATCH 2/3] Fix build with musl libc
On musl libc the fopen64 and fopen are the same thing, but for
compatibility they have a `#define fopen64 fopen`. Same applies for
fseek64, fstat64, fstatvfs64, ftello64, lstat64, stat64 and tmpfile64.
---
include/llvm/Analysis/TargetLibraryInfo.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/include/llvm/Analysis/TargetLibraryInfo.h b/include/llvm/Analysis/TargetLibraryInfo.h
index 7becdf0..7f14427 100644
--- a/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/include/llvm/Analysis/TargetLibraryInfo.h
@@ -18,6 +18,15 @@
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
+#undef fopen64
+#undef fseeko64
+#undef fstat64
+#undef fstatvfs64
+#undef ftello64
+#undef lstat64
+#undef stat64
+#undef tmpfile64
+
namespace llvm {
/// VecDesc - Describes a possible vectorization of a function.
/// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized
--
2.7.3

View File

@ -9,43 +9,29 @@
, zlib
, which
, debugVersion ? false
, enableManpages ? false
, enableSharedLibraries ? false
, extraCmakeFlags ? []
}:
let
inherit (lib) optional optionals optionalString;
release_version = "14.0.6";
candidate = ""; # empty or "rcN"
dash-candidate = lib.optionalString (candidate != "") "-${candidate}";
version = "${release_version}${dash-candidate}"; # differentiating these (variables) is important for RCs
fetch = name: sha256: fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/${name}-${release_version}${candidate}.src.tar.xz";
inherit sha256;
};
# Used when creating a version-suffixed symlink of libLLVM.dylib
shortVersion = with lib;
concatStringsSep "." (take 1 (splitString "." release_version));
in stdenv.mkDerivation (rec {
sources = import ../llvm/sources.nix { inherit fetchurl; };
in stdenv.mkDerivation rec {
pname = "llvm";
inherit version;
src = fetch pname "sha256-BQki7KrKV4H99mMeqSvHFRg/IC+dLxUUcibwI0FPYZo=";
inherit (sources) version;
unpackPhase = ''
unpackFile $src
mv llvm-${release_version}* llvm
mkdir llvm
tar xf ${sources.llvm} -C llvm --strip-components=1
tar xf ${sources.cmake} -C llvm/cmake --strip-components=2
mkdir cmake
ln -s $PWD/llvm/cmake cmake/Modules
sourceRoot=$PWD/llvm
'';
outputs = [ "out" "lib" "dev" "python" ];
nativeBuildInputs = [ cmake python3 ]
++ optionals enableManpages [ python3.pkgs.sphinx python3.pkgs.recommonmark ];
nativeBuildInputs = [ cmake python3 ];
buildInputs = [ ];
@ -55,44 +41,18 @@ in stdenv.mkDerivation (rec {
patches = [
./gnu-install-dirs.patch
./llvm-future-riscv-abi.diff
];
postPatch = optionalString stdenv.isDarwin ''
substituteInPlace cmake/modules/AddLLVM.cmake \
--replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
--replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
''
# Patch llvm-config to return correct library path based on --link-{shared,static}.
+ ''
substitute '${./outputs.patch}' ./outputs.patch --subst-var lib
patch -p1 < ./outputs.patch
'' + ''
postPatch =
''
# FileSystem permissions tests fail with various special bits
substituteInPlace unittests/Support/CMakeLists.txt \
--replace "Path.cpp" ""
--replace-fail "Path.cpp" ""
rm unittests/Support/Path.cpp
substituteInPlace unittests/IR/CMakeLists.txt \
--replace "PassBuilderCallbacksTest.cpp" ""
--replace-fail "PassBuilderCallbacksTest.cpp" ""
rm unittests/IR/PassBuilderCallbacksTest.cpp
rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
'' + optionalString stdenv.hostPlatform.isMusl ''
patch -p1 -i ${./TLI-musl.patch}
substituteInPlace unittests/Support/CMakeLists.txt \
--replace "add_subdirectory(DynamicLibrary)" ""
rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
# valgrind unhappy with musl or glibc, but fails w/musl only
rm test/CodeGen/AArch64/wineh4.mir
'' + optionalString stdenv.hostPlatform.isAarch32 ''
# skip failing X86 test cases on 32-bit ARM
rm test/DebugInfo/X86/convert-debugloc.ll
rm test/DebugInfo/X86/convert-inlined.ll
rm test/DebugInfo/X86/convert-linked.ll
rm test/tools/dsymutil/X86/op-convert.test
'' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
# Seems to require certain floating point hardware (NEON?)
rm test/ExecutionEngine/frem.ll
'' + ''
patchShebangs test/BugPoint/compile-custom.ll.py
'';
@ -103,12 +63,12 @@ in stdenv.mkDerivation (rec {
'';
# E.g. mesa.drivers use the build-id as a cache key (see #93946):
LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
LDFLAGS = optionalString enableSharedLibraries "-Wl,--build-id=sha1";
cmakeFlags = with stdenv; [
"-DLLVM_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/llvm/"
"-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
"-DCMAKE_BUILD_TYPE=${if debugVersion then "Debug" else "Release"}"
"-DLLVM_BUILD_TESTS=${if stdenv.targetPlatform.isMinGW then "OFF" else "ON"}"
"-DLLVM_INCLUDE_TESTS=OFF"
"-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
"-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
"-DLLVM_ENABLE_UNWIND_TABLES=OFF"
@ -118,17 +78,8 @@ in stdenv.mkDerivation (rec {
"-DLLVM_TARGETS_TO_BUILD=X86;ARM;RISCV"
] ++ optionals enableSharedLibraries [
"-DLLVM_LINK_LLVM_DYLIB=ON"
] ++ optionals enableManpages [
"-DLLVM_BUILD_DOCS=ON"
"-DLLVM_ENABLE_SPHINX=ON"
"-DSPHINX_OUTPUT_MAN=ON"
"-DSPHINX_OUTPUT_HTML=OFF"
"-DSPHINX_WARNINGS_AS_ERRORS=OFF"
] ++ optionals (!isDarwin && !stdenv.targetPlatform.isMinGW) [
"-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
] ++ optionals isDarwin [
"-DLLVM_ENABLE_LIBCXX=ON"
"-DCAN_TARGET_i386=false"
] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
"-DCMAKE_CROSSCOMPILING=True"
(
@ -166,10 +117,6 @@ in stdenv.mkDerivation (rec {
substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
--replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}'"$lib"'")'
''
+ optionalString (stdenv.isDarwin && enableSharedLibraries) ''
ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
''
+ optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
'';
@ -197,27 +144,4 @@ in stdenv.mkDerivation (rec {
under the "Apache 2.0 License with LLVM exceptions".
'';
};
} // lib.optionalAttrs enableManpages {
pname = "llvm-manpages";
buildPhase = ''
make docs-llvm-man
'';
propagatedBuildInputs = [];
installPhase = ''
make -C docs install
'';
postPatch = null;
postInstall = null;
outputs = [ "out" ];
doCheck = false;
meta = {
description = "man pages for LLVM ${version}";
};
})
}

View File

@ -1,22 +1,21 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fec956091cd5..5a766f5c5d7c 100644
index 7e25e0407db2..72f031a82b75 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -303,6 +303,9 @@ set(LLVM_EXAMPLES_INSTALL_DIR "examples" CACHE STRING
"Path for examples subdirectory (enabled by LLVM_BUILD_EXAMPLES=ON) (defaults to 'examples')")
mark_as_advanced(LLVM_EXAMPLES_INSTALL_DIR)
+set(LLVM_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}/cmake/llvm" CACHE STRING
+ "Path for CMake subdirectory (defaults to lib/cmake/llvm)" )
+
# They are used as destination of target generators.
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
@@ -995,7 +995,7 @@ if (NOT TENSORFLOW_AOT_PATH STREQUAL "")
add_subdirectory(${TENSORFLOW_AOT_PATH}/xla_aot_runtime_src
${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/tf_runtime)
install(TARGETS tf_xla_runtime EXPORT LLVMExports
- ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT tf_xla_runtime)
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX} COMPONENT tf_xla_runtime)
set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS tf_xla_runtime)
# Once we add more modules, we should handle this more automatically.
if (DEFINED LLVM_OVERRIDE_MODEL_HEADER_INLINERSIZEMODEL)
diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake
index fed1fec7d72e..4baed19b9e98 100644
index 93e6d67551de..8d367457af5a 100644
--- a/cmake/modules/AddLLVM.cmake
+++ b/cmake/modules/AddLLVM.cmake
@@ -838,8 +838,8 @@ macro(add_llvm_library name)
@@ -874,8 +874,8 @@ macro(add_llvm_library name)
get_target_export_arg(${name} LLVM export_to_llvmexports ${umbrella})
install(TARGETS ${name}
${export_to_llvmexports}
@ -25,62 +24,55 @@ index fed1fec7d72e..4baed19b9e98 100644
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" COMPONENT ${name}
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" COMPONENT ${name}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT ${name})
if (NOT LLVM_ENABLE_IDE)
@@ -1056,7 +1056,7 @@ function(process_llvm_pass_plugins)
"set(LLVM_STATIC_EXTENSIONS ${LLVM_STATIC_EXTENSIONS})")
install(FILES
${llvm_cmake_builddir}/LLVMConfigExtensions.cmake
- DESTINATION ${LLVM_INSTALL_PACKAGE_DIR}
+ DESTINATION ${LLVM_INSTALL_CMAKE_DIR}
COMPONENT cmake-exports)
set(ExtensionDef "${LLVM_BINARY_DIR}/include/llvm/Support/Extension.def")
@@ -1902,7 +1902,7 @@ function(llvm_install_library_symlink name dest type)
@@ -2043,7 +2043,7 @@ function(llvm_install_library_symlink name dest type)
set(full_name ${CMAKE_${type}_LIBRARY_PREFIX}${name}${CMAKE_${type}_LIBRARY_SUFFIX})
set(full_dest ${CMAKE_${type}_LIBRARY_PREFIX}${dest}${CMAKE_${type}_LIBRARY_SUFFIX})
- set(output_dir lib${LLVM_LIBDIR_SUFFIX})
+ set(output_dir ${CMAKE_INSTALL_FULL_LIBDIR}${LLVM_LIBDIR_SUFFIX})
if(WIN32 AND "${type}" STREQUAL "SHARED")
set(output_dir bin)
set(output_dir "${CMAKE_INSTALL_BINDIR}")
endif()
@@ -1913,7 +1913,7 @@ function(llvm_install_library_symlink name dest type)
endfunction()
-function(llvm_install_symlink name dest)
+function(llvm_install_symlink name dest output_dir)
cmake_parse_arguments(ARG "ALWAYS_GENERATE" "COMPONENT" "" ${ARGN})
foreach(path ${CMAKE_MODULE_PATH})
if(EXISTS ${path}/LLVMInstallSymlink.cmake)
@@ -1936,7 +1936,7 @@ function(llvm_install_symlink name dest)
set(full_dest ${dest}${CMAKE_EXECUTABLE_SUFFIX})
install(SCRIPT ${INSTALL_SYMLINK}
- CODE "install_symlink(${full_name} ${full_dest} ${LLVM_TOOLS_INSTALL_DIR})"
+ CODE "install_symlink(${full_name} ${full_dest} ${output_dir})"
COMPONENT ${component})
if (NOT LLVM_ENABLE_IDE AND NOT ARG_ALWAYS_GENERATE)
@@ -2019,7 +2019,8 @@ function(add_llvm_tool_symlink link_name target)
endif()
if ((TOOL_IS_TOOLCHAIN OR NOT LLVM_INSTALL_TOOLCHAIN_ONLY) AND LLVM_BUILD_TOOLS)
- llvm_install_symlink(${link_name} ${target})
+ GNUInstallDirs_get_absolute_install_dir(output_dir LLVM_TOOLS_INSTALL_DIR)
+ llvm_install_symlink(${link_name} ${target} ${output_dir})
endif()
endif()
endfunction()
@@ -2148,9 +2149,9 @@ function(llvm_setup_rpath name)
@@ -2312,16 +2312,37 @@ function(llvm_setup_rpath name)
if (APPLE)
set(_install_name_dir INSTALL_NAME_DIR "@rpath")
- set(_install_rpath "@loader_path/../lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
+ set(_install_rpath "@loader_path/../${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "AIX" AND BUILD_SHARED_LIBS)
# $ORIGIN is not interpreted at link time by aix ld.
# Since BUILD_SHARED_LIBS is only recommended for use by developers,
# hardcode the rpath to build/install lib dir first in this mode.
# FIXME: update this when there is better solution.
- set(_install_rpath "${LLVM_LIBRARY_OUTPUT_INTDIR}" "${CMAKE_INSTALL_PREFIX}/lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
+ set(_install_rpath "${LLVM_LIBRARY_OUTPUT_INTDIR}" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
+ set(_install_rpath "${LLVM_LIBRARY_OUTPUT_INTDIR}" "${CMAKE_INSTALL_FULL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
elseif(UNIX)
- set(_install_rpath "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
- set(_build_rpath "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
- set(_install_rpath "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}")
+ # Note that we add `extra_libdir` (aka `LLVM_LIBRARY_DIR` in our case) back
+ # to `_install_rpath` here.
+ #
+ # In nixpkgs we do not build and install LLVM alongside rdeps of LLVM (i.e.
+ # clang); instead LLVM is its own package and thus lands at its own nix
+ # store path. This makes it so that the default relative rpath (`../lib/`)
+ # does not point at the LLVM shared objects.
+ #
+ # More discussion here:
+ # - https://github.com/NixOS/nixpkgs/pull/235624#discussion_r1220150329
+ # - https://reviews.llvm.org/D146918 (16.0.5+)
+ #
+ # Note that we leave `extra_libdir` in `_build_rpath`: without FHS there is
+ # no potential that this will result in us pulling in the "wrong" LLVM.
+ # Adding this to the build rpath means we aren't forced to use
+ # `installCheckPhase` instead of `checkPhase` (i.e. binaries in the build
+ # dir, pre-install, will have the right rpath for LLVM).
+ #
+ # As noted in the differential above, an alternative solution is to have
+ # all rdeps of nixpkgs' LLVM (that use the AddLLVM.cmake machinery) set
+ # `CMAKE_INSTALL_RPATH`.
+ set(_build_rpath "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
+ set(_install_rpath "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}" ${extra_libdir})
if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)")
set_property(TARGET ${name} APPEND_STRING PROPERTY
@ -91,7 +83,7 @@ index 891c9e6d618c..8d963f3b0069 100644
+++ b/cmake/modules/AddOCaml.cmake
@@ -147,9 +147,9 @@ function(add_ocaml_library name)
endforeach()
if( APPLE )
- set(ocaml_rpath "@executable_path/../../../lib${LLVM_LIBDIR_SUFFIX}")
+ set(ocaml_rpath "@executable_path/../../../${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}")
@ -100,121 +92,70 @@ index 891c9e6d618c..8d963f3b0069 100644
+ set(ocaml_rpath "\\$ORIGIN/../../../${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}")
endif()
list(APPEND ocaml_flags "-ldopt" "-Wl,-rpath,${ocaml_rpath}")
diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt
index cea0c1df0a14..eedcd9450312 100644
index d99af79aa38e..21e794224b99 100644
--- a/cmake/modules/CMakeLists.txt
+++ b/cmake/modules/CMakeLists.txt
@@ -2,7 +2,7 @@ include(ExtendPath)
include(LLVMDistributionSupport)
include(FindPrefixFromConfig)
-set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm)
+set(LLVM_INSTALL_PACKAGE_DIR ${LLVM_INSTALL_CMAKE_DIR} CACHE STRING "Path for CMake subdirectory (defaults to 'cmake/llvm')")
set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}")
# First for users who use an installed LLVM, create the LLVMExports.cmake file.
@@ -122,7 +122,7 @@ set(LLVM_CONFIG_INCLUDE_DIRS
@@ -127,7 +127,7 @@ set(LLVM_CONFIG_INCLUDE_DIRS
)
list(REMOVE_DUPLICATES LLVM_CONFIG_INCLUDE_DIRS)
-extend_path(LLVM_CONFIG_LIBRARY_DIR "\${LLVM_INSTALL_PREFIX}" "lib\${LLVM_LIBDIR_SUFFIX}")
+extend_path(LLVM_CONFIG_LIBRARY_DIR "\${LLVM_INSTALL_PREFIX}" "${CMAKE_INSTALL_LIBDIR}\${LLVM_LIBDIR_SUFFIX}")
set(LLVM_CONFIG_LIBRARY_DIRS
"${LLVM_CONFIG_LIBRARY_DIR}"
# FIXME: Should there be other entries here?
diff --git a/cmake/modules/LLVMInstallSymlink.cmake b/cmake/modules/LLVMInstallSymlink.cmake
index b5c35f706cb7..9261ab797de6 100644
--- a/cmake/modules/LLVMInstallSymlink.cmake
+++ b/cmake/modules/LLVMInstallSymlink.cmake
@@ -6,7 +6,7 @@ include(GNUInstallDirs)
function(install_symlink name target outdir)
set(DESTDIR $ENV{DESTDIR})
- set(bindir "${DESTDIR}${CMAKE_INSTALL_PREFIX}/${outdir}")
+ set(bindir "${DESTDIR}${outdir}/")
message(STATUS "Creating ${name}")
diff --git a/docs/CMake.rst b/docs/CMake.rst
index 044ec8a4d39d..504d0eac3ade 100644
index 7926de258ec8..5ae01adc3905 100644
--- a/docs/CMake.rst
+++ b/docs/CMake.rst
@@ -224,7 +224,7 @@ description is in `LLVM-related variables`_ below.
@@ -250,7 +250,7 @@ description is in `LLVM-related variables`_ below.
**LLVM_LIBDIR_SUFFIX**:STRING
Extra suffix to append to the directory where libraries are to be
installed. On a 64-bit architecture, one could use ``-DLLVM_LIBDIR_SUFFIX=64``
- to install libraries to ``/usr/lib64``.
+ to install libraries to ``/usr/lib64``. See also ``CMAKE_INSTALL_LIBDIR``.
**LLVM_PARALLEL_{COMPILE,LINK}_JOBS**:STRING
Building the llvm toolchain can use a lot of resources, particularly
@@ -910,9 +910,11 @@ the ``cmake`` command or by setting it directly in ``ccmake`` or ``cmake-gui``).
This file is available in two different locations.
-* ``<INSTALL_PREFIX>/lib/cmake/llvm/LLVMConfig.cmake`` where
- ``<INSTALL_PREFIX>`` is the install prefix of an installed version of LLVM.
- On Linux typically this is ``/usr/lib/cmake/llvm/LLVMConfig.cmake``.
+* ``<LLVM_INSTALL_PACKAGE_DIR>LLVMConfig.cmake`` where
+ ``<LLVM_INSTALL_PACKAGE_DIR>`` is the location where LLVM CMake modules are
+ installed as part of an installed version of LLVM. This is typically
+ ``cmake/llvm/`` within the lib directory. On Linux, this is typically
+ ``/usr/lib/cmake/llvm/LLVMConfig.cmake``.
* ``<LLVM_BUILD_ROOT>/lib/cmake/llvm/LLVMConfig.cmake`` where
``<LLVM_BUILD_ROOT>`` is the root of the LLVM build tree. **Note: this is only
diff --git a/include/llvm/CMakeLists.txt b/include/llvm/CMakeLists.txt
index b46319f24fc8..2feabd1954e4 100644
--- a/include/llvm/CMakeLists.txt
+++ b/include/llvm/CMakeLists.txt
@@ -5,5 +5,5 @@ add_subdirectory(Frontend)
# If we're doing an out-of-tree build, copy a module map for generated
# header files into the build area.
if (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
- configure_file(module.modulemap.build module.modulemap COPYONLY)
+ configure_file(module.modulemap.build ${LLVM_INCLUDE_DIR}/module.modulemap COPYONLY)
endif (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
@@ -284,6 +284,10 @@ manual, or execute ``cmake --help-variable VARIABLE_NAME``.
The path to install executables, relative to the *CMAKE_INSTALL_PREFIX*.
Defaults to "bin".
+**CMAKE_INSTALL_LIBDIR**:PATH
+ The path to install libraries, relative to the *CMAKE_INSTALL_PREFIX*.
+ Defaults to "lib".
+
**CMAKE_INSTALL_INCLUDEDIR**:PATH
The path to install header files, relative to the *CMAKE_INSTALL_PREFIX*.
Defaults to "include".
diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in
index abbb8a450da6..70c497be12f5 100644
index 370005cd8d7d..7e790bc52111 100644
--- a/tools/llvm-config/BuildVariables.inc.in
+++ b/tools/llvm-config/BuildVariables.inc.in
@@ -23,7 +23,10 @@
@@ -23,6 +23,7 @@
#define LLVM_CXXFLAGS "@LLVM_CXXFLAGS@"
#define LLVM_BUILDMODE "@LLVM_BUILDMODE@"
#define LLVM_LIBDIR_SUFFIX "@LLVM_LIBDIR_SUFFIX@"
+#define LLVM_INSTALL_BINDIR "@CMAKE_INSTALL_BINDIR@"
+#define LLVM_INSTALL_LIBDIR "@CMAKE_INSTALL_LIBDIR@"
#define LLVM_INSTALL_INCLUDEDIR "@CMAKE_INSTALL_INCLUDEDIR@"
+#define LLVM_INSTALL_CMAKEDIR "@LLVM_INSTALL_CMAKE_DIR@"
#define LLVM_INSTALL_PACKAGE_DIR "@LLVM_INSTALL_PACKAGE_DIR@"
#define LLVM_TARGETS_BUILT "@LLVM_TARGETS_BUILT@"
#define LLVM_SYSTEM_LIBS "@LLVM_SYSTEM_LIBS@"
#define LLVM_BUILD_SYSTEM "@LLVM_BUILD_SYSTEM@"
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 8ed88f33ead4..5e7184bab90d 100644
index b1d795a0a349..de6cb1514f05 100644
--- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp
@@ -363,12 +363,20 @@ int main(int argc, char **argv) {
ActiveIncludeDir = std::string(Path.str());
}
{
- SmallString<256> Path(LLVM_TOOLS_INSTALL_DIR);
+ SmallString<256> Path(LLVM_INSTALL_BINDIR);
@@ -366,7 +366,11 @@ int main(int argc, char **argv) {
sys::fs::make_absolute(ActivePrefix, Path);
ActiveBinDir = std::string(Path.str());
}
- ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX;
- ActiveCMakeDir = ActiveLibDir + "/cmake/llvm";
+ {
+ SmallString<256> Path(LLVM_INSTALL_LIBDIR LLVM_LIBDIR_SUFFIX);
+ sys::fs::make_absolute(ActivePrefix, Path);
+ ActiveLibDir = std::string(Path.str());
+ }
+ {
+ SmallString<256> Path(LLVM_INSTALL_CMAKEDIR);
+ sys::fs::make_absolute(ActivePrefix, Path);
+ ActiveCMakeDir = std::string(Path.str());
+ }
ActiveIncludeOption = "-I" + ActiveIncludeDir;
}
{
SmallString<256> Path(LLVM_INSTALL_PACKAGE_DIR);
sys::fs::make_absolute(ActivePrefix, Path);

View File

@ -1,28 +0,0 @@
diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index 0aba18b20..9bb75e7f4 100644
--- a/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -33,6 +33,8 @@ ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits,
auto TargetABI = getTargetABI(ABIName);
bool IsRV64 = TT.isArch64Bit();
bool IsRV32E = FeatureBits[RISCV::FeatureRV32E];
+ bool IsRV32D = FeatureBits[RISCV::FeatureStdExtD];
+ bool IsRV32F = FeatureBits[RISCV::FeatureStdExtF];
if (!ABIName.empty() && TargetABI == ABI_Unknown) {
errs()
@@ -56,10 +58,10 @@ ABI computeTargetABI(const Triple &TT, FeatureBitset FeatureBits,
if (TargetABI != ABI_Unknown)
return TargetABI;
- // For now, default to the ilp32/ilp32e/lp64 ABI if no explicit ABI is given
- // or an invalid/unrecognised string is given. In the future, it might be
- // worth changing this to default to ilp32f/lp64f and ilp32d/lp64d when
- // hardware support for floating point is present.
+ if (IsRV32D)
+ return ABI_ILP32D;
+ if (IsRV32F)
+ return ABI_ILP32F;
if (IsRV32E)
return ABI_ILP32E;
if (IsRV64)

View File

@ -1,16 +0,0 @@
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 94d426b..37f7794 100644
--- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp
@@ -333,6 +333,11 @@ int main(int argc, char **argv) {
ActiveIncludeOption = "-I" + ActiveIncludeDir;
}
+ /// Nix-specific multiple-output handling: override ActiveLibDir
+ if (!IsInDevelopmentTree) {
+ ActiveLibDir = std::string("@lib@") + "/lib" + LLVM_LIBDIR_SUFFIX;
+ }
+
/// We only use `shared library` mode in cases where the static library form
/// of the components provided are not available; note however that this is
/// skipped if we're run from within the build dir. However, once installed,

15
nix/llvm/sources.nix Normal file
View File

@ -0,0 +1,15 @@
{ fetchurl }: rec {
version = "16.0.6";
cmake = fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/cmake-${version}.src.tar.xz";
sha256 = "sha256-OdNCpBYQldLyj7ElPkWFl4rFBSERfaZm4rH28oti9RQ=";
};
llvm = fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-${version}.src.tar.xz";
sha256 = "sha256-6R20TRs7scM/zqmn0fJCO4g+qpFj09VsoqptLwcRvCk=";
};
clang = fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/clang-${version}.src.tar.xz";
sha256 = "sha256-EYa25u7+rdCZEu1zs3KehbWfBDckuygYqVouwCRXGEA=";
};
}

View File

@ -31,32 +31,26 @@ let
suppress_build_script_link_lines=false
'';
};
sources = import ../llvm/sources.nix { inherit (pkgs) fetchurl; };
in rec {
llvm-nac3 = pkgs.stdenvNoCC.mkDerivation rec {
pname = "llvm-nac3-msys2";
version = "14.0.6";
src-llvm = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-${version}.src.tar.xz";
sha256 = "sha256-BQki7KrKV4H99mMeqSvHFRg/IC+dLxUUcibwI0FPYZo=";
};
src-clang = pkgs.fetchurl {
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/clang-${version}.src.tar.xz";
sha256 = "sha256-K1hHtqYxGLnv5chVSDY8gf/glrZsOzZ16VPiY0KuQDE=";
};
version = "16.0.6";
buildInputs = [ pkgs.wineWowPackages.stable ];
phases = [ "unpackPhase" "patchPhase" "configurePhase" "buildPhase" "installPhase" ];
unpackPhase =
''
mkdir llvm
tar xf ${src-llvm} -C llvm --strip-components=1
mv llvm/Modules/* llvm/cmake/modules # work around https://github.com/llvm/llvm-project/issues/53281
tar xf ${sources.llvm} -C llvm --strip-components=1
tar xf ${sources.cmake} -C llvm/cmake --strip-components=2
mkdir clang
tar xf ${src-clang} -C clang --strip-components=1
tar xf ${sources.clang} -C clang --strip-components=1
mkdir cmake
ln -s $PWD/llvm/cmake cmake/Modules
cd llvm
# build of llvm-lto fails and -DLLVM_BUILD_TOOLS=OFF does not disable it reliably because cmake
rm -rf tools/lto
'';
patches = [ ../llvm/llvm-future-riscv-abi.diff ];
configurePhase =
''
export HOME=`mktemp -d`
@ -65,7 +59,7 @@ in rec {
${silenceFontconfig}
mkdir build
cd build
wine64 cmake .. -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_UNWIND_TABLES=OFF -DLLVM_ENABLE_THREADS=ON -DLLVM_TARGETS_TO_BUILD=X86\;ARM\;RISCV -DLLVM_LINK_LLVM_DYLIB=OFF -DLLVM_ENABLE_FFI=OFF -DFFI_INCLUDE_DIR=fck-cmake -DFFI_LIBRARY_DIR=fck-cmake -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX=Z:$out
wine64 cmake .. -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_UNWIND_TABLES=OFF -DLLVM_ENABLE_THREADS=ON -DLLVM_TARGETS_TO_BUILD=X86\;ARM\;RISCV -DLLVM_LINK_LLVM_DYLIB=OFF -DLLVM_ENABLE_FFI=OFF -DFFI_INCLUDE_DIR=fck-cmake -DFFI_LIBRARY_DIR=fck-cmake -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX=Z:$out
'';
buildPhase =
''
@ -88,6 +82,9 @@ in rec {
src = ../../.;
cargoLock = {
lockFile = ../../Cargo.lock;
outputHashes = {
"inkwell-0.5.0" = "sha256-Qsqy/fhD/qK0rKBeXetE99vW9G9XAePxlXv0An3Yeuo=";
};
};
nativeBuildInputs = [ pkgs.wineWowPackages.stable ];
buildPhase =
@ -98,7 +95,7 @@ in rec {
${silenceFontconfig}
export PYO3_CONFIG_FILE=Z:${pyo3-mingw-config}
export CC=clang
export LLVM_SYS_140_PREFIX=Z:${llvm-nac3}
export LLVM_SYS_160_PREFIX=Z:${llvm-nac3}
wine64 cargo build --release -p nac3artiq
'';
installPhase =

View File

@ -1,21 +1,21 @@
{ pkgs } : [
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-19.1.6-1-any.pkg.tar.zst";
sha256 = "1gv6hbqvfgjzirpljql1shlchldmf5ww3rfsspg90pq1frnwavjl";
name = "mingw-w64-clang-x86_64-libunwind-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-19.1.7-1-any.pkg.tar.zst";
sha256 = "0yhxd3hix069gy2gh69vbyg95m6x5nar1r9rm3rb8459nlhqxid5";
name = "mingw-w64-clang-x86_64-libunwind-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-19.1.6-1-any.pkg.tar.zst";
sha256 = "1wbkvrx14ahc04cgkydvlxwmsl8jfnqwhy9sy4kn4wkdzmlcp1ax";
name = "mingw-w64-clang-x86_64-libc++-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc++-19.1.7-1-any.pkg.tar.zst";
sha256 = "09gbfk91j07a7pxqmama9rjnqdzr3nw9v92b865mrgbn3lz8p5a3";
name = "mingw-w64-clang-x86_64-libc++-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libffi-3.4.6-1-any.pkg.tar.zst";
sha256 = "1q6gms980985bp087rnnpvz2fwfakgm5266izfk3b1mbp620s1yv";
name = "mingw-w64-clang-x86_64-libffi-3.4.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libffi-3.4.7-1-any.pkg.tar.zst";
sha256 = "0yi36mq6gzf4bdmx19fh9wzq7592q2c0zq0zj6rc0zn0bglcnm0r";
name = "mingw-w64-clang-x86_64-libffi-3.4.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -31,9 +31,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.3-3-any.pkg.tar.zst";
sha256 = "1a7gc462gnrjy5qb0zfkr9qm8bsnnf02y6wp3c59n618dhsq7rcf";
name = "mingw-w64-clang-x86_64-xz-5.6.3-3-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-xz-5.6.4-1-any.pkg.tar.zst";
sha256 = "121srzvczq16aq0ki6yyym17lnjp6i4hka5wmydjvgrr7nbgik64";
name = "mingw-w64-clang-x86_64-xz-5.6.4-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -43,9 +43,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.9-2-any.pkg.tar.zst";
sha256 = "1b1r5llgqv88id8iwhqh23qwqmn5ic9hdamdc8xzij9hmcvdmmci";
name = "mingw-w64-clang-x86_64-libxml2-2.12.9-2-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.12.10-1-any.pkg.tar.zst";
sha256 = "1dch932lvsjfwp13cjm5d8sv84ql22c3gfjdrd4vayr8cpykfw4y";
name = "mingw-w64-clang-x86_64-libxml2-2.12.10-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -55,69 +55,69 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-19.1.6-1-any.pkg.tar.zst";
sha256 = "0fpsnfyf0bg39a4ygzga06sr4wv4jp1jnc8lk6sr3z0nim0nlhjn";
name = "mingw-w64-clang-x86_64-llvm-libs-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-19.1.7-1-any.pkg.tar.zst";
sha256 = "1688sknvlk8qy3zxh717pzdy882l5cmpbhyq8bg950hzvf1lpg79";
name = "mingw-w64-clang-x86_64-llvm-libs-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-19.1.6-1-any.pkg.tar.zst";
sha256 = "0whqs9nvfmgxj3c83px6dipcdw9zi858kgd8130201fy1mbnafp1";
name = "mingw-w64-clang-x86_64-llvm-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-19.1.7-1-any.pkg.tar.zst";
sha256 = "0c02mphj003s6k92nxkcvih3m7lj16wi0hwf17qr6m69b0dv691p";
name = "mingw-w64-clang-x86_64-llvm-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-19.1.6-1-any.pkg.tar.zst";
sha256 = "0rmzri7h043i73jy3c2jcrg3hy40dr5s9n96kmxgaghfhvlpilps";
name = "mingw-w64-clang-x86_64-clang-libs-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-19.1.7-1-any.pkg.tar.zst";
sha256 = "08ksr9jvbqb3shrixgjazrq0v3ag3g9ysqc93miwj57z7g75z8j4";
name = "mingw-w64-clang-x86_64-clang-libs-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-19.1.6-1-any.pkg.tar.zst";
sha256 = "04cqlh35asvlh06nmhwnx9h0yrqk8zxd9lpzxmm1xh64kvm9maxn";
name = "mingw-w64-clang-x86_64-compiler-rt-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-19.1.7-1-any.pkg.tar.zst";
sha256 = "04icdns7wydlagc2h9m587859x0pad62gkqg12vcc2nwgl485lz0";
name = "mingw-w64-clang-x86_64-compiler-rt-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
sha256 = "05zsqgq8zwdcfacyqdxdjcf80447bgnrz71xv5cds0y135yziy7l";
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
sha256 = "0zmwqbmdhgkr8qpyxad64ks9p8lxw9mkr2hj7v5fnqcnsswlj8c6";
name = "mingw-w64-clang-x86_64-headers-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
sha256 = "12fkxpk7rwy36snvvc7sdivx81pd4ckzh5ilyh7gl6ly4qayppp6";
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
sha256 = "14nmaw2rjs1818b8gi0n227ifcwi9s4sg9d6kv5yivpvn6pxyrvl";
name = "mingw-w64-clang-x86_64-crt-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-19.1.6-1-any.pkg.tar.zst";
sha256 = "102bbv5acq1fvrfn8bp1x3503cb8hvcxmlpr86qsba4vm11l0wrw";
name = "mingw-w64-clang-x86_64-lld-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-19.1.7-1-any.pkg.tar.zst";
sha256 = "1z1h40yfllns0n679j9s98r0hvg7i67kmhhf7iw97kz66jc1dkfy";
name = "mingw-w64-clang-x86_64-lld-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
sha256 = "1sris0qczxk5px9xy85976hbmqrpg49ns7yyzd9p455ckf740cid";
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
sha256 = "0bk73xy9hgffc2pvainwvnprcxngx8y7af8w72i279cdd5f9xx1f";
name = "mingw-w64-clang-x86_64-libwinpthread-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
sha256 = "1r0m5xpsxdl00a2daj4p0wgl6037700pvw6p6zl91h1dr092r6pa";
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r473.gce0d0bfb7-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
sha256 = "18y196l9dhqdqmjvs7g2jzdm8rrbrr5rqff7l30a9hpgwmra2xgv";
name = "mingw-w64-clang-x86_64-winpthreads-git-12.0.0.r509.g079e6092b-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-19.1.6-1-any.pkg.tar.zst";
sha256 = "0j4a642fpnvqs79chhinc8r5q53q1wllmc1bzb01a4y7w9rqg4hw";
name = "mingw-w64-clang-x86_64-clang-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-19.1.7-1-any.pkg.tar.zst";
sha256 = "1cgm8mdlfi18494zqz88gkgxagqhb82ls5hlgn07r3xldcwz4dma";
name = "mingw-w64-clang-x86_64-clang-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.84.0-1-any.pkg.tar.zst";
sha256 = "0nrz9788grl50nkbhxswry143rrwpdnc6pk6f0k30kcp19qq6y2d";
name = "mingw-w64-clang-x86_64-rust-1.84.0-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-rust-1.84.1-1-any.pkg.tar.zst";
sha256 = "064l3kxrmx2fj19ljq0xv3cpb24spg2a33lk13z90fzymivwxsab";
name = "mingw-w64-clang-x86_64-rust-1.84.1-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -157,9 +157,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libtasn1-4.19.0-1-any.pkg.tar.zst";
sha256 = "19m59mjxww26ah2gk9c0i512fmqpyaj6r5na564kmg6wpwvkihcj";
name = "mingw-w64-clang-x86_64-libtasn1-4.19.0-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libtasn1-4.20.0-1-any.pkg.tar.zst";
sha256 = "0hv0xayhzhpwp8bdcs2r4xdvimk6266h68ki8abnii0pqiwfi86r";
name = "mingw-w64-clang-x86_64-libtasn1-4.20.0-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -175,9 +175,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.4.0-1-any.pkg.tar.zst";
sha256 = "0cgiqjmgdnwnv9r88z634dmqrzh06dmsfncyzymw0s16nnv2k7k2";
name = "mingw-w64-clang-x86_64-openssl-3.4.0-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-openssl-3.4.1-1-any.pkg.tar.zst";
sha256 = "0c5n7pib853xpgqxs0lb9gdaz4lbia94nf2jps1j7rispspclwwk";
name = "mingw-w64-clang-x86_64-openssl-3.4.1-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -199,9 +199,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.11.1-1-any.pkg.tar.zst";
sha256 = "16yvyqjzxyzawgv26r1g145wphvhjil2b0pyhy4nj7v5d19n6wvh";
name = "mingw-w64-clang-x86_64-curl-8.11.1-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-curl-8.12.1-1-any.pkg.tar.zst";
sha256 = "05hq63qibshgar42vi6dsrcph3m1i0khnr2xdkvdqjjys7badrvp";
name = "mingw-w64-clang-x86_64-curl-8.12.1-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -253,9 +253,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libuv-1.49.2-1-any.pkg.tar.zst";
sha256 = "1b9slshbcprxjaj2qqypaywr0f2pgajg1bgspjk83hk65sx6sklb";
name = "mingw-w64-clang-x86_64-libuv-1.49.2-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libuv-1.50.0-1-any.pkg.tar.zst";
sha256 = "1qwds9kl6x1afqwpqkha1my7xzwh39q5v0rrkj997i2wa1xgpr5c";
name = "mingw-w64-clang-x86_64-libuv-1.50.0-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -277,9 +277,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.31.4-1-any.pkg.tar.zst";
sha256 = "1xjjwgkqf2j97pcx0yd6j0lgmzgbgqjjf0s7j29mc03g89fhdhw0";
name = "mingw-w64-clang-x86_64-cmake-3.31.4-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-cmake-3.31.5-1-any.pkg.tar.zst";
sha256 = "04zyhhi3a58y5fy8l9nnsmn1qh5h1n02czh9d81f4fcnjs9fs4rj";
name = "mingw-w64-clang-x86_64-cmake-3.31.5-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -325,21 +325,21 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tzdata-2024b-1-any.pkg.tar.zst";
sha256 = "0jihnr1i7vyzczxz60ds1x3gcm3p4ad2pq9d5vvpwjdwrxkvxmkc";
name = "mingw-w64-clang-x86_64-tzdata-2024b-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-tzdata-2025a-1-any.pkg.tar.zst";
sha256 = "1q09i8lj96m1kwkxh0qs96ssam8a6vpiylrlf4i55zrazrj9kvk1";
name = "mingw-w64-clang-x86_64-tzdata-2025a-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.12.8-2-any.pkg.tar.zst";
sha256 = "0lksgrmylvpr7yyjcc1szm30pnag7ixrj7vhdql1ryi4k9309v8s";
name = "mingw-w64-clang-x86_64-python-3.12.8-2-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-3.12.9-3-any.pkg.tar.zst";
sha256 = "054v2fw5rbj9n264alpav50573npa706lsmlxilcyc4xxc87k9v9";
name = "mingw-w64-clang-x86_64-python-3.12.9-3-any.pkg.tar.zst";
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-19.1.6-1-any.pkg.tar.zst";
sha256 = "0d3mm26hnw716n0ppzqhydxcgm4im081hiiy6l4zp267ad3kfg93";
name = "mingw-w64-clang-x86_64-llvm-openmp-19.1.6-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-openmp-19.1.7-1-any.pkg.tar.zst";
sha256 = "05qz2niykj5azx3n3wr2h48152ahcfcj9xsdpdqqvada1hh4c6cx";
name = "mingw-w64-clang-x86_64-llvm-openmp-19.1.7-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {
@ -349,9 +349,9 @@
})
(pkgs.fetchurl {
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-numpy-2.2.1-1-any.pkg.tar.zst";
sha256 = "0sgkhax9cwmkkrfrir45l91h6pgg339gaw6147gsayf8h8ag4brg";
name = "mingw-w64-clang-x86_64-python-numpy-2.2.1-1-any.pkg.tar.zst";
url = "https://mirror.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-python-numpy-2.2.3-1-any.pkg.tar.zst";
sha256 = "0jzx828gb3d1pw7w4asv4jhp4yi802qdllkvb1c58msmn43pp76b";
name = "mingw-w64-clang-x86_64-python-numpy-2.2.3-1-any.pkg.tar.zst";
})
(pkgs.fetchurl {