got some basics working!
This commit is contained in:
@@ -43,6 +43,11 @@ pub enum BackendError {
|
||||
InvalidTypeCast { from: PrimitiveType, to: Type },
|
||||
#[error("Unknown string constant '{0}")]
|
||||
UnknownString(ArcIntern<String>),
|
||||
#[error("Compiler doesn't currently support function arguments")]
|
||||
NoFunctionArguments {
|
||||
function_name: String,
|
||||
argument_name: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<BackendError> for Diagnostic<usize> {
|
||||
@@ -73,6 +78,13 @@ impl From<BackendError> for Diagnostic<usize> {
|
||||
),
|
||||
BackendError::UnknownString(str) => Diagnostic::error()
|
||||
.with_message(format!("Unknown string found trying to compile: '{}'", str)),
|
||||
BackendError::NoFunctionArguments {
|
||||
function_name,
|
||||
argument_name,
|
||||
} => Diagnostic::error().with_message(format!(
|
||||
"Function {} takes a function argument ({}), which is not supported",
|
||||
function_name, argument_name
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +140,17 @@ impl PartialEq for BackendError {
|
||||
BackendError::UnknownString(b) => a == b,
|
||||
_ => false,
|
||||
},
|
||||
|
||||
BackendError::NoFunctionArguments {
|
||||
function_name: f1,
|
||||
argument_name: a1,
|
||||
} => match other {
|
||||
BackendError::NoFunctionArguments {
|
||||
function_name: f2,
|
||||
argument_name: a2,
|
||||
} => f1 == f2 && a1 == a2,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,15 +206,15 @@ proptest::proptest! {
|
||||
#[test]
|
||||
fn jit_backend(program in Program::arbitrary()) {
|
||||
use crate::eval::PrimOpError;
|
||||
// use pretty::{DocAllocator, Pretty};
|
||||
// let allocator = pretty::BoxAllocator;
|
||||
// allocator
|
||||
// .text("---------------")
|
||||
// .append(allocator.hardline())
|
||||
// .append(program.pretty(&allocator))
|
||||
// .1
|
||||
// .render_colored(70, pretty::termcolor::StandardStream::stdout(pretty::termcolor::ColorChoice::Auto))
|
||||
// .expect("rendering works");
|
||||
use pretty::{DocAllocator, Pretty};
|
||||
let allocator = pretty::BoxAllocator;
|
||||
allocator
|
||||
.text("---------------")
|
||||
.append(allocator.hardline())
|
||||
.append(program.pretty(&allocator))
|
||||
.1
|
||||
.render_colored(70, pretty::termcolor::StandardStream::stdout(pretty::termcolor::ColorChoice::Auto))
|
||||
.expect("rendering works");
|
||||
|
||||
|
||||
let basic_result = program.eval().map(|(_,x)| x);
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::backend::Backend;
|
||||
enum ReferenceBuilder {
|
||||
Global(ConstantType, GlobalValue),
|
||||
Local(ConstantType, cranelift_frontend::Variable),
|
||||
Argument(ConstantType, entities::Value),
|
||||
}
|
||||
|
||||
impl ReferenceBuilder {
|
||||
@@ -36,6 +37,8 @@ impl ReferenceBuilder {
|
||||
let value = builder.use_var(*var);
|
||||
(value, *ty)
|
||||
}
|
||||
|
||||
ReferenceBuilder::Argument(ty, val) => (*val, *ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,6 +175,21 @@ impl<M: Module> Backend<M> {
|
||||
// flow, we might add more blocks after this one. But, for now, we only have
|
||||
// the one block.
|
||||
let main_block = builder.create_block();
|
||||
// add the block parameters, which should be the function parameters
|
||||
for (name, ty) in arguments.iter() {
|
||||
let constant_type = ty
|
||||
.try_into()
|
||||
.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(
|
||||
name.clone(),
|
||||
ReferenceBuilder::Argument(constant_type, value),
|
||||
);
|
||||
}
|
||||
|
||||
builder.switch_to_block(main_block);
|
||||
|
||||
let (value, _) = self.compile_expression(body, &mut variables, &mut builder)?;
|
||||
@@ -388,14 +406,23 @@ impl<M: Module> Backend<M> {
|
||||
match valref {
|
||||
ValueOrRef::Value(_, _, val) => match val {
|
||||
Value::I8(_, v) => {
|
||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::I8))
|
||||
// Cranelift does a funny thing where it checks you aren't using bits in the I64
|
||||
// we provide above the size of the type we provide. So, in this case, we can only
|
||||
// set the low 8 bits of the i64. This restriction creates a bit of a problem when
|
||||
// casting direction from i8 to i64, because Rust will (helpfully) sign-extend the
|
||||
// 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,
|
||||
// and *then* we cast to i64.
|
||||
Ok((builder.ins().iconst(types::I8, v as u8 as i64), ConstantType::I8))
|
||||
}
|
||||
Value::I16(_, v) => Ok((
|
||||
builder.ins().iconst(types::I16, v as i64),
|
||||
// see above note for the "... as ... as"
|
||||
builder.ins().iconst(types::I16, v as u16 as i64),
|
||||
ConstantType::I16,
|
||||
)),
|
||||
Value::I32(_, v) => Ok((
|
||||
builder.ins().iconst(types::I32, v as i64),
|
||||
// see above note for the "... as ... as"
|
||||
builder.ins().iconst(types::I32, v as u32 as i64),
|
||||
ConstantType::I32,
|
||||
)),
|
||||
Value::I64(_, v) => Ok((builder.ins().iconst(types::I64, v), ConstantType::I64)),
|
||||
|
||||
Reference in New Issue
Block a user