A fairly major refactor / simplification.
This commit is contained in:
150
src/backend/into_crane.rs
Normal file
150
src/backend/into_crane.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
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::{
|
||||
entities, types, Function, GlobalValue, InstBuilder, Signature, UserFuncName,
|
||||
};
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||
use cranelift_module::{DataContext, Linkage, Module, ModuleCompiledFunction, ModuleError};
|
||||
use internment::ArcIntern;
|
||||
|
||||
type StringTable = HashMap<ArcIntern<String>, GlobalValue>;
|
||||
|
||||
impl Program {
|
||||
pub fn into_cranelift<M: Module>(
|
||||
mut self,
|
||||
module: &mut M,
|
||||
rtfuns: &RuntimeFunctions,
|
||||
) -> Result<ModuleCompiledFunction, super::BackendError> {
|
||||
let basic_signature = Signature {
|
||||
params: vec![],
|
||||
returns: vec![],
|
||||
call_conv: CallConv::SystemV,
|
||||
};
|
||||
|
||||
let func_id = module.declare_function("gogogo", 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 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 mut fctx = FunctionBuilderContext::new();
|
||||
let mut builder = FunctionBuilder::new(&mut ctx.func, &mut fctx);
|
||||
let main_block = builder.create_block();
|
||||
builder.switch_to_block(main_block);
|
||||
|
||||
for stmt in self.statements.drain(..) {
|
||||
match stmt {
|
||||
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));
|
||||
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 {
|
||||
Expression::Value(_, Value::Number(_, v)) => {
|
||||
builder.ins().iconst(types::I64, v)
|
||||
}
|
||||
|
||||
Expression::Reference(_, name) => {
|
||||
let value_var_num = variable_table.get(&name).unwrap();
|
||||
builder.use_var(Variable::new(*value_var_num))
|
||||
}
|
||||
|
||||
Expression::Primitive(_, prim, mut vals) => {
|
||||
let right = vals
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_cranelift(&mut builder, &variable_table);
|
||||
let left = vals
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_cranelift(&mut builder, &variable_table);
|
||||
|
||||
match prim {
|
||||
Primitive::Plus => builder.ins().iadd(left, right),
|
||||
Primitive::Minus => builder.ins().isub(left, right),
|
||||
Primitive::Times => builder.ins().imul(left, right),
|
||||
Primitive::Divide => builder.ins().sdiv(left, right),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
builder.def_var(var, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.ins().return_(&[]);
|
||||
builder.seal_block(main_block);
|
||||
builder.finalize();
|
||||
|
||||
Ok(module.define_function(func_id, &mut ctx)?)
|
||||
}
|
||||
|
||||
fn build_string_table<M: Module>(
|
||||
&self,
|
||||
module: &mut M,
|
||||
func: &mut Function,
|
||||
) -> 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 local_data = module.declare_data_in_func(global_id, func);
|
||||
string_table.insert(interned_value, local_data);
|
||||
}
|
||||
|
||||
Ok(string_table)
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueOrRef {
|
||||
fn into_cranelift(
|
||||
self,
|
||||
builder: &mut FunctionBuilder,
|
||||
varmap: &HashMap<ArcIntern<String>, usize>,
|
||||
) -> entities::Value {
|
||||
match self {
|
||||
ValueOrRef::Value(_, value) => match value {
|
||||
Value::Number(_base, numval) => builder.ins().iconst(types::I64, numval),
|
||||
},
|
||||
|
||||
ValueOrRef::Ref(_, name) => {
|
||||
let num = varmap.get(&name).unwrap();
|
||||
builder.use_var(Variable::new(*num))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user