mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
implement List.map in the dev backend
This commit is contained in:
parent
b62ee37d8e
commit
b59ada4bc8
8 changed files with 449 additions and 21 deletions
|
@ -7,13 +7,15 @@ use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::code_gen_help::{CallerProc, CodeGenHelp, HelperOp};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout, SelfRecursive, Stmt,
|
||||
BranchInfo, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout,
|
||||
SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout,
|
||||
};
|
||||
use roc_mono::low_level::HigherOrder;
|
||||
use roc_target::TargetInfo;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -496,6 +498,7 @@ pub struct Backend64Bit<
|
|||
interns: &'r mut Interns,
|
||||
helper_proc_gen: CodeGenHelp<'a>,
|
||||
helper_proc_symbols: Vec<'a, (Symbol, ProcLayout<'a>)>,
|
||||
caller_procs: Vec<'a, CallerProc<'a>>,
|
||||
buf: Vec<'a, u8>,
|
||||
relocs: Vec<'a, Relocation>,
|
||||
proc_name: Option<String>,
|
||||
|
@ -533,6 +536,7 @@ pub fn new_backend_64bit<
|
|||
layout_interner,
|
||||
helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id),
|
||||
helper_proc_symbols: bumpalo::vec![in env.arena],
|
||||
caller_procs: bumpalo::vec![in env.arena],
|
||||
proc_name: None,
|
||||
is_self_recursive: None,
|
||||
buf: bumpalo::vec![in env.arena],
|
||||
|
@ -574,6 +578,9 @@ impl<
|
|||
fn interns(&self) -> &Interns {
|
||||
self.interns
|
||||
}
|
||||
fn interns_mut(&mut self) -> &mut Interns {
|
||||
self.interns
|
||||
}
|
||||
fn interner(&self) -> &STLayoutInterner<'a> {
|
||||
self.layout_interner
|
||||
}
|
||||
|
@ -584,12 +591,14 @@ impl<
|
|||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
&mut Vec<'a, CallerProc<'a>>,
|
||||
) {
|
||||
(
|
||||
self.env.module_id,
|
||||
self.layout_interner,
|
||||
self.interns,
|
||||
&mut self.helper_proc_gen,
|
||||
&mut self.caller_procs,
|
||||
)
|
||||
}
|
||||
fn helper_proc_gen_mut(&mut self) -> &mut CodeGenHelp<'a> {
|
||||
|
@ -1579,6 +1588,174 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn build_higher_order_lowlevel(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
higher_order: &HigherOrderLowLevel<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
) {
|
||||
let ident_ids = self
|
||||
.interns
|
||||
.all_ident_ids
|
||||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let (inc_n_data_symbol, inc_n_data_linker_data) = self.helper_proc_gen.gen_refcount_proc(
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
Layout::UNIT,
|
||||
HelperOp::Inc,
|
||||
);
|
||||
|
||||
let caller_proc = CallerProc::new(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
);
|
||||
|
||||
match higher_order.op {
|
||||
HigherOrder::ListMap { xs } => {
|
||||
let old_element_layout = higher_order.passed_function.argument_layouts[0];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
let input_list_layout = Layout::Builtin(Builtin::List(old_element_layout));
|
||||
let input_list_in_layout = self.layout_interner.insert(input_list_layout);
|
||||
|
||||
let caller = self.debug_symbol("caller");
|
||||
let data = self.debug_symbol("data");
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width = self.debug_symbol("old_element_width");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
|
||||
self.load_layout_alignment(new_element_layout, alignment);
|
||||
|
||||
self.load_layout_stack_size(old_element_layout, old_element_width);
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
self.helper_proc_symbols.extend(inc_n_data_linker_data);
|
||||
self.helper_proc_symbols
|
||||
.extend([(caller_proc.proc_symbol, caller_proc.proc_layout)]);
|
||||
|
||||
let inc_n_data_string = self.function_symbol_to_string(
|
||||
inc_n_data_symbol,
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
let caller_string = self.function_symbol_to_string(
|
||||
caller_proc.proc_symbol,
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
self.caller_procs.push(caller_proc);
|
||||
|
||||
let inc_n_data = Symbol::DEV_TMP5;
|
||||
self.build_fn_pointer(&inc_n_data, inc_n_data_string);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
if let Some(_closure_data_layout) = higher_order.closure_env_layout {
|
||||
let data_symbol = higher_order.passed_function.captured_environment;
|
||||
self.storage_manager
|
||||
.ensure_symbol_on_stack(&mut self.buf, &data_symbol);
|
||||
let (new_elem_offset, _) =
|
||||
self.storage_manager.stack_offset_and_size(&data_symbol);
|
||||
|
||||
// Load address of output element into register.
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &data);
|
||||
ASM::add_reg64_reg64_imm32(
|
||||
&mut self.buf,
|
||||
reg,
|
||||
CC::BASE_PTR_REG,
|
||||
new_elem_offset,
|
||||
);
|
||||
} else {
|
||||
// use a null pointer
|
||||
self.load_literal(&data, &Layout::U64, &Literal::Int(0u128.to_be_bytes()));
|
||||
}
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP3,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(higher_order.passed_function.owns_captured_environment),
|
||||
);
|
||||
|
||||
// list: RocList,
|
||||
// caller: Caller1,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// old_element_width: usize,
|
||||
// new_element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP3,
|
||||
alignment,
|
||||
old_element_width,
|
||||
new_element_width,
|
||||
];
|
||||
|
||||
let ptr = Layout::U64;
|
||||
let usize_ = Layout::U64;
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_,
|
||||
usize_,
|
||||
];
|
||||
|
||||
// Setup the return location.
|
||||
let base_offset = self
|
||||
.storage_manager
|
||||
.claim_stack_area(dst, self.layout_interner.stack_size(ret_layout));
|
||||
|
||||
self.build_fn_call(
|
||||
&Symbol::DEV_TMP4,
|
||||
bitcode::LIST_MAP.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP3);
|
||||
self.free_symbol(&Symbol::DEV_TMP5);
|
||||
|
||||
// Return list value from fn call
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
base_offset,
|
||||
&Symbol::DEV_TMP4,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP4);
|
||||
}
|
||||
HigherOrder::ListMap2 { xs, ys } => todo!(),
|
||||
HigherOrder::ListMap3 { xs, ys, zs } => todo!(),
|
||||
HigherOrder::ListMap4 { xs, ys, zs, ws } => {
|
||||
todo!()
|
||||
}
|
||||
HigherOrder::ListSortWith { xs } => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol) {
|
||||
self.storage_manager.list_len(&mut self.buf, dst, list);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::ident::ModuleName;
|
||||
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::code_gen_help::{CallerProc, CodeGenHelp};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, Param, Proc, ProcLayout,
|
||||
SelfRecursive, Stmt,
|
||||
BranchInfo, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal,
|
||||
Param, Proc, ProcLayout, SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, TagIdIntType,
|
||||
|
@ -65,8 +65,21 @@ pub enum Relocation {
|
|||
trait Backend<'a> {
|
||||
fn env(&self) -> &Env<'a>;
|
||||
fn interns(&self) -> &Interns;
|
||||
fn interns_mut(&mut self) -> &mut Interns;
|
||||
fn interner(&self) -> &STLayoutInterner<'a>;
|
||||
|
||||
fn debug_symbol(&mut self, name: &str) -> Symbol {
|
||||
let module_id = self.env().module_id;
|
||||
let ident_ids = self
|
||||
.interns_mut()
|
||||
.all_ident_ids
|
||||
.get_mut(&module_id)
|
||||
.unwrap();
|
||||
|
||||
let ident_id = ident_ids.add_str(name);
|
||||
Symbol::new(self.env().module_id, ident_id)
|
||||
}
|
||||
|
||||
// This method is suboptimal, but it seems to be the only way to make rust understand
|
||||
// that all of these values can be mutable at the same time. By returning them together,
|
||||
// rust understands that they are part of a single use of mutable self.
|
||||
|
@ -77,6 +90,7 @@ trait Backend<'a> {
|
|||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
&mut Vec<'a, CallerProc<'a>>,
|
||||
);
|
||||
|
||||
fn function_symbol_to_string<'b, I>(
|
||||
|
@ -201,7 +215,7 @@ trait Backend<'a> {
|
|||
// If this layout requires a new RC proc, we get enough info to create a linker symbol
|
||||
// for it. Here we don't create linker symbols at this time, but in Wasm backend, we do.
|
||||
let (rc_stmt, new_specializations) = {
|
||||
let (module_id, layout_interner, interns, rc_proc_gen) =
|
||||
let (module_id, layout_interner, interns, rc_proc_gen, _) =
|
||||
self.module_interns_helpers_mut();
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
|
@ -319,6 +333,12 @@ trait Backend<'a> {
|
|||
ret_layout,
|
||||
..
|
||||
} => {
|
||||
dbg!(
|
||||
func_sym,
|
||||
func_sym.name() == Symbol::BOOL_TRUE,
|
||||
func_sym.name().is_builtin()
|
||||
);
|
||||
|
||||
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
||||
LowLevelWrapperType::from_symbol(func_sym.name())
|
||||
{
|
||||
|
@ -373,6 +393,9 @@ trait Backend<'a> {
|
|||
layout,
|
||||
)
|
||||
}
|
||||
CallType::HigherOrder(higher_order) => {
|
||||
self.build_higher_order_lowlevel(sym, higher_order, *layout)
|
||||
}
|
||||
x => todo!("the call type, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1366,6 +1389,14 @@ trait Backend<'a> {
|
|||
/// build_list_len returns the length of a list.
|
||||
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol);
|
||||
|
||||
/// generate a call to a higher-order lowlevel
|
||||
fn build_higher_order_lowlevel(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
holl: &HigherOrderLowLevel<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
);
|
||||
|
||||
/// build_list_with_capacity creates and returns a list with the given capacity.
|
||||
fn build_list_with_capacity(
|
||||
&mut self,
|
||||
|
|
|
@ -246,10 +246,16 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
|
||||
// Generate IR for specialized helper procs (refcounting & equality)
|
||||
let helper_procs = {
|
||||
let (module_id, _interner, interns, helper_proc_gen) = backend.module_interns_helpers_mut();
|
||||
let (module_id, _interner, interns, helper_proc_gen, caller_procs) =
|
||||
backend.module_interns_helpers_mut();
|
||||
|
||||
let mut owned_caller_procs = bumpalo::collections::Vec::new_in(arena);
|
||||
std::mem::swap(caller_procs, &mut owned_caller_procs);
|
||||
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
let helper_procs = helper_proc_gen.take_procs();
|
||||
let mut helper_procs = helper_proc_gen.take_procs();
|
||||
|
||||
helper_procs.extend(owned_caller_procs.into_iter().map(|cp| cp.proc));
|
||||
module_id.register_debug_idents(ident_ids);
|
||||
|
||||
helper_procs
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue