feat: migrate to cranelift (WIP)

This commit is contained in:
2025-06-27 22:40:53 +08:00
parent e26789f3b7
commit 5625f28e9b
13 changed files with 720 additions and 732 deletions

421
Cargo.lock generated
View File

@@ -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"

View File

@@ -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 }

View File

@@ -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<HashSet<Dep>>,
jit: &'exec JITContext<'ctx>,
compiled: Box<[OnceCell<JITFunc<'ctx, 'exec>>]>,
jit: &'exec JITContext,
compiled: Box<[OnceCell<JITFunc<'exec>>]>,
tasks: PriorityQueue<CompileTask, usize>,
}
@@ -79,8 +80,12 @@ impl<'ctx, 'exec> Engine<'ctx, 'exec> {
}
pub fn eval_thunk(&mut self, idx: usize, env: &mut Env) -> Result<i::Value> {
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<JITValue> = MaybeUninit::uninit();
unsafe {
func(self as *const Engine, env as *const Env, core::mem::transmute::<*mut MaybeUninit<JITValue>, *mut JITValue>(&mut ret as *mut _));
Ok(ret.assume_init().into())
}
}
pub fn eval_func_deps(&mut self, idx: usize, env: &mut Env) -> Result<()> {

View File

@@ -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<HashMap<usize, Value>>,
with: Vec<Rc<HashMap<EcoString, Value>>>,
args: Vec<Value>,
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<Value> {

View File

@@ -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,
}

View File

@@ -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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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(
let arg_ptr = unsafe {
ctx.func_builder
.build_gep(
ctx.helpers.value_type,
args,
&[ctx.helpers.const_ptr_int(i)],
"args_gep",
)
},
arg.compile(ctx, func, values),
)
.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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> 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<Value>,
) -> StructValue<'gc> {
ctx: &mut JITContext,
builder: &mut FunctionBuilder,
block: Block,
) -> ir::Value {
todo!()
}
}

View File

@@ -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(&not, 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<Env>, level: u64) {
dbg!(env, level);
dbg!(unsafe { env.as_ref() }.lookup_arg(level as usize));
}
extern "C" fn helper_lookup_arg(env_ptr: NonNull<Env>, level: u64, ret: NonNull<JITValue>) {
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<Env>, 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<Env>, 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::<JITValue>(len).unwrap()) }
unsafe { alloc(Layout::array::<JITValue>(len).unwrap()) }
}

View File

@@ -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<JITValue> 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<Value> for JITValue {
Value::List(list) => JITValue {
tag: ValueTag::List,
data: JITValueData {
slice: Slice {
ptr: list.as_ptr() as *const (),
len: list.len(),
},
},
},
Value::Func(idx) => JITValue {
@@ -103,69 +99,82 @@ impl From<Value> 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<F<'ctx, 'exec>> for JITFunc<'ctx, 'exec> {
fn from(value: F<'ctx, 'exec>) -> Self {
impl<'exec> From<F<'exec>> 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(
std::mem::transmute(
self.execution_engine
.get_function(func.get_name().to_str().unwrap())
.unwrap()
.into_raw(),
.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,

View File

@@ -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 }),
);

View File

@@ -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<Value>) -> 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),)*
}
}
}

View File

@@ -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::*;

View File

@@ -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<H: std::hash::Hasher>(&self, state: &mut H) {
fn hash<H: core::hash::Hasher>(&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),

View File

@@ -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<Self>) -> Rc<HashMap<EcoString, Value>> {
unsafe { std::mem::transmute(self) }
unsafe { core::mem::transmute(self) }
}
pub fn from_inner(data: HashMap<EcoString, Value>) -> Self {