You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

156 lines
3.2 KiB

pub mod function;
pub mod nat;
pub mod types;
pub(self) use self::{function::*, types::*};
pub(self) use super::parser::Datum;
pub(self) use crate::ffi;
pub(self) use llvm_sys::{
analysis::*, core::*, execution_engine::*, prelude::*, target::*,
target_machine::*,
};
#[derive(Error, Debug)]
pub enum Err {
#[error("Couldn't initialize JIT: {0}")]
JitInit(String),
#[error("Verifying function failed: {0}")]
VerifyFunc(String),
#[error("Invalid syntax")]
Syntax,
#[error("Not in compilation context")]
Context,
}
pub struct Context {
contx: LLVMContextRef,
modul: LLVMModuleRef,
build: LLVMBuilderRef,
engin: LLVMExecutionEngineRef,
types: Vec<ComplType>,
funcs: Vec<Function>,
}
impl Context {
pub fn new() -> Result<Self, Err> {
const MODULE: ffi::Nts = c_str!("main");
const NAT_FUNCTIONS: &[fn(&mut Context)] = &[
nat::c_dbgi,
nat::c_addi,
nat::c_subi,
nat::c_muli,
nat::c_divi,
nat::c_remi,
];
unsafe {
init_llvm();
}
let contx = unsafe { LLVMContextCreate() };
let modul = unsafe { LLVMModuleCreateWithNameInContext(MODULE, contx) };
let build = unsafe { LLVMCreateBuilderInContext(contx) };
let engin = unsafe { jit_engine(modul)? };
let types = Vec::new();
let funcs = Vec::new();
let mut c = Self { contx, modul, build, engin, types, funcs };
for ty in types::Basic::iter() {
c.types.push(types::ComplType::Basic(types::BasicType::new(ty)));
}
for decl in NAT_FUNCTIONS.iter() {
decl(&mut c);
}
Ok(c)
}
pub fn basic_type(&self, ty: Basic) -> &ComplType {
&self.types[usize::from(u8::from(ty))]
}
pub fn compile_all(&self, datum: Vec<Datum>) -> Result<(), Err> {
let mut main = IncompleteFunction::new(
self,
c_str!("-main"),
blonkus_ma::compl_type![self, || -> Void],
);
main.begin_context(|f| {
for data in datum {
f.compile(&data)?;
}
Ok(())
})?;
let _main = main.complete()?;
Ok(())
}
pub fn execute(&self) -> Result<(), Err> {
unsafe {
let func: unsafe extern "C" fn() = std::mem::transmute(
LLVMGetFunctionAddress(self.engin, c_str!("-main")),
);
func();
}
Ok(())
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
LLVMDisposeExecutionEngine(self.engin);
LLVMDisposeBuilder(self.build);
LLVMContextDispose(self.contx);
}
}
}
unsafe fn jit_engine(
modul: LLVMModuleRef,
) -> Result<LLVMExecutionEngineRef, Err> {
let mut opt = LLVMMCJITCompilerOptions {
OptLevel: LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive as _,
CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
NoFramePointerElim: 0,
EnableFastISel: 0,
MCJMM: std::ptr::null_mut(),
};
let mut jit = std::ptr::null_mut();
let mut msg = std::ptr::null_mut();
let res = LLVMCreateMCJITCompilerForModule(
&mut jit,
modul,
&mut opt,
std::mem::size_of::<LLVMMCJITCompilerOptions>(),
&mut msg,
);
if res != 0 {
let msg =
ffi::cstr_from_ptr(msg).unwrap_or("Couldn't parse error").to_owned();
Err(Err::JitInit(msg))
} else {
Ok(jit)
}
}
unsafe fn init_llvm() {
static INIT: std::sync::Once = std::sync::Once::new();
INIT.call_once(|| {
LLVMLinkInMCJIT();
LLVM_InitializeNativeTarget();
LLVM_InitializeNativeAsmPrinter();
LLVM_InitializeNativeAsmParser();
});
}
// EOF