167 lines
4.1 KiB
Rust
167 lines
4.1 KiB
Rust
use std::marker::PhantomData;
|
|
use std::ops::Deref;
|
|
|
|
use inkwell::OptimizationLevel;
|
|
use inkwell::builder::Builder;
|
|
use inkwell::context::Context;
|
|
use inkwell::execution_engine::ExecutionEngine;
|
|
use inkwell::module::Module;
|
|
use inkwell::values::{AnyValue, AsValueRef, BasicMetadataValueEnum, BasicValueEnum, IntValue, StructValue};
|
|
|
|
use crate::env::VmEnv;
|
|
use crate::ir::{Ir, UnOpKind};
|
|
use crate::ty::internal::Value;
|
|
|
|
mod compile;
|
|
mod helpers;
|
|
|
|
pub use compile::JITCompile;
|
|
use helpers::Helpers;
|
|
|
|
#[cfg(test)]
|
|
mod test;
|
|
|
|
#[repr(u64)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum ValueTag {
|
|
Null,
|
|
Int,
|
|
Float,
|
|
String,
|
|
Bool,
|
|
AttrSet,
|
|
List,
|
|
Function,
|
|
Thunk,
|
|
Path,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
pub struct JITValue {
|
|
tag: ValueTag,
|
|
data: JITValueData,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy)]
|
|
pub union JITValueData {
|
|
int: i64,
|
|
float: f64,
|
|
bool: bool,
|
|
ptr: *const (),
|
|
}
|
|
|
|
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 { Rc::from_raw(value.data.ptr as *const _) }),
|
|
Thunk => Value::Thunk(self::Thunk {
|
|
thunk: unsafe { Rc::from_raw(value.data.ptr as *const _) },
|
|
}), */
|
|
_ => todo!("not implemented for {:?}", value.tag),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Value> for JITValue {
|
|
fn from(value: Value) -> Self {
|
|
match value {
|
|
Value::Int(int) => JITValue {
|
|
tag: ValueTag::Int,
|
|
data: JITValueData { int },
|
|
},
|
|
/* Value::Func(func) => JITValue {
|
|
tag: ValueTag::Function,
|
|
data: JITValueData {
|
|
ptr: Rc::into_raw(func) as *const _,
|
|
},
|
|
},
|
|
Value::Thunk(thunk) => JITValue {
|
|
tag: ValueTag::Thunk,
|
|
data: JITValueData {
|
|
ptr: Rc::into_raw(thunk.thunk) as *const _,
|
|
},
|
|
}, */
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct JITFunc<'ctx>(F, PhantomData<&'ctx mut ()>);
|
|
type F = unsafe extern "C" fn(*const VmEnv) -> JITValue;
|
|
|
|
impl From<F> for JITFunc<'_> {
|
|
fn from(value: F) -> Self {
|
|
Self(value, PhantomData)
|
|
}
|
|
}
|
|
|
|
impl Deref for JITFunc<'_> {
|
|
type Target = F;
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
pub struct JITContext<'ctx> {
|
|
context: &'ctx Context,
|
|
module: Module<'ctx>,
|
|
builder: Builder<'ctx>,
|
|
execution_engine: ExecutionEngine<'ctx>,
|
|
|
|
helpers: Helpers<'ctx>,
|
|
}
|
|
|
|
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)
|
|
.unwrap();
|
|
let helpers = Helpers::new(context, &module, &execution_engine);
|
|
|
|
JITContext {
|
|
execution_engine,
|
|
builder: context.create_builder(),
|
|
context,
|
|
module,
|
|
|
|
helpers,
|
|
}
|
|
}
|
|
|
|
pub fn compile(&self, ir: Ir) -> JITFunc {
|
|
todo!()
|
|
}
|
|
|
|
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.context.bool_type(),
|
|
self.builder
|
|
.build_struct_gep(self.helpers.value_type, alloca, 1, "get_tag_gep").unwrap(),
|
|
"get_tag",
|
|
).unwrap()
|
|
.into_int_value()
|
|
}
|
|
|
|
pub fn call(&self, args: &[BasicMetadataValueEnum<'ctx>]) -> StructValue<'ctx> {
|
|
self.builder.build_call(self.helpers.call, args, "call")
|
|
.unwrap()
|
|
.as_any_value_enum()
|
|
.into_struct_value()
|
|
}
|
|
}
|