Very weirdly organized, but it JITs!

This commit is contained in:
2023-03-24 10:28:32 -05:00
parent ff8412acca
commit 4aa3a9419a
14 changed files with 441 additions and 81 deletions

View File

@@ -4,37 +4,51 @@ use crate::backend::runtime::RuntimeFunctions;
use crate::ir::{Expression, Primitive, Program, Statement, Value, ValueOrRef};
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{
entities, types, Function, GlobalValue, InstBuilder, Signature, UserFuncName,
entities, types, Function, GlobalValue, InstBuilder, Signature, UserFuncName, MemFlags,
};
use cranelift_codegen::isa::CallConv;
use cranelift_codegen::Context;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use cranelift_module::{DataContext, Linkage, Module, ModuleCompiledFunction, ModuleError};
use cranelift_module::{DataContext, FuncId, Linkage, Module, ModuleError, DataId};
use internment::ArcIntern;
use super::RuntimeFunctionError;
type StringTable = HashMap<ArcIntern<String>, GlobalValue>;
impl Program {
pub fn into_cranelift<M: Module>(
pub fn into_cranelift<E, M>(
mut self,
module: &mut M,
function_name: &str,
rtfuns: &RuntimeFunctions,
) -> Result<ModuleCompiledFunction, super::BackendError> {
pre_defined_strings: &HashMap<String, DataId>,
pre_defined_symbols: &HashMap<String, DataId>,
) -> Result<FuncId, E>
where
E: From<ModuleError>,
E: From<RuntimeFunctionError>,
M: Module,
{
let basic_signature = Signature {
params: vec![],
returns: vec![],
call_conv: CallConv::SystemV,
};
let func_id = module.declare_function("gogogo", Linkage::Export, &basic_signature)?;
let func_id = 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)?;
let string_table = self.build_string_table(module, &mut ctx.func, pre_defined_strings)?;
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.iter().map(|(k, v)| {
let local_data = module.declare_data_in_func(*v, &mut ctx.func);
(k.clone(), local_data)
}).collect();
let mut fctx = FunctionBuilderContext::new();
let mut builder = FunctionBuilder::new(&mut ctx.func, &mut fctx);
@@ -43,21 +57,15 @@ impl Program {
for stmt in self.statements.drain(..) {
match stmt {
Statement::Print(_ann, var) => {
Statement::Print(ann, var) => {
let local_name_ref = string_table.get(&var).unwrap();
let name_ptr = builder.ins().symbol_value(types::I64, *local_name_ref);
let value_var_num = variable_table.get(&var).unwrap();
let val = builder.use_var(Variable::new(*value_var_num));
let val = ValueOrRef::Ref(ann, var).into_cranelift(&mut builder, &variable_table, &pre_defined_symbols)?;
builder.ins().call(print_func_ref, &[name_ptr, val]);
}
Statement::Binding(_, var_name, value) => {
let var = Variable::new(next_var_num);
variable_table.insert(var_name, next_var_num);
next_var_num += 1;
builder.declare_var(var, types::I64);
let val = match value {
let val = match value {
Expression::Value(_, Value::Number(_, v)) => {
builder.ins().iconst(types::I64, v)
}
@@ -71,11 +79,11 @@ impl Program {
let right = vals
.pop()
.unwrap()
.into_cranelift(&mut builder, &variable_table);
.into_cranelift(&mut builder, &variable_table, &pre_defined_symbols)?;
let left = vals
.pop()
.unwrap()
.into_cranelift(&mut builder, &variable_table);
.into_cranelift(&mut builder, &variable_table, &pre_defined_symbols)?;
match prim {
Primitive::Plus => builder.ins().iadd(left, right),
@@ -86,7 +94,16 @@ impl Program {
}
};
builder.def_var(var, val);
if let Some(global_id) = pre_defined_symbols.get(var_name.as_str()) {
let val_ptr = builder.ins().symbol_value(types::I64, *global_id);
builder.ins().store(MemFlags::new(), val, val_ptr, 0);
} else {
let var = Variable::new(next_var_num);
variable_table.insert(var_name, next_var_num);
next_var_num += 1;
builder.declare_var(var, types::I64);
builder.def_var(var, val);
}
}
}
}
@@ -95,33 +112,42 @@ impl Program {
builder.seal_block(main_block);
builder.finalize();
Ok(module.define_function(func_id, &mut ctx)?)
let _ = module.define_function(func_id, &mut ctx)?;
Ok(func_id)
}
fn build_string_table<M: Module>(
&self,
module: &mut M,
func: &mut Function,
pre_defined_strings: &HashMap<String, DataId>,
) -> Result<StringTable, ModuleError> {
let mut string_table = HashMap::new();
for (idx, interned_value) in self.strings().drain().enumerate() {
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)?;
let global_id = match pre_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
}
};
let local_data = module.declare_data_in_func(global_id, func);
string_table.insert(interned_value, local_data);
}
@@ -134,16 +160,25 @@ impl ValueOrRef {
fn into_cranelift(
self,
builder: &mut FunctionBuilder,
varmap: &HashMap<ArcIntern<String>, usize>,
) -> entities::Value {
local_variables: &HashMap<ArcIntern<String>, usize>,
global_variables: &HashMap<String, GlobalValue>,
) -> Result<entities::Value, ModuleError> {
match self {
ValueOrRef::Value(_, value) => match value {
Value::Number(_base, numval) => builder.ins().iconst(types::I64, numval),
Value::Number(_base, numval) => Ok(builder.ins().iconst(types::I64, numval)),
},
ValueOrRef::Ref(_, name) => {
let num = varmap.get(&name).unwrap();
builder.use_var(Variable::new(*num))
if let Some(local_num) = local_variables.get(&name) {
return Ok(builder.use_var(Variable::new(*local_num)));
}
if let Some(global_id) = global_variables.get(name.as_str()) {
let val_ptr = builder.ins().symbol_value(types::I64, *global_id);
return Ok(builder.ins().load(types::I64, MemFlags::new(), val_ptr, 0))
}
Err(ModuleError::Undeclared(name.to_string()))
}
}
}