Add ability to return int literals

This commit is contained in:
Brendan Hansknecht 2020-11-15 14:06:20 -08:00
parent 86c3c0a409
commit a8986087f9
4 changed files with 136 additions and 32 deletions

View file

@ -11,11 +11,11 @@
// re-enable this when working on performance optimizations than have it block PRs.
#![allow(clippy::large_enum_variant)]
use bumpalo::Bump;
use bumpalo::{collections::Vec, Bump};
use object::write::Object;
use roc_collections::all::{MutMap, MutSet};
use roc_module::symbol::{Interns, Symbol};
use roc_mono::ir::Proc;
use roc_mono::ir::{Expr, Literal, Proc, Stmt};
use roc_mono::layout::Layout;
use target_lexicon::{BinaryFormat, Triple};
@ -44,9 +44,11 @@ pub fn build_module<'a>(
}
}
trait Backend {
trait Backend<'a> {
/// new creates a new backend that will output to the specific Object.
fn new() -> Self;
fn new(env: &'a Env) -> Self;
fn env(&self) -> &'a Env<'a>;
/// reset resets any registers or other values that may be occupied at the end of a procedure.
fn reset(&mut self);
@ -54,12 +56,56 @@ trait Backend {
/// build_proc creates a procedure and outputs it to the wrapped object writer.
/// This will need to return the list of relocations because they have to be added differently based on file format.
/// Also, assembly will of course be generated by individual calls on backend like may setup_stack.
fn build_proc<'a>(&mut self, env: &'a Env, _proc: Proc<'a>) -> &'a [u8] {
let mut out = bumpalo::vec![in env.arena; 0x55, 0x48, 0x89, 0xE5];
let body = [0xb8, 0x06, 0x00, 0x00, 0x00];
out.extend(body.iter());
out.push(0x5D);
out.push(0xC3);
out.into_bump_slice()
fn build_proc(&mut self, proc: Proc<'a>) -> &'a [u8] {
self.reset();
// TODO: let the backend know of all the arguments.
let mut buf = bumpalo::vec!(in self.env().arena);
self.build_stmt(&mut buf, &proc.body);
self.wrap_proc(buf).into_bump_slice()
}
/// wrap_proc does any setup and cleanup that should happen around the procedure.
/// For example, this can store the frame pionter and setup stack space.
/// wrap_proc is run at the end of build_proc when all internal code is finalized.
/// wrap_proc returns a Vec because it is expected to prepend data.
fn wrap_proc(&mut self, buf: Vec<'a, u8>) -> Vec<'a, u8>;
/// build_stmt builds a statement and outputs at the end of the buffer.
fn build_stmt(&mut self, buf: &mut Vec<'a, u8>, stmt: &Stmt<'a>) {
match stmt {
Stmt::Let(sym, expr, layout, following) => {
self.build_expr(buf, sym, expr, layout);
self.build_stmt(buf, following);
}
Stmt::Ret(sym) => {
self.return_symbol(buf, sym);
}
x => unimplemented!("the statement, {:?}, is not yet implemented", x),
}
}
/// build_expr builds the expressions for the specified symbol.
/// The builder must keep track of the symbol because it may be refered to later.
/// In many cases values can be lazy loaded, like literals.
fn build_expr(
&mut self,
_buf: &mut Vec<'a, u8>,
sym: &Symbol,
expr: &Expr<'a>,
layout: &Layout<'a>,
) {
match expr {
Expr::Literal(lit) => {
self.set_symbol_to_lit(sym, lit, layout);
}
x => unimplemented!("the expression, {:?}, is not yet implemented", x),
}
}
/// set_symbol_to_lit sets a symbol to be equal to a literal.
/// When the symbol is used, the literal should be loaded.
fn set_symbol_to_lit(&mut self, sym: &Symbol, lit: &Literal<'a>, layout: &Layout<'a>);
/// return_symbol moves a symbol to the correct return location for the backend.
fn return_symbol(&mut self, buf: &mut Vec<'a, u8>, sym: &Symbol);
}