From 5625f28e9bf00b75627672aeeceda33f7624c30d Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Fri, 27 Jun 2025 22:40:53 +0800 Subject: [PATCH] feat: migrate to cranelift (WIP) --- Cargo.lock | 421 ++++++++++++++++++++++++++++--------- Cargo.toml | 5 +- src/engine/mod.rs | 17 +- src/env.rs | 6 +- src/error.rs | 4 +- src/eval/jit/compile.rs | 353 ++++++++++++++++--------------- src/eval/jit/helpers.rs | 367 +++++++------------------------- src/eval/jit/mod.rs | 245 +++++++++------------ src/ir/ctx.rs | 12 +- src/ir/mod.rs | 6 +- src/stack.rs | 4 +- src/ty/common.rs | 8 +- src/ty/internal/attrset.rs | 4 +- 13 files changed, 720 insertions(+), 732 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 047f162..fcf8a27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,12 +23,24 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.0" @@ -36,12 +48,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] -name = "cc" -version = "1.2.21" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" dependencies = [ - "shlex", + "allocator-api2", ] [[package]] @@ -80,6 +92,177 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" +[[package]] +name = "cranelift" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c4a83217cefee80a63921d524b7c98c4dc0c9913bd876fcdfa76a4fcef9b62" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", + "cranelift-module", +] + +[[package]] +name = "cranelift-assembler-x64" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b7077389885873ffad5d778e8512742580a6e11b0f723072f41f305d3652f" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9cfeae5a23c8cf9c43381f49211f3ce6dc1da1d46f1c5d06966e6258cc483fa" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c88c577c6af92b550cb83455c331cf8e1bc89fe0ccc3e7eb0fa617ed1d63056" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "370f0aa7f1816bf0f838048d69b72d6cf12ef2fc3b37f6997fe494ffb9feb3ad" + +[[package]] +name = "cranelift-codegen" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1a10a8a2958b68ecd261e565eef285249e242a8447ac959978319eabbb4a55" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.15.3", + "log", + "regalloc2", + "rustc-hash 2.1.1", + "serde", + "smallvec", + "target-lexicon", + "wasmtime-math", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f319986d5ae1386cfec625c70f8c01e52dc1f910aa6aaee7740bf8842d4e19c7" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed52f5660397039c3c741c3acf18746445f4e20629b7280d9f2ccfe57e2b1efd" + +[[package]] +name = "cranelift-control" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79bde8d48e1840702574e28c5d7d4499441435af71e6c47450881f84ce2b60a5" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0335ac187211ac94c254826b6e78d23b8654ae09ebf0830506a827a2647162f" +dependencies = [ + "cranelift-bitset", +] + +[[package]] +name = "cranelift-frontend" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fce5fcf93c1fece95d0175b15fbaf0808b187430bc06c8ecde80db0ed58c5e" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13fc8d838a2bf28438dbaf6ccdbc34531b6a972054f43fd23be7f124121ce6e0" + +[[package]] +name = "cranelift-jit" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e50932cee220b782812b728c0e63adf2b8eef63e823df8e5fea84c18f3fff99" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-module", + "cranelift-native", + "libc", + "log", + "region", + "target-lexicon", + "wasmtime-jit-icache-coherence", + "windows-sys 0.59.0", +] + +[[package]] +name = "cranelift-module" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2707466bd2c786bd637e6b6375ebb472a158be35b6efbe85d2a744ec82e16356" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", +] + +[[package]] +name = "cranelift-native" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0975ce66adcf2e0729d06b1d3efea0398d793d1f39c2e0a6f52a347537836693" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.121.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4493a9b500bb02837ea2fb7d4b58c1c21c37a470ae33c92659f4e637aad14c9" + [[package]] name = "derive_more" version = "2.0.1" @@ -133,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -142,6 +325,12 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fd-lock" version = "4.0.4" @@ -150,7 +339,7 @@ checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -159,6 +348,17 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -182,7 +382,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -195,31 +395,6 @@ dependencies = [ "hashbrown 0.15.3", ] -[[package]] -name = "inkwell" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67349bd7578d4afebbe15eaa642a80b884e8623db74b1716611b131feb1deef" -dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "inkwell_internals" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f365c8de536236cfdebd0ba2130de22acefed18b1fb99c32783b3840aec5fb46" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "itertools" version = "0.14.0" @@ -229,38 +404,24 @@ dependencies = [ "either", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libc" version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "linux-raw-sys" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" -[[package]] -name = "llvm-sys" -version = "181.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320f9d2723c97d4b78f9190a61ed25cc7cfbe456668c08e6e7dd8e50ceb8500" -dependencies = [ - "anyhow", - "cc", - "lazy_static", - "libc", - "regex-lite", - "semver", -] - [[package]] name = "log" version = "0.4.27" @@ -276,6 +437,15 @@ dependencies = [ "hashbrown 0.15.3", ] +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -306,7 +476,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cfg-if", "cfg_aliases", "libc", @@ -316,10 +486,13 @@ dependencies = [ name = "nixjit" version = "0.0.0" dependencies = [ + "cranelift", + "cranelift-jit", + "cranelift-module", + "cranelift-native", "derive_more", "ecow", "hashbrown 0.15.3", - "inkwell", "itertools", "lru", "priority-queue", @@ -327,15 +500,9 @@ dependencies = [ "replace_with", "rnix", "rustyline", - "thiserror 2.0.12", + "thiserror", ] -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - [[package]] name = "priority-queue" version = "2.5.0" @@ -375,6 +542,20 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "regalloc2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.3", + "log", + "rustc-hash 2.1.1", + "smallvec", +] + [[package]] name = "regex" version = "1.11.1" @@ -398,18 +579,24 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-lite" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" - [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "mach2", + "windows-sys 0.52.0", +] + [[package]] name = "replace_with" version = "0.1.8" @@ -434,7 +621,7 @@ dependencies = [ "countme", "hashbrown 0.14.3", "memoffset", - "rustc-hash", + "rustc-hash 1.1.0", "text-size", ] @@ -444,17 +631,23 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -463,7 +656,7 @@ version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ee1e066dc922e513bda599c6ccb5f3bb2b0ea5870a579448f2622993f0a9a2f" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cfg-if", "clipboard-win", "fd-lock", @@ -476,20 +669,28 @@ dependencies = [ "unicode-segmentation", "unicode-width", "utf8parse", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] -name = "semver" -version = "1.0.26" +name = "serde" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] [[package]] -name = "shlex" -version = "1.3.0" +name = "serde_derive" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "smallvec" @@ -497,6 +698,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "2.0.101" @@ -508,39 +715,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" + [[package]] name = "text-size" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "thiserror-impl", ] [[package]] @@ -584,6 +777,36 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "34.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c71d64e8ebe132cd45e9d299a4d0daf261d66bd05cf50a204a1bf8cf96ff1f" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-math" +version = "34.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222bfa4769c6931c985711eb49a92748ea0acc4ca85fcd24e945a2f1bacda0c1" +dependencies = [ + "libm", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 988e521..bc281a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,9 @@ hashbrown = "0.15" priority-queue = "2.5" lru = "0.14" replace_with = "0.1" -inkwell = { version = "0.6.0", features = ["llvm18-1"] } +cranelift = "0.121" +cranelift-module = "0.121" +cranelift-jit = "0.121" +cranelift-native = "0.121" rustyline = { version = "15.0", optional = true } diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 46ed558..1463d4f 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -1,4 +1,5 @@ use std::cell::OnceCell; +use core::mem::MaybeUninit; use std::rc::Rc; use hashbrown::HashSet; @@ -7,7 +8,7 @@ use priority_queue::PriorityQueue; use crate::env::Env; use crate::error::Result; -use crate::eval::jit::{JITContext, JITFunc}; +use crate::eval::jit::{JITContext, JITFunc, JITValue}; use crate::eval::Evaluate; use crate::ir::{Dep, Downgraded, Ir, SccNode}; use crate::ty::internal as i; @@ -19,12 +20,12 @@ mod test; type ThunkIdx = usize; type EnvIdx = usize; -pub struct Engine<'ctx: 'exec, 'exec> { +pub struct Engine<'exec> { pub thunks: Box<[Ir]>, pub func_offset: usize, pub func_deps: Vec>, - jit: &'exec JITContext<'ctx>, - compiled: Box<[OnceCell>]>, + jit: &'exec JITContext, + compiled: Box<[OnceCell>]>, tasks: PriorityQueue, } @@ -79,8 +80,12 @@ impl<'ctx, 'exec> Engine<'ctx, 'exec> { } pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result { - let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx])); - Ok(unsafe { func(self as *const Engine, env as *const Env).into() }) + let func = self.compiled[idx].get_or_init(|| self.jit.compile(&self.thunks[idx], idx)); + let mut ret: MaybeUninit = MaybeUninit::uninit(); + unsafe { + func(self as *const Engine, env as *const Env, core::mem::transmute::<*mut MaybeUninit, *mut JITValue>(&mut ret as *mut _)); + Ok(ret.assume_init().into()) + } } pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> { diff --git a/src/env.rs b/src/env.rs index 7798f3a..567f982 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,4 +1,4 @@ -use std::fmt::Debug; +use core::fmt::Debug; use std::rc::Rc; use ecow::EcoString; @@ -12,7 +12,6 @@ pub struct Env { cache: Vec>, with: Vec>>, args: Vec, - pub args_len: usize, } impl Env { @@ -21,7 +20,6 @@ impl Env { cache: Vec::from([HashMap::new()]), with: Vec::new(), args: Vec::new(), - args_len: 0, } } @@ -89,7 +87,7 @@ impl Env { } pub fn enter_arg(&mut self, arg: Value) { - self.args.push(arg) + self.args.push(arg); } pub fn pop_args(&mut self, len: usize) -> Vec { diff --git a/src/error.rs b/src/error.rs index 3970873..02e53dc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,8 +10,8 @@ pub enum Error { DowngradeError(String), #[error("error occurred during evaluation stage: {0}")] EvalError(String), - #[error("error occurred during JIT compile stage: {0}")] - CompileError(#[from] inkwell::builder::BuilderError), + // #[error("error occurred during JIT compile stage: {0}")] + // CompileError(#[from] inkwell::builder::BuilderError), #[error("unknown error")] Unknown, } diff --git a/src/eval/jit/compile.rs b/src/eval/jit/compile.rs index c8ca698..528ad83 100644 --- a/src/eval/jit/compile.rs +++ b/src/eval/jit/compile.rs @@ -1,70 +1,71 @@ use std::{alloc::Layout, ffi::CStr}; -use inkwell::values::{FunctionValue, StructValue}; +use cranelift::prelude::*; +use cranelift::codegen::ir; +use crate::eval::jit::JITValue; +use crate::ir::*; use crate::ty::common as c; use crate::ty::internal::Value; -use crate::{eval::jit::JITValue, ir::*}; use super::{JITContext, ValueTag}; pub trait JITCompile { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc>; + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value; } impl JITCompile for Attrs { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for List { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for HasAttr { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for BinOp { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { use BinOpKind::*; - use ValueTag::*; - let lhs = self.lhs.compile(ctx, func, values); - let rhs = self.rhs.compile(ctx, func, values); + let lhs = self.lhs.compile(ctx, builder, block); + let rhs = self.rhs.compile(ctx, builder, block); let lhs_tag = ctx.get_tag(lhs); let rhs_tag = ctx.get_tag(rhs); let tag = ctx - .builder + .func_builder .build_int_add( lhs_tag.const_shl(ctx.helpers.const_int(8)), rhs_tag, @@ -73,7 +74,7 @@ impl JITCompile for BinOp { .unwrap(); let ret = ctx.context.append_basic_block(func, "fallback"); let res = ctx - .builder + .func_builder .build_alloca(ctx.helpers.value_type, "res_alloca") .unwrap(); match self.kind { @@ -83,7 +84,7 @@ impl JITCompile for BinOp { let float_int = ctx.context.append_basic_block(func, "float_int"); let float_float = ctx.context.append_basic_block(func, "float_float"); let fallback = ctx.context.append_basic_block(func, "fallback"); - ctx.builder + ctx.func_builder .build_switch( tag, fallback, @@ -107,19 +108,19 @@ impl JITCompile for BinOp { ], ) .unwrap(); - ctx.builder.position_at_end(int_int); + ctx.func_builder.position_at_end(int_int); let val = ctx - .builder + .func_builder .build_int_add(ctx.get_int(lhs), ctx.get_int(rhs), "add") .unwrap(); - ctx.builder + ctx.func_builder .build_store(res, ctx.helpers.new_value(Int, val.into())) .unwrap(); - ctx.builder.position_at_end(int_float); + ctx.func_builder.position_at_end(int_float); let val = ctx - .builder + .func_builder .build_float_add( - ctx.builder + ctx.func_builder .build_signed_int_to_float( ctx.get_int(lhs), ctx.helpers.float_type, @@ -130,15 +131,15 @@ impl JITCompile for BinOp { "add", ) .unwrap(); - ctx.builder + ctx.func_builder .build_store(res, ctx.helpers.new_value(Float, val.into())) .unwrap(); - ctx.builder.position_at_end(float_int); + ctx.func_builder.position_at_end(float_int); let val = ctx - .builder + .func_builder .build_float_add( ctx.get_float(lhs), - ctx.builder + ctx.func_builder .build_signed_int_to_float( ctx.get_int(rhs), ctx.helpers.float_type, @@ -148,23 +149,23 @@ impl JITCompile for BinOp { "add", ) .unwrap(); - ctx.builder + ctx.func_builder .build_store(res, ctx.helpers.new_value(Float, val.into())) .unwrap(); - ctx.builder.position_at_end(int_int); + ctx.func_builder.position_at_end(int_int); let val = ctx - .builder + .func_builder .build_float_add(ctx.get_float(lhs), ctx.get_float(rhs), "add") .unwrap(); - ctx.builder + ctx.func_builder .build_store(res, ctx.helpers.new_value(Float, val.into())) .unwrap(); - ctx.builder.position_at_end(fallback); + ctx.func_builder.position_at_end(fallback); } Or => { let bool_bool = ctx.context.append_basic_block(func, "int_int"); let fallback = ctx.context.append_basic_block(func, "fallback"); - ctx.builder + ctx.func_builder .build_switch( tag, fallback, @@ -174,20 +175,20 @@ impl JITCompile for BinOp { )], ) .unwrap(); - ctx.builder.position_at_end(bool_bool); + ctx.func_builder.position_at_end(bool_bool); let val = ctx - .builder + .func_builder .build_or(ctx.get_bool(lhs), ctx.get_bool(rhs), "or") .unwrap(); - ctx.builder + ctx.func_builder .build_store(res, ctx.helpers.new_value(Bool, val.into())) .unwrap(); - ctx.builder.position_at_end(fallback); + ctx.func_builder.position_at_end(fallback); } _ => todo!(), } - ctx.builder.position_at_end(ret); - ctx.builder + ctx.func_builder.position_at_end(ret); + ctx.func_builder .build_load(ctx.helpers.value_type, res, "load_res") .unwrap() .try_into() @@ -196,25 +197,25 @@ impl JITCompile for BinOp { } impl JITCompile for UnOp { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!(); - let rhs = self.rhs.compile(ctx, func, values); + let rhs = self.rhs.compile(ctx, builder, block); let tag = ctx.get_tag(rhs); let fallback = ctx.context.append_basic_block(func, "fallback"); let ret = ctx.context.append_basic_block(func, "fallback"); let res = ctx - .builder + .func_builder .build_alloca(ctx.helpers.value_type, "res_alloca") .unwrap(); - ctx.builder.build_switch(tag, fallback, &[]).unwrap(); - ctx.builder.position_at_end(fallback); - ctx.builder.position_at_end(ret); - ctx.builder + ctx.func_builder.build_switch(tag, fallback, &[]).unwrap(); + ctx.func_builder.position_at_end(fallback); + ctx.func_builder.position_at_end(ret); + ctx.func_builder .build_load(ctx.helpers.value_type, res, "load_res") .unwrap() .try_into() @@ -223,34 +224,34 @@ impl JITCompile for UnOp { } impl JITCompile for Select { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for If { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for LoadFunc { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - _: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { ctx.helpers.new_value( ValueTag::Function, ctx.helpers.const_int(self.idx as i64).into(), @@ -259,14 +260,18 @@ impl JITCompile for LoadFunc { } impl JITCompile for Call { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { + let ret = ctx + .func_builder + .build_alloca(ctx.helpers.value_type, "ret") + .unwrap(); let args = ctx - .builder + .func_builder .build_call( ctx.helpers.alloc_array, &[ctx.helpers.const_ptr_int(self.args.len()).into()], @@ -277,89 +282,93 @@ impl JITCompile for Call { .unwrap_left() .into_pointer_value(); for (i, arg) in self.args.iter().enumerate() { - ctx.builder - .build_store( - unsafe { - args.const_in_bounds_gep( - ctx.helpers.value_type, - &[ctx.helpers.const_ptr_int(i)], - ) - }, - arg.compile(ctx, func, values), - ) + let arg_ptr = unsafe { + ctx.func_builder + .build_gep( + ctx.helpers.value_type, + args, + &[ctx.helpers.const_ptr_int(i)], + "args_gep", + ) + .unwrap() + }; + ctx.func_builder + .build_store(arg_ptr, arg.compile(ctx, builder, block)) .unwrap(); } - ctx.builder + ctx.func_builder .build_call( ctx.helpers.call, &[ - self.func.compile(ctx, func, values).into(), + self.func.compile(ctx, builder, block).into(), args.into(), ctx.helpers.const_ptr_int(self.args.len()).into(), - func.get_first_param().unwrap().into(), - func.get_last_param().unwrap().into(), + func.get_nth_param(0).unwrap().into(), + func.get_nth_param(1).unwrap().into(), + ret.into(), ], "call", ) + .unwrap(); + ctx.func_builder + .build_load(ctx.helpers.value_type, ret, "load_ret") .unwrap() - .try_as_basic_value() - .unwrap_left() - .try_into() - .unwrap() + .into_struct_value() } } impl JITCompile for Let { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { unreachable!() } } impl JITCompile for With { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { + todo!() todo!() } } impl JITCompile for Assert { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for ConcatStrings { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for Const { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { use c::Const::*; match self.val { Bool(x) => ctx.helpers.new_bool(x), @@ -371,28 +380,27 @@ impl JITCompile for Const { } impl JITCompile for String { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } impl JITCompile for Var { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { let env = func.get_nth_param(1).unwrap(); let ptr = self.sym.as_ptr(); let len = self.sym.len(); - // values.push(Value::String(self.sym.clone())); - ctx.builder + ctx.func_builder .build_direct_call( ctx.helpers.lookup, &[ @@ -411,43 +419,54 @@ impl JITCompile for Var { } impl JITCompile for Arg { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { - let env = func.get_last_param().unwrap(); - let ret = ctx.builder.build_alloca(ctx.helpers.value_type, "alloca_ret").unwrap(); - ctx.builder + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { + let env = builder.block_params(block)[]; + let env = func.get_nth_param(1).unwrap(); + let arg = ctx + .func_builder + .build_alloca(ctx.helpers.value_type, "alloca_arg") + .unwrap(); + ctx.func_builder .build_direct_call( ctx.helpers.lookup_arg, - &[env.into(), ctx.helpers.const_ptr_int(self.level).into(), ret.into()], + &[ + env.into(), + ctx.helpers.const_ptr_int(self.level).into(), + arg.into(), + ], "lookup_arg", ) .unwrap(); - ctx.builder.build_load(ctx.helpers.value_type,ret, "load_ret").unwrap().into_struct_value() + ctx.func_builder + .build_load(ctx.helpers.value_type, arg, "load_arg") + .unwrap() + .into_struct_value() } } impl JITCompile for LetVar { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { unreachable!() } } impl JITCompile for Thunk { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - _: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { ctx.helpers.new_value( ValueTag::Thunk, ctx.helpers.const_int(self.idx as i64).into(), @@ -456,12 +475,12 @@ impl JITCompile for Thunk { } impl JITCompile for Path { - fn compile<'gc>( + fn compile( &self, - ctx: &JITContext<'gc>, - func: FunctionValue<'gc>, - values: &mut Vec, - ) -> StructValue<'gc> { + ctx: &mut JITContext, + builder: &mut FunctionBuilder, + block: Block, + ) -> ir::Value { todo!() } } diff --git a/src/eval/jit/helpers.rs b/src/eval/jit/helpers.rs index 9f5cbbd..461e9df 100644 --- a/src/eval/jit/helpers.rs +++ b/src/eval/jit/helpers.rs @@ -1,14 +1,14 @@ use std::alloc::Layout; -use std::ffi::CStr; -use std::ptr::NonNull; -use std::{slice, str}; +use std::alloc::alloc; +use core::ptr::NonNull; +use core::{slice, str}; -use inkwell::AddressSpace; -use inkwell::context::Context; -use inkwell::execution_engine::ExecutionEngine; -use inkwell::module::Module; -use inkwell::types::{FloatType, FunctionType, IntType, PointerType, StructType}; -use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, StructValue}; +use cranelift::codegen::ir::ArgumentExtension; +use cranelift::codegen::ir::ArgumentPurpose; +use cranelift::prelude::*; +use cranelift_module::FuncId; +use cranelift_module::Linkage; +use cranelift_module::Module; use crate::env::Env; use crate::eval::Engine; @@ -16,153 +16,71 @@ use crate::ty::internal::Value; use super::{JITContext, JITValue, JITValueData, ValueTag}; -pub struct Helpers<'ctx> { - pub int_type: IntType<'ctx>, - pub float_type: FloatType<'ctx>, - pub bool_type: IntType<'ctx>, - pub ptr_int_type: IntType<'ctx>, - pub ptr_type: PointerType<'ctx>, - pub value_type: StructType<'ctx>, - pub func_type: FunctionType<'ctx>, +pub struct Helpers { + pub int_type: Type, + pub float_type: Type, + pub bool_type: Type, + pub ptr_int_type: Type, + pub ptr_type: Type, + pub value_type: Type, + pub func_sig: Signature, - pub new_thunk: FunctionValue<'ctx>, - pub debug: FunctionValue<'ctx>, - pub capture_env: FunctionValue<'ctx>, - pub neg: FunctionValue<'ctx>, - pub not: FunctionValue<'ctx>, - pub add: FunctionValue<'ctx>, - pub sub: FunctionValue<'ctx>, - pub eq: FunctionValue<'ctx>, - pub or: FunctionValue<'ctx>, - pub call: FunctionValue<'ctx>, - pub lookup_arg: FunctionValue<'ctx>, - pub lookup: FunctionValue<'ctx>, - pub force: FunctionValue<'ctx>, + pub call: FuncId, + pub lookup_arg: FuncId, + pub lookup: FuncId, + pub force: FuncId, - pub alloc_array: FunctionValue<'ctx>, + pub alloc_array: FuncId, } -impl<'ctx> Helpers<'ctx> { +impl Helpers { pub fn new( - ctx: &'ctx Context, - module: &Module<'ctx>, - execution_engine: &ExecutionEngine<'ctx>, + ctx: &codegen::Context, + module: &mut dyn Module, ) -> Self { - let int_type = ctx.i64_type(); - let float_type = ctx.f64_type(); - let bool_type = ctx.bool_type(); - let ptr_int_type = ctx.ptr_sized_int_type(execution_engine.get_target_data(), None); - let ptr_type = ctx.ptr_type(AddressSpace::default()); - let value_type = - ctx.struct_type(&[int_type.into(), int_type.into(), int_type.into()], false); - let func_type = value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false); + let int_type = types::I64; + let float_type = types::F64; + let bool_type = types::I8; + // let ptr_type = ctx.ptr_type(AddressSpace::default()); + let ptr_type = module.target_config().pointer_type(); + let ptr_int_type = ptr_type; + let value_type = types::I128; + // let func_sig = ctx.void_type().fn_type(&[ptr_type.into(), ptr_type.into(), ptr_type.into()], false); + let mut func_sig = Signature::new(isa::CallConv::SystemV); + func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + func_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + func_sig.returns.push(AbiParam { value_type, purpose: ArgumentPurpose::StructReturn, extension: ArgumentExtension::None }); - let new_thunk = module.add_function( - "new_thunk", - value_type.fn_type(&[ptr_type.into(), ptr_type.into()], false), - None, - ); - let capture_env = module.add_function( - "capture_env", - ctx - .void_type() - .fn_type(&[value_type.into(), ptr_type.into()], false), - None, - ); - let neg = module.add_function( - "neg", - value_type.fn_type(&[value_type.into(), ptr_type.into()], false), - None, - ); - let not = module.add_function( - "not", - value_type.fn_type(&[value_type.into(), ptr_type.into()], false), - None, - ); - let add = module.add_function( - "add", - value_type.fn_type(&[value_type.into(), value_type.into()], false), - None, - ); - let sub = module.add_function( - "sub", - value_type.fn_type(&[value_type.into(), value_type.into()], false), - None, - ); - let eq = module.add_function( - "eq", - value_type.fn_type(&[value_type.into(), value_type.into()], false), - None, - ); - let or = module.add_function( - "or", - value_type.fn_type(&[value_type.into(), value_type.into()], false), - None, - ); - let call = module.add_function( - "call", - value_type.fn_type( - &[ - value_type.into(), - ptr_type.into(), - ptr_int_type.into(), - ptr_type.into(), - ptr_type.into(), - ], - false, - ), - None, - ); - let debug = module.add_function( - "debug", - ctx - .void_type() - .fn_type(&[ptr_type.into(), int_type.into()], false), - None, - ); - let lookup_arg = module.add_function( - "lookup_arg", - // value_type.fn_type(&[ptr_type.into(), int_type.into()], false), - ctx.void_type().fn_type(&[ptr_type.into(), int_type.into(), ptr_type.into()], false), - None, - ); - let lookup = module.add_function( - "lookup", - value_type.fn_type( - &[ptr_int_type.into(), ptr_type.into(), ptr_int_type.into()], - false, - ), - None, - ); - let force = module.add_function( - "force", - value_type.fn_type( - &[value_type.into(), ptr_type.into(), ptr_type.into()], - false, - ), - None, - ); - let alloc_array = module.add_function( - "alloc_array", - value_type.fn_type(&[ptr_int_type.into()], false), - None, - ); + let mut call_sig = Signature::new(isa::CallConv::SystemV); + call_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None }); + call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + call_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + call_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + let call = module.declare_function("helper_call", Linkage::Import, &call_sig).unwrap(); - execution_engine.add_global_mapping(&new_thunk, helper_new_thunk as _); - execution_engine.add_global_mapping(&debug, helper_debug as _); - execution_engine.add_global_mapping(&capture_env, helper_capture_env as _); - execution_engine.add_global_mapping(&neg, helper_neg as _); - execution_engine.add_global_mapping(¬, helper_not as _); - execution_engine.add_global_mapping(&add, helper_add as _); - execution_engine.add_global_mapping(&sub, helper_sub as _); - execution_engine.add_global_mapping(&eq, helper_eq as _); - execution_engine.add_global_mapping(&or, helper_or as _); - execution_engine.add_global_mapping(&call, helper_call as _); - execution_engine.add_global_mapping(&lookup_arg, helper_lookup_arg as _); - execution_engine.add_global_mapping(&lookup, helper_lookup as _); - execution_engine.add_global_mapping(&force, helper_force as _); - execution_engine.add_global_mapping(&alloc_array, helper_alloc_array as _); + let mut lookup_arg_sig = Signature::new(isa::CallConv::SystemV); + lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + lookup_arg_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + let lookup_arg = module.declare_function("helper_lookup_arg", Linkage::Import, &call_sig).unwrap(); + + let mut lookup_sig = Signature::new(isa::CallConv::SystemV); + lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + lookup_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + lookup_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + let lookup = module.declare_function("helper_lookup", Linkage::Import, &call_sig).unwrap(); + + let mut force_sig = Signature::new(isa::CallConv::SystemV); + force_sig.params.push(AbiParam { value_type, purpose: ArgumentPurpose::StructArgument(24), extension: ArgumentExtension::None }); + force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + force_sig.params.push(AbiParam { value_type: ptr_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + let force = module.declare_function("helper_force", Linkage::Import, &call_sig).unwrap(); + + let mut alloc_array_sig = Signature::new(isa::CallConv::SystemV); + alloc_array_sig.params.push(AbiParam { value_type: ptr_int_type, purpose: ArgumentPurpose::Normal, extension: ArgumentExtension::None }); + let alloc_array = module.declare_function("helper_alloc_array", Linkage::Import, &call_sig).unwrap(); Helpers { int_type, @@ -171,18 +89,8 @@ impl<'ctx> Helpers<'ctx> { ptr_int_type, ptr_type, value_type, - func_type, + func_sig, - new_thunk, - - debug, - capture_env, - neg, - not, - add, - sub, - eq, - or, call, lookup_arg, lookup, @@ -192,7 +100,7 @@ impl<'ctx> Helpers<'ctx> { } } - pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum<'ctx>) -> StructValue<'ctx> { + pub fn new_value(&self, tag: ValueTag, data: BasicValueEnum) -> StructValue { self.value_type.const_named_struct(&[ self.const_int(tag as i64).into(), data, @@ -200,143 +108,39 @@ impl<'ctx> Helpers<'ctx> { ]) } - pub fn const_ptr_int(&self, int: usize) -> IntValue<'ctx> { + pub fn const_ptr_int(&self, int: usize) -> IntValue { self.ptr_int_type.const_int(int as _, false) } - pub fn const_int(&self, int: i64) -> IntValue<'ctx> { + pub fn const_int(&self, int: i64) -> IntValue { self.int_type.const_int(int as _, false) } - pub fn new_int(&self, int: i64) -> StructValue<'ctx> { + pub fn new_int(&self, int: i64) -> StructValue { self.new_value(ValueTag::Int, self.const_int(int).into()) } - pub fn const_float(&self, float: f64) -> FloatValue<'ctx> { + pub fn const_float(&self, float: f64) -> FloatValue { self.float_type.const_float(float) } - pub fn new_float(&self, float: f64) -> StructValue<'ctx> { + pub fn new_float(&self, float: f64) -> StructValue { self.new_value(ValueTag::Float, self.const_float(float).into()) } - pub fn const_bool(&self, bool: bool) -> IntValue<'ctx> { + pub fn const_bool(&self, bool: bool) -> IntValue { self.bool_type.const_int(bool as _, false) } - pub fn new_bool(&self, bool: bool) -> StructValue<'ctx> { + pub fn new_bool(&self, bool: bool) -> StructValue { self.new_value(ValueTag::Bool, self.const_bool(bool).into()) } - pub fn new_null(&self) -> StructValue<'ctx> { + pub fn new_null(&self) -> StructValue { self.new_value(ValueTag::Null, self.int_type.const_zero().into()) } } -extern "C" fn helper_capture_env(thunk: JITValue, env: *const Env) { - todo!() -} - -extern "C" fn helper_neg(rhs: JITValue, _env: *const Env) -> JITValue { - use ValueTag::*; - match rhs.tag { - Int => JITValue { - tag: Int, - data: JITValueData { - int: -unsafe { rhs.data.int }, - }, - }, - Float => JITValue { - tag: Float, - data: JITValueData { - float: -unsafe { rhs.data.float }, - }, - }, - _ => todo!(), - } -} - -extern "C" fn helper_not(rhs: JITValue, _env: *const Env) -> JITValue { - use ValueTag::*; - match rhs.tag { - Bool => JITValue { - tag: Bool, - data: JITValueData { - bool: !unsafe { rhs.data.bool }, - }, - }, - _ => todo!(), - } -} - -extern "C" fn helper_add(lhs: JITValue, rhs: JITValue) -> JITValue { - use ValueTag::*; - match (lhs.tag, rhs.tag) { - (Int, Int) => JITValue { - tag: Int, - data: JITValueData { - int: unsafe { lhs.data.int + rhs.data.int }, - }, - }, - _ => todo!( - "Addition not implemented for {:?} and {:?}", - lhs.tag, - rhs.tag - ), - } -} - -extern "C" fn helper_sub(lhs: JITValue, rhs: JITValue) -> JITValue { - use ValueTag::*; - match (lhs.tag, rhs.tag) { - (Int, Int) => JITValue { - tag: Int, - data: JITValueData { - int: unsafe { lhs.data.int - rhs.data.int }, - }, - }, - _ => todo!( - "Substruction not implemented for {:?} and {:?}", - lhs.tag, - rhs.tag - ), - } -} - -extern "C" fn helper_eq(lhs: JITValue, rhs: JITValue) -> JITValue { - use ValueTag::*; - match (lhs.tag, rhs.tag) { - (Int, Int) => JITValue { - tag: Bool, - data: JITValueData { - bool: unsafe { lhs.data.int == rhs.data.int }, - }, - }, - _ => todo!( - "Equation not implemented for {:?} and {:?}", - lhs.tag, - rhs.tag - ), - } -} - -extern "C" fn helper_or(lhs: JITValue, rhs: JITValue) -> JITValue { - use ValueTag::*; - match (lhs.tag, rhs.tag) { - (Bool, Bool) => JITValue { - tag: Bool, - data: JITValueData { - bool: unsafe { lhs.data.bool || rhs.data.bool }, - }, - }, - _ => todo!( - "Substraction not implemented for {:?} and {:?}", - lhs.tag, - rhs.tag - ), - } -} - extern "C" fn helper_call( func: JITValue, args: *mut JITValue, @@ -354,19 +158,12 @@ extern "C" fn helper_call( unsafe { env.as_mut() }, ) .unwrap(); - todo!() + func.into() } -extern "C" fn helper_debug(env: NonNull, level: u64) { - dbg!(env, level); - dbg!(unsafe { env.as_ref() }.lookup_arg(level as usize)); -} - -extern "C" fn helper_lookup_arg(env_ptr: NonNull, level: u64, ret: NonNull) { - dbg!(env_ptr, level); - let env_ref = unsafe { env_ptr.as_ref() }; - let val: JITValue = env_ref.lookup_arg(level as usize).into(); - unsafe { ret.write(val) } +extern "C" fn helper_lookup_arg(env: NonNull, level: u64) -> JITValue { + let env_ref = unsafe { env.as_ref() }; + env_ref.lookup_arg(level as usize).into() } extern "C" fn helper_lookup(env: NonNull, ptr: *const u8, len: usize) -> JITValue { @@ -391,10 +188,6 @@ extern "C" fn helper_force( todo!() } -extern "C" fn helper_new_thunk(opcodes: *const ()) -> JITValue { - todo!() -} - unsafe extern "C" fn helper_alloc_array(len: usize) -> *mut u8 { - unsafe { std::alloc::alloc(Layout::array::(len).unwrap()) } + unsafe { alloc(Layout::array::(len).unwrap()) } } diff --git a/src/eval/jit/mod.rs b/src/eval/jit/mod.rs index abbcf15..5025e9d 100644 --- a/src/eval/jit/mod.rs +++ b/src/eval/jit/mod.rs @@ -2,14 +2,11 @@ use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; -use inkwell::OptimizationLevel; -use inkwell::builder::Builder; -use inkwell::context::Context; -use inkwell::execution_engine::ExecutionEngine; -use inkwell::module::Module; -use inkwell::values::{ - AnyValue, BasicMetadataValueEnum, FloatValue, IntValue, PointerValue, StructValue, -}; +use cranelift::codegen::ir::Function; +use cranelift::prelude::*; +use cranelift::codegen::ir; +use cranelift_module::{DataDescription, Linkage, Module}; +use cranelift_jit::{JITModule, JITBuilder}; use crate::engine::Engine; use crate::env::Env; @@ -22,19 +19,30 @@ mod helpers; pub use compile::JITCompile; use helpers::Helpers; -#[repr(u64)] -#[derive(Debug, Clone, Copy)] -pub enum ValueTag { - Null, - Int, - Float, - String, - Bool, - AttrSet, - List, - Function, - Thunk, - Path, +#[repr(transparent)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ValueTag(u64); + +#[allow(non_upper_case_globals)] +#[allow(non_snake_case)] +impl ValueTag { + const Null: Self = Self(0); + const Int: Self = Self(1); + const Float: Self = Self(2); + const Path: Self = Self(3); + const Bool: Self = Self(4); + const AttrSet: Self = Self(5); + const List: Self = Self(6); + const Function: Self = Self(7); + const Thunk: Self = Self(8); + + pub fn String(len: usize) -> Self { + Self(len as u64 ^ (1 << 31)) + } + + pub fn is_str(&self) -> bool { + self.0 >> 31 != 0 + } } #[repr(C)] @@ -51,24 +59,15 @@ pub union JITValueData { float: f64, bool: bool, ptr: *const (), - slice: Slice, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Slice { - ptr: *const (), - len: usize, } impl From for Value { fn from(value: JITValue) -> Self { - use ValueTag::*; match value.tag { - Int => Value::Int(unsafe { value.data.int }), - Null => Value::Null, - Function => Value::Func(unsafe { value.data.int as usize }), - Thunk => Value::Thunk(unsafe { value.data.int as usize }), + ValueTag::Int => Value::Int(unsafe { value.data.int }), + ValueTag::Null => Value::Null, + ValueTag::Function => Value::Func(unsafe { value.data.int as usize }), + ValueTag::Thunk => Value::Thunk(unsafe { value.data.int as usize }), _ => todo!("not implemented for {:?}", value.tag), } } @@ -84,10 +83,7 @@ impl From for JITValue { Value::List(list) => JITValue { tag: ValueTag::List, data: JITValueData { - slice: Slice { - ptr: list.as_ptr() as *const (), - len: list.len(), - }, + ptr: list.as_ptr() as *const (), }, }, Value::Func(idx) => JITValue { @@ -103,69 +99,82 @@ impl From for JITValue { } } -pub struct JITFunc<'ctx, 'exec>(F<'ctx, 'exec>, PhantomData<&'exec mut ()>); -type F<'ctx, 'exec> = unsafe extern "C" fn(*const Engine<'ctx, 'exec>, *const Env) -> JITValue; +pub struct JITFunc<'exec>(F<'exec>, PhantomData<&'exec mut ()>); +type F<'exec> = unsafe extern "C" fn(*const Engine<'exec>, *const Env, *mut JITValue); -impl<'ctx, 'exec> From> for JITFunc<'ctx, 'exec> { - fn from(value: F<'ctx, 'exec>) -> Self { +impl<'exec> From> for JITFunc<'exec> { + fn from(value: F<'exec>) -> Self { Self(value, PhantomData) } } -impl<'ctx: 'exec, 'exec> Deref for JITFunc<'ctx, 'exec> { - type Target = F<'ctx, 'exec>; +impl<'exec> Deref for JITFunc<'exec> { + type Target = F<'exec>; fn deref(&self) -> &Self::Target { &self.0 } } -pub struct JITContext<'ctx> { - context: &'ctx Context, - module: Module<'ctx>, - builder: Builder<'ctx>, - execution_engine: ExecutionEngine<'ctx>, +pub struct JITContext { + func_builder: FunctionBuilderContext, - helpers: Helpers<'ctx>, + ctx: codegen::Context, + data_description: DataDescription, + module: JITModule, + func: Function, + + helpers: Helpers, } -impl<'ctx> JITContext<'ctx> { - pub fn new(context: &'ctx Context) -> Self { - // force linker to link JIT engine - unsafe { - inkwell::llvm_sys::execution_engine::LLVMLinkInMCJIT(); - } - let module = context.create_module("nixjit"); - let execution_engine = module - .create_jit_execution_engine(OptimizationLevel::Aggressive) +impl JITContext { + pub fn new() -> Self { + let mut flag_builder = settings::builder(); + flag_builder.set("use_colocated_libcalls", "false").unwrap(); + flag_builder.set("is_pic", "false").unwrap(); + let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| { + panic!("host machine is not supported: {}", msg); + }); + let isa = isa_builder + .finish(settings::Flags::new(flag_builder)) .unwrap(); - let helpers = Helpers::new(context, &module, &execution_engine); + let builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); - JITContext { - execution_engine, - builder: context.create_builder(), - context, + let mut module = JITModule::new(builder); + let ctx = module.make_context(); + + Self { + func_builder: FunctionBuilderContext::new(), + helpers: Helpers::new(&ctx, &mut module), + data_description: DataDescription::new(), + func: Function::new(), + ctx, module, - - helpers, } } - pub fn compile<'exec>(&'exec self, ir: &Ir) -> JITFunc<'ctx, 'exec> { - let func = self - .module - .add_function("nixjit_func", self.helpers.func_type, None); - let entry = self.context.append_basic_block(func, "entry"); - self.builder.position_at_end(entry); + pub fn compile<'exec>(&'exec mut self, ir: &Ir, id: usize) -> JITFunc<'exec> { + let func_id = self.module.declare_function(format!("nixjit_thunk{id}").as_str(), Linkage::Local, &self.helpers.func_sig).unwrap(); + let mut func = Function::new(); + let builder = FunctionBuilder::new(&mut func, &mut self.func_builder); + let entry = builder.create_block(); + builder.switch_to_block(entry); // TODO: - let ret = ir.compile(self, func, &mut Vec::new()); - self.builder.build_return(Some(&ret)).unwrap(); - if func.verify(true) { + let ret = ir.compile(self, func_id, &mut Vec::new()); + self.func_builder + .build_store(func_id.get_nth_param(2).unwrap().into_pointer_value(), ret) + .unwrap(); + self.func_builder.build_return(None).unwrap(); + self.module.print_to_stderr(); + let _ = self.execution_engine.remove_module(&self.module); + let _ = self.execution_engine.add_module(&self.module); + if func_id.verify(true) { unsafe { JITFunc( - self.execution_engine - .get_function(func.get_name().to_str().unwrap()) - .unwrap() - .into_raw(), + std::mem::transmute( + self.execution_engine + .get_function_address(func_id.get_name().to_str().unwrap()) + .unwrap(), + ), PhantomData, ) } @@ -174,80 +183,18 @@ impl<'ctx> JITContext<'ctx> { } } - pub fn get_float(&self, val: StructValue<'ctx>) -> FloatValue<'ctx> { - let alloca = self - .builder - .build_alloca(self.helpers.int_type, "get_value_alloca") - .unwrap(); - self.builder.build_store(alloca, val).unwrap(); - self.builder - .build_load( - self.helpers.float_type, - self.builder - .build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep") - .unwrap(), - "get_value", - ) - .unwrap() - .into_float_value() + pub fn get_value(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value { + let offset = builder.ins().iconst(types::I8, 64); + builder.ins().rotl(val, offset) } - pub fn get_int(&self, val: StructValue<'ctx>) -> IntValue<'ctx> { - let alloca = self - .builder - .build_alloca(self.helpers.int_type, "get_value_alloca") - .unwrap(); - self.builder.build_store(alloca, val).unwrap(); - self.builder - .build_load( - self.helpers.int_type, - self.builder - .build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep") - .unwrap(), - "get_value", - ) - .unwrap() - .into_int_value() + pub fn get_tag(&self, builder: &mut FunctionBuilder, val: ir::Value) -> ir::Value { + let offset = builder.ins().iconst(types::I8, 64); + builder.ins().rotl(val, offset) } - pub fn get_bool(&self, val: StructValue<'ctx>) -> IntValue<'ctx> { - let alloca = self - .builder - .build_alloca(self.helpers.bool_type, "get_value_alloca") - .unwrap(); - self.builder.build_store(alloca, val).unwrap(); - self.builder - .build_load( - self.helpers.bool_type, - self.builder - .build_struct_gep(self.helpers.value_type, alloca, 1, "get_value_gep") - .unwrap(), - "get_value", - ) - .unwrap() - .into_int_value() - } - - pub fn get_tag(&self, val: StructValue<'ctx>) -> IntValue<'ctx> { - let alloca = self - .builder - .build_alloca(self.helpers.value_type, "get_tag_alloca") - .unwrap(); - self.builder.build_store(alloca, val).unwrap(); - self.builder - .build_load( - self.helpers.int_type, - self.builder - .build_struct_gep(self.helpers.value_type, alloca, 0, "get_tag_gep") - .unwrap(), - "get_tag", - ) - .unwrap() - .into_int_value() - } - - pub fn const_ptr(&self, ptr: *const ()) -> PointerValue<'ctx> { - self.builder + pub fn const_ptr(&self, ptr: *const ()) -> PointerValue { + self.func_builder .build_int_to_ptr( self.helpers.int_type.const_int(ptr as _, false), self.helpers.ptr_type, diff --git a/src/ir/ctx.rs b/src/ir/ctx.rs index 998c056..750dff3 100644 --- a/src/ir/ctx.rs +++ b/src/ir/ctx.rs @@ -195,11 +195,11 @@ impl DowngradeContext { || unreachable!(), |func| { unsafe { - let old = std::ptr::read(func); + let old = core::ptr::read(func); match old.resolve(Index::Func(idx), self_ptr.as_mut().unwrap(), env) { - Ok(ok) => std::ptr::write(func, ok), + Ok(ok) => core::ptr::write(func, ok), Err(err) => { - std::ptr::write( + core::ptr::write( func, Func { param: crate::ir::Param::Ident(EcoString::new()), @@ -225,11 +225,11 @@ impl DowngradeContext { || unreachable!(), |thunk| { unsafe { - let (old, _) = std::ptr::read(thunk); + let (old, _) = core::ptr::read(thunk); match old.resolve(Index::Thunk(idx), self_ptr.as_mut().unwrap(), env) { - Ok(ok) => std::ptr::write(&mut thunk.0, ok), + Ok(ok) => core::ptr::write(&mut thunk.0, ok), Err(err) => { - std::ptr::write( + core::ptr::write( &mut thunk.0, Ir::Const(super::Const { val: Const::Null }), ); diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 582cce8..60df80d 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,7 +1,7 @@ use derive_more::{IsVariant, TryUnwrap, Unwrap}; use ecow::EcoString; use hashbrown::HashMap; -use inkwell::values::{FunctionValue, StructValue}; +use cranelift::codegen; use itertools::Itertools; use rnix::ast::HasEntry; use rnix::ast::{self, Expr}; @@ -90,9 +90,9 @@ macro_rules! ir { } impl JITCompile for Ir { - fn compile<'ctx>(&self, ctx: &JITContext<'ctx>, func: FunctionValue<'ctx>, values: &mut Vec) -> StructValue<'ctx>{ + fn compile(&self, ctx: &mut JITContext, builder: &mut FunctionBuilder) -> StructValue{ match self { - $(Ir::$ty(ir) => ir.compile(ctx, func, values),)* + $(Ir::$ty(ir) => ir.compile(ctx, builder),)* } } } diff --git a/src/stack.rs b/src/stack.rs index 163a389..a79cfb0 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,5 +1,5 @@ -use std::mem::{MaybeUninit, replace, transmute}; -use std::ops::{Deref, DerefMut}; +use core::mem::{MaybeUninit, replace, transmute}; +use core::ops::{Deref, DerefMut}; use crate::error::*; diff --git a/src/ty/common.rs b/src/ty/common.rs index b42ada3..05bbf95 100644 --- a/src/ty/common.rs +++ b/src/ty/common.rs @@ -1,5 +1,5 @@ -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::hash::Hash; +use core::fmt::{Display, Formatter, Result as FmtResult}; +use core::hash::Hash; use derive_more::{Constructor, IsVariant, Unwrap}; use ecow::EcoString; @@ -30,9 +30,9 @@ pub enum Const { } impl Hash for Const { - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { use Const::*; - std::mem::discriminant(self).hash(state); + core::mem::discriminant(self).hash(state); match self { Int(x) => x.hash(state), Float(x) => x.to_bits().hash(state), diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index 627c70c..b4c7506 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -1,4 +1,4 @@ -use std::ops::Deref; +use core::ops::Deref; use std::rc::Rc; use derive_more::Constructor; @@ -99,7 +99,7 @@ impl AttrSet { } pub fn into_inner(self: Rc) -> Rc> { - unsafe { std::mem::transmute(self) } + unsafe { core::mem::transmute(self) } } pub fn from_inner(data: HashMap) -> Self {