Some cleanups.
This commit is contained in:
134
src/backend.rs
134
src/backend.rs
@@ -1,85 +1,74 @@
|
||||
mod error;
|
||||
mod into_crane;
|
||||
mod runtime;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use self::error::BackendError;
|
||||
pub use self::runtime::{RuntimeFunctionError, RuntimeFunctions};
|
||||
use crate::ir;
|
||||
use codespan_reporting::diagnostic::Diagnostic;
|
||||
use cranelift_codegen::isa::LookupError;
|
||||
use cranelift_codegen::settings::{Configurable, SetError};
|
||||
use cranelift_codegen::{isa, settings, CodegenError};
|
||||
use cranelift_module::{default_libcall_names, FuncId, ModuleError};
|
||||
use cranelift_codegen::settings::{Configurable};
|
||||
use cranelift_codegen::{isa, settings};
|
||||
use cranelift_jit::{JITModule, JITBuilder};
|
||||
use cranelift_module::{default_libcall_names, DataContext, DataId, Module, Linkage, FuncId};
|
||||
use cranelift_object::{object, ObjectBuilder, ObjectModule};
|
||||
use target_lexicon::Triple;
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct Program {
|
||||
_func_id: FuncId,
|
||||
module: ObjectModule,
|
||||
const EMPTY_DATUM: [u8; 8] = [0; 8];
|
||||
|
||||
pub struct Backend<M: Module> {
|
||||
pub module: M,
|
||||
data_ctx: DataContext,
|
||||
runtime_functions: RuntimeFunctions,
|
||||
defined_strings: HashMap<String, DataId>,
|
||||
defined_symbols: HashMap<String, DataId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BackendError {
|
||||
#[error("Cranelift module error: {0}")]
|
||||
Cranelift(#[from] ModuleError),
|
||||
#[error("Builtin function error: {0}")]
|
||||
BuiltinError(#[from] RuntimeFunctionError),
|
||||
#[error("Internal variable lookup error")]
|
||||
VariableLookupFailure,
|
||||
#[error(transparent)]
|
||||
CodegenError(#[from] CodegenError),
|
||||
#[error(transparent)]
|
||||
SetError(#[from] SetError),
|
||||
#[error(transparent)]
|
||||
LookupError(#[from] LookupError),
|
||||
impl Backend<JITModule> {
|
||||
pub fn jit() -> Result<Self, BackendError> {
|
||||
let platform = Triple::host();
|
||||
let isa_builder = isa::lookup(platform.clone())?;
|
||||
let mut settings_builder = settings::builder();
|
||||
settings_builder.set("use_colocated_libcalls", "false")?;
|
||||
settings_builder.set("is_pic", "false")?;
|
||||
let isa = isa_builder.finish(settings::Flags::new(settings_builder))?;
|
||||
let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
|
||||
RuntimeFunctions::register_jit_implementations(&mut builder);
|
||||
|
||||
let mut module = JITModule::new(builder);
|
||||
let runtime_functions = RuntimeFunctions::new(&platform, &mut module)?;
|
||||
|
||||
Ok(Backend {
|
||||
module,
|
||||
data_ctx: DataContext::new(),
|
||||
runtime_functions,
|
||||
defined_strings: HashMap::new(),
|
||||
defined_symbols: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
impl From<BackendError> for Diagnostic<usize> {
|
||||
fn from(value: BackendError) -> Self {
|
||||
match value {
|
||||
BackendError::Cranelift(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal cranelift error: {}", me))
|
||||
}
|
||||
BackendError::BuiltinError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal runtime function error: {}", me))
|
||||
}
|
||||
BackendError::VariableLookupFailure => {
|
||||
Diagnostic::error().with_message("Internal variable lookup error!")
|
||||
}
|
||||
BackendError::CodegenError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal codegen error: {}", me))
|
||||
}
|
||||
BackendError::SetError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal backend setup error: {}", me))
|
||||
}
|
||||
BackendError::LookupError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal error: {}", me))
|
||||
}
|
||||
}
|
||||
pub fn bytes(&self, function_id: FuncId) -> *const u8 {
|
||||
self.module.get_finalized_function(function_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn new(platform: Triple, ir: ir::Program) -> Result<Program, BackendError> {
|
||||
impl Backend<ObjectModule> {
|
||||
pub fn object_file(platform: Triple) -> Result<Self, BackendError> {
|
||||
let isa_builder = isa::lookup(platform.clone())?;
|
||||
let mut settings_builder = settings::builder();
|
||||
settings_builder.set("is_pic", "true")?;
|
||||
let isa = isa_builder.finish(settings::Flags::new(settings_builder))?;
|
||||
|
||||
let object_builder = ObjectBuilder::new(isa, "example", default_libcall_names())?;
|
||||
let mut object_module = ObjectModule::new(object_builder);
|
||||
let rtfuns = RuntimeFunctions::new(&platform, &mut object_module)?;
|
||||
let mut module = ObjectModule::new(object_builder);
|
||||
let runtime_functions = RuntimeFunctions::new(&platform, &mut module)?;
|
||||
|
||||
Ok(Program {
|
||||
_func_id: ir.into_cranelift::<BackendError, _>(
|
||||
&mut object_module,
|
||||
"gogogo",
|
||||
&rtfuns,
|
||||
&HashMap::new(),
|
||||
&HashMap::new(),
|
||||
)?,
|
||||
module: object_module,
|
||||
Ok(Backend {
|
||||
module,
|
||||
data_ctx: DataContext::new(),
|
||||
runtime_functions,
|
||||
defined_strings: HashMap::new(),
|
||||
defined_symbols: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -87,3 +76,30 @@ impl Program {
|
||||
self.module.finish().emit()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Module> Backend<M>
|
||||
{
|
||||
pub fn define_string(&mut self, s: &str) -> Result<DataId, BackendError> {
|
||||
let name = format!("<string_constant>{}", s);
|
||||
let global_id = self
|
||||
.module
|
||||
.declare_data(&name, Linkage::Local, false, false)?;
|
||||
let mut data_context = DataContext::new();
|
||||
data_context.set_align(8);
|
||||
data_context.define(s.to_owned().into_boxed_str().into_boxed_bytes());
|
||||
self.module.define_data(global_id, &data_context)?;
|
||||
self.defined_strings.insert(s.to_owned(), global_id);
|
||||
Ok(global_id)
|
||||
}
|
||||
|
||||
pub fn define_variable(&mut self, name: String) -> Result<DataId, BackendError> {
|
||||
self.data_ctx.define(Box::new(EMPTY_DATUM));
|
||||
let id = self
|
||||
.module
|
||||
.declare_data(&name, Linkage::Export, true, false)?;
|
||||
self.module.define_data(id, &self.data_ctx)?;
|
||||
self.data_ctx.clear();
|
||||
self.defined_symbols.insert(name, id);
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
47
src/backend/error.rs
Normal file
47
src/backend/error.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use codespan_reporting::diagnostic::Diagnostic;
|
||||
use cranelift_codegen::{CodegenError, settings::SetError, isa::LookupError};
|
||||
use cranelift_module::ModuleError;
|
||||
use crate::backend::runtime::RuntimeFunctionError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BackendError {
|
||||
#[error("Cranelift module error: {0}")]
|
||||
Cranelift(#[from] ModuleError),
|
||||
#[error("Builtin function error: {0}")]
|
||||
BuiltinError(#[from] RuntimeFunctionError),
|
||||
#[error("Internal variable lookup error")]
|
||||
VariableLookupFailure,
|
||||
#[error(transparent)]
|
||||
CodegenError(#[from] CodegenError),
|
||||
#[error(transparent)]
|
||||
SetError(#[from] SetError),
|
||||
#[error(transparent)]
|
||||
LookupError(#[from] LookupError),
|
||||
}
|
||||
|
||||
impl From<BackendError> for Diagnostic<usize> {
|
||||
fn from(value: BackendError) -> Self {
|
||||
match value {
|
||||
BackendError::Cranelift(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal cranelift error: {}", me))
|
||||
}
|
||||
BackendError::BuiltinError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal runtime function error: {}", me))
|
||||
}
|
||||
BackendError::VariableLookupFailure => {
|
||||
Diagnostic::error().with_message("Internal variable lookup error!")
|
||||
}
|
||||
BackendError::CodegenError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal codegen error: {}", me))
|
||||
}
|
||||
BackendError::SetError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal backend setup error: {}", me))
|
||||
}
|
||||
BackendError::LookupError(me) => {
|
||||
Diagnostic::error().with_message(format!("Internal error: {}", me))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::backend::runtime::RuntimeFunctions;
|
||||
use crate::ir::{Expression, Primitive, Program, Statement, Value, ValueOrRef};
|
||||
use cranelift_codegen::entity::EntityRef;
|
||||
use cranelift_codegen::ir::{
|
||||
@@ -9,26 +8,20 @@ use cranelift_codegen::ir::{
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||
use cranelift_module::{DataContext, DataId, FuncId, Linkage, Module, ModuleError};
|
||||
use cranelift_module::{FuncId, Linkage, Module, ModuleError};
|
||||
use internment::ArcIntern;
|
||||
|
||||
use super::RuntimeFunctionError;
|
||||
use crate::backend::Backend;
|
||||
use crate::backend::error::BackendError;
|
||||
|
||||
type StringTable = HashMap<ArcIntern<String>, GlobalValue>;
|
||||
|
||||
impl Program {
|
||||
pub fn into_cranelift<E, M>(
|
||||
mut self,
|
||||
module: &mut M,
|
||||
impl<M: Module> Backend<M> {
|
||||
pub fn compile_function(
|
||||
&mut self,
|
||||
function_name: &str,
|
||||
rtfuns: &RuntimeFunctions,
|
||||
pre_defined_strings: &HashMap<String, DataId>,
|
||||
pre_defined_symbols: &HashMap<String, DataId>,
|
||||
) -> Result<FuncId, E>
|
||||
where
|
||||
E: From<ModuleError>,
|
||||
E: From<RuntimeFunctionError>,
|
||||
M: Module,
|
||||
mut program: Program,
|
||||
) -> Result<FuncId, BackendError>
|
||||
{
|
||||
let basic_signature = Signature {
|
||||
params: vec![],
|
||||
@@ -36,19 +29,20 @@ impl Program {
|
||||
call_conv: CallConv::SystemV,
|
||||
};
|
||||
|
||||
let func_id = module.declare_function(function_name, Linkage::Export, &basic_signature)?;
|
||||
let func_id = self.module.declare_function(function_name, Linkage::Export, &basic_signature)?;
|
||||
let mut ctx = Context::new();
|
||||
ctx.func =
|
||||
Function::with_name_signature(UserFuncName::user(0, func_id.as_u32()), basic_signature);
|
||||
|
||||
let string_table = self.build_string_table(module, &mut ctx.func, pre_defined_strings)?;
|
||||
let string_table = self.build_string_table(&mut ctx.func, &program)?;
|
||||
let mut variable_table = HashMap::new();
|
||||
let mut next_var_num = 1;
|
||||
let print_func_ref = rtfuns.include_runtime_function("print", module, &mut ctx.func)?;
|
||||
let pre_defined_symbols: HashMap<String, GlobalValue> = pre_defined_symbols
|
||||
let print_func_ref = self.runtime_functions.include_runtime_function("print", &mut self.module, &mut ctx.func)?;
|
||||
let pre_defined_symbols: HashMap<String, GlobalValue> = self
|
||||
.defined_symbols
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
let local_data = module.declare_data_in_func(*v, &mut ctx.func);
|
||||
let local_data = self.module.declare_data_in_func(*v, &mut ctx.func);
|
||||
(k.clone(), local_data)
|
||||
})
|
||||
.collect();
|
||||
@@ -58,7 +52,7 @@ impl Program {
|
||||
let main_block = builder.create_block();
|
||||
builder.switch_to_block(main_block);
|
||||
|
||||
for stmt in self.statements.drain(..) {
|
||||
for stmt in program.statements.drain(..) {
|
||||
match stmt {
|
||||
Statement::Print(ann, var) => {
|
||||
let local_name_ref = string_table.get(&var).unwrap();
|
||||
@@ -121,43 +115,24 @@ impl Program {
|
||||
builder.seal_block(main_block);
|
||||
builder.finalize();
|
||||
|
||||
let _ = module.define_function(func_id, &mut ctx)?;
|
||||
let _ = self.module.define_function(func_id, &mut ctx)?;
|
||||
|
||||
Ok(func_id)
|
||||
}
|
||||
|
||||
fn build_string_table<M: Module>(
|
||||
&self,
|
||||
module: &mut M,
|
||||
fn build_string_table(
|
||||
&mut self,
|
||||
func: &mut Function,
|
||||
pre_defined_strings: &HashMap<String, DataId>,
|
||||
) -> Result<StringTable, ModuleError> {
|
||||
program: &Program,
|
||||
) -> Result<StringTable, BackendError> {
|
||||
let mut string_table = HashMap::new();
|
||||
|
||||
for (idx, interned_value) in self.strings().drain().enumerate() {
|
||||
let global_id = match pre_defined_strings.get(interned_value.as_str()) {
|
||||
for interned_value in program.strings().drain() {
|
||||
let global_id = match self.defined_strings.get(interned_value.as_str()) {
|
||||
Some(x) => *x,
|
||||
None => {
|
||||
let global_id = module.declare_data(
|
||||
&format!("local-string-{}", idx),
|
||||
Linkage::Local,
|
||||
false,
|
||||
false,
|
||||
)?;
|
||||
let mut data_context = DataContext::new();
|
||||
data_context.set_align(8);
|
||||
data_context.define(
|
||||
interned_value
|
||||
.as_str()
|
||||
.to_owned()
|
||||
.into_boxed_str()
|
||||
.into_boxed_bytes(),
|
||||
);
|
||||
module.define_data(global_id, &data_context)?;
|
||||
global_id
|
||||
}
|
||||
None => self.define_string(interned_value.as_str())?,
|
||||
};
|
||||
let local_data = module.declare_data_in_func(global_id, func);
|
||||
let local_data = self.module.declare_data_in_func(global_id, func);
|
||||
string_table.insert(interned_value, local_data);
|
||||
}
|
||||
|
||||
|
||||
8
src/backend/object.rs
Normal file
8
src/backend/object.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
struct BackendObject {
|
||||
}
|
||||
|
||||
impl BackendObject {
|
||||
pub fn new() -> Result<Self, ()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
use cranelift_codegen::ir::{types, AbiParam, FuncRef, Function, Signature};
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use cranelift_jit::JITBuilder;
|
||||
use cranelift_module::{FuncId, Linkage, Module, ModuleResult};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CStr;
|
||||
use target_lexicon::Triple;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -16,6 +18,12 @@ pub enum RuntimeFunctionError {
|
||||
CannotFindRuntimeFunction(String),
|
||||
}
|
||||
|
||||
extern "C" fn runtime_print(name: *const i8, value: u64) {
|
||||
let cstr = unsafe { CStr::from_ptr(name) };
|
||||
let reconstituted = cstr.to_string_lossy();
|
||||
println!("{} = {}", reconstituted, value);
|
||||
}
|
||||
|
||||
impl RuntimeFunctions {
|
||||
pub fn new<M: Module>(platform: &Triple, module: &mut M) -> ModuleResult<RuntimeFunctions> {
|
||||
let mut builtin_functions = HashMap::new();
|
||||
@@ -54,4 +62,9 @@ impl RuntimeFunctions {
|
||||
Some(func_id) => Ok(module.declare_func_in_func(*func_id, func)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_jit_implementations(builder: &mut JITBuilder) {
|
||||
builder.symbol("print", runtime_print as *const u8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use cranelift_object::object;
|
||||
|
||||
use ngr::backend::BackendError;
|
||||
use ngr::backend::Program as Cranelift;
|
||||
use ngr::backend::Backend;
|
||||
use ngr::ir::Program as IR;
|
||||
use ngr::syntax::{ParserError, Program as Syntax};
|
||||
use target_lexicon::Triple;
|
||||
@@ -70,8 +70,9 @@ fn compile(file_database: &mut SimpleFiles<String, String>) -> Result<(), MainEr
|
||||
}
|
||||
|
||||
let ir = IR::from(syntax.simplify());
|
||||
let compiled = Cranelift::new(Triple::host(), ir)?;
|
||||
let bytes = compiled.bytes()?;
|
||||
let mut backend = Backend::object_file(Triple::host())?;
|
||||
backend.compile_function("gogogo", ir)?;
|
||||
let bytes = backend.bytes()?;
|
||||
std::fs::write(args.output.unwrap_or_else(|| "output.o".to_string()), bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use codespan_reporting::diagnostic::Diagnostic;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term::{self, Config};
|
||||
use cranelift_jit::JITModule;
|
||||
use cranelift_module::ModuleError;
|
||||
use ngr::backend::{Backend, BackendError};
|
||||
use ngr::ir::Program as IR;
|
||||
use ngr::jit::{JITEngine, JITError};
|
||||
use ngr::syntax::{Location, ParserError, Statement};
|
||||
use pretty::termcolor::{ColorChoice, StandardStream, WriteColor};
|
||||
use rustyline::error::ReadlineError;
|
||||
@@ -11,7 +13,7 @@ use std::collections::HashMap;
|
||||
|
||||
pub struct RunLoop<'a> {
|
||||
file_database: SimpleFiles<&'a str, String>,
|
||||
jitter: JITEngine,
|
||||
jitter: Backend<JITModule>,
|
||||
variable_binding_sites: HashMap<String, Location>,
|
||||
gensym_index: usize,
|
||||
writer: &'a mut dyn WriteColor,
|
||||
@@ -24,7 +26,9 @@ enum REPLError {
|
||||
#[error("Error parsing statement: {0}")]
|
||||
Parser(#[from] ParserError),
|
||||
#[error("JIT error: {0}")]
|
||||
JIT(#[from] JITError),
|
||||
JIT(#[from] BackendError),
|
||||
#[error("Internal cranelift error: {0}")]
|
||||
Cranelift(#[from] ModuleError),
|
||||
#[error(transparent)]
|
||||
Reporting(#[from] codespan_reporting::files::Error),
|
||||
}
|
||||
@@ -34,16 +38,17 @@ impl From<REPLError> for Diagnostic<usize> {
|
||||
match value {
|
||||
REPLError::Parser(err) => Diagnostic::from(&err),
|
||||
REPLError::JIT(err) => Diagnostic::from(err),
|
||||
REPLError::Cranelift(err) => Diagnostic::bug().with_message(format!("{}", err)),
|
||||
REPLError::Reporting(err) => Diagnostic::bug().with_message(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RunLoop<'a> {
|
||||
pub fn new(writer: &'a mut dyn WriteColor, config: Config) -> Result<Self, JITError> {
|
||||
pub fn new(writer: &'a mut dyn WriteColor, config: Config) -> Result<Self, BackendError> {
|
||||
Ok(RunLoop {
|
||||
file_database: SimpleFiles::new(),
|
||||
jitter: JITEngine::new()?,
|
||||
jitter: Backend::jit()?,
|
||||
variable_binding_sites: HashMap::new(),
|
||||
gensym_index: 1,
|
||||
writer,
|
||||
@@ -83,7 +88,7 @@ impl<'a> RunLoop<'a> {
|
||||
// then we won't use this definition until someone tries again.
|
||||
if let Statement::Binding(_, ref name, _) = syntax {
|
||||
if !self.variable_binding_sites.contains_key(name.as_str()) {
|
||||
self.jitter.define_string(name.clone())?;
|
||||
self.jitter.define_string(name)?;
|
||||
self.jitter.define_variable(name.clone())?;
|
||||
}
|
||||
};
|
||||
@@ -104,13 +109,17 @@ impl<'a> RunLoop<'a> {
|
||||
}
|
||||
|
||||
let ir = IR::from(syntax.simplify(&mut self.gensym_index));
|
||||
let compiled = self.jitter.compile(line_no, ir)?;
|
||||
compiled();
|
||||
let name = format!("line{}", line_no);
|
||||
let function_id = self.jitter.compile_function(&name, ir)?;
|
||||
self.jitter.module.finalize_definitions()?;
|
||||
let compiled_bytes = self.jitter.bytes(function_id);
|
||||
let compiled_function = unsafe { std::mem::transmute::<_, fn() -> ()>(compiled_bytes) };
|
||||
compiled_function();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), JITError> {
|
||||
fn main() -> Result<(), BackendError> {
|
||||
let mut editor = DefaultEditor::new().expect("rustyline works");
|
||||
let mut line_no = 0;
|
||||
let mut writer = StandardStream::stdout(ColorChoice::Auto);
|
||||
|
||||
32
src/jit.rs
32
src/jit.rs
@@ -1,32 +0,0 @@
|
||||
use crate::backend::RuntimeFunctionError;
|
||||
use codespan_reporting::diagnostic::Diagnostic;
|
||||
use cranelift_codegen::{isa, settings::SetError, CodegenError};
|
||||
use cranelift_module::ModuleError;
|
||||
|
||||
pub mod engine;
|
||||
|
||||
pub use self::engine::JITEngine;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum JITError {
|
||||
#[error("JIT code generation error: {0}")]
|
||||
Codegen(#[from] CodegenError),
|
||||
|
||||
#[error("JIT configuration flag error: {0}")]
|
||||
Set(#[from] SetError),
|
||||
|
||||
#[error("ISA lookup error: {0}")]
|
||||
Lookup(#[from] isa::LookupError),
|
||||
|
||||
#[error("Cranelift module error: {0}")]
|
||||
Cranelift(#[from] ModuleError),
|
||||
|
||||
#[error("Runtime function error: {0}")]
|
||||
Runtime(#[from] RuntimeFunctionError),
|
||||
}
|
||||
|
||||
impl From<JITError> for Diagnostic<usize> {
|
||||
fn from(value: JITError) -> Self {
|
||||
Diagnostic::bug().with_message(format!("{}", value))
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
use crate::backend::RuntimeFunctions;
|
||||
use crate::ir::Program as IR;
|
||||
use crate::jit::JITError;
|
||||
use cranelift_codegen::{
|
||||
isa,
|
||||
settings::{self, Configurable},
|
||||
};
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
use cranelift_module::{DataContext, DataId, Linkage, Module};
|
||||
use std::{collections::HashMap, ffi::CStr};
|
||||
use target_lexicon::Triple;
|
||||
|
||||
const EMPTY_DATUM: [u8; 8] = [0; 8];
|
||||
|
||||
pub struct JITEngine {
|
||||
data_ctx: DataContext,
|
||||
module: JITModule,
|
||||
runtime_functions: RuntimeFunctions,
|
||||
defined_strings: HashMap<String, DataId>,
|
||||
defined_symbols: HashMap<String, DataId>,
|
||||
}
|
||||
|
||||
extern "C" fn runtime_print(name: *const i8, value: u64) {
|
||||
let cstr = unsafe { CStr::from_ptr(name) };
|
||||
let reconstituted = cstr.to_string_lossy();
|
||||
println!("{} = {}", reconstituted, value);
|
||||
}
|
||||
|
||||
impl JITEngine {
|
||||
pub fn new() -> Result<JITEngine, JITError> {
|
||||
let platform = Triple::host();
|
||||
let isa_builder = isa::lookup(platform.clone())?;
|
||||
let mut settings_builder = settings::builder();
|
||||
settings_builder.set("use_colocated_libcalls", "false")?;
|
||||
settings_builder.set("is_pic", "false")?;
|
||||
let isa = isa_builder.finish(settings::Flags::new(settings_builder))?;
|
||||
let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
|
||||
builder.symbol("print", runtime_print as *const u8);
|
||||
|
||||
let mut module = JITModule::new(builder);
|
||||
let runtime_functions = RuntimeFunctions::new(&platform, &mut module)?;
|
||||
|
||||
Ok(JITEngine {
|
||||
data_ctx: DataContext::new(),
|
||||
module,
|
||||
runtime_functions,
|
||||
defined_strings: HashMap::new(),
|
||||
defined_symbols: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn define_string(&mut self, s: String) -> Result<(), JITError> {
|
||||
let name = format!("<string_constant>{}", s);
|
||||
let global_id = self
|
||||
.module
|
||||
.declare_data(&name, Linkage::Local, false, false)?;
|
||||
let mut data_context = DataContext::new();
|
||||
data_context.set_align(8);
|
||||
data_context.define(s.as_str().to_owned().into_boxed_str().into_boxed_bytes());
|
||||
self.module.define_data(global_id, &data_context)?;
|
||||
self.defined_strings.insert(s, global_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn define_variable(&mut self, name: String) -> Result<(), JITError> {
|
||||
self.data_ctx.define(Box::new(EMPTY_DATUM));
|
||||
let id = self
|
||||
.module
|
||||
.declare_data(&name, Linkage::Export, true, false)?;
|
||||
self.module.define_data(id, &self.data_ctx)?;
|
||||
self.data_ctx.clear();
|
||||
self.module.finalize_definitions()?;
|
||||
self.defined_symbols.insert(name, id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, line: usize, program: IR) -> Result<fn() -> (), JITError> {
|
||||
let function_name = format!("line{}", line);
|
||||
let function_id = program.into_cranelift::<JITError, _>(
|
||||
&mut self.module,
|
||||
&function_name,
|
||||
&self.runtime_functions,
|
||||
&self.defined_strings,
|
||||
&self.defined_symbols,
|
||||
)?;
|
||||
self.module.finalize_definitions()?;
|
||||
let code_ptr = self.module.get_finalized_function(function_id);
|
||||
|
||||
unsafe { Ok(std::mem::transmute::<_, fn() -> ()>(code_ptr)) }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod backend;
|
||||
pub mod ir;
|
||||
pub mod jit;
|
||||
pub mod syntax;
|
||||
|
||||
Reference in New Issue
Block a user