λ Support functions! #5
@@ -35,6 +35,7 @@ pub use self::error::BackendError;
|
|||||||
pub use self::runtime::{RuntimeFunctionError, RuntimeFunctions};
|
pub use self::runtime::{RuntimeFunctionError, RuntimeFunctions};
|
||||||
use crate::syntax::ConstantType;
|
use crate::syntax::ConstantType;
|
||||||
use cranelift_codegen::entity::EntityRef;
|
use cranelift_codegen::entity::EntityRef;
|
||||||
|
use cranelift_codegen::ir::types;
|
||||||
use cranelift_codegen::settings::Configurable;
|
use cranelift_codegen::settings::Configurable;
|
||||||
use cranelift_codegen::{isa, settings};
|
use cranelift_codegen::{isa, settings};
|
||||||
use cranelift_jit::{JITBuilder, JITModule};
|
use cranelift_jit::{JITBuilder, JITModule};
|
||||||
@@ -61,7 +62,7 @@ pub struct Backend<M: Module> {
|
|||||||
runtime_functions: RuntimeFunctions,
|
runtime_functions: RuntimeFunctions,
|
||||||
defined_strings: HashMap<String, DataId>,
|
defined_strings: HashMap<String, DataId>,
|
||||||
defined_functions: HashMap<ArcIntern<String>, FuncId>,
|
defined_functions: HashMap<ArcIntern<String>, FuncId>,
|
||||||
defined_symbols: HashMap<ArcIntern<String>, (DataId, ConstantType)>,
|
defined_symbols: HashMap<ArcIntern<String>, (DataId, types::Type)>,
|
||||||
output_buffer: Option<String>,
|
output_buffer: Option<String>,
|
||||||
platform: Triple,
|
platform: Triple,
|
||||||
next_variable: usize,
|
next_variable: usize,
|
||||||
@@ -190,7 +191,7 @@ impl<M: Module> Backend<M> {
|
|||||||
self.module.define_data(id, &self.data_ctx)?;
|
self.module.define_data(id, &self.data_ctx)?;
|
||||||
self.data_ctx.clear();
|
self.data_ctx.clear();
|
||||||
self.defined_symbols
|
self.defined_symbols
|
||||||
.insert(ArcIntern::new(name), (id, ctype));
|
.insert(ArcIntern::new(name), (id, ctype.into()));
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{backend::runtime::RuntimeFunctionError, eval::PrimitiveType, ir::Type};
|
use crate::{backend::runtime::RuntimeFunctionError, ir::Type};
|
||||||
use codespan_reporting::diagnostic::Diagnostic;
|
use codespan_reporting::diagnostic::Diagnostic;
|
||||||
use cranelift_codegen::{isa::LookupError, settings::SetError, CodegenError};
|
use cranelift_codegen::{isa::LookupError, settings::SetError, CodegenError};
|
||||||
use cranelift_module::ModuleError;
|
use cranelift_module::ModuleError;
|
||||||
@@ -40,7 +40,10 @@ pub enum BackendError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Write(#[from] cranelift_object::object::write::Error),
|
Write(#[from] cranelift_object::object::write::Error),
|
||||||
#[error("Invalid type cast from {from} to {to}")]
|
#[error("Invalid type cast from {from} to {to}")]
|
||||||
InvalidTypeCast { from: PrimitiveType, to: Type },
|
InvalidTypeCast {
|
||||||
|
from: cranelift_codegen::ir::types::Type,
|
||||||
|
to: Type,
|
||||||
|
},
|
||||||
#[error("Unknown string constant '{0}")]
|
#[error("Unknown string constant '{0}")]
|
||||||
UnknownString(ArcIntern<String>),
|
UnknownString(ArcIntern<String>),
|
||||||
#[error("Compiler doesn't currently support function arguments")]
|
#[error("Compiler doesn't currently support function arguments")]
|
||||||
|
|||||||
@@ -14,14 +14,16 @@ use cranelift_module::{DataDescription, FuncId, Linkage, Module};
|
|||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::{hash_map, HashMap};
|
||||||
|
|
||||||
|
const VOID_REPR_TYPE: types::Type = types::I64;
|
||||||
|
|
||||||
/// When we're talking about variables, it's handy to just have a table that points
|
/// When we're talking about variables, it's handy to just have a table that points
|
||||||
/// from a variable to "what to do if you want to reference this variable", which is
|
/// from a variable to "what to do if you want to reference this variable", which is
|
||||||
/// agnostic about whether the variable is local, global, an argument, etc. Since
|
/// agnostic about whether the variable is local, global, an argument, etc. Since
|
||||||
/// the type of that function is a little bit annoying, we summarize it here.
|
/// the type of that function is a little bit annoying, we summarize it here.
|
||||||
pub enum ReferenceBuilder {
|
pub enum ReferenceBuilder {
|
||||||
Global(ConstantType, GlobalValue),
|
Global(types::Type, GlobalValue),
|
||||||
Local(ConstantType, cranelift_frontend::Variable),
|
Local(types::Type, cranelift_frontend::Variable),
|
||||||
Argument(ConstantType, entities::Value),
|
Argument(types::Type, entities::Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Module> Backend<M> {
|
impl<M: Module> Backend<M> {
|
||||||
@@ -29,13 +31,10 @@ impl<M: Module> Backend<M> {
|
|||||||
/// best as possible.
|
/// best as possible.
|
||||||
fn translate_type(&self, t: &Type) -> AbiParam {
|
fn translate_type(&self, t: &Type) -> AbiParam {
|
||||||
let (value_type, extension) = match t {
|
let (value_type, extension) = match t {
|
||||||
Type::Function(_, _) => (
|
Type::Function(_, _) | Type::Structure(_) => (
|
||||||
types::Type::triple_pointer_type(&self.platform),
|
types::Type::triple_pointer_type(&self.platform),
|
||||||
ir::ArgumentExtension::None,
|
ir::ArgumentExtension::None,
|
||||||
),
|
),
|
||||||
Type::Structure(_) => {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
Type::Primitive(PrimitiveType::Void) => (types::I8, ir::ArgumentExtension::None), // FIXME?
|
Type::Primitive(PrimitiveType::Void) => (types::I8, ir::ArgumentExtension::None), // FIXME?
|
||||||
Type::Primitive(PrimitiveType::I8) => (types::I8, ir::ArgumentExtension::Sext),
|
Type::Primitive(PrimitiveType::I8) => (types::I8, ir::ArgumentExtension::Sext),
|
||||||
Type::Primitive(PrimitiveType::I16) => (types::I16, ir::ArgumentExtension::Sext),
|
Type::Primitive(PrimitiveType::I16) => (types::I16, ir::ArgumentExtension::Sext),
|
||||||
@@ -88,12 +87,23 @@ impl<M: Module> Backend<M> {
|
|||||||
)?;
|
)?;
|
||||||
tracing::info!(name = %top_level_name, data_type = %pt, "defining top-level data");
|
tracing::info!(name = %top_level_name, data_type = %pt, "defining top-level data");
|
||||||
self.module.define_data(data_id, &pt.blank_data())?;
|
self.module.define_data(data_id, &pt.blank_data())?;
|
||||||
|
let constant_type = ConstantType::from(pt);
|
||||||
self.defined_symbols
|
self.defined_symbols
|
||||||
.insert(top_level_name, (data_id, pt.into()));
|
.insert(top_level_name, (data_id, constant_type.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Structure(_) => {
|
Type::Structure(mut fields) => {
|
||||||
unimplemented!()
|
let data_id = self.module.declare_data(
|
||||||
|
top_level_name.as_str(),
|
||||||
|
Linkage::Export,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
tracing::info!(name = %top_level_name, "defining top-level data structure");
|
||||||
|
self.module.define_data(data_id, fields.blank_data())?;
|
||||||
|
let pointer = self.module.target_config().pointer_type();
|
||||||
|
self.defined_symbols
|
||||||
|
.insert(top_level_name, (data_id, pointer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,13 +236,8 @@ impl<M: Module> Backend<M> {
|
|||||||
let main_block = builder.create_block();
|
let main_block = builder.create_block();
|
||||||
// add the block parameters, which should be the function parameters
|
// add the block parameters, which should be the function parameters
|
||||||
for (name, ty) in arguments.iter() {
|
for (name, ty) in arguments.iter() {
|
||||||
let constant_type = ty
|
let constant_type = self.translate_type(ty).value_type;
|
||||||
.try_into()
|
let value = builder.append_block_param(main_block, constant_type);
|
||||||
.map_err(|_| BackendError::NoFunctionArguments {
|
|
||||||
function_name: function_name.to_string(),
|
|
||||||
argument_name: name.to_string(),
|
|
||||||
})?;
|
|
||||||
let value = builder.append_block_param(main_block, ir::Type::from(constant_type));
|
|
||||||
variables.insert(
|
variables.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
ReferenceBuilder::Argument(constant_type, value),
|
ReferenceBuilder::Argument(constant_type, value),
|
||||||
@@ -273,96 +278,98 @@ impl<M: Module> Backend<M> {
|
|||||||
expr: Expression<Type>,
|
expr: Expression<Type>,
|
||||||
variables: &mut HashMap<Variable, ReferenceBuilder>,
|
variables: &mut HashMap<Variable, ReferenceBuilder>,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
) -> Result<(entities::Value, ConstantType), BackendError> {
|
) -> Result<(entities::Value, types::Type), BackendError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expression::Atomic(x) => self.compile_value_or_ref(x, variables, builder),
|
Expression::Atomic(x) => self.compile_value_or_ref(x, variables, builder),
|
||||||
Expression::Cast(_, target_type, valref) => {
|
Expression::Cast(_, target_type, valref) => {
|
||||||
|
let val_is_signed = valref.type_of().is_signed();
|
||||||
let (val, val_type) = self.compile_value_or_ref(valref, variables, builder)?;
|
let (val, val_type) = self.compile_value_or_ref(valref, variables, builder)?;
|
||||||
|
|
||||||
match (val_type, &target_type) {
|
match (val_type, &target_type) {
|
||||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I8)) => Ok((val, val_type)),
|
(types::I8, Type::Primitive(PrimitiveType::I8)) => Ok((val, val_type)),
|
||||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I16)) => {
|
(types::I8, Type::Primitive(PrimitiveType::I16)) => {
|
||||||
Ok((builder.ins().sextend(types::I16, val), ConstantType::I16))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I16, val), types::I16))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I16, val), types::I16))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I32)) => {
|
(types::I8, Type::Primitive(PrimitiveType::I32)) => {
|
||||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I32, val), types::I32))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I32, val), types::I32))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I64)) => {
|
(types::I8, Type::Primitive(PrimitiveType::I64)) => {
|
||||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I64, val), types::I64))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I16)) => Ok((val, val_type)),
|
(types::I16, Type::Primitive(PrimitiveType::I16)) => Ok((val, val_type)),
|
||||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I32)) => {
|
(types::I16, Type::Primitive(PrimitiveType::I32)) => {
|
||||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I32, val), types::I32))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I32, val), types::I32))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I64)) => {
|
(types::I16, Type::Primitive(PrimitiveType::I64)) => {
|
||||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I64, val), types::I64))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::I32, Type::Primitive(PrimitiveType::I32)) => Ok((val, val_type)),
|
(types::I32, Type::Primitive(PrimitiveType::I32)) => Ok((val, val_type)),
|
||||||
(ConstantType::I32, Type::Primitive(PrimitiveType::I64)) => {
|
(types::I32, Type::Primitive(PrimitiveType::I64)) => {
|
||||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
if val_is_signed {
|
||||||
|
Ok((builder.ins().sextend(types::I64, val), types::I64))
|
||||||
|
} else {
|
||||||
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::I64, Type::Primitive(PrimitiveType::I64)) => Ok((val, val_type)),
|
(types::I64, Type::Primitive(PrimitiveType::I64)) => Ok((val, val_type)),
|
||||||
|
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U8)) => Ok((val, val_type)),
|
(types::I8, Type::Primitive(PrimitiveType::U8)) => Ok((val, val_type)),
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U16)) => {
|
(types::I8, Type::Primitive(PrimitiveType::U16)) => {
|
||||||
Ok((builder.ins().uextend(types::I16, val), ConstantType::U16))
|
Ok((builder.ins().uextend(types::I16, val), types::I16))
|
||||||
}
|
}
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U32)) => {
|
(types::I8, Type::Primitive(PrimitiveType::U32)) => {
|
||||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32))
|
Ok((builder.ins().uextend(types::I32, val), types::I32))
|
||||||
}
|
}
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U64)) => {
|
(types::I8, Type::Primitive(PrimitiveType::U64)) => {
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U16)) => Ok((val, val_type)),
|
(types::I16, Type::Primitive(PrimitiveType::U16)) => Ok((val, val_type)),
|
||||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U32)) => {
|
(types::I16, Type::Primitive(PrimitiveType::U32)) => {
|
||||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32))
|
Ok((builder.ins().uextend(types::I32, val), types::I32))
|
||||||
}
|
}
|
||||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U64)) => {
|
(types::I16, Type::Primitive(PrimitiveType::U64)) => {
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::U32, Type::Primitive(PrimitiveType::U32)) => Ok((val, val_type)),
|
(types::I32, Type::Primitive(PrimitiveType::U32)) => Ok((val, val_type)),
|
||||||
(ConstantType::U32, Type::Primitive(PrimitiveType::U64)) => {
|
(types::I32, Type::Primitive(PrimitiveType::U64)) => {
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
Ok((builder.ins().uextend(types::I64, val), types::I64))
|
||||||
}
|
}
|
||||||
|
|
||||||
(ConstantType::U64, Type::Primitive(PrimitiveType::U64)) => Ok((val, val_type)),
|
(types::I64, Type::Primitive(PrimitiveType::U64)) => Ok((val, val_type)),
|
||||||
|
|
||||||
(ConstantType::Void, Type::Primitive(PrimitiveType::Void)) => {
|
|
||||||
Ok((val, val_type))
|
|
||||||
}
|
|
||||||
|
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::I16)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I16, val), ConstantType::I16))
|
|
||||||
}
|
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::I32)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::I32))
|
|
||||||
}
|
|
||||||
(ConstantType::U8, Type::Primitive(PrimitiveType::I64)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::I64))
|
|
||||||
}
|
|
||||||
(ConstantType::U16, Type::Primitive(PrimitiveType::I32)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::I32))
|
|
||||||
}
|
|
||||||
(ConstantType::U16, Type::Primitive(PrimitiveType::I64)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::I64))
|
|
||||||
}
|
|
||||||
(ConstantType::U32, Type::Primitive(PrimitiveType::I64)) => {
|
|
||||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::I64))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => Err(BackendError::InvalidTypeCast {
|
_ => Err(BackendError::InvalidTypeCast {
|
||||||
from: val_type.into(),
|
from: val_type,
|
||||||
to: target_type,
|
to: target_type,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Primitive(_, _, prim, mut vals) => {
|
Expression::Primitive(_, ret_type, prim, mut vals) => {
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
let mut first_type = None;
|
let mut first_type = None;
|
||||||
|
|
||||||
@@ -392,7 +399,7 @@ impl<M: Module> Backend<M> {
|
|||||||
}
|
}
|
||||||
Primitive::Minus => Ok((builder.ins().ineg(values[0]), first_type)),
|
Primitive::Minus => Ok((builder.ins().ineg(values[0]), first_type)),
|
||||||
Primitive::Times => Ok((builder.ins().imul(values[0], values[1]), first_type)),
|
Primitive::Times => Ok((builder.ins().imul(values[0], values[1]), first_type)),
|
||||||
Primitive::Divide if first_type.is_signed() => {
|
Primitive::Divide if ret_type.is_signed() => {
|
||||||
Ok((builder.ins().sdiv(values[0], values[1]), first_type))
|
Ok((builder.ins().sdiv(values[0], values[1]), first_type))
|
||||||
}
|
}
|
||||||
Primitive::Divide => Ok((builder.ins().udiv(values[0], values[1]), first_type)),
|
Primitive::Divide => Ok((builder.ins().udiv(values[0], values[1]), first_type)),
|
||||||
@@ -403,7 +410,7 @@ impl<M: Module> Backend<M> {
|
|||||||
Expression::FieldRef(_, _, _, _) => unimplemented!(),
|
Expression::FieldRef(_, _, _, _) => unimplemented!(),
|
||||||
|
|
||||||
Expression::Block(_, _, mut exprs) => match exprs.pop() {
|
Expression::Block(_, _, mut exprs) => match exprs.pop() {
|
||||||
None => Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void)),
|
None => Ok((builder.ins().iconst(types::I64, 0), VOID_REPR_TYPE)),
|
||||||
Some(last) => {
|
Some(last) => {
|
||||||
for inner in exprs {
|
for inner in exprs {
|
||||||
// we can ignore all of these return values and such, because we
|
// we can ignore all of these return values and such, because we
|
||||||
@@ -431,20 +438,31 @@ impl<M: Module> Backend<M> {
|
|||||||
.declare_data_in_func(string_data_id, builder.func);
|
.declare_data_in_func(string_data_id, builder.func);
|
||||||
let name_ptr = builder.ins().symbol_value(types::I64, local_name_ref);
|
let name_ptr = builder.ins().symbol_value(types::I64, local_name_ref);
|
||||||
|
|
||||||
let (val, vtype) = self.compile_value_or_ref(var, variables, builder)?;
|
let var_type = var.type_of();
|
||||||
|
let (val, _) = self.compile_value_or_ref(var, variables, builder)?;
|
||||||
|
|
||||||
let vtype_repr = builder.ins().iconst(types::I64, vtype as i64);
|
let (repr_val, casted_val) = match var_type {
|
||||||
|
Type::Structure(_) => (ConstantType::I64 as i64, val),
|
||||||
|
Type::Function(_, _) => (ConstantType::I64 as i64, val),
|
||||||
|
Type::Primitive(pt) => {
|
||||||
|
let constant_type = pt.into();
|
||||||
|
|
||||||
let casted_val = match vtype {
|
let new_val = match constant_type {
|
||||||
ConstantType::U64 | ConstantType::I64 | ConstantType::Void => val,
|
ConstantType::U64 | ConstantType::I64 | ConstantType::Void => val,
|
||||||
ConstantType::I8 | ConstantType::I16 | ConstantType::I32 => {
|
ConstantType::I8 | ConstantType::I16 | ConstantType::I32 => {
|
||||||
builder.ins().sextend(types::I64, val)
|
builder.ins().sextend(types::I64, val)
|
||||||
}
|
}
|
||||||
ConstantType::U8 | ConstantType::U16 | ConstantType::U32 => {
|
ConstantType::U8 | ConstantType::U16 | ConstantType::U32 => {
|
||||||
builder.ins().uextend(types::I64, val)
|
builder.ins().uextend(types::I64, val)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(constant_type as i64, new_val)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let vtype_repr = builder.ins().iconst(types::I64, repr_val);
|
||||||
|
|
||||||
// Finally, we can generate the call to print.
|
// Finally, we can generate the call to print.
|
||||||
let print_func_ref = self.runtime_functions.include_runtime_function(
|
let print_func_ref = self.runtime_functions.include_runtime_function(
|
||||||
"print",
|
"print",
|
||||||
@@ -455,12 +473,11 @@ impl<M: Module> Backend<M> {
|
|||||||
print_func_ref,
|
print_func_ref,
|
||||||
&[buffer_ptr, name_ptr, vtype_repr, casted_val],
|
&[buffer_ptr, name_ptr, vtype_repr, casted_val],
|
||||||
);
|
);
|
||||||
Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void))
|
Ok((builder.ins().iconst(types::I64, 0), VOID_REPR_TYPE))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Bind(_, name, _, expr) => {
|
Expression::Bind(_, name, _, expr) => {
|
||||||
let (value, value_type) = self.compile_expression(*expr, variables, builder)?;
|
let (value, value_type) = self.compile_expression(*expr, variables, builder)?;
|
||||||
let ir_type = ir::Type::from(value_type);
|
|
||||||
let variable = self.generate_local();
|
let variable = self.generate_local();
|
||||||
|
|
||||||
match variables.get(&name) {
|
match variables.get(&name) {
|
||||||
@@ -468,7 +485,7 @@ impl<M: Module> Backend<M> {
|
|||||||
let pointer = self.module.target_config().pointer_type();
|
let pointer = self.module.target_config().pointer_type();
|
||||||
let pointer_to = builder.ins().symbol_value(pointer, *global_value);
|
let pointer_to = builder.ins().symbol_value(pointer, *global_value);
|
||||||
builder.ins().store(MemFlags::new(), value, pointer_to, 0);
|
builder.ins().store(MemFlags::new(), value, pointer_to, 0);
|
||||||
Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void))
|
Ok((builder.ins().iconst(types::I64, 0), VOID_REPR_TYPE))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ReferenceBuilder::Argument(_, _)) => {
|
Some(ReferenceBuilder::Argument(_, _)) => {
|
||||||
@@ -480,10 +497,10 @@ impl<M: Module> Backend<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
builder.declare_var(variable, ir_type);
|
builder.declare_var(variable, value_type);
|
||||||
builder.def_var(variable, value);
|
builder.def_var(variable, value);
|
||||||
variables.insert(name, ReferenceBuilder::Local(value_type, variable));
|
variables.insert(name, ReferenceBuilder::Local(value_type, variable));
|
||||||
Ok((builder.ins().iconst(types::I64, 0), ConstantType::Void))
|
Ok((builder.ins().iconst(types::I64, 0), VOID_REPR_TYPE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -511,21 +528,10 @@ impl<M: Module> Backend<M> {
|
|||||||
let results = builder.inst_results(call);
|
let results = builder.inst_results(call);
|
||||||
|
|
||||||
match results {
|
match results {
|
||||||
[] => Ok((
|
[] => Ok((builder.ins().iconst(types::I64, 0), VOID_REPR_TYPE)),
|
||||||
builder.ins().iconst(types::I64, 0),
|
[result] => {
|
||||||
ConstantType::Void,
|
Ok((*result, self.translate_type(&result_type).value_type))
|
||||||
)),
|
}
|
||||||
[result] => match result_type {
|
|
||||||
Type::Primitive(ct) => Ok((*result, ct.into())),
|
|
||||||
Type::Function(_, rt) => match *rt {
|
|
||||||
Type::Function(_, _) => {
|
|
||||||
panic!("function returns a function?")
|
|
||||||
}
|
|
||||||
Type::Structure(_) => unimplemented!(),
|
|
||||||
Type::Primitive(ct) => Ok((*result, ct.into())),
|
|
||||||
},
|
|
||||||
Type::Structure(_) => unimplemented!(),
|
|
||||||
},
|
|
||||||
_ => panic!("don't support multi-value returns yet"),
|
_ => panic!("don't support multi-value returns yet"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,7 +550,7 @@ impl<M: Module> Backend<M> {
|
|||||||
value_or_ref: ValueOrRef<Type>,
|
value_or_ref: ValueOrRef<Type>,
|
||||||
variables: &HashMap<Variable, ReferenceBuilder>,
|
variables: &HashMap<Variable, ReferenceBuilder>,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
) -> Result<(entities::Value, ConstantType), BackendError> {
|
) -> Result<(entities::Value, types::Type), BackendError> {
|
||||||
match value_or_ref {
|
match value_or_ref {
|
||||||
ValueOrRef::Value(_, _, val) => match val {
|
ValueOrRef::Value(_, _, val) => match val {
|
||||||
Value::I8(_, v) => {
|
Value::I8(_, v) => {
|
||||||
@@ -555,49 +561,31 @@ impl<M: Module> Backend<M> {
|
|||||||
// negative number for us. Which sets the high bits, which makes Cranelift unhappy.
|
// negative number for us. Which sets the high bits, which makes Cranelift unhappy.
|
||||||
// So first we cast the i8 as u8, to get rid of the whole concept of sign extension,
|
// So first we cast the i8 as u8, to get rid of the whole concept of sign extension,
|
||||||
// and *then* we cast to i64.
|
// and *then* we cast to i64.
|
||||||
Ok((
|
Ok((builder.ins().iconst(types::I8, v as u8 as i64), types::I8))
|
||||||
builder.ins().iconst(types::I8, v as u8 as i64),
|
|
||||||
ConstantType::I8,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Value::I16(_, v) => Ok((
|
Value::I16(_, v) => Ok((
|
||||||
// see above note for the "... as ... as"
|
// see above note for the "... as ... as"
|
||||||
builder.ins().iconst(types::I16, v as u16 as i64),
|
builder.ins().iconst(types::I16, v as u16 as i64),
|
||||||
ConstantType::I16,
|
types::I16,
|
||||||
)),
|
)),
|
||||||
Value::I32(_, v) => Ok((
|
Value::I32(_, v) => Ok((
|
||||||
// see above note for the "... as ... as"
|
// see above note for the "... as ... as"
|
||||||
builder.ins().iconst(types::I32, v as u32 as i64),
|
builder.ins().iconst(types::I32, v as u32 as i64),
|
||||||
ConstantType::I32,
|
types::I32,
|
||||||
)),
|
)),
|
||||||
Value::I64(_, v) => Ok((builder.ins().iconst(types::I64, v), ConstantType::I64)),
|
Value::I64(_, v) => Ok((builder.ins().iconst(types::I64, v), types::I64)),
|
||||||
Value::U8(_, v) => {
|
Value::U8(_, v) => Ok((builder.ins().iconst(types::I8, v as i64), types::I8)),
|
||||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::U8))
|
Value::U16(_, v) => Ok((builder.ins().iconst(types::I16, v as i64), types::I16)),
|
||||||
}
|
Value::U32(_, v) => Ok((builder.ins().iconst(types::I32, v as i64), types::I32)),
|
||||||
Value::U16(_, v) => Ok((
|
Value::U64(_, v) => Ok((builder.ins().iconst(types::I64, v as i64), types::I64)),
|
||||||
builder.ins().iconst(types::I16, v as i64),
|
Value::Void => Ok((builder.ins().iconst(types::I64, 0i64), VOID_REPR_TYPE)),
|
||||||
ConstantType::U16,
|
|
||||||
)),
|
|
||||||
Value::U32(_, v) => Ok((
|
|
||||||
builder.ins().iconst(types::I32, v as i64),
|
|
||||||
ConstantType::U32,
|
|
||||||
)),
|
|
||||||
Value::U64(_, v) => Ok((
|
|
||||||
builder.ins().iconst(types::I64, v as i64),
|
|
||||||
ConstantType::U64,
|
|
||||||
)),
|
|
||||||
Value::Void => Ok((builder.ins().iconst(types::I64, 0i64), ConstantType::Void)),
|
|
||||||
},
|
},
|
||||||
ValueOrRef::Ref(_, _, name) => match variables.get(&name) {
|
ValueOrRef::Ref(_, _, name) => match variables.get(&name) {
|
||||||
None => Err(BackendError::VariableLookupFailure(name)),
|
None => Err(BackendError::VariableLookupFailure(name)),
|
||||||
Some(ReferenceBuilder::Global(ty, gv)) => {
|
Some(ReferenceBuilder::Global(ty, gv)) => {
|
||||||
let pointer_to = self.module.target_config().pointer_type();
|
let pointer_to = self.module.target_config().pointer_type();
|
||||||
let pointer_value = builder.ins().symbol_value(pointer_to, *gv);
|
let pointer_value = builder.ins().symbol_value(pointer_to, *gv);
|
||||||
let cranelift_type = ir::Type::from(*ty);
|
let value = builder.ins().load(*ty, MemFlags::new(), pointer_value, 0);
|
||||||
let value =
|
|
||||||
builder
|
|
||||||
.ins()
|
|
||||||
.load(cranelift_type, MemFlags::new(), pointer_value, 0);
|
|
||||||
|
|
||||||
Ok((value, *ty))
|
Ok((value, *ty))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,6 +257,16 @@ impl Type {
|
|||||||
pub fn is_printable(&self) -> bool {
|
pub fn is_printable(&self) -> bool {
|
||||||
matches!(self, Type::Primitive(_))
|
matches!(self, Type::Primitive(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the variable is signed.
|
||||||
|
pub fn is_signed(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Type::Primitive(
|
||||||
|
PrimitiveType::I8 | PrimitiveType::I16 | PrimitiveType::I32 | PrimitiveType::I64
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PrimitiveType> for Type {
|
impl From<PrimitiveType> for Type {
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
|
use cranelift_module::DataDescription;
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone)]
|
||||||
pub struct Fields<T> {
|
pub struct Fields<T> {
|
||||||
ordering: FieldOrdering,
|
ordering: FieldOrdering,
|
||||||
|
total_size: usize,
|
||||||
|
cranelift_description: Option<DataDescription>,
|
||||||
fields: Vec<(ArcIntern<String>, T)>,
|
fields: Vec<(ArcIntern<String>, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> PartialEq for Fields<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ordering == other.ordering && self.fields == other.fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> Eq for Fields<T> {}
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for Fields<T> {
|
impl<T: fmt::Debug> fmt::Debug for Fields<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Fields:")?;
|
write!(f, "Fields:")?;
|
||||||
@@ -29,6 +40,8 @@ impl<T> Fields<T> {
|
|||||||
pub fn new(ordering: FieldOrdering) -> Fields<T> {
|
pub fn new(ordering: FieldOrdering) -> Fields<T> {
|
||||||
Fields {
|
Fields {
|
||||||
ordering,
|
ordering,
|
||||||
|
total_size: 0,
|
||||||
|
cranelift_description: None,
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,6 +51,7 @@ impl<T> Fields<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, name: ArcIntern<String>, t: T) {
|
pub fn insert(&mut self, name: ArcIntern<String>, t: T) {
|
||||||
|
self.total_size += 8;
|
||||||
self.fields.push((name, t));
|
self.fields.push((name, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +68,8 @@ impl<T> Fields<T> {
|
|||||||
pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Fields<T2> {
|
pub fn map<T2, F: Fn(T) -> T2>(self, f: F) -> Fields<T2> {
|
||||||
Fields {
|
Fields {
|
||||||
ordering: self.ordering,
|
ordering: self.ordering,
|
||||||
|
total_size: self.total_size,
|
||||||
|
cranelift_description: self.cranelift_description,
|
||||||
fields: self.fields.into_iter().map(|(n, t)| (n, f(t))).collect(),
|
fields: self.fields.into_iter().map(|(n, t)| (n, f(t))).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,10 +99,6 @@ impl<T> Fields<T> {
|
|||||||
self.fields.iter().map(|(x, y)| (x, y))
|
self.fields.iter().map(|(x, y)| (x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_iter(self) -> impl Iterator<Item = (ArcIntern<String>, T)> {
|
|
||||||
self.fields.into_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_names(&self) -> impl Iterator<Item = &ArcIntern<String>> {
|
pub fn field_names(&self) -> impl Iterator<Item = &ArcIntern<String>> {
|
||||||
self.fields.iter().map(|(n, _)| n)
|
self.fields.iter().map(|(n, _)| n)
|
||||||
}
|
}
|
||||||
@@ -98,4 +110,22 @@ impl<T> Fields<T> {
|
|||||||
pub fn types_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
pub fn types_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||||
self.fields.iter_mut().map(|(_, x)| x)
|
self.fields.iter_mut().map(|(_, x)| x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn blank_data(&mut self) -> &DataDescription {
|
||||||
|
self.cranelift_description.get_or_insert_with(|| {
|
||||||
|
let mut cranelift_description = DataDescription::new();
|
||||||
|
cranelift_description.set_align(8);
|
||||||
|
cranelift_description.define_zeroinit(self.total_size);
|
||||||
|
cranelift_description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for Fields<T> {
|
||||||
|
type Item = (ArcIntern<String>, T);
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.fields.into_iter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,14 +206,6 @@ impl From<ConstantType> for cranelift_codegen::ir::Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConstantType {
|
impl ConstantType {
|
||||||
/// Returns true if the given type is (a) numeric and (b) signed;
|
|
||||||
pub fn is_signed(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
ConstantType::I8 | ConstantType::I16 | ConstantType::I32 | ConstantType::I64
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the set of types that can be safely casted into this type.
|
/// Return the set of types that can be safely casted into this type.
|
||||||
pub fn safe_casts_to(self) -> Vec<ConstantType> {
|
pub fn safe_casts_to(self) -> Vec<ConstantType> {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
Reference in New Issue
Block a user