mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge pull request #4833 from roc-lang/intern-layouts
Intern all the layouts
This commit is contained in:
commit
858670fac7
36 changed files with 927 additions and 514 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3273,6 +3273,7 @@ dependencies = [
|
|||
"morphic_lib",
|
||||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_intern",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
]
|
||||
|
@ -3646,6 +3647,7 @@ dependencies = [
|
|||
"roc_collections",
|
||||
"roc_debug_flags",
|
||||
"roc_error_macros",
|
||||
"roc_intern",
|
||||
"roc_module",
|
||||
"roc_mono",
|
||||
"roc_region",
|
||||
|
|
|
@ -8,6 +8,7 @@ version = "0.0.1"
|
|||
[dependencies]
|
||||
morphic_lib = {path = "../../vendor/morphic_lib"}
|
||||
roc_collections = {path = "../collections"}
|
||||
roc_intern = {path = "../intern"}
|
||||
roc_module = {path = "../module"}
|
||||
roc_mono = {path = "../mono"}
|
||||
roc_debug_flags = {path = "../debug_flags"}
|
||||
|
|
|
@ -6,6 +6,7 @@ use morphic_lib::{
|
|||
TypeDefBuilder, TypeId, TypeName, UpdateModeVar, ValueId,
|
||||
};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_intern::Interner;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
|
@ -1730,6 +1731,7 @@ fn layout_spec_help<'a>(
|
|||
}
|
||||
|
||||
Boxed(inner_layout) => {
|
||||
let inner_layout = interner.get(*inner_layout);
|
||||
let inner_type =
|
||||
layout_spec_help(env, builder, interner, inner_layout, when_recursive)?;
|
||||
let cell_type = builder.add_heap_cell_type();
|
||||
|
|
|
@ -470,7 +470,7 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
|||
module_id,
|
||||
procedures,
|
||||
mut interns,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
|
@ -483,7 +483,6 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
|||
|
||||
let env = roc_gen_wasm::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
module_id,
|
||||
exposed_to_host,
|
||||
stack_bytes: wasm_dev_stack_bytes.unwrap_or(roc_gen_wasm::Env::DEFAULT_STACK_BYTES),
|
||||
|
@ -505,8 +504,13 @@ fn gen_from_mono_module_dev_wasm32<'a>(
|
|||
)
|
||||
});
|
||||
|
||||
let final_binary_bytes =
|
||||
roc_gen_wasm::build_app_binary(&env, &mut interns, host_module, procedures);
|
||||
let final_binary_bytes = roc_gen_wasm::build_app_binary(
|
||||
&env,
|
||||
&mut layout_interner,
|
||||
&mut interns,
|
||||
host_module,
|
||||
procedures,
|
||||
);
|
||||
|
||||
let code_gen = code_gen_start.elapsed();
|
||||
|
||||
|
@ -536,20 +540,20 @@ fn gen_from_mono_module_dev_assembly<'a>(
|
|||
procedures,
|
||||
mut interns,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
let env = roc_gen_dev::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
module_id,
|
||||
exposed_to_host: exposed_to_host.values.keys().copied().collect(),
|
||||
lazy_literals,
|
||||
generate_allocators,
|
||||
};
|
||||
|
||||
let module_object = roc_gen_dev::build_module(&env, &mut interns, target, procedures);
|
||||
let module_object =
|
||||
roc_gen_dev::build_module(&env, &mut interns, &mut layout_interner, target, procedures);
|
||||
|
||||
let code_gen = code_gen_start.elapsed();
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use bumpalo::collections::Vec;
|
|||
use packed_struct::prelude::*;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_mono::layout::{Layout, STLayoutInterner};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
#[allow(dead_code)]
|
||||
|
@ -305,15 +305,17 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn load_args<'a>(
|
||||
fn load_args<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
AArch64GeneralReg,
|
||||
AArch64FloatReg,
|
||||
AArch64Assembler,
|
||||
AArch64Call,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_args: &'a [(Layout<'a>, Symbol)],
|
||||
_ret_layout: &Layout<'a>,
|
||||
) {
|
||||
|
@ -321,15 +323,17 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn store_args<'a>(
|
||||
fn store_args<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
AArch64GeneralReg,
|
||||
AArch64FloatReg,
|
||||
AArch64Assembler,
|
||||
AArch64Call,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_dst: &Symbol,
|
||||
_args: &[Symbol],
|
||||
_arg_layouts: &[Layout<'a>],
|
||||
|
@ -338,30 +342,34 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
|
|||
todo!("Storing args for AArch64");
|
||||
}
|
||||
|
||||
fn return_complex_symbol<'a>(
|
||||
fn return_complex_symbol<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
AArch64GeneralReg,
|
||||
AArch64FloatReg,
|
||||
AArch64Assembler,
|
||||
AArch64Call,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_sym: &Symbol,
|
||||
_layout: &Layout<'a>,
|
||||
) {
|
||||
todo!("Returning complex symbols for AArch64");
|
||||
}
|
||||
|
||||
fn load_returned_complex_symbol<'a>(
|
||||
fn load_returned_complex_symbol<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
AArch64GeneralReg,
|
||||
AArch64FloatReg,
|
||||
AArch64Assembler,
|
||||
AArch64Call,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_sym: &Symbol,
|
||||
_layout: &Layout<'a>,
|
||||
) {
|
||||
|
@ -443,9 +451,9 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
todo!("register signed multiplication for AArch64");
|
||||
}
|
||||
|
||||
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn umul_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<'a, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_storage_manager: &mut StorageManager<'a, 'r, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
|
@ -456,9 +464,9 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
todo!("register unsigned multiplication for AArch64");
|
||||
}
|
||||
|
||||
fn idiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn idiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<'a, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_storage_manager: &mut StorageManager<'a, 'r, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
|
@ -469,9 +477,9 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
todo!("register signed division for AArch64");
|
||||
}
|
||||
|
||||
fn udiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn udiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<'a, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_storage_manager: &mut StorageManager<'a, 'r, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
|
||||
_dst: AArch64GeneralReg,
|
||||
_src1: AArch64GeneralReg,
|
||||
_src2: AArch64GeneralReg,
|
||||
|
|
|
@ -6,12 +6,12 @@ use bumpalo::collections::Vec;
|
|||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::code_gen_help::CodeGenHelp;
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout, SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{Builtin, Layout, TagIdIntType, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -69,9 +69,10 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
|
|||
);
|
||||
|
||||
/// load_args updates the storage manager to know where every arg is stored.
|
||||
fn load_args<'a>(
|
||||
fn load_args<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, Self>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
// ret_layout is needed because if it is a complex type, we pass a pointer as the first arg.
|
||||
ret_layout: &Layout<'a>,
|
||||
|
@ -79,9 +80,10 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
|
|||
|
||||
/// store_args stores the args in registers and on the stack for function calling.
|
||||
/// It also updates the amount of temporary stack space needed in the storage manager.
|
||||
fn store_args<'a>(
|
||||
fn store_args<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, Self>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
dst: &Symbol,
|
||||
args: &[Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
|
@ -91,18 +93,20 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
|
|||
|
||||
/// return_complex_symbol returns the specified complex/non-primative symbol.
|
||||
/// It uses the layout to determine how the data should be returned.
|
||||
fn return_complex_symbol<'a>(
|
||||
fn return_complex_symbol<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, Self>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
);
|
||||
|
||||
/// load_returned_complex_symbol loads a complex symbol that was returned from a function call.
|
||||
/// It uses the layout to determine how the data should be loaded into the symbol.
|
||||
fn load_returned_complex_symbol<'a>(
|
||||
fn load_returned_complex_symbol<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, Self>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
);
|
||||
|
@ -261,9 +265,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn umul_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
|
@ -271,18 +275,18 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>;
|
||||
|
||||
fn idiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn idiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
) where
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>;
|
||||
fn udiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn udiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
|
@ -354,6 +358,7 @@ pub trait RegTrait:
|
|||
|
||||
pub struct Backend64Bit<
|
||||
'a,
|
||||
'r,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
|
@ -364,8 +369,9 @@ pub struct Backend64Bit<
|
|||
phantom_asm: PhantomData<ASM>,
|
||||
phantom_cc: PhantomData<CC>,
|
||||
target_info: TargetInfo,
|
||||
env: &'a Env<'a>,
|
||||
interns: &'a mut Interns,
|
||||
env: &'r Env<'a>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
interns: &'r mut Interns,
|
||||
helper_proc_gen: CodeGenHelp<'a>,
|
||||
helper_proc_symbols: Vec<'a, (Symbol, ProcLayout<'a>)>,
|
||||
buf: Vec<'a, u8>,
|
||||
|
@ -380,33 +386,31 @@ pub struct Backend64Bit<
|
|||
literal_map: MutMap<Symbol, (*const Literal<'a>, *const Layout<'a>)>,
|
||||
join_map: MutMap<JoinPointId, Vec<'a, (u64, u64)>>,
|
||||
|
||||
storage_manager: StorageManager<'a, GeneralReg, FloatReg, ASM, CC>,
|
||||
storage_manager: StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
|
||||
}
|
||||
|
||||
/// new creates a new backend that will output to the specific Object.
|
||||
pub fn new_backend_64bit<
|
||||
'a,
|
||||
'r,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
>(
|
||||
env: &'a Env,
|
||||
env: &'r Env<'a>,
|
||||
target_info: TargetInfo,
|
||||
interns: &'a mut Interns,
|
||||
) -> Backend64Bit<'a, GeneralReg, FloatReg, ASM, CC> {
|
||||
interns: &'r mut Interns,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
) -> Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC> {
|
||||
Backend64Bit {
|
||||
phantom_asm: PhantomData,
|
||||
phantom_cc: PhantomData,
|
||||
target_info,
|
||||
env,
|
||||
interns,
|
||||
helper_proc_gen: CodeGenHelp::new(
|
||||
env.arena,
|
||||
env.layout_interner,
|
||||
target_info,
|
||||
env.module_id,
|
||||
),
|
||||
layout_interner,
|
||||
helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id),
|
||||
helper_proc_symbols: bumpalo::vec![in env.arena],
|
||||
proc_name: None,
|
||||
is_self_recursive: None,
|
||||
|
@ -436,11 +440,12 @@ macro_rules! quadword_and_smaller {
|
|||
|
||||
impl<
|
||||
'a,
|
||||
'r,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
> Backend<'a> for Backend64Bit<'a, GeneralReg, FloatReg, ASM, CC>
|
||||
> Backend<'a> for Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
fn env(&self) -> &Env<'a> {
|
||||
self.env
|
||||
|
@ -448,8 +453,20 @@ impl<
|
|||
fn interns(&self) -> &Interns {
|
||||
self.interns
|
||||
}
|
||||
fn env_interns_helpers_mut(&mut self) -> (&Env<'a>, &mut Interns, &mut CodeGenHelp<'a>) {
|
||||
(self.env, self.interns, &mut self.helper_proc_gen)
|
||||
fn module_interns_helpers_mut(
|
||||
&mut self,
|
||||
) -> (
|
||||
ModuleId,
|
||||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
) {
|
||||
(
|
||||
self.env.module_id,
|
||||
self.layout_interner,
|
||||
self.interns,
|
||||
&mut self.helper_proc_gen,
|
||||
)
|
||||
}
|
||||
fn helper_proc_gen_mut(&mut self) -> &mut CodeGenHelp<'a> {
|
||||
&mut self.helper_proc_gen
|
||||
|
@ -587,7 +604,13 @@ impl<
|
|||
}
|
||||
|
||||
fn load_args(&mut self, args: &'a [(Layout<'a>, Symbol)], ret_layout: &Layout<'a>) {
|
||||
CC::load_args(&mut self.buf, &mut self.storage_manager, args, ret_layout);
|
||||
CC::load_args(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
self.layout_interner,
|
||||
args,
|
||||
ret_layout,
|
||||
);
|
||||
}
|
||||
|
||||
/// Used for generating wrappers for malloc/realloc/free
|
||||
|
@ -619,6 +642,7 @@ impl<
|
|||
CC::store_args(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
self.layout_interner,
|
||||
dst,
|
||||
args,
|
||||
arg_layouts,
|
||||
|
@ -642,6 +666,7 @@ impl<
|
|||
CC::load_returned_complex_symbol(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
self.layout_interner,
|
||||
dst,
|
||||
ret_layout,
|
||||
);
|
||||
|
@ -732,7 +757,7 @@ impl<
|
|||
// Ensure all the joinpoint parameters have storage locations.
|
||||
// On jumps to the joinpoint, we will overwrite those locations as a way to "pass parameters" to the joinpoint.
|
||||
self.storage_manager
|
||||
.setup_joinpoint(&mut self.buf, id, parameters);
|
||||
.setup_joinpoint(self.layout_interner, &mut self.buf, id, parameters);
|
||||
|
||||
self.join_map.insert(*id, bumpalo::vec![in self.env.arena]);
|
||||
|
||||
|
@ -764,7 +789,7 @@ impl<
|
|||
_ret_layout: &Layout<'a>,
|
||||
) {
|
||||
self.storage_manager
|
||||
.setup_jump(&mut self.buf, id, args, arg_layouts);
|
||||
.setup_jump(self.layout_interner, &mut self.buf, id, args, arg_layouts);
|
||||
|
||||
let jmp_location = self.buf.len();
|
||||
let start_offset = ASM::jmp_imm32(&mut self.buf, 0x1234_5678);
|
||||
|
@ -832,7 +857,7 @@ impl<
|
|||
|
||||
let buf = &mut self.buf;
|
||||
|
||||
let struct_size = return_layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
let struct_size = return_layout.stack_size(self.layout_interner, self.target_info);
|
||||
|
||||
let base_offset = self.storage_manager.claim_stack_area(dst, struct_size);
|
||||
|
||||
|
@ -1170,7 +1195,7 @@ impl<
|
|||
.storage_manager
|
||||
.load_to_general_reg(&mut self.buf, index);
|
||||
let ret_stack_size =
|
||||
ret_layout.stack_size(self.env.layout_interner, self.storage_manager.target_info());
|
||||
ret_layout.stack_size(self.layout_interner, self.storage_manager.target_info());
|
||||
// TODO: This can be optimized with smarter instructions.
|
||||
// Also can probably be moved into storage manager at least partly.
|
||||
self.storage_manager.with_tmp_general_reg(
|
||||
|
@ -1212,8 +1237,8 @@ impl<
|
|||
let elem_layout = arg_layouts[2];
|
||||
|
||||
let u32_layout = &Layout::Builtin(Builtin::Int(IntWidth::U32));
|
||||
let list_alignment = list_layout
|
||||
.alignment_bytes(self.env.layout_interner, self.storage_manager.target_info());
|
||||
let list_alignment =
|
||||
list_layout.alignment_bytes(self.layout_interner, self.storage_manager.target_info());
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP,
|
||||
u32_layout,
|
||||
|
@ -1233,7 +1258,7 @@ impl<
|
|||
|
||||
// Load the elements size.
|
||||
let elem_stack_size =
|
||||
elem_layout.stack_size(self.env.layout_interner, self.storage_manager.target_info());
|
||||
elem_layout.stack_size(self.layout_interner, self.storage_manager.target_info());
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP3,
|
||||
u64_layout,
|
||||
|
@ -1243,7 +1268,7 @@ impl<
|
|||
// Setup the return location.
|
||||
let base_offset = self.storage_manager.claim_stack_area(
|
||||
dst,
|
||||
ret_layout.stack_size(self.env.layout_interner, self.storage_manager.target_info()),
|
||||
ret_layout.stack_size(self.layout_interner, self.storage_manager.target_info()),
|
||||
);
|
||||
|
||||
let ret_fields = if let Layout::Struct { field_layouts, .. } = ret_layout {
|
||||
|
@ -1262,7 +1287,7 @@ impl<
|
|||
(
|
||||
base_offset
|
||||
+ ret_fields[0]
|
||||
.stack_size(self.env.layout_interner, self.storage_manager.target_info())
|
||||
.stack_size(self.layout_interner, self.storage_manager.target_info())
|
||||
as i32,
|
||||
base_offset,
|
||||
)
|
||||
|
@ -1271,7 +1296,7 @@ impl<
|
|||
base_offset,
|
||||
base_offset
|
||||
+ ret_fields[0]
|
||||
.stack_size(self.env.layout_interner, self.storage_manager.target_info())
|
||||
.stack_size(self.layout_interner, self.storage_manager.target_info())
|
||||
as i32,
|
||||
)
|
||||
};
|
||||
|
@ -1315,6 +1340,7 @@ impl<
|
|||
|
||||
// Copy from list to the output record.
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
out_list_offset,
|
||||
&Symbol::DEV_TMP5,
|
||||
|
@ -1354,14 +1380,13 @@ impl<
|
|||
let allocation_alignment = std::cmp::max(
|
||||
8,
|
||||
elem_layout.allocation_alignment_bytes(
|
||||
self.env.layout_interner,
|
||||
self.layout_interner,
|
||||
self.storage_manager.target_info(),
|
||||
) as u64,
|
||||
);
|
||||
|
||||
let elem_size = elem_layout
|
||||
.stack_size(self.env.layout_interner, self.storage_manager.target_info())
|
||||
as u64;
|
||||
let elem_size =
|
||||
elem_layout.stack_size(self.layout_interner, self.storage_manager.target_info()) as u64;
|
||||
let allocation_size = elem_size * elems.len() as u64 + allocation_alignment /* add space for refcount */;
|
||||
let u64_layout = Layout::Builtin(Builtin::Int(IntWidth::U64));
|
||||
self.load_literal(
|
||||
|
@ -1465,8 +1490,13 @@ impl<
|
|||
}
|
||||
|
||||
fn create_struct(&mut self, sym: &Symbol, layout: &Layout<'a>, fields: &'a [Symbol]) {
|
||||
self.storage_manager
|
||||
.create_struct(&mut self.buf, sym, layout, fields);
|
||||
self.storage_manager.create_struct(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
sym,
|
||||
layout,
|
||||
fields,
|
||||
);
|
||||
}
|
||||
|
||||
fn load_struct_at_index(
|
||||
|
@ -1476,8 +1506,13 @@ impl<
|
|||
index: u64,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
) {
|
||||
self.storage_manager
|
||||
.load_field_at_index(sym, structure, index, field_layouts);
|
||||
self.storage_manager.load_field_at_index(
|
||||
self.layout_interner,
|
||||
sym,
|
||||
structure,
|
||||
index,
|
||||
field_layouts,
|
||||
);
|
||||
}
|
||||
|
||||
fn load_union_at_index(
|
||||
|
@ -1491,6 +1526,7 @@ impl<
|
|||
match union_layout {
|
||||
UnionLayout::NonRecursive(tag_layouts) | UnionLayout::Recursive(tag_layouts) => {
|
||||
self.storage_manager.load_field_at_index(
|
||||
self.layout_interner,
|
||||
sym,
|
||||
structure,
|
||||
index,
|
||||
|
@ -1502,8 +1538,13 @@ impl<
|
|||
}
|
||||
|
||||
fn get_tag_id(&mut self, sym: &Symbol, structure: &Symbol, union_layout: &UnionLayout<'a>) {
|
||||
self.storage_manager
|
||||
.load_union_tag_id(&mut self.buf, sym, structure, union_layout);
|
||||
self.storage_manager.load_union_tag_id(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
sym,
|
||||
structure,
|
||||
union_layout,
|
||||
);
|
||||
}
|
||||
|
||||
fn tag(
|
||||
|
@ -1513,8 +1554,14 @@ impl<
|
|||
union_layout: &UnionLayout<'a>,
|
||||
tag_id: TagIdIntType,
|
||||
) {
|
||||
self.storage_manager
|
||||
.create_union(&mut self.buf, sym, union_layout, fields, tag_id)
|
||||
self.storage_manager.create_union(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
sym,
|
||||
union_layout,
|
||||
fields,
|
||||
tag_id,
|
||||
)
|
||||
}
|
||||
|
||||
fn load_literal(&mut self, sym: &Symbol, layout: &Layout<'a>, lit: &Literal<'a>) {
|
||||
|
@ -1611,7 +1658,13 @@ impl<
|
|||
}
|
||||
}
|
||||
} else {
|
||||
CC::return_complex_symbol(&mut self.buf, &mut self.storage_manager, sym, layout)
|
||||
CC::return_complex_symbol(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
self.layout_interner,
|
||||
sym,
|
||||
layout,
|
||||
)
|
||||
}
|
||||
let inst_loc = self.buf.len() as u64;
|
||||
let offset = ASM::jmp_imm32(&mut self.buf, 0x1234_5678) as u64;
|
||||
|
@ -1687,11 +1740,12 @@ impl<
|
|||
/// For example, loading a symbol for doing a computation.
|
||||
impl<
|
||||
'a,
|
||||
'r,
|
||||
FloatReg: RegTrait,
|
||||
GeneralReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
> Backend64Bit<'a, GeneralReg, FloatReg, ASM, CC>
|
||||
> Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
/// Updates a jump instruction to a new offset and returns the number of bytes written.
|
||||
fn update_jmp_imm32_offset(
|
||||
|
|
|
@ -10,7 +10,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::{
|
||||
ir::{JoinPointId, Param},
|
||||
layout::{Builtin, Layout, TagIdIntType, UnionLayout},
|
||||
layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout},
|
||||
};
|
||||
use roc_target::TargetInfo;
|
||||
use std::cmp::max;
|
||||
|
@ -79,6 +79,7 @@ enum Storage<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
|||
#[derive(Clone)]
|
||||
pub struct StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
|
@ -86,7 +87,7 @@ pub struct StorageManager<
|
|||
> {
|
||||
phantom_cc: PhantomData<CC>,
|
||||
phantom_asm: PhantomData<ASM>,
|
||||
pub(crate) env: &'a Env<'a>,
|
||||
pub(crate) env: &'r Env<'a>,
|
||||
target_info: TargetInfo,
|
||||
// Data about where each symbol is stored.
|
||||
symbol_storage_map: MutMap<Symbol, Storage<GeneralReg, FloatReg>>,
|
||||
|
@ -127,14 +128,15 @@ pub struct StorageManager<
|
|||
|
||||
pub fn new_storage_manager<
|
||||
'a,
|
||||
'r,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
>(
|
||||
env: &'a Env,
|
||||
env: &'r Env<'a>,
|
||||
target_info: TargetInfo,
|
||||
) -> StorageManager<'a, GeneralReg, FloatReg, ASM, CC> {
|
||||
) -> StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC> {
|
||||
StorageManager {
|
||||
phantom_asm: PhantomData,
|
||||
phantom_cc: PhantomData,
|
||||
|
@ -157,11 +159,12 @@ pub fn new_storage_manager<
|
|||
|
||||
impl<
|
||||
'a,
|
||||
'r,
|
||||
FloatReg: RegTrait,
|
||||
GeneralReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
> StorageManager<'a, GeneralReg, FloatReg, ASM, CC>
|
||||
> StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
pub fn reset(&mut self) {
|
||||
self.symbol_storage_map.clear();
|
||||
|
@ -526,6 +529,7 @@ impl<
|
|||
/// This is lazy by default. It will not copy anything around.
|
||||
pub fn load_field_at_index(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
sym: &Symbol,
|
||||
structure: &Symbol,
|
||||
index: u64,
|
||||
|
@ -541,12 +545,12 @@ impl<
|
|||
let (base_offset, size) = (*base_offset, *size);
|
||||
let mut data_offset = base_offset;
|
||||
for layout in field_layouts.iter().take(index as usize) {
|
||||
let field_size = layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
let field_size = layout.stack_size(layout_interner, self.target_info);
|
||||
data_offset += field_size as i32;
|
||||
}
|
||||
debug_assert!(data_offset < base_offset + size as i32);
|
||||
let layout = field_layouts[index as usize];
|
||||
let size = layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
let size = layout.stack_size(layout_interner, self.target_info);
|
||||
self.allocation_map.insert(*sym, owned_data);
|
||||
self.symbol_storage_map.insert(
|
||||
*sym,
|
||||
|
@ -578,6 +582,7 @@ impl<
|
|||
|
||||
pub fn load_union_tag_id(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
sym: &Symbol,
|
||||
structure: &Symbol,
|
||||
|
@ -591,8 +596,8 @@ impl<
|
|||
UnionLayout::NonRecursive(_) => {
|
||||
let (union_offset, _) = self.stack_offset_and_size(structure);
|
||||
|
||||
let (data_size, data_alignment) = union_layout
|
||||
.data_size_and_alignment(self.env.layout_interner, self.target_info);
|
||||
let (data_size, data_alignment) =
|
||||
union_layout.data_size_and_alignment(layout_interner, self.target_info);
|
||||
let id_offset = data_size - data_alignment;
|
||||
let discriminant = union_layout.discriminant();
|
||||
|
||||
|
@ -630,12 +635,13 @@ impl<
|
|||
/// Creates a struct on the stack, moving the data in fields into the struct.
|
||||
pub fn create_struct(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
buf: &mut Vec<'a, u8>,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
fields: &'a [Symbol],
|
||||
) {
|
||||
let struct_size = layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
let struct_size = layout.stack_size(layout_interner, self.target_info);
|
||||
if struct_size == 0 {
|
||||
self.symbol_storage_map.insert(*sym, NoData);
|
||||
return;
|
||||
|
@ -645,21 +651,27 @@ impl<
|
|||
if let Layout::Struct { field_layouts, .. } = layout {
|
||||
let mut current_offset = base_offset;
|
||||
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
|
||||
self.copy_symbol_to_stack_offset(buf, current_offset, field, field_layout);
|
||||
let field_size =
|
||||
field_layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
self.copy_symbol_to_stack_offset(
|
||||
layout_interner,
|
||||
buf,
|
||||
current_offset,
|
||||
field,
|
||||
field_layout,
|
||||
);
|
||||
let field_size = field_layout.stack_size(layout_interner, self.target_info);
|
||||
current_offset += field_size as i32;
|
||||
}
|
||||
} else {
|
||||
// This is a single element struct. Just copy the single field to the stack.
|
||||
debug_assert_eq!(fields.len(), 1);
|
||||
self.copy_symbol_to_stack_offset(buf, base_offset, &fields[0], layout);
|
||||
self.copy_symbol_to_stack_offset(layout_interner, buf, base_offset, &fields[0], layout);
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a union on the stack, moving the data in fields into the union and tagging it.
|
||||
pub fn create_union(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
buf: &mut Vec<'a, u8>,
|
||||
sym: &Symbol,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
|
@ -668,8 +680,8 @@ impl<
|
|||
) {
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(field_layouts) => {
|
||||
let (data_size, data_alignment) = union_layout
|
||||
.data_size_and_alignment(self.env.layout_interner, self.target_info);
|
||||
let (data_size, data_alignment) =
|
||||
union_layout.data_size_and_alignment(layout_interner, self.target_info);
|
||||
let id_offset = data_size - data_alignment;
|
||||
if data_alignment < 8 || data_alignment % 8 != 0 {
|
||||
todo!("small/unaligned tagging");
|
||||
|
@ -679,9 +691,14 @@ impl<
|
|||
for (field, field_layout) in
|
||||
fields.iter().zip(field_layouts[tag_id as usize].iter())
|
||||
{
|
||||
self.copy_symbol_to_stack_offset(buf, current_offset, field, field_layout);
|
||||
let field_size =
|
||||
field_layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
self.copy_symbol_to_stack_offset(
|
||||
layout_interner,
|
||||
buf,
|
||||
current_offset,
|
||||
field,
|
||||
field_layout,
|
||||
);
|
||||
let field_size = field_layout.stack_size(layout_interner, self.target_info);
|
||||
current_offset += field_size as i32;
|
||||
}
|
||||
self.with_tmp_general_reg(buf, |_symbol_storage, buf, reg| {
|
||||
|
@ -719,6 +736,7 @@ impl<
|
|||
/// Always interact with the stack using aligned 64bit movement.
|
||||
pub fn copy_symbol_to_stack_offset(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
buf: &mut Vec<'a, u8>,
|
||||
to_offset: i32,
|
||||
sym: &Symbol,
|
||||
|
@ -735,19 +753,16 @@ impl<
|
|||
let reg = self.load_to_float_reg(buf, sym);
|
||||
ASM::mov_base32_freg64(buf, to_offset, reg);
|
||||
}
|
||||
_ if layout.stack_size(self.env.layout_interner, self.target_info) == 0 => {}
|
||||
_ if layout.stack_size(layout_interner, self.target_info) == 0 => {}
|
||||
// TODO: Verify this is always true.
|
||||
// The dev backend does not deal with refcounting and does not care about if data is safe to memcpy.
|
||||
// It is just temporarily storing the value due to needing to free registers.
|
||||
// Later, it will be reloaded and stored in refcounted as needed.
|
||||
_ if layout.stack_size(self.env.layout_interner, self.target_info) > 8 => {
|
||||
_ if layout.stack_size(layout_interner, self.target_info) > 8 => {
|
||||
let (from_offset, size) = self.stack_offset_and_size(sym);
|
||||
debug_assert!(from_offset % 8 == 0);
|
||||
debug_assert!(size % 8 == 0);
|
||||
debug_assert_eq!(
|
||||
size,
|
||||
layout.stack_size(self.env.layout_interner, self.target_info)
|
||||
);
|
||||
debug_assert_eq!(size, layout.stack_size(layout_interner, self.target_info));
|
||||
self.with_tmp_general_reg(buf, |_storage_manager, buf, reg| {
|
||||
for i in (0..size as i32).step_by(8) {
|
||||
ASM::mov_reg64_base32(buf, reg, from_offset + i);
|
||||
|
@ -988,6 +1003,7 @@ impl<
|
|||
/// Later jumps to the join point can overwrite the stored locations to pass parameters.
|
||||
pub fn setup_joinpoint(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
id: &JoinPointId,
|
||||
params: &'a [Param<'a>],
|
||||
|
@ -1021,7 +1037,7 @@ impl<
|
|||
.insert(*symbol, Rc::new((base_offset, 8)));
|
||||
}
|
||||
_ => {
|
||||
let stack_size = layout.stack_size(self.env.layout_interner, self.target_info);
|
||||
let stack_size = layout.stack_size(layout_interner, self.target_info);
|
||||
if stack_size == 0 {
|
||||
self.symbol_storage_map.insert(*symbol, NoData);
|
||||
} else {
|
||||
|
@ -1038,6 +1054,7 @@ impl<
|
|||
/// This enables the jump to correctly passe arguments to the joinpoint.
|
||||
pub fn setup_jump(
|
||||
&mut self,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
buf: &mut Vec<'a, u8>,
|
||||
id: &JoinPointId,
|
||||
args: &[Symbol],
|
||||
|
@ -1065,7 +1082,13 @@ impl<
|
|||
// Maybe we want a more memcpy like method to directly get called here.
|
||||
// That would also be capable of asserting the size.
|
||||
// Maybe copy stack to stack or something.
|
||||
self.copy_symbol_to_stack_offset(buf, *base_offset, sym, layout);
|
||||
self.copy_symbol_to_stack_offset(
|
||||
layout_interner,
|
||||
buf,
|
||||
*base_offset,
|
||||
sym,
|
||||
layout,
|
||||
);
|
||||
}
|
||||
Stack(Primitive {
|
||||
base_offset,
|
||||
|
|
|
@ -251,27 +251,29 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn load_args<'a>(
|
||||
fn load_args<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64SystemV,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
ret_layout: &Layout<'a>,
|
||||
) {
|
||||
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 16; // 16 is the size of the pushed return address and base pointer.
|
||||
let mut general_i = 0;
|
||||
let mut float_i = 0;
|
||||
if X86_64SystemV::returns_via_arg_pointer(storage_manager.env.layout_interner, ret_layout) {
|
||||
if X86_64SystemV::returns_via_arg_pointer(layout_interner, ret_layout) {
|
||||
storage_manager.ret_pointer_arg(Self::GENERAL_PARAM_REGS[0]);
|
||||
general_i += 1;
|
||||
}
|
||||
for (layout, sym) in args.iter() {
|
||||
let stack_size = layout.stack_size(storage_manager.env.layout_interner, TARGET_INFO);
|
||||
let stack_size = layout.stack_size(layout_interner, TARGET_INFO);
|
||||
match layout {
|
||||
single_register_integers!() => {
|
||||
if general_i < Self::GENERAL_PARAM_REGS.len() {
|
||||
|
@ -307,15 +309,17 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn store_args<'a>(
|
||||
fn store_args<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64SystemV,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
dst: &Symbol,
|
||||
args: &[Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
|
@ -324,12 +328,10 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
let mut tmp_stack_offset = Self::SHADOW_SPACE_SIZE as i32;
|
||||
let mut general_i = 0;
|
||||
let mut float_i = 0;
|
||||
if Self::returns_via_arg_pointer(storage_manager.env.layout_interner, ret_layout) {
|
||||
if Self::returns_via_arg_pointer(layout_interner, ret_layout) {
|
||||
// Save space on the stack for the result we will be return.
|
||||
let base_offset = storage_manager.claim_stack_area(
|
||||
dst,
|
||||
ret_layout.stack_size(storage_manager.env.layout_interner, TARGET_INFO),
|
||||
);
|
||||
let base_offset = storage_manager
|
||||
.claim_stack_area(dst, ret_layout.stack_size(layout_interner, TARGET_INFO));
|
||||
// Set the first reg to the address base + offset.
|
||||
let ret_reg = Self::GENERAL_PARAM_REGS[general_i];
|
||||
general_i += 1;
|
||||
|
@ -388,8 +390,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
tmp_stack_offset += 8;
|
||||
}
|
||||
}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) > 16 => {
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) > 16 => {
|
||||
// TODO: Double check this.
|
||||
// Just copy onto the stack.
|
||||
// Use return reg as buffer because it will be empty right now.
|
||||
|
@ -417,15 +419,17 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
storage_manager.update_fn_call_stack_size(tmp_stack_offset as u32);
|
||||
}
|
||||
|
||||
fn return_complex_symbol<'a>(
|
||||
fn return_complex_symbol<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64SystemV,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) {
|
||||
|
@ -433,8 +437,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
single_register_layouts!() => {
|
||||
internal_error!("single register layouts are not complex symbols");
|
||||
}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if !Self::returns_via_arg_pointer(storage_manager.env.layout_interner, x) => {
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if !Self::returns_via_arg_pointer(layout_interner, x) => {
|
||||
let (base_offset, size) = storage_manager.stack_offset_and_size(sym);
|
||||
debug_assert_eq!(base_offset % 8, 0);
|
||||
if size <= 8 {
|
||||
|
@ -473,15 +477,17 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
}
|
||||
}
|
||||
|
||||
fn load_returned_complex_symbol<'a>(
|
||||
fn load_returned_complex_symbol<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64SystemV,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
sym: &Symbol,
|
||||
layout: &Layout<'a>,
|
||||
) {
|
||||
|
@ -489,9 +495,9 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
|
|||
single_register_layouts!() => {
|
||||
internal_error!("single register layouts are not complex symbols");
|
||||
}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if !Self::returns_via_arg_pointer(storage_manager.env.layout_interner, x) => {
|
||||
let size = layout.stack_size(storage_manager.env.layout_interner, TARGET_INFO);
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if !Self::returns_via_arg_pointer(layout_interner, x) => {
|
||||
let size = layout.stack_size(layout_interner, TARGET_INFO);
|
||||
let offset = storage_manager.claim_stack_area(sym, size);
|
||||
if size <= 8 {
|
||||
X86_64Assembler::mov_base32_reg64(buf, offset, Self::GENERAL_RETURN_REGS[0]);
|
||||
|
@ -658,24 +664,23 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn load_args<'a>(
|
||||
fn load_args<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64WindowsFastcall,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
args: &'a [(Layout<'a>, Symbol)],
|
||||
ret_layout: &Layout<'a>,
|
||||
) {
|
||||
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 16; // 16 is the size of the pushed return address and base pointer.
|
||||
let mut i = 0;
|
||||
if X86_64WindowsFastcall::returns_via_arg_pointer(
|
||||
storage_manager.env.layout_interner,
|
||||
ret_layout,
|
||||
) {
|
||||
if X86_64WindowsFastcall::returns_via_arg_pointer(layout_interner, ret_layout) {
|
||||
storage_manager.ret_pointer_arg(Self::GENERAL_PARAM_REGS[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
@ -690,7 +695,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
storage_manager.float_reg_arg(sym, Self::FLOAT_PARAM_REGS[i]);
|
||||
i += 1;
|
||||
}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) == 0 => {}
|
||||
x => {
|
||||
todo!("Loading args with layout {:?}", x);
|
||||
}
|
||||
|
@ -710,27 +715,27 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn store_args<'a>(
|
||||
fn store_args<'a, 'r>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64WindowsFastcall,
|
||||
>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
dst: &Symbol,
|
||||
args: &[Symbol],
|
||||
arg_layouts: &[Layout<'a>],
|
||||
ret_layout: &Layout<'a>,
|
||||
) {
|
||||
let mut tmp_stack_offset = Self::SHADOW_SPACE_SIZE as i32;
|
||||
if Self::returns_via_arg_pointer(storage_manager.env.layout_interner, ret_layout) {
|
||||
if Self::returns_via_arg_pointer(layout_interner, ret_layout) {
|
||||
// Save space on the stack for the arg we will return.
|
||||
storage_manager.claim_stack_area(
|
||||
dst,
|
||||
ret_layout.stack_size(storage_manager.env.layout_interner, TARGET_INFO),
|
||||
);
|
||||
storage_manager
|
||||
.claim_stack_area(dst, ret_layout.stack_size(layout_interner, TARGET_INFO));
|
||||
todo!("claim first parama reg for the address");
|
||||
}
|
||||
for (i, (sym, layout)) in args.iter().zip(arg_layouts.iter()).enumerate() {
|
||||
|
@ -779,7 +784,7 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
tmp_stack_offset += 8;
|
||||
}
|
||||
}
|
||||
x if x.stack_size(storage_manager.env.layout_interner, TARGET_INFO) == 0 => {}
|
||||
x if x.stack_size(layout_interner, TARGET_INFO) == 0 => {}
|
||||
x => {
|
||||
todo!("calling with arg type, {:?}", x);
|
||||
}
|
||||
|
@ -788,30 +793,34 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
|
|||
storage_manager.update_fn_call_stack_size(tmp_stack_offset as u32);
|
||||
}
|
||||
|
||||
fn return_complex_symbol<'a>(
|
||||
fn return_complex_symbol<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64WindowsFastcall,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_sym: &Symbol,
|
||||
_layout: &Layout<'a>,
|
||||
) {
|
||||
todo!("Returning complex symbols for X86_64");
|
||||
}
|
||||
|
||||
fn load_returned_complex_symbol<'a>(
|
||||
fn load_returned_complex_symbol<'a, 'r>(
|
||||
_buf: &mut Vec<'a, u8>,
|
||||
_storage_manager: &mut StorageManager<
|
||||
'a,
|
||||
'r,
|
||||
X86_64GeneralReg,
|
||||
X86_64FloatReg,
|
||||
X86_64Assembler,
|
||||
X86_64WindowsFastcall,
|
||||
>,
|
||||
_layout_interner: &mut STLayoutInterner<'a>,
|
||||
_sym: &Symbol,
|
||||
_layout: &Layout<'a>,
|
||||
) {
|
||||
|
@ -1029,9 +1038,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
imul_reg64_reg64(buf, dst, src2);
|
||||
}
|
||||
|
||||
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn umul_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
dst: X86_64GeneralReg,
|
||||
src1: X86_64GeneralReg,
|
||||
src2: X86_64GeneralReg,
|
||||
|
@ -1113,9 +1122,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
}
|
||||
}
|
||||
|
||||
fn idiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn idiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
dst: X86_64GeneralReg,
|
||||
src1: X86_64GeneralReg,
|
||||
src2: X86_64GeneralReg,
|
||||
|
@ -1133,9 +1142,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
mov_reg64_reg64(buf, dst, X86_64GeneralReg::RAX);
|
||||
}
|
||||
|
||||
fn udiv_reg64_reg64_reg64<'a, ASM, CC>(
|
||||
fn udiv_reg64_reg64_reg64<'a, 'r, ASM, CC>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
storage_manager: &mut StorageManager<'a, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
|
||||
dst: X86_64GeneralReg,
|
||||
src1: X86_64GeneralReg,
|
||||
src2: X86_64GeneralReg,
|
||||
|
|
|
@ -28,7 +28,6 @@ mod run_roc;
|
|||
|
||||
pub struct Env<'a> {
|
||||
pub arena: &'a Bump,
|
||||
pub layout_interner: &'a STLayoutInterner<'a>,
|
||||
pub module_id: ModuleId,
|
||||
pub exposed_to_host: MutSet<Symbol>,
|
||||
pub lazy_literals: bool,
|
||||
|
@ -68,7 +67,14 @@ trait Backend<'a> {
|
|||
// 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.
|
||||
fn env_interns_helpers_mut(&mut self) -> (&Env<'a>, &mut Interns, &mut CodeGenHelp<'a>);
|
||||
fn module_interns_helpers_mut(
|
||||
&mut self,
|
||||
) -> (
|
||||
ModuleId,
|
||||
&mut STLayoutInterner<'a>,
|
||||
&mut Interns,
|
||||
&mut CodeGenHelp<'a>,
|
||||
);
|
||||
|
||||
fn symbol_to_string(&self, symbol: Symbol, layout_id: LayoutId) -> String {
|
||||
layout_id.to_symbol_string(symbol, self.interns())
|
||||
|
@ -155,11 +161,17 @@ 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 (env, interns, rc_proc_gen) = self.env_interns_helpers_mut();
|
||||
let module_id = env.module_id;
|
||||
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();
|
||||
|
||||
rc_proc_gen.expand_refcount_stmt(ident_ids, layout, modify, following)
|
||||
rc_proc_gen.expand_refcount_stmt(
|
||||
ident_ids,
|
||||
layout_interner,
|
||||
layout,
|
||||
modify,
|
||||
following,
|
||||
)
|
||||
};
|
||||
|
||||
for spec in new_specializations.into_iter() {
|
||||
|
|
|
@ -12,7 +12,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::symbol;
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_mono::ir::{Proc, ProcLayout};
|
||||
use roc_mono::layout::LayoutIds;
|
||||
use roc_mono::layout::{LayoutIds, STLayoutInterner};
|
||||
use roc_target::TargetInfo;
|
||||
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
|
||||
|
||||
|
@ -22,9 +22,10 @@ use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Tripl
|
|||
|
||||
/// build_module is the high level builder/delegator.
|
||||
/// It takes the request to build a module and output the object file for the module.
|
||||
pub fn build_module<'a>(
|
||||
env: &'a Env,
|
||||
interns: &'a mut Interns,
|
||||
pub fn build_module<'a, 'r>(
|
||||
env: &'r Env<'a>,
|
||||
interns: &'r mut Interns,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
target: &Triple,
|
||||
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) -> Object<'a> {
|
||||
|
@ -39,7 +40,7 @@ pub fn build_module<'a>(
|
|||
x86_64::X86_64FloatReg,
|
||||
x86_64::X86_64Assembler,
|
||||
x86_64::X86_64SystemV,
|
||||
>(env, TargetInfo::default_x86_64(), interns);
|
||||
>(env, TargetInfo::default_x86_64(), interns, layout_interner);
|
||||
build_object(
|
||||
procedures,
|
||||
backend,
|
||||
|
@ -56,7 +57,7 @@ pub fn build_module<'a>(
|
|||
x86_64::X86_64FloatReg,
|
||||
x86_64::X86_64Assembler,
|
||||
x86_64::X86_64SystemV,
|
||||
>(env, TargetInfo::default_x86_64(), interns);
|
||||
>(env, TargetInfo::default_x86_64(), interns, layout_interner);
|
||||
build_object(
|
||||
procedures,
|
||||
backend,
|
||||
|
@ -72,12 +73,13 @@ pub fn build_module<'a>(
|
|||
binary_format: TargetBF::Elf,
|
||||
..
|
||||
} if cfg!(feature = "target-aarch64") => {
|
||||
let backend = new_backend_64bit::<
|
||||
aarch64::AArch64GeneralReg,
|
||||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns);
|
||||
let backend =
|
||||
new_backend_64bit::<
|
||||
aarch64::AArch64GeneralReg,
|
||||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns, layout_interner);
|
||||
build_object(
|
||||
procedures,
|
||||
backend,
|
||||
|
@ -89,12 +91,13 @@ pub fn build_module<'a>(
|
|||
binary_format: TargetBF::Macho,
|
||||
..
|
||||
} if cfg!(feature = "target-aarch64") => {
|
||||
let backend = new_backend_64bit::<
|
||||
aarch64::AArch64GeneralReg,
|
||||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns);
|
||||
let backend =
|
||||
new_backend_64bit::<
|
||||
aarch64::AArch64GeneralReg,
|
||||
aarch64::AArch64FloatReg,
|
||||
aarch64::AArch64Assembler,
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns, layout_interner);
|
||||
build_object(
|
||||
procedures,
|
||||
backend,
|
||||
|
@ -243,13 +246,11 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
|
||||
// Generate IR for specialized helper procs (refcounting & equality)
|
||||
let helper_procs = {
|
||||
let module_id = backend.env().module_id;
|
||||
|
||||
let (env, interns, helper_proc_gen) = backend.env_interns_helpers_mut();
|
||||
let (module_id, _interner, interns, helper_proc_gen) = backend.module_interns_helpers_mut();
|
||||
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
let helper_procs = helper_proc_gen.take_procs();
|
||||
env.module_id.register_debug_idents(ident_ids);
|
||||
module_id.register_debug_idents(ident_ids);
|
||||
|
||||
helper_procs
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
roc_alias_analysis = { path = "../alias_analysis" }
|
||||
roc_collections = { path = "../collections" }
|
||||
roc_intern = { path = "../intern" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
|
|
|
@ -12,8 +12,9 @@ use inkwell::values::{
|
|||
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
use super::build::{load_roc_value, use_roc_value, BuilderExt};
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
|
@ -182,7 +183,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
*inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
),
|
||||
|
@ -371,7 +372,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
*inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
)
|
||||
|
@ -1283,7 +1284,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
|||
layout_ids: &mut LayoutIds<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
box_layout: &Layout<'a>,
|
||||
inner_layout: &Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
tag1: BasicValueEnum<'ctx>,
|
||||
tag2: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
|
@ -1336,7 +1337,7 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
|||
layout_ids: &mut LayoutIds<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
inner_layout: &Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
) {
|
||||
let ctx = env.context;
|
||||
let builder = env.builder;
|
||||
|
@ -1400,6 +1401,8 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
|||
let box1 = box1.into_pointer_value();
|
||||
let box2 = box2.into_pointer_value();
|
||||
|
||||
let inner_layout = env.layout_interner.get(inner_layout);
|
||||
|
||||
let value1 = load_roc_value(env, *inner_layout, box1, "load_box1");
|
||||
let value2 = load_roc_value(env, *inner_layout, box2, "load_box2");
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
|||
use inkwell::values::StructValue;
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_intern::Interner;
|
||||
use roc_mono::layout::{round_up_to_alignment, Builtin, Layout, STLayoutInterner, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
|
@ -38,6 +39,7 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
||||
}
|
||||
Boxed(inner_layout) => {
|
||||
let inner_layout = env.layout_interner.get(*inner_layout);
|
||||
let inner_type = basic_type_from_layout(env, inner_layout);
|
||||
|
||||
inner_type.ptr_type(AddressSpace::Generic).into()
|
||||
|
|
|
@ -9,6 +9,7 @@ use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
|
|||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::LookupType;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
|
@ -348,6 +349,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
build_copy(env, ptr, cursors.offset, cursors.extra_offset.into());
|
||||
|
||||
let source = value.into_pointer_value();
|
||||
let inner_layout = env.layout_interner.get(inner_layout);
|
||||
let value = load_roc_value(env, *inner_layout, source, "inner");
|
||||
|
||||
let inner_width = env.ptr_int().const_int(
|
||||
|
|
|
@ -17,7 +17,7 @@ use inkwell::values::{
|
|||
use inkwell::{AddressSpace, IntPredicate};
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||
|
||||
use super::build::{cast_if_necessary_for_opaque_recursive_pointers, load_roc_value, FunctionSpec};
|
||||
use super::convert::{argument_type_from_layout, argument_type_from_union_layout};
|
||||
|
@ -531,7 +531,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
Boxed(inner) => {
|
||||
let function = modify_refcount_boxed(env, layout_ids, mode, inner);
|
||||
let function = modify_refcount_boxed(env, layout_ids, mode, *inner);
|
||||
|
||||
Some(function)
|
||||
}
|
||||
|
@ -851,7 +851,7 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
inner_layout: &'a Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
@ -889,7 +889,7 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
|||
fn modify_refcount_box_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
mode: Mode,
|
||||
inner_layout: &Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
fn_val: FunctionValue<'ctx>,
|
||||
) {
|
||||
let builder = env.builder;
|
||||
|
|
|
@ -4,6 +4,7 @@ use bumpalo::collections::{String, Vec};
|
|||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_mono::code_gen_help::{CodeGenHelp, HelperOp, REFCOUNT_MAX};
|
||||
|
@ -11,7 +12,7 @@ use roc_mono::ir::{
|
|||
BranchInfo, CallType, CrashTag, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc,
|
||||
Param, Proc, ProcLayout, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, TagIdIntType, UnionLayout};
|
||||
use roc_std::RocDec;
|
||||
|
||||
use roc_wasm_module::linking::{DataSymbol, WasmObjectSymbol};
|
||||
|
@ -48,9 +49,10 @@ pub struct ProcLookupData<'a> {
|
|||
pub source: ProcSource,
|
||||
}
|
||||
|
||||
pub struct WasmBackend<'a> {
|
||||
pub env: &'a Env<'a>,
|
||||
interns: &'a mut Interns,
|
||||
pub struct WasmBackend<'a, 'r> {
|
||||
pub env: &'r Env<'a>,
|
||||
pub(crate) layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
interns: &'r mut Interns,
|
||||
|
||||
// Module-level data
|
||||
module: WasmModule<'a>,
|
||||
|
@ -72,11 +74,12 @@ pub struct WasmBackend<'a> {
|
|||
joinpoint_label_map: MutMap<JoinPointId, (u32, Vec<'a, StoredValue>)>,
|
||||
}
|
||||
|
||||
impl<'a> WasmBackend<'a> {
|
||||
impl<'a, 'r> WasmBackend<'a, 'r> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
env: &'a Env<'a>,
|
||||
interns: &'a mut Interns,
|
||||
env: &'r Env<'a>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
interns: &'r mut Interns,
|
||||
layout_ids: LayoutIds<'a>,
|
||||
proc_lookup: Vec<'a, ProcLookupData<'a>>,
|
||||
host_to_app_map: Vec<'a, (&'a str, u32)>,
|
||||
|
@ -114,6 +117,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
WasmBackend {
|
||||
env,
|
||||
layout_interner,
|
||||
interns,
|
||||
|
||||
// Module-level data
|
||||
|
@ -403,7 +407,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
fn start_proc(&mut self, proc: &Proc<'a>) {
|
||||
use ReturnMethod::*;
|
||||
let ret_layout = WasmLayout::new(self.env.layout_interner, &proc.ret_layout);
|
||||
let ret_layout = WasmLayout::new(self.layout_interner, &proc.ret_layout);
|
||||
|
||||
let ret_type = match ret_layout.return_method(CallConv::C) {
|
||||
Primitive(ty, _) => Some(ty),
|
||||
|
@ -422,7 +426,7 @@ impl<'a> WasmBackend<'a> {
|
|||
self.start_block();
|
||||
|
||||
self.storage.allocate_args(
|
||||
self.env.layout_interner,
|
||||
self.layout_interner,
|
||||
proc.args,
|
||||
&mut self.code_builder,
|
||||
self.env.arena,
|
||||
|
@ -500,7 +504,9 @@ impl<'a> WasmBackend<'a> {
|
|||
// Our convention is that the last arg of the wrapper is the heap return pointer
|
||||
let heap_return_ptr_id = LocalId(wrapper_arg_layouts.len() as u32 - 1);
|
||||
let inner_ret_layout = match wrapper_arg_layouts.last() {
|
||||
Some(Layout::Boxed(inner)) => WasmLayout::new(self.env.layout_interner, inner),
|
||||
Some(Layout::Boxed(inner)) => {
|
||||
WasmLayout::new(self.layout_interner, self.layout_interner.get(*inner))
|
||||
}
|
||||
x => internal_error!("Higher-order wrapper: invalid return layout {:?}", x),
|
||||
};
|
||||
|
||||
|
@ -531,10 +537,10 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
|
||||
let inner_layout = match wrapper_arg {
|
||||
Layout::Boxed(inner) => inner,
|
||||
Layout::Boxed(inner) => self.layout_interner.get(*inner),
|
||||
x => internal_error!("Expected a Boxed layout, got {:?}", x),
|
||||
};
|
||||
if inner_layout.stack_size(self.env.layout_interner, TARGET_INFO) == 0 {
|
||||
if inner_layout.stack_size(self.layout_interner, TARGET_INFO) == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -546,7 +552,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
// If the inner function has closure data, it's the last arg of the inner fn
|
||||
let closure_data_layout = wrapper_arg_layouts[0];
|
||||
if closure_data_layout.stack_size(self.env.layout_interner, TARGET_INFO) > 0 {
|
||||
if closure_data_layout.stack_size(self.layout_interner, TARGET_INFO) > 0 {
|
||||
// The closure data exists, and will have been passed in to the wrapper as a
|
||||
// one-element struct.
|
||||
let inner_closure_data_layout = match closure_data_layout {
|
||||
|
@ -621,13 +627,13 @@ impl<'a> WasmBackend<'a> {
|
|||
let value_layout = wrapper_proc_layout.arguments[1];
|
||||
|
||||
let mut n_inner_args = 2;
|
||||
if closure_data_layout.stack_size(self.env.layout_interner, TARGET_INFO) > 0 {
|
||||
if closure_data_layout.stack_size(self.layout_interner, TARGET_INFO) > 0 {
|
||||
self.code_builder.get_local(LocalId(0));
|
||||
n_inner_args += 1;
|
||||
}
|
||||
|
||||
let inner_layout = match value_layout {
|
||||
Layout::Boxed(inner) => inner,
|
||||
Layout::Boxed(inner) => self.layout_interner.get(inner),
|
||||
x => internal_error!("Expected a Boxed layout, got {:?}", x),
|
||||
};
|
||||
self.code_builder.get_local(LocalId(1));
|
||||
|
@ -770,7 +776,7 @@ impl<'a> WasmBackend<'a> {
|
|||
) {
|
||||
let sym_storage = self
|
||||
.storage
|
||||
.allocate_var(self.env.layout_interner, *layout, sym, kind);
|
||||
.allocate_var(self.layout_interner, *layout, sym, kind);
|
||||
|
||||
self.expr(sym, expr, layout, &sym_storage);
|
||||
|
||||
|
@ -848,7 +854,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Bool));
|
||||
let cond_type =
|
||||
WasmLayout::new(self.env.layout_interner, cond_layout).arg_types(CallConv::C)[0];
|
||||
WasmLayout::new(self.layout_interner, cond_layout).arg_types(CallConv::C)[0];
|
||||
|
||||
// then, we jump whenever the value under scrutiny is equal to the value of a branch
|
||||
for (i, (value, _, _)) in branches.iter().enumerate() {
|
||||
|
@ -910,7 +916,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let mut jp_param_storages = Vec::with_capacity_in(parameters.len(), self.env.arena);
|
||||
for parameter in parameters.iter() {
|
||||
let mut param_storage = self.storage.allocate_var(
|
||||
self.env.layout_interner,
|
||||
self.layout_interner,
|
||||
parameter.layout,
|
||||
parameter.symbol,
|
||||
StoredVarKind::Variable,
|
||||
|
@ -967,15 +973,19 @@ impl<'a> WasmBackend<'a> {
|
|||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let (rc_stmt, new_specializations) = self
|
||||
.helper_proc_gen
|
||||
.expand_refcount_stmt(ident_ids, layout, modify, following);
|
||||
let (rc_stmt, new_specializations) = self.helper_proc_gen.expand_refcount_stmt(
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
layout,
|
||||
modify,
|
||||
following,
|
||||
);
|
||||
|
||||
if false {
|
||||
self.register_symbol_debug_names();
|
||||
println!(
|
||||
"## rc_stmt:\n{}\n{:?}",
|
||||
rc_stmt.to_pretty(self.env.layout_interner, 200, true),
|
||||
rc_stmt.to_pretty(self.layout_interner, 200, true),
|
||||
rc_stmt
|
||||
);
|
||||
}
|
||||
|
@ -991,7 +1001,7 @@ impl<'a> WasmBackend<'a> {
|
|||
pub fn stmt_internal_error(&mut self, msg: &'a str) {
|
||||
let msg_sym = self.create_symbol("panic_str");
|
||||
let msg_storage = self.storage.allocate_var(
|
||||
self.env.layout_interner,
|
||||
self.layout_interner,
|
||||
Layout::Builtin(Builtin::Str),
|
||||
msg_sym,
|
||||
StoredVarKind::Variable,
|
||||
|
@ -1264,7 +1274,7 @@ impl<'a> WasmBackend<'a> {
|
|||
ret_layout,
|
||||
} => {
|
||||
let name = foreign_symbol.as_str();
|
||||
let wasm_layout = WasmLayout::new(self.env.layout_interner, ret_layout);
|
||||
let wasm_layout = WasmLayout::new(self.layout_interner, ret_layout);
|
||||
let (num_wasm_args, has_return_val, ret_zig_packed_struct) =
|
||||
self.storage.load_symbols_for_call(
|
||||
self.env.arena,
|
||||
|
@ -1289,7 +1299,7 @@ impl<'a> WasmBackend<'a> {
|
|||
ret_layout: &Layout<'a>,
|
||||
ret_storage: &StoredValue,
|
||||
) {
|
||||
let wasm_layout = WasmLayout::new(self.env.layout_interner, ret_layout);
|
||||
let wasm_layout = WasmLayout::new(self.layout_interner, ret_layout);
|
||||
|
||||
// If this function is just a lowlevel wrapper, then inline it
|
||||
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
||||
|
@ -1391,7 +1401,7 @@ impl<'a> WasmBackend<'a> {
|
|||
// Get an IR expression for the call to the specialized procedure
|
||||
let (specialized_call_expr, new_specializations) = self
|
||||
.helper_proc_gen
|
||||
.call_specialized_equals(ident_ids, arg_layout, arguments);
|
||||
.call_specialized_equals(ident_ids, self.layout_interner, arg_layout, arguments);
|
||||
|
||||
// If any new specializations were created, register their symbol data
|
||||
for (spec_sym, spec_layout) in new_specializations.into_iter() {
|
||||
|
@ -1446,7 +1456,7 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
Layout::LambdaSet(lambdaset) => self.expr_struct(
|
||||
sym,
|
||||
&lambdaset.runtime_representation(self.env.layout_interner),
|
||||
&lambdaset.runtime_representation(self.layout_interner),
|
||||
storage,
|
||||
fields,
|
||||
),
|
||||
|
@ -1497,7 +1507,7 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
};
|
||||
for field in field_layouts.iter().take(index as usize) {
|
||||
offset += field.stack_size(self.env.layout_interner, TARGET_INFO);
|
||||
offset += field.stack_size(self.layout_interner, TARGET_INFO);
|
||||
}
|
||||
self.storage
|
||||
.copy_value_from_memory(&mut self.code_builder, sym, from_addr_val, offset);
|
||||
|
@ -1515,12 +1525,12 @@ impl<'a> WasmBackend<'a> {
|
|||
elems: &'a [ListLiteralElement<'a>],
|
||||
) {
|
||||
if let StoredValue::StackMemory { location, .. } = storage {
|
||||
let size = elem_layout.stack_size(self.env.layout_interner, TARGET_INFO)
|
||||
* (elems.len() as u32);
|
||||
let size =
|
||||
elem_layout.stack_size(self.layout_interner, TARGET_INFO) * (elems.len() as u32);
|
||||
|
||||
// Allocate heap space and store its address in a local variable
|
||||
let heap_local_id = self.storage.create_anonymous_local(PTR_TYPE);
|
||||
let heap_alignment = elem_layout.alignment_bytes(self.env.layout_interner, TARGET_INFO);
|
||||
let heap_alignment = elem_layout.alignment_bytes(self.layout_interner, TARGET_INFO);
|
||||
self.allocate_with_refcount(Some(size), heap_alignment, 1);
|
||||
self.code_builder.set_local(heap_local_id);
|
||||
|
||||
|
@ -1618,7 +1628,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let stores_tag_id_as_data = union_layout.stores_tag_id_as_data(TARGET_INFO);
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
|
||||
let (data_size, data_alignment) =
|
||||
union_layout.data_size_and_alignment(self.env.layout_interner, TARGET_INFO);
|
||||
union_layout.data_size_and_alignment(self.layout_interner, TARGET_INFO);
|
||||
|
||||
// We're going to use the pointer many times, so put it in a local variable
|
||||
let stored_with_local =
|
||||
|
@ -1672,7 +1682,7 @@ impl<'a> WasmBackend<'a> {
|
|||
if stores_tag_id_as_data {
|
||||
let id_offset = data_offset
|
||||
+ union_layout
|
||||
.tag_id_offset(self.env.layout_interner, TARGET_INFO)
|
||||
.tag_id_offset(self.layout_interner, TARGET_INFO)
|
||||
.unwrap();
|
||||
|
||||
let id_align = union_layout.discriminant().alignment_bytes();
|
||||
|
@ -1757,7 +1767,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
if union_layout.stores_tag_id_as_data(TARGET_INFO) {
|
||||
let id_offset = union_layout
|
||||
.tag_id_offset(self.env.layout_interner, TARGET_INFO)
|
||||
.tag_id_offset(self.layout_interner, TARGET_INFO)
|
||||
.unwrap();
|
||||
|
||||
let id_align = union_layout.discriminant().alignment_bytes();
|
||||
|
@ -1818,7 +1828,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let field_offset: u32 = field_layouts
|
||||
.iter()
|
||||
.take(index as usize)
|
||||
.map(|field_layout| field_layout.stack_size(self.env.layout_interner, TARGET_INFO))
|
||||
.map(|field_layout| field_layout.stack_size(self.layout_interner, TARGET_INFO))
|
||||
.sum();
|
||||
|
||||
// Get pointer and offset to the tag's data
|
||||
|
@ -1881,11 +1891,11 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
// allocate heap memory and load its data address onto the value stack
|
||||
let arg_layout = match layout {
|
||||
Layout::Boxed(arg) => *arg,
|
||||
Layout::Boxed(arg) => self.layout_interner.get(*arg),
|
||||
_ => internal_error!("ExprBox should always produce a Boxed layout"),
|
||||
};
|
||||
let (size, alignment) =
|
||||
arg_layout.stack_size_and_alignment(self.env.layout_interner, TARGET_INFO);
|
||||
arg_layout.stack_size_and_alignment(self.layout_interner, TARGET_INFO);
|
||||
self.allocate_with_refcount(Some(size), alignment, 1);
|
||||
|
||||
// store the pointer value from the value stack into the local variable
|
||||
|
@ -1984,7 +1994,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let layout = self.storage.symbol_layouts[&argument];
|
||||
let (specialized_call_expr, new_specializations) = self
|
||||
.helper_proc_gen
|
||||
.call_reset_refcount(ident_ids, layout, argument);
|
||||
.call_reset_refcount(ident_ids, self.layout_interner, layout, argument);
|
||||
|
||||
// If any new specializations were created, register their symbol data
|
||||
for (spec_sym, spec_layout) in new_specializations.into_iter() {
|
||||
|
@ -2009,9 +2019,9 @@ impl<'a> WasmBackend<'a> {
|
|||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let (proc_symbol, new_specializations) = self
|
||||
.helper_proc_gen
|
||||
.gen_refcount_proc(ident_ids, layout, op);
|
||||
let (proc_symbol, new_specializations) =
|
||||
self.helper_proc_gen
|
||||
.gen_refcount_proc(ident_ids, self.layout_interner, layout, op);
|
||||
|
||||
// If any new specializations were created, register their symbol data
|
||||
for (spec_sym, spec_layout) in new_specializations.into_iter() {
|
||||
|
|
|
@ -43,7 +43,6 @@ pub const STACK_POINTER_NAME: &str = "__stack_pointer";
|
|||
|
||||
pub struct Env<'a> {
|
||||
pub arena: &'a Bump,
|
||||
pub layout_interner: &'a STLayoutInterner<'a>,
|
||||
pub module_id: ModuleId,
|
||||
pub exposed_to_host: MutSet<Symbol>,
|
||||
pub stack_bytes: u32,
|
||||
|
@ -65,13 +64,15 @@ pub fn parse_host<'a>(arena: &'a Bump, host_bytes: &[u8]) -> Result<WasmModule<'
|
|||
/// interns names of functions and variables (as memory-efficient interned strings)
|
||||
/// host_module parsed module from a Wasm object file containing all of the non-Roc code
|
||||
/// procedures Roc code in monomorphized intermediate representation
|
||||
pub fn build_app_binary<'a>(
|
||||
env: &'a Env<'a>,
|
||||
interns: &'a mut Interns,
|
||||
pub fn build_app_binary<'a, 'r>(
|
||||
env: &'r Env<'a>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
interns: &'r mut Interns,
|
||||
host_module: WasmModule<'a>,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) -> std::vec::Vec<u8> {
|
||||
let (mut wasm_module, called_fns, _) = build_app_module(env, interns, host_module, procedures);
|
||||
let (mut wasm_module, called_fns, _) =
|
||||
build_app_module(env, layout_interner, interns, host_module, procedures);
|
||||
|
||||
wasm_module.eliminate_dead_code(env.arena, called_fns);
|
||||
|
||||
|
@ -84,9 +85,10 @@ pub fn build_app_binary<'a>(
|
|||
/// Shared by all consumers of gen_wasm: roc_build, roc_repl_wasm, and test_gen
|
||||
/// (roc_repl_wasm and test_gen will add more generated code for a wrapper function
|
||||
/// that defines a common interface to `main`, independent of return type.)
|
||||
pub fn build_app_module<'a>(
|
||||
env: &'a Env<'a>,
|
||||
interns: &'a mut Interns,
|
||||
pub fn build_app_module<'a, 'r>(
|
||||
env: &'r Env<'a>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
interns: &'r mut Interns,
|
||||
host_module: WasmModule<'a>,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) -> (WasmModule<'a>, BitVec<usize>, u32) {
|
||||
|
@ -126,24 +128,20 @@ pub fn build_app_module<'a>(
|
|||
|
||||
let mut backend = WasmBackend::new(
|
||||
env,
|
||||
layout_interner,
|
||||
interns,
|
||||
layout_ids,
|
||||
proc_lookup,
|
||||
host_to_app_map,
|
||||
host_module,
|
||||
fn_index_offset,
|
||||
CodeGenHelp::new(
|
||||
env.arena,
|
||||
env.layout_interner,
|
||||
TargetInfo::default_wasm32(),
|
||||
env.module_id,
|
||||
),
|
||||
CodeGenHelp::new(env.arena, TargetInfo::default_wasm32(), env.module_id),
|
||||
);
|
||||
|
||||
if DEBUG_SETTINGS.user_procs_ir {
|
||||
println!("## procs");
|
||||
for proc in procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
println!("{}", proc.to_pretty(backend.layout_interner, 200, true));
|
||||
// println!("{:?}", proc);
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +159,7 @@ pub fn build_app_module<'a>(
|
|||
if DEBUG_SETTINGS.helper_procs_ir {
|
||||
println!("## helper_procs");
|
||||
for proc in helper_procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
println!("{}", proc.to_pretty(backend.layout_interner, 200, true));
|
||||
// println!("{:#?}", proc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use bumpalo::collections::Vec;
|
|||
use bumpalo::Bump;
|
||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::code_gen_help::HelperOp;
|
||||
|
@ -34,7 +35,7 @@ enum CodeGenNumType {
|
|||
}
|
||||
|
||||
impl CodeGenNumType {
|
||||
pub fn for_symbol(backend: &WasmBackend<'_>, symbol: Symbol) -> Self {
|
||||
pub fn for_symbol(backend: &WasmBackend<'_, '_>, symbol: Symbol) -> Self {
|
||||
Self::from(backend.storage.get(&symbol))
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ fn layout_is_signed_int(layout: &Layout) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn symbol_is_signed_int(backend: &WasmBackend<'_>, symbol: Symbol) -> bool {
|
||||
fn symbol_is_signed_int(backend: &WasmBackend<'_, '_>, symbol: Symbol) -> bool {
|
||||
layout_is_signed_int(&backend.storage.symbol_layouts[&symbol])
|
||||
}
|
||||
|
||||
|
@ -141,18 +142,18 @@ impl<'a> LowLevelCall<'a> {
|
|||
/// For numerical ops, this just pushes the arguments to the Wasm VM's value stack
|
||||
/// It implements the calling convention used by Zig for both numbers and structs
|
||||
/// Result is the type signature of the call
|
||||
fn load_args(&self, backend: &mut WasmBackend<'a>) -> (usize, bool, bool) {
|
||||
fn load_args(&self, backend: &mut WasmBackend<'a, '_>) -> (usize, bool, bool) {
|
||||
backend.storage.load_symbols_for_call(
|
||||
backend.env.arena,
|
||||
&mut backend.code_builder,
|
||||
self.arguments,
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
)
|
||||
}
|
||||
|
||||
fn load_args_and_call_zig(&self, backend: &mut WasmBackend<'a>, name: &'a str) {
|
||||
fn load_args_and_call_zig(&self, backend: &mut WasmBackend<'a, '_>, name: &'a str) {
|
||||
let (num_wasm_args, has_return_val, ret_zig_packed_struct) = self.load_args(backend);
|
||||
backend.call_host_fn_after_loading_args(name, num_wasm_args, has_return_val);
|
||||
|
||||
|
@ -182,7 +183,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
/// This may seem like deliberately introducing an error!
|
||||
/// But we want all targets to behave the same, and hash algos rely on wrapping.
|
||||
/// Discussion: https://github.com/roc-lang/roc/pull/2117#discussion_r760723063
|
||||
fn wrap_small_int(&self, backend: &mut WasmBackend<'a>, int_width: IntWidth) {
|
||||
fn wrap_small_int(&self, backend: &mut WasmBackend<'a, '_>, int_width: IntWidth) {
|
||||
let bits = 8 * int_width.stack_size() as i32;
|
||||
let shift = 32 - bits;
|
||||
if shift <= 0 {
|
||||
|
@ -200,7 +201,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
|
||||
/// Main entrypoint from WasmBackend
|
||||
pub fn generate(&self, backend: &mut WasmBackend<'a>) {
|
||||
pub fn generate(&self, backend: &mut WasmBackend<'a, '_>) {
|
||||
use CodeGenNumType::*;
|
||||
use LowLevel::*;
|
||||
|
||||
|
@ -281,7 +282,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
self.arguments,
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||
|
@ -360,7 +361,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
.load_symbols(&mut backend.code_builder, &[index]);
|
||||
let elem_size = self
|
||||
.ret_layout
|
||||
.stack_size(backend.env.layout_interner, TARGET_INFO);
|
||||
.stack_size(backend.layout_interner, TARGET_INFO);
|
||||
backend.code_builder.i32_const(elem_size as i32);
|
||||
backend.code_builder.i32_mul(); // index*size
|
||||
|
||||
|
@ -418,7 +419,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
} if value_layout == *list_elem => {
|
||||
let list_offset = 0;
|
||||
let elem_offset = Layout::Builtin(Builtin::List(list_elem))
|
||||
.stack_size(backend.env.layout_interner, TARGET_INFO);
|
||||
.stack_size(backend.layout_interner, TARGET_INFO);
|
||||
(list_offset, elem_offset, value_layout)
|
||||
}
|
||||
Layout::Struct {
|
||||
|
@ -426,7 +427,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
..
|
||||
} if value_layout == *list_elem => {
|
||||
let list_offset =
|
||||
value_layout.stack_size(backend.env.layout_interner, TARGET_INFO);
|
||||
value_layout.stack_size(backend.layout_interner, TARGET_INFO);
|
||||
let elem_offset = 0;
|
||||
(list_offset, elem_offset, value_layout)
|
||||
}
|
||||
|
@ -434,7 +435,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
};
|
||||
|
||||
let (elem_width, elem_alignment) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
// Ensure the new element is stored in memory so we can pass a pointer to Zig
|
||||
let (new_elem_local, new_elem_offset, _) =
|
||||
|
@ -484,7 +485,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
let capacity: Symbol = self.arguments[0];
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
// Zig arguments Wasm types
|
||||
// (return pointer) i32
|
||||
|
@ -515,14 +516,14 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
self.arguments,
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
// Load monomorphization constants
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
backend.code_builder.i32_const(elem_align as i32);
|
||||
backend.code_builder.i32_const(elem_width as i32);
|
||||
|
||||
|
@ -537,7 +538,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
let (spare_local, spare_offset, _) = ensure_symbol_is_in_memory(
|
||||
backend,
|
||||
spare,
|
||||
|
@ -559,7 +560,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -585,7 +586,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
let elem: Symbol = self.arguments[1];
|
||||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let elem_width = elem_layout.stack_size(backend.env.layout_interner, TARGET_INFO);
|
||||
let elem_width = elem_layout.stack_size(backend.layout_interner, TARGET_INFO);
|
||||
let (elem_local, elem_offset, _) =
|
||||
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
|
||||
|
||||
|
@ -601,7 +602,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -623,7 +624,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
let (elem_local, elem_offset, _) =
|
||||
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
|
||||
|
||||
|
@ -640,7 +641,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -665,7 +666,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
// The refcount function receives a pointer to an element in the list
|
||||
// This is the same as a Struct containing the element
|
||||
|
@ -690,7 +691,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -710,7 +711,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
// The refcount function receives a pointer to an element in the list
|
||||
// This is the same as a Struct containing the element
|
||||
|
@ -735,7 +736,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -756,7 +757,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
// Zig arguments Wasm types
|
||||
// (return pointer) i32
|
||||
|
@ -773,7 +774,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
&mut backend.code_builder,
|
||||
&[list],
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(backend.env.layout_interner, &self.ret_layout),
|
||||
&WasmLayout::new(backend.layout_interner, &self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
|
||||
|
@ -1631,7 +1632,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
||||
let bit_width = 8 * self
|
||||
.ret_layout
|
||||
.stack_size(backend.env.layout_interner, TARGET_INFO)
|
||||
.stack_size(backend.layout_interner, TARGET_INFO)
|
||||
as i32;
|
||||
if bit_width < 32 && !symbol_is_signed_int(backend, num) {
|
||||
// Sign-extend the number by shifting left and right again
|
||||
|
@ -1680,7 +1681,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
||||
let bit_width = 8 * self
|
||||
.ret_layout
|
||||
.stack_size(backend.env.layout_interner, TARGET_INFO);
|
||||
.stack_size(backend.layout_interner, TARGET_INFO);
|
||||
if bit_width < 32 && symbol_is_signed_int(backend, num) {
|
||||
let mask = (1 << bit_width) - 1;
|
||||
|
||||
|
@ -1872,11 +1873,11 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
/// Equality and inequality
|
||||
/// These can operate on any data type (except functions) so they're more complex than other operators.
|
||||
fn eq_or_neq(&self, backend: &mut WasmBackend<'a>) {
|
||||
fn eq_or_neq(&self, backend: &mut WasmBackend<'a, '_>) {
|
||||
let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]]
|
||||
.runtime_representation(backend.env.layout_interner);
|
||||
.runtime_representation(backend.layout_interner);
|
||||
let other_arg_layout = backend.storage.symbol_layouts[&self.arguments[1]]
|
||||
.runtime_representation(backend.env.layout_interner);
|
||||
.runtime_representation(backend.layout_interner);
|
||||
debug_assert!(
|
||||
arg_layout == other_arg_layout,
|
||||
"Cannot do `==` comparison on different types: {:?} vs {:?}",
|
||||
|
@ -1941,7 +1942,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eq_or_neq_number(&self, backend: &mut WasmBackend<'a>) {
|
||||
fn eq_or_neq_number(&self, backend: &mut WasmBackend<'a, '_>) {
|
||||
use StoredValue::*;
|
||||
|
||||
match backend.storage.get(&self.arguments[0]).to_owned() {
|
||||
|
@ -1986,7 +1987,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
/// Takes care of loading the arguments
|
||||
fn eq_num128(
|
||||
&self,
|
||||
backend: &mut WasmBackend<'a>,
|
||||
backend: &mut WasmBackend<'a, '_>,
|
||||
format: StackMemoryFormat,
|
||||
locations: [StackMemoryLocation; 2],
|
||||
) {
|
||||
|
@ -2004,7 +2005,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
/// Check that two 128-bit numbers contain the same bytes
|
||||
/// Loads *half* an argument at a time
|
||||
/// (Don't call "load arguments" or "load symbols" helpers before this, it'll just waste instructions)
|
||||
fn eq_num128_bytes(backend: &mut WasmBackend<'a>, locations: [StackMemoryLocation; 2]) {
|
||||
fn eq_num128_bytes(backend: &mut WasmBackend<'a, '_>, locations: [StackMemoryLocation; 2]) {
|
||||
let (local0, offset0) = locations[0].local_and_offset(backend.storage.stack_frame_pointer);
|
||||
let (local1, offset1) = locations[1].local_and_offset(backend.storage.stack_frame_pointer);
|
||||
|
||||
|
@ -2026,7 +2027,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
backend.code_builder.i32_and();
|
||||
}
|
||||
|
||||
fn num_to_str(&self, backend: &mut WasmBackend<'a>) {
|
||||
fn num_to_str(&self, backend: &mut WasmBackend<'a, '_>) {
|
||||
let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]];
|
||||
match arg_layout {
|
||||
Layout::Builtin(Builtin::Int(width)) => {
|
||||
|
@ -2051,7 +2052,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
|
||||
/// Helper for NumIsFinite op, and also part of Eq/NotEq
|
||||
fn num_is_finite(backend: &mut WasmBackend<'_>, argument: Symbol) {
|
||||
fn num_is_finite(backend: &mut WasmBackend<'_, '_>, argument: Symbol) {
|
||||
use StoredValue::*;
|
||||
let stored = backend.storage.get(&argument).to_owned();
|
||||
match stored {
|
||||
|
@ -2094,7 +2095,7 @@ fn num_is_finite(backend: &mut WasmBackend<'_>, argument: Symbol) {
|
|||
}
|
||||
|
||||
pub fn call_higher_order_lowlevel<'a>(
|
||||
backend: &mut WasmBackend<'a>,
|
||||
backend: &mut WasmBackend<'a, '_>,
|
||||
return_sym: Symbol,
|
||||
return_layout: &Layout<'a>,
|
||||
higher_order: &'a HigherOrderLowLevel<'a>,
|
||||
|
@ -2131,12 +2132,9 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
let (closure_data_layout, closure_data_exists) =
|
||||
match backend.storage.symbol_layouts[captured_environment] {
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
if lambda_set
|
||||
.is_represented(backend.env.layout_interner)
|
||||
.is_some()
|
||||
{
|
||||
if lambda_set.is_represented(backend.layout_interner).is_some() {
|
||||
(
|
||||
lambda_set.runtime_representation(backend.env.layout_interner),
|
||||
lambda_set.runtime_representation(backend.layout_interner),
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
|
@ -2162,7 +2160,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
// make sure that the wrapping struct is available in stack memory, so we can hand out a
|
||||
// pointer to it.
|
||||
let wrapped_storage = backend.storage.allocate_var(
|
||||
backend.env.layout_interner,
|
||||
backend.layout_interner,
|
||||
wrapped_captures_layout,
|
||||
wrapped_closure_data_sym,
|
||||
crate::storage::StoredVarKind::Variable,
|
||||
|
@ -2226,17 +2224,19 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
argument_layouts.len()
|
||||
};
|
||||
|
||||
let boxed_closure_arg_layouts =
|
||||
argument_layouts.iter().take(n_non_closure_args).map(|lay| {
|
||||
let lay_in = backend.layout_interner.insert(lay);
|
||||
Layout::Boxed(lay_in)
|
||||
});
|
||||
|
||||
wrapper_arg_layouts.push(wrapped_captures_layout);
|
||||
wrapper_arg_layouts.extend(
|
||||
argument_layouts
|
||||
.iter()
|
||||
.take(n_non_closure_args)
|
||||
.map(Layout::Boxed),
|
||||
);
|
||||
wrapper_arg_layouts.extend(boxed_closure_arg_layouts);
|
||||
|
||||
match helper_proc_source {
|
||||
ProcSource::HigherOrderMapper(_) => {
|
||||
// Our convention for mappers is that they write to the heap via the last argument
|
||||
let result_layout = backend.layout_interner.insert(result_layout);
|
||||
wrapper_arg_layouts.push(Layout::Boxed(result_layout));
|
||||
ProcLayout {
|
||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||
|
@ -2326,7 +2326,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
ListSortWith { xs } => {
|
||||
let elem_layout = unwrap_list_elem_layout(backend.storage.symbol_layouts[xs]);
|
||||
let (element_width, alignment) =
|
||||
elem_layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
let cb = &mut backend.code_builder;
|
||||
|
||||
|
@ -2371,7 +2371,7 @@ fn unwrap_list_elem_layout(list_layout: Layout<'_>) -> &Layout<'_> {
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn list_map_n<'a>(
|
||||
zig_fn_name: &'static str,
|
||||
backend: &mut WasmBackend<'a>,
|
||||
backend: &mut WasmBackend<'a, '_>,
|
||||
arg_symbols: &[Symbol],
|
||||
return_sym: Symbol,
|
||||
return_layout: Layout<'a>,
|
||||
|
@ -2390,7 +2390,7 @@ fn list_map_n<'a>(
|
|||
|
||||
let elem_ret = unwrap_list_elem_layout(return_layout);
|
||||
let (elem_ret_size, elem_ret_align) =
|
||||
elem_ret.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
elem_ret.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
|
||||
let cb = &mut backend.code_builder;
|
||||
|
||||
|
@ -2411,7 +2411,7 @@ fn list_map_n<'a>(
|
|||
cb.i32_const(owns_captured_environment as i32);
|
||||
cb.i32_const(elem_ret_align as i32);
|
||||
for el in arg_elem_layouts.iter() {
|
||||
cb.i32_const(el.stack_size(backend.env.layout_interner, TARGET_INFO) as i32);
|
||||
cb.i32_const(el.stack_size(backend.layout_interner, TARGET_INFO) as i32);
|
||||
}
|
||||
cb.i32_const(elem_ret_size as i32);
|
||||
|
||||
|
@ -2438,7 +2438,7 @@ fn list_map_n<'a>(
|
|||
}
|
||||
|
||||
fn ensure_symbol_is_in_memory<'a>(
|
||||
backend: &mut WasmBackend<'a>,
|
||||
backend: &mut WasmBackend<'a, '_>,
|
||||
symbol: Symbol,
|
||||
layout: Layout<'a>,
|
||||
arena: &'a Bump,
|
||||
|
@ -2451,7 +2451,7 @@ fn ensure_symbol_is_in_memory<'a>(
|
|||
}
|
||||
_ => {
|
||||
let (width, alignment) =
|
||||
layout.stack_size_and_alignment(backend.env.layout_interner, TARGET_INFO);
|
||||
layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
|
||||
let (frame_ptr, offset) = backend
|
||||
.storage
|
||||
.allocate_anonymous_stack_memory(width, alignment);
|
||||
|
|
|
@ -2280,9 +2280,9 @@ macro_rules! debug_check_ir {
|
|||
|
||||
let procedures = &$state.procedures;
|
||||
|
||||
let problems = check_procs($arena, $interner, procedures);
|
||||
let problems = check_procs($arena, &mut $interner, procedures);
|
||||
if !problems.is_empty() {
|
||||
let formatted = format_problems(&interns, $interner, problems);
|
||||
let formatted = format_problems(&interns, &$interner, problems);
|
||||
eprintln!("IR PROBLEMS FOUND:\n{formatted}");
|
||||
}
|
||||
})
|
||||
|
@ -3036,10 +3036,13 @@ fn update<'a>(
|
|||
.unwrap()
|
||||
.expect("outstanding references to global layout interener, but we just drained all layout caches");
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let mut layout_interner = layout_interner;
|
||||
|
||||
log!("specializations complete from {:?}", module_id);
|
||||
|
||||
debug_print_ir!(state, &layout_interner, ROC_PRINT_IR_AFTER_SPECIALIZATION);
|
||||
debug_check_ir!(state, arena, &layout_interner, ROC_CHECK_MONO_IR);
|
||||
debug_check_ir!(state, arena, layout_interner, ROC_CHECK_MONO_IR);
|
||||
|
||||
let ident_ids = state.constrained_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use bumpalo::collections::vec::Vec;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{IdentIds, Symbol};
|
||||
|
||||
use crate::ir::{
|
||||
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, Param, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, TagIdIntType, UnionLayout};
|
||||
use crate::layout::{Builtin, InLayout, Layout, STLayoutInterner, TagIdIntType, UnionLayout};
|
||||
|
||||
use super::{let_lowlevel, CodeGenHelp, Context, LAYOUT_BOOL};
|
||||
|
||||
|
@ -16,6 +17,7 @@ pub fn eq_generic<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let main_body = match layout {
|
||||
|
@ -28,10 +30,18 @@ pub fn eq_generic<'a>(
|
|||
Layout::Builtin(Builtin::Str) => {
|
||||
unreachable!("No generated helper proc for `==` on Str. Use Zig function.")
|
||||
}
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => eq_list(root, ident_ids, ctx, elem_layout),
|
||||
Layout::Struct { field_layouts, .. } => eq_struct(root, ident_ids, ctx, field_layouts),
|
||||
Layout::Union(union_layout) => eq_tag_union(root, ident_ids, ctx, union_layout),
|
||||
Layout::Boxed(inner_layout) => eq_boxed(root, ident_ids, ctx, inner_layout),
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
eq_list(root, ident_ids, ctx, layout_interner, elem_layout)
|
||||
}
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
eq_struct(root, ident_ids, ctx, layout_interner, field_layouts)
|
||||
}
|
||||
Layout::Union(union_layout) => {
|
||||
eq_tag_union(root, ident_ids, ctx, layout_interner, union_layout)
|
||||
}
|
||||
Layout::Boxed(inner_layout) => {
|
||||
eq_boxed(root, ident_ids, ctx, layout_interner, inner_layout)
|
||||
}
|
||||
Layout::LambdaSet(_) => unreachable!("`==` is not defined on functions"),
|
||||
Layout::RecursivePointer => {
|
||||
unreachable!(
|
||||
|
@ -129,6 +139,7 @@ fn eq_struct<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
) -> Stmt<'a> {
|
||||
let mut else_stmt = Stmt::Ret(Symbol::BOOL_TRUE);
|
||||
|
@ -153,6 +164,7 @@ fn eq_struct<'a>(
|
|||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
*layout,
|
||||
root.arena.alloc([field1_sym, field2_sym]),
|
||||
)
|
||||
|
@ -181,6 +193,7 @@ fn eq_tag_union<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
use UnionLayout::*;
|
||||
|
@ -191,13 +204,37 @@ fn eq_tag_union<'a>(
|
|||
}
|
||||
|
||||
let body = match union_layout {
|
||||
NonRecursive(tags) => eq_tag_union_help(root, ident_ids, ctx, union_layout, tags, None),
|
||||
NonRecursive(tags) => eq_tag_union_help(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tags,
|
||||
None,
|
||||
),
|
||||
|
||||
Recursive(tags) => eq_tag_union_help(root, ident_ids, ctx, union_layout, tags, None),
|
||||
Recursive(tags) => eq_tag_union_help(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tags,
|
||||
None,
|
||||
),
|
||||
|
||||
NonNullableUnwrapped(field_layouts) => {
|
||||
let tags = root.arena.alloc([field_layouts]);
|
||||
eq_tag_union_help(root, ident_ids, ctx, union_layout, tags, None)
|
||||
eq_tag_union_help(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tags,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
NullableWrapped {
|
||||
|
@ -207,6 +244,7 @@ fn eq_tag_union<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
other_tags,
|
||||
Some(nullable_id),
|
||||
|
@ -219,6 +257,7 @@ fn eq_tag_union<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
root.arena.alloc([other_fields]),
|
||||
Some(nullable_id as TagIdIntType),
|
||||
|
@ -234,6 +273,7 @@ fn eq_tag_union_help<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
nullable_id: Option<TagIdIntType>,
|
||||
|
@ -314,6 +354,7 @@ fn eq_tag_union_help<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
tailrec_loop,
|
||||
union_layout,
|
||||
field_layouts,
|
||||
|
@ -335,6 +376,7 @@ fn eq_tag_union_help<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
tailrec_loop,
|
||||
union_layout,
|
||||
tag_layouts.last().unwrap(),
|
||||
|
@ -395,6 +437,7 @@ fn eq_tag_fields<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
tailrec_loop: JoinPointId,
|
||||
union_layout: UnionLayout<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
|
@ -482,6 +525,7 @@ fn eq_tag_fields<'a>(
|
|||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
*layout,
|
||||
root.arena.alloc([field1_sym, field2_sym]),
|
||||
)
|
||||
|
@ -530,8 +574,11 @@ fn eq_boxed<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
inner_layout: &'a Layout<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
|
||||
let a = root.create_symbol(ident_ids, "a");
|
||||
let b = root.create_symbol(ident_ids, "b");
|
||||
let result = root.create_symbol(ident_ids, "result");
|
||||
|
@ -539,7 +586,13 @@ fn eq_boxed<'a>(
|
|||
let a_expr = Expr::ExprUnbox { symbol: ARG_1 };
|
||||
let b_expr = Expr::ExprUnbox { symbol: ARG_2 };
|
||||
let eq_call_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *inner_layout, root.arena.alloc([a, b]))
|
||||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
*inner_layout,
|
||||
root.arena.alloc([a, b]),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Stmt::Let(
|
||||
|
@ -576,6 +629,7 @@ fn eq_list<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
elem_layout: &Layout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
use LowLevel::*;
|
||||
|
@ -629,7 +683,7 @@ fn eq_list<'a>(
|
|||
// let size = literal int
|
||||
let size = root.create_symbol(ident_ids, "size");
|
||||
let size_expr = Expr::Literal(Literal::Int(
|
||||
(elem_layout.stack_size(root.layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
(elem_layout.stack_size(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
));
|
||||
let size_stmt = |next| Stmt::Let(size, size_expr, layout_isize, next);
|
||||
|
||||
|
@ -703,7 +757,7 @@ fn eq_list<'a>(
|
|||
let eq_elems = root.create_symbol(ident_ids, "eq_elems");
|
||||
let eq_elems_args = root.arena.alloc([elem1, elem2]);
|
||||
let eq_elems_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *elem_layout, eq_elems_args)
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, *elem_layout, eq_elems_args)
|
||||
.unwrap();
|
||||
|
||||
let eq_elems_stmt = |next| Stmt::Let(eq_elems, eq_elems_expr, LAYOUT_BOOL, next);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_target::TargetInfo;
|
||||
|
@ -73,7 +74,6 @@ pub struct Context<'a> {
|
|||
///
|
||||
pub struct CodeGenHelp<'a> {
|
||||
arena: &'a Bump,
|
||||
layout_interner: &'a STLayoutInterner<'a>,
|
||||
home: ModuleId,
|
||||
target_info: TargetInfo,
|
||||
layout_isize: Layout<'a>,
|
||||
|
@ -83,12 +83,7 @@ pub struct CodeGenHelp<'a> {
|
|||
}
|
||||
|
||||
impl<'a> CodeGenHelp<'a> {
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
layout_interner: &'a STLayoutInterner<'a>,
|
||||
target_info: TargetInfo,
|
||||
home: ModuleId,
|
||||
) -> Self {
|
||||
pub fn new(arena: &'a Bump, target_info: TargetInfo, home: ModuleId) -> Self {
|
||||
let layout_isize = Layout::isize(target_info);
|
||||
|
||||
// Refcount is a boxed isize. TODO: use the new Box layout when dev backends support it
|
||||
|
@ -96,7 +91,6 @@ impl<'a> CodeGenHelp<'a> {
|
|||
|
||||
CodeGenHelp {
|
||||
arena,
|
||||
layout_interner,
|
||||
home,
|
||||
target_info,
|
||||
layout_isize,
|
||||
|
@ -125,11 +119,12 @@ impl<'a> CodeGenHelp<'a> {
|
|||
pub fn expand_refcount_stmt(
|
||||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
modify: &ModifyRc,
|
||||
following: &'a Stmt<'a>,
|
||||
) -> (&'a Stmt<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
if !refcount::is_rc_implemented_yet(self.layout_interner, &layout) {
|
||||
if !refcount::is_rc_implemented_yet(layout_interner, &layout) {
|
||||
// Just a warning, so we can decouple backend development from refcounting development.
|
||||
// When we are closer to completion, we can change it to a panic.
|
||||
println!(
|
||||
|
@ -154,13 +149,22 @@ impl<'a> CodeGenHelp<'a> {
|
|||
op,
|
||||
};
|
||||
|
||||
let rc_stmt = refcount::refcount_stmt(self, ident_ids, &mut ctx, layout, modify, following);
|
||||
let rc_stmt = refcount::refcount_stmt(
|
||||
self,
|
||||
ident_ids,
|
||||
&mut ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
modify,
|
||||
following,
|
||||
);
|
||||
(rc_stmt, ctx.new_linker_data)
|
||||
}
|
||||
|
||||
pub fn call_reset_refcount(
|
||||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
argument: Symbol,
|
||||
) -> (Expr<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
|
@ -170,7 +174,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
op: HelperOp::Reset,
|
||||
};
|
||||
|
||||
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout);
|
||||
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout_interner, layout);
|
||||
|
||||
let arguments = self.arena.alloc([argument]);
|
||||
let ret_layout = self.arena.alloc(layout);
|
||||
|
@ -194,6 +198,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
pub fn gen_refcount_proc(
|
||||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
op: HelperOp,
|
||||
) -> (Symbol, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
|
@ -203,7 +208,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
op,
|
||||
};
|
||||
|
||||
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout);
|
||||
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout_interner, layout);
|
||||
|
||||
(proc_name, ctx.new_linker_data)
|
||||
}
|
||||
|
@ -213,6 +218,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
pub fn call_specialized_equals(
|
||||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
) -> (Expr<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
|
@ -223,7 +229,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
};
|
||||
|
||||
let expr = self
|
||||
.call_specialized_op(ident_ids, &mut ctx, *layout, arguments)
|
||||
.call_specialized_op(ident_ids, &mut ctx, layout_interner, *layout, arguments)
|
||||
.unwrap();
|
||||
|
||||
(expr, ctx.new_linker_data)
|
||||
|
@ -239,6 +245,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
called_layout: Layout<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
) -> Option<Expr<'a>> {
|
||||
|
@ -255,10 +262,10 @@ impl<'a> CodeGenHelp<'a> {
|
|||
};
|
||||
|
||||
if layout_needs_helper_proc(&layout, ctx.op) {
|
||||
let proc_name = self.find_or_create_proc(ident_ids, ctx, layout);
|
||||
let proc_name = self.find_or_create_proc(ident_ids, ctx, layout_interner, layout);
|
||||
|
||||
let (ret_layout, arg_layouts): (&'a Layout<'a>, &'a [Layout<'a>]) = {
|
||||
let arg = self.replace_rec_ptr(ctx, layout);
|
||||
let arg = self.replace_rec_ptr(ctx, layout_interner, layout);
|
||||
match ctx.op {
|
||||
Dec | DecRef(_) => (&LAYOUT_UNIT, self.arena.alloc([arg])),
|
||||
Reset => (self.arena.alloc(layout), self.arena.alloc([layout])),
|
||||
|
@ -293,11 +300,12 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
orig_layout: Layout<'a>,
|
||||
) -> Symbol {
|
||||
use HelperOp::*;
|
||||
|
||||
let layout = self.replace_rec_ptr(ctx, orig_layout);
|
||||
let layout = self.replace_rec_ptr(ctx, layout_interner, orig_layout);
|
||||
|
||||
let found = self
|
||||
.specializations
|
||||
|
@ -325,15 +333,29 @@ impl<'a> CodeGenHelp<'a> {
|
|||
let (ret_layout, body) = match ctx.op {
|
||||
Inc | Dec | DecRef(_) => (
|
||||
LAYOUT_UNIT,
|
||||
refcount::refcount_generic(self, ident_ids, ctx, layout, Symbol::ARG_1),
|
||||
refcount::refcount_generic(
|
||||
self,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
Symbol::ARG_1,
|
||||
),
|
||||
),
|
||||
Reset => (
|
||||
layout,
|
||||
refcount::refcount_reset_proc_body(self, ident_ids, ctx, layout, Symbol::ARG_1),
|
||||
refcount::refcount_reset_proc_body(
|
||||
self,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
Symbol::ARG_1,
|
||||
),
|
||||
),
|
||||
Eq => (
|
||||
LAYOUT_BOOL,
|
||||
equality::eq_generic(self, ident_ids, ctx, layout),
|
||||
equality::eq_generic(self, ident_ids, ctx, layout_interner, layout),
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -415,10 +437,16 @@ impl<'a> CodeGenHelp<'a> {
|
|||
// For example if a program uses `RoseTree a : [Tree a (List (RoseTree a))]`
|
||||
// then it could have both `RoseTree I64` and `RoseTree Str`. In this case it
|
||||
// needs *two* specializations for `List(RecursivePointer)`, not just one.
|
||||
fn replace_rec_ptr(&self, ctx: &Context<'a>, layout: Layout<'a>) -> Layout<'a> {
|
||||
fn replace_rec_ptr(
|
||||
&mut self,
|
||||
ctx: &Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
) -> Layout<'a> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(v)) => Layout::Builtin(Builtin::List(
|
||||
self.arena.alloc(self.replace_rec_ptr(ctx, *v)),
|
||||
self.arena
|
||||
.alloc(self.replace_rec_ptr(ctx, layout_interner, *v)),
|
||||
)),
|
||||
|
||||
Layout::Builtin(_) => layout,
|
||||
|
@ -427,9 +455,12 @@ impl<'a> CodeGenHelp<'a> {
|
|||
field_layouts,
|
||||
field_order_hash,
|
||||
} => {
|
||||
let new_fields_iter = field_layouts.iter().map(|f| self.replace_rec_ptr(ctx, *f));
|
||||
let mut new_field_layouts = Vec::with_capacity_in(field_layouts.len(), self.arena);
|
||||
for f in field_layouts.iter() {
|
||||
new_field_layouts.push(self.replace_rec_ptr(ctx, layout_interner, *f));
|
||||
}
|
||||
Layout::Struct {
|
||||
field_layouts: self.arena.alloc_slice_fill_iter(new_fields_iter),
|
||||
field_layouts: new_field_layouts.into_bump_slice(),
|
||||
field_order_hash,
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +470,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
for fields in tags {
|
||||
let mut new_fields = Vec::with_capacity_in(fields.len(), self.arena);
|
||||
for field in fields.iter() {
|
||||
new_fields.push(self.replace_rec_ptr(ctx, *field))
|
||||
new_fields.push(self.replace_rec_ptr(ctx, layout_interner, *field))
|
||||
}
|
||||
new_tags.push(new_fields.into_bump_slice());
|
||||
}
|
||||
|
@ -453,12 +484,19 @@ impl<'a> CodeGenHelp<'a> {
|
|||
}
|
||||
|
||||
Layout::Boxed(inner) => {
|
||||
Layout::Boxed(self.arena.alloc(self.replace_rec_ptr(ctx, *inner)))
|
||||
let inner = layout_interner.get(inner);
|
||||
let inner = self
|
||||
.arena
|
||||
.alloc(self.replace_rec_ptr(ctx, layout_interner, *inner));
|
||||
let inner = layout_interner.insert(inner);
|
||||
Layout::Boxed(inner)
|
||||
}
|
||||
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
self.replace_rec_ptr(ctx, lambda_set.runtime_representation(self.layout_interner))
|
||||
}
|
||||
Layout::LambdaSet(lambda_set) => self.replace_rec_ptr(
|
||||
ctx,
|
||||
layout_interner,
|
||||
lambda_set.runtime_representation(layout_interner),
|
||||
),
|
||||
|
||||
// This line is the whole point of the function
|
||||
Layout::RecursivePointer => Layout::Union(ctx.recursive_union.unwrap()),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use roc_builtins::bitcode::IntWidth;
|
||||
use roc_intern::Interner;
|
||||
|
@ -9,7 +11,7 @@ use crate::code_gen_help::let_lowlevel;
|
|||
use crate::ir::{
|
||||
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, ModifyRc, Param, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, TagIdIntType, UnionLayout};
|
||||
use crate::layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout};
|
||||
|
||||
use super::{CodeGenHelp, Context, HelperOp};
|
||||
|
||||
|
@ -24,6 +26,7 @@ pub fn refcount_stmt<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
modify: &ModifyRc,
|
||||
following: &'a Stmt<'a>,
|
||||
|
@ -45,6 +48,7 @@ pub fn refcount_stmt<'a>(
|
|||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
arena.alloc([*structure, amount_sym]),
|
||||
)
|
||||
|
@ -58,7 +62,13 @@ pub fn refcount_stmt<'a>(
|
|||
// Call helper proc, passing the Roc structure
|
||||
let call_result_empty = root.create_symbol(ident_ids, "call_result_empty");
|
||||
let call_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, layout, arena.alloc([*structure]))
|
||||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
arena.alloc([*structure]),
|
||||
)
|
||||
.unwrap();
|
||||
let call_stmt = Stmt::Let(call_result_empty, call_expr, LAYOUT_UNIT, following);
|
||||
arena.alloc(call_stmt)
|
||||
|
@ -69,7 +79,15 @@ pub fn refcount_stmt<'a>(
|
|||
// Str has no children, so we might as well do what we normally do and call the helper.
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
ctx.op = HelperOp::Dec;
|
||||
refcount_stmt(root, ident_ids, ctx, layout, modify, following)
|
||||
refcount_stmt(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
modify,
|
||||
following,
|
||||
)
|
||||
}
|
||||
|
||||
// Struct and non-recursive Unions are stack-only, so DecRef is a no-op
|
||||
|
@ -80,7 +98,14 @@ pub fn refcount_stmt<'a>(
|
|||
// and replace any return statements with jumps to the `following` statement.
|
||||
_ => match ctx.op {
|
||||
HelperOp::DecRef(jp_decref) => {
|
||||
let rc_stmt = refcount_generic(root, ident_ids, ctx, layout, *structure);
|
||||
let rc_stmt = refcount_generic(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
*structure,
|
||||
);
|
||||
let join = Stmt::Join {
|
||||
id: jp_decref,
|
||||
parameters: &[],
|
||||
|
@ -100,10 +125,11 @@ pub fn refcount_generic<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
debug_assert!(is_rc_implemented_yet(root.layout_interner, &layout));
|
||||
debug_assert!(is_rc_implemented_yet(layout_interner, &layout));
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal) => {
|
||||
|
@ -112,24 +138,56 @@ pub fn refcount_generic<'a>(
|
|||
rc_return_stmt(root, ident_ids, ctx)
|
||||
}
|
||||
Layout::Builtin(Builtin::Str) => refcount_str(root, ident_ids, ctx),
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
refcount_list(root, ident_ids, ctx, &layout, elem_layout, structure)
|
||||
}
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
refcount_struct(root, ident_ids, ctx, field_layouts, structure)
|
||||
}
|
||||
Layout::Union(union_layout) => {
|
||||
refcount_union(root, ident_ids, ctx, union_layout, structure)
|
||||
}
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => refcount_list(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
&layout,
|
||||
elem_layout,
|
||||
structure,
|
||||
),
|
||||
Layout::Struct { field_layouts, .. } => refcount_struct(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
field_layouts,
|
||||
structure,
|
||||
),
|
||||
Layout::Union(union_layout) => refcount_union(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
structure,
|
||||
),
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
let runtime_layout = lambda_set.runtime_representation(root.layout_interner);
|
||||
refcount_generic(root, ident_ids, ctx, runtime_layout, structure)
|
||||
let runtime_layout = lambda_set.runtime_representation(layout_interner);
|
||||
refcount_generic(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
runtime_layout,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
Layout::RecursivePointer => unreachable!(
|
||||
"We should never call a refcounting helper on a RecursivePointer layout directly"
|
||||
),
|
||||
Layout::Boxed(inner_layout) => {
|
||||
refcount_boxed(root, ident_ids, ctx, &layout, inner_layout, structure)
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
refcount_boxed(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
&layout,
|
||||
inner_layout,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +196,7 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
|
@ -206,8 +265,7 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
let alloc_addr_stmt = {
|
||||
let alignment = root.create_symbol(ident_ids, "alignment");
|
||||
let alignment_expr = Expr::Literal(Literal::Int(
|
||||
(layout.alignment_bytes(root.layout_interner, root.target_info) as i128)
|
||||
.to_ne_bytes(),
|
||||
(layout.alignment_bytes(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
));
|
||||
let alloc_addr = root.create_symbol(ident_ids, "alloc_addr");
|
||||
let alloc_addr_expr = Expr::Call(Call {
|
||||
|
@ -241,6 +299,7 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tag_layouts,
|
||||
null_id,
|
||||
|
@ -260,7 +319,13 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
let else_stmt = {
|
||||
let decrement_unit = root.create_symbol(ident_ids, "decrement_unit");
|
||||
let decrement_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, layout, root.arena.alloc([structure]))
|
||||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
root.arena.alloc([structure]),
|
||||
)
|
||||
.unwrap();
|
||||
let decrement_stmt = |next| Stmt::Let(decrement_unit, decrement_expr, LAYOUT_UNIT, next);
|
||||
|
||||
|
@ -694,6 +759,7 @@ fn refcount_list<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout,
|
||||
elem_layout: &'a Layout,
|
||||
structure: Symbol,
|
||||
|
@ -743,7 +809,7 @@ fn refcount_list<'a>(
|
|||
//
|
||||
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = layout.alignment_bytes(root.layout_interner, root.target_info);
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_list = modify_refcount(
|
||||
|
@ -769,6 +835,7 @@ fn refcount_list<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
elem_layout,
|
||||
LAYOUT_UNIT,
|
||||
box_union_layout,
|
||||
|
@ -814,11 +881,11 @@ fn refcount_list<'a>(
|
|||
))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn refcount_list_elems<'a>(
|
||||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
elem_layout: &Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
box_union_layout: UnionLayout<'a>,
|
||||
|
@ -841,7 +908,7 @@ fn refcount_list_elems<'a>(
|
|||
// let size = literal int
|
||||
let elem_size = root.create_symbol(ident_ids, "elem_size");
|
||||
let elem_size_expr = Expr::Literal(Literal::Int(
|
||||
(elem_layout.stack_size(root.layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
(elem_layout.stack_size(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
));
|
||||
let elem_size_stmt = |next| Stmt::Let(elem_size, elem_size_expr, layout_isize, next);
|
||||
|
||||
|
@ -901,7 +968,7 @@ fn refcount_list_elems<'a>(
|
|||
let mod_elem_unit = root.create_symbol(ident_ids, "mod_elem_unit");
|
||||
let mod_elem_args = refcount_args(root, ctx, elem);
|
||||
let mod_elem_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *elem_layout, mod_elem_args)
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, *elem_layout, mod_elem_args)
|
||||
.unwrap();
|
||||
let mod_elem_stmt = |next| Stmt::Let(mod_elem_unit, mod_elem_expr, LAYOUT_UNIT, next);
|
||||
|
||||
|
@ -984,13 +1051,14 @@ fn refcount_struct<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let mut stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate().rev() {
|
||||
if field_layout.contains_refcounted(root.layout_interner) {
|
||||
if field_layout.contains_refcounted(layout_interner) {
|
||||
let field_val = root.create_symbol(ident_ids, &format!("field_val_{}", i));
|
||||
let field_val_expr = Expr::StructAtIndex {
|
||||
index: i as u64,
|
||||
|
@ -1002,7 +1070,7 @@ fn refcount_struct<'a>(
|
|||
let mod_unit = root.create_symbol(ident_ids, &format!("mod_field_{}", i));
|
||||
let mod_args = refcount_args(root, ctx, field_val);
|
||||
let mod_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *field_layout, mod_args)
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, *field_layout, mod_args)
|
||||
.unwrap();
|
||||
let mod_stmt = |next| Stmt::Let(mod_unit, mod_expr, LAYOUT_UNIT, next);
|
||||
|
||||
|
@ -1023,6 +1091,7 @@ fn refcount_union<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union: UnionLayout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
|
@ -1034,14 +1103,41 @@ fn refcount_union<'a>(
|
|||
}
|
||||
|
||||
let body = match union {
|
||||
NonRecursive(tags) => refcount_union_nonrec(root, ident_ids, ctx, union, tags, structure),
|
||||
NonRecursive(tags) => refcount_union_nonrec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
structure,
|
||||
),
|
||||
|
||||
Recursive(tags) => {
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(root, ident_ids, ctx, union, tags, None, tail_idx, structure)
|
||||
refcount_union_tailrec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
None,
|
||||
tail_idx,
|
||||
structure,
|
||||
)
|
||||
} else {
|
||||
refcount_union_rec(root, ident_ids, ctx, union, tags, None, structure)
|
||||
refcount_union_rec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
None,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1147,16 @@ fn refcount_union<'a>(
|
|||
// a direct RecursionPointer is only possible if there's at least one non-recursive variant.
|
||||
// This nesting makes it harder to do tail recursion, so we just don't.
|
||||
let tags = root.arena.alloc([field_layouts]);
|
||||
refcount_union_rec(root, ident_ids, ctx, union, tags, None, structure)
|
||||
refcount_union_rec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
None,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
|
||||
NullableWrapped {
|
||||
|
@ -1062,10 +1167,27 @@ fn refcount_union<'a>(
|
|||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(
|
||||
root, ident_ids, ctx, union, tags, null_id, tail_idx, structure,
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
null_id,
|
||||
tail_idx,
|
||||
structure,
|
||||
)
|
||||
} else {
|
||||
refcount_union_rec(root, ident_ids, ctx, union, tags, null_id, structure)
|
||||
refcount_union_rec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
null_id,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1078,10 +1200,27 @@ fn refcount_union<'a>(
|
|||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(
|
||||
root, ident_ids, ctx, union, tags, null_id, tail_idx, structure,
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
null_id,
|
||||
tail_idx,
|
||||
structure,
|
||||
)
|
||||
} else {
|
||||
refcount_union_rec(root, ident_ids, ctx, union, tags, null_id, structure)
|
||||
refcount_union_rec(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union,
|
||||
tags,
|
||||
null_id,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1095,6 +1234,7 @@ fn refcount_union_nonrec<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
structure: Symbol,
|
||||
|
@ -1120,6 +1260,7 @@ fn refcount_union_nonrec<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tag_layouts,
|
||||
None,
|
||||
|
@ -1135,11 +1276,11 @@ fn refcount_union_nonrec<'a>(
|
|||
))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn refcount_union_contents<'a>(
|
||||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
|
@ -1173,6 +1314,7 @@ fn refcount_union_contents<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
field_layouts,
|
||||
structure,
|
||||
|
@ -1207,6 +1349,7 @@ fn refcount_union_rec<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
|
@ -1231,7 +1374,7 @@ fn refcount_union_rec<'a>(
|
|||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
|
||||
let alignment =
|
||||
Layout::Union(union_layout).alignment_bytes(root.layout_interner, root.target_info);
|
||||
Layout::Union(union_layout).alignment_bytes(layout_interner, root.target_info);
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_structure_stmt = modify_refcount(
|
||||
root,
|
||||
|
@ -1259,6 +1402,7 @@ fn refcount_union_rec<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tag_layouts,
|
||||
null_id,
|
||||
|
@ -1280,11 +1424,11 @@ fn refcount_union_rec<'a>(
|
|||
}
|
||||
|
||||
// Refcount a recursive union using tail-call elimination to limit stack growth
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn refcount_union_tailrec<'a>(
|
||||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
|
@ -1339,7 +1483,7 @@ fn refcount_union_tailrec<'a>(
|
|||
)
|
||||
};
|
||||
|
||||
let alignment = layout.alignment_bytes(root.layout_interner, root.target_info);
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
let modify_structure_stmt = modify_refcount(
|
||||
root,
|
||||
ident_ids,
|
||||
|
@ -1427,6 +1571,7 @@ fn refcount_union_tailrec<'a>(
|
|||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
non_tailrec_fields,
|
||||
current,
|
||||
|
@ -1483,11 +1628,11 @@ fn refcount_union_tailrec<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn refcount_tag_fields<'a>(
|
||||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
structure: Symbol,
|
||||
|
@ -1497,7 +1642,7 @@ fn refcount_tag_fields<'a>(
|
|||
let mut stmt = following;
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate().rev() {
|
||||
if field_layout.contains_refcounted(root.layout_interner) {
|
||||
if field_layout.contains_refcounted(layout_interner) {
|
||||
let field_val = root.create_symbol(ident_ids, &format!("field_{}_{}", tag_id, i));
|
||||
let field_val_expr = Expr::UnionAtIndex {
|
||||
union_layout,
|
||||
|
@ -1510,7 +1655,7 @@ fn refcount_tag_fields<'a>(
|
|||
let mod_unit = root.create_symbol(ident_ids, &format!("mod_field_{}_{}", tag_id, i));
|
||||
let mod_args = refcount_args(root, ctx, field_val);
|
||||
let mod_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *field_layout, mod_args)
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, *field_layout, mod_args)
|
||||
.unwrap();
|
||||
let mod_stmt = |next| Stmt::Let(mod_unit, mod_expr, LAYOUT_UNIT, next);
|
||||
|
||||
|
@ -1531,6 +1676,7 @@ fn refcount_boxed<'a>(
|
|||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout,
|
||||
inner_layout: &'a Layout,
|
||||
outer: Symbol,
|
||||
|
@ -1544,7 +1690,7 @@ fn refcount_boxed<'a>(
|
|||
//
|
||||
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = layout.alignment_bytes(root.layout_interner, root.target_info);
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_outer = modify_refcount(
|
||||
root,
|
||||
|
@ -1571,7 +1717,13 @@ fn refcount_boxed<'a>(
|
|||
let mod_inner_unit = root.create_symbol(ident_ids, "mod_inner_unit");
|
||||
let mod_inner_args = refcount_args(root, ctx, inner);
|
||||
let mod_inner_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, *inner_layout, mod_inner_args)
|
||||
.call_specialized_op(
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
*inner_layout,
|
||||
mod_inner_args,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Stmt::Let(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::{MutMap, VecMap, VecSet};
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::{
|
||||
|
@ -131,8 +132,8 @@ impl<'a> Problems<'a> {
|
|||
|
||||
pub fn check_procs<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
interner: &mut STLayoutInterner<'a>,
|
||||
procs: &Procs<'a>,
|
||||
) -> Problems<'a> {
|
||||
let mut problems = Default::default();
|
||||
|
||||
|
@ -161,9 +162,9 @@ type JoinPoints<'a> = VecMap<JoinPointId, (usize, &'a [Param<'a>])>;
|
|||
type CallSpecIds = VecMap<CallSpecId, usize>;
|
||||
struct Ctx<'a, 'r> {
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
interner: &'r mut STLayoutInterner<'a>,
|
||||
problems: &'r mut Vec<Problem<'a>>,
|
||||
proc: &'a Proc<'a>,
|
||||
proc: &'r Proc<'a>,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
procs: &'r Procs<'a>,
|
||||
call_spec_ids: CallSpecIds,
|
||||
|
@ -180,7 +181,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
|
||||
fn problem(&mut self, problem_kind: ProblemKind<'a>) {
|
||||
self.problems.push(Problem {
|
||||
proc: self.proc,
|
||||
proc: self.arena.alloc(self.proc.clone()),
|
||||
proc_layout: self.proc_layout,
|
||||
line: self.line,
|
||||
kind: problem_kind,
|
||||
|
@ -433,11 +434,12 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
None
|
||||
}
|
||||
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
|
||||
Some(Layout::Boxed(ctx.alloc(layout)))
|
||||
let inner = ctx.interner.insert(ctx.alloc(layout));
|
||||
Some(Layout::Boxed(inner))
|
||||
}),
|
||||
&Expr::ExprUnbox { symbol } => {
|
||||
self.with_sym_layout(symbol, |ctx, def_line, layout| match ctx.resolve(layout) {
|
||||
Layout::Boxed(inner) => Some(*inner),
|
||||
Layout::Boxed(inner) => Some(*ctx.interner.get(inner)),
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::UnboxNotABox { symbol, def_line });
|
||||
None
|
||||
|
@ -526,7 +528,8 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
return None;
|
||||
}
|
||||
let layout = resolve_recursive_layout(
|
||||
self.arena,
|
||||
ctx.arena,
|
||||
ctx.interner,
|
||||
payloads[index as usize],
|
||||
union_layout,
|
||||
);
|
||||
|
@ -613,8 +616,12 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
});
|
||||
}
|
||||
for (arg, wanted_layout) in arguments.iter().zip(payloads.iter()) {
|
||||
let wanted_layout =
|
||||
resolve_recursive_layout(self.arena, *wanted_layout, union_layout);
|
||||
let wanted_layout = resolve_recursive_layout(
|
||||
self.arena,
|
||||
self.interner,
|
||||
*wanted_layout,
|
||||
union_layout,
|
||||
);
|
||||
self.check_sym_layout(*arg, wanted_layout, UseKind::TagPayloadArg);
|
||||
}
|
||||
}
|
||||
|
@ -633,18 +640,23 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
|
||||
fn resolve_recursive_layout<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
when_recursive: UnionLayout<'a>,
|
||||
) -> Layout<'a> {
|
||||
macro_rules! go {
|
||||
($lay:expr) => {
|
||||
resolve_recursive_layout(arena, interner, $lay, when_recursive)
|
||||
};
|
||||
}
|
||||
|
||||
// TODO check if recursive pointer not in recursive union
|
||||
match layout {
|
||||
Layout::RecursivePointer => Layout::Union(when_recursive),
|
||||
Layout::Union(union_layout) => match union_layout {
|
||||
UnionLayout::NonRecursive(payloads) => {
|
||||
let payloads = payloads.iter().map(|args| {
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|lay| resolve_recursive_layout(arena, *lay, when_recursive));
|
||||
let args = args.iter().map(|lay| go!(*lay));
|
||||
&*arena.alloc_slice_fill_iter(args)
|
||||
});
|
||||
let payloads = arena.alloc_slice_fill_iter(payloads);
|
||||
|
@ -661,7 +673,8 @@ fn resolve_recursive_layout<'a>(
|
|||
}
|
||||
},
|
||||
Layout::Boxed(inner) => {
|
||||
Layout::Boxed(arena.alloc(resolve_recursive_layout(arena, *inner, when_recursive)))
|
||||
let inner = go!(*interner.get(inner));
|
||||
Layout::Boxed(interner.insert(arena.alloc(inner)))
|
||||
}
|
||||
Layout::Struct {
|
||||
field_order_hash,
|
||||
|
@ -669,7 +682,7 @@ fn resolve_recursive_layout<'a>(
|
|||
} => {
|
||||
let field_layouts = field_layouts
|
||||
.iter()
|
||||
.map(|lay| resolve_recursive_layout(arena, *lay, when_recursive));
|
||||
.map(|lay| resolve_recursive_layout(arena, interner, *lay, when_recursive));
|
||||
let field_layouts = arena.alloc_slice_fill_iter(field_layouts);
|
||||
Layout::Struct {
|
||||
field_order_hash,
|
||||
|
@ -678,7 +691,12 @@ fn resolve_recursive_layout<'a>(
|
|||
}
|
||||
Layout::Builtin(builtin) => match builtin {
|
||||
Builtin::List(inner) => {
|
||||
let inner = arena.alloc(resolve_recursive_layout(arena, *inner, when_recursive));
|
||||
let inner = arena.alloc(resolve_recursive_layout(
|
||||
arena,
|
||||
interner,
|
||||
*inner,
|
||||
when_recursive,
|
||||
));
|
||||
Layout::Builtin(Builtin::List(inner))
|
||||
}
|
||||
Builtin::Int(_)
|
||||
|
@ -692,9 +710,10 @@ fn resolve_recursive_layout<'a>(
|
|||
representation,
|
||||
}) => {
|
||||
let set = set.iter().map(|(symbol, captures)| {
|
||||
let captures = captures
|
||||
.iter()
|
||||
.map(|lay| resolve_recursive_layout(arena, *lay, when_recursive));
|
||||
let captures = captures.iter().map(|lay_in| {
|
||||
let new_lay = go!(*interner.get(*lay_in));
|
||||
interner.insert(arena.alloc(new_lay))
|
||||
});
|
||||
let captures = &*arena.alloc_slice_fill_iter(captures);
|
||||
(*symbol, captures)
|
||||
});
|
||||
|
|
|
@ -487,7 +487,7 @@ where
|
|||
captures_niche
|
||||
.0
|
||||
.iter()
|
||||
.map(|c| c.to_doc(f, interner, Parens::NotNeeded)),
|
||||
.map(|&c| interner.get(c).to_doc(f, interner, Parens::NotNeeded)),
|
||||
f.reflow(", "),
|
||||
),
|
||||
f.reflow("})"),
|
||||
|
|
|
@ -3533,10 +3533,12 @@ fn specialize_proc_help<'a>(
|
|||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 =
|
||||
layout1.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 =
|
||||
layout2.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size1 = layout_cache
|
||||
.get_in(**layout1)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout_cache
|
||||
.get_in(**layout2)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
|
@ -3575,16 +3577,20 @@ fn specialize_proc_help<'a>(
|
|||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 =
|
||||
layout1.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 =
|
||||
layout2.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size1 = layout_cache
|
||||
.get_in(**layout1)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout_cache
|
||||
.get_in(**layout2)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
|
||||
let ordered_field_layouts = Vec::from_iter_in(
|
||||
combined.iter().map(|(_, layout)| **layout),
|
||||
combined
|
||||
.iter()
|
||||
.map(|(_, layout)| *layout_cache.get_in(**layout)),
|
||||
env.arena,
|
||||
);
|
||||
let ordered_field_layouts = ordered_field_layouts.into_bump_slice();
|
||||
|
@ -3610,7 +3616,7 @@ fn specialize_proc_help<'a>(
|
|||
specialized_body = Stmt::Let(
|
||||
symbol,
|
||||
expr,
|
||||
**layout,
|
||||
*layout_cache.get_in(**layout),
|
||||
env.arena.alloc(specialized_body),
|
||||
);
|
||||
}
|
||||
|
@ -5730,8 +5736,12 @@ where
|
|||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size1 = layout_cache
|
||||
.get_in(**layout1)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout_cache
|
||||
.get_in(**layout2)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
|
@ -5760,16 +5770,23 @@ where
|
|||
let ptr_bytes = env.target_info;
|
||||
|
||||
combined.sort_by(|(_, layout1), (_, layout2)| {
|
||||
let size1 = layout1.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout2.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size1 = layout_cache
|
||||
.get_in(**layout1)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
let size2 = layout_cache
|
||||
.get_in(**layout2)
|
||||
.alignment_bytes(&layout_cache.interner, ptr_bytes);
|
||||
|
||||
size2.cmp(&size1)
|
||||
});
|
||||
|
||||
let symbols =
|
||||
Vec::from_iter_in(combined.iter().map(|(a, _)| *a), env.arena).into_bump_slice();
|
||||
let field_layouts =
|
||||
Vec::from_iter_in(combined.iter().map(|(_, b)| **b), env.arena).into_bump_slice();
|
||||
let field_layouts = Vec::from_iter_in(
|
||||
combined.iter().map(|(_, b)| *layout_cache.get_in(**b)),
|
||||
env.arena,
|
||||
)
|
||||
.into_bump_slice();
|
||||
|
||||
debug_assert_eq!(
|
||||
Layout::struct_no_name_order(field_layouts),
|
||||
|
|
|
@ -5,7 +5,7 @@ use bumpalo::Bump;
|
|||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{default_hasher, FnvMap, MutMap};
|
||||
use roc_error_macros::{internal_error, todo_abilities};
|
||||
use roc_intern::{Interned, Interner, SingleThreadedInterner, ThreadLocalInterner};
|
||||
use roc_intern::{Interner, SingleThreadedInterner, ThreadLocalInterner};
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_problem::can::RuntimeError;
|
||||
|
@ -311,6 +311,14 @@ impl<'a> LayoutCache<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_in(&self, interned: InLayout<'a>) -> &Layout<'a> {
|
||||
self.interner.get(interned)
|
||||
}
|
||||
|
||||
pub fn put_in(&mut self, layout: &'a Layout<'a>) -> InLayout<'a> {
|
||||
self.interner.insert(layout)
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn statistics(&self) -> (CacheStatistics, CacheStatistics) {
|
||||
(self.stats, self.raw_function_stats)
|
||||
|
@ -653,6 +661,10 @@ impl FieldOrderHash {
|
|||
}
|
||||
}
|
||||
|
||||
/// An interned layout.
|
||||
// One day I would like to take over `LayoutId` as the name here, but that is currently used elsewhere.
|
||||
pub type InLayout<'a> = roc_intern::Interned<Layout<'a>>;
|
||||
|
||||
/// Types for code gen must be monomorphic. No type variables allowed!
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum Layout<'a> {
|
||||
|
@ -670,7 +682,7 @@ pub enum Layout<'a> {
|
|||
field_order_hash: FieldOrderHash,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
},
|
||||
Boxed(&'a Layout<'a>),
|
||||
Boxed(InLayout<'a>),
|
||||
Union(UnionLayout<'a>),
|
||||
LambdaSet(LambdaSet<'a>),
|
||||
RecursivePointer,
|
||||
|
@ -1174,7 +1186,7 @@ impl Discriminant {
|
|||
/// concurrently. The number does not change and will give a reliable output.
|
||||
struct SetElement<'a> {
|
||||
symbol: Symbol,
|
||||
layout: &'a [Layout<'a>],
|
||||
layout: &'a [InLayout<'a>],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SetElement<'_> {
|
||||
|
@ -1188,7 +1200,7 @@ impl std::fmt::Debug for SetElement<'_> {
|
|||
impl std::fmt::Debug for LambdaSet<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
struct Helper<'a> {
|
||||
set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
set: &'a [(Symbol, &'a [InLayout<'a>])],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Helper<'_> {
|
||||
|
@ -1229,7 +1241,7 @@ impl std::fmt::Debug for LambdaSet<'_> {
|
|||
///
|
||||
/// See also https://github.com/roc-lang/roc/issues/3336.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct CapturesNiche<'a>(pub(crate) &'a [Layout<'a>]);
|
||||
pub struct CapturesNiche<'a>(pub(crate) &'a [InLayout<'a>]);
|
||||
|
||||
impl CapturesNiche<'_> {
|
||||
pub fn no_niche() -> Self {
|
||||
|
@ -1279,9 +1291,9 @@ impl<'a> LambdaName<'a> {
|
|||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct LambdaSet<'a> {
|
||||
/// collection of function names and their closure arguments
|
||||
pub(crate) set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
pub(crate) set: &'a [(Symbol, &'a [InLayout<'a>])],
|
||||
/// how the closure will be represented at runtime
|
||||
pub(crate) representation: Interned<Layout<'a>>,
|
||||
pub(crate) representation: InLayout<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1296,7 +1308,7 @@ pub enum ClosureRepresentation<'a> {
|
|||
/// The closure is represented as a union. Includes the tag ID!
|
||||
/// Each variant is a different function, and its payloads are the captures.
|
||||
Union {
|
||||
alphabetic_order_fields: &'a [Layout<'a>],
|
||||
alphabetic_order_fields: &'a [InLayout<'a>],
|
||||
closure_name: Symbol,
|
||||
tag_id: TagIdIntType,
|
||||
union_layout: UnionLayout<'a>,
|
||||
|
@ -1305,9 +1317,9 @@ pub enum ClosureRepresentation<'a> {
|
|||
/// The layouts are sorted alphabetically by the identifier that is captured.
|
||||
///
|
||||
/// We MUST sort these according to their stack size before code gen!
|
||||
AlphabeticOrderStruct(&'a [Layout<'a>]),
|
||||
AlphabeticOrderStruct(&'a [InLayout<'a>]),
|
||||
/// The closure is one function that captures a single identifier, whose value is unwrapped.
|
||||
UnwrappedCapture(Layout<'a>),
|
||||
UnwrappedCapture(InLayout<'a>),
|
||||
/// The closure dispatches to multiple functions, but none of them capture anything, so this is
|
||||
/// a boolean or integer flag.
|
||||
EnumDispatch(EnumDispatch),
|
||||
|
@ -1391,7 +1403,7 @@ impl<'a> LambdaSet<'a> {
|
|||
{
|
||||
debug_assert!(self.contains(lambda_name.name));
|
||||
|
||||
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||
let comparator = |other_name: Symbol, other_captures_layouts: &[InLayout]| {
|
||||
other_name == lambda_name.name
|
||||
// Make sure all captures are equal
|
||||
&& other_captures_layouts
|
||||
|
@ -1419,7 +1431,7 @@ impl<'a> LambdaSet<'a> {
|
|||
self
|
||||
);
|
||||
|
||||
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||
let comparator = |other_name: Symbol, other_captures_layouts: &[InLayout<'a>]| {
|
||||
other_name == function_symbol
|
||||
&& other_captures_layouts.iter().zip(captures_layouts).all(
|
||||
|(other_layout, layout)| {
|
||||
|
@ -1449,10 +1461,11 @@ impl<'a> LambdaSet<'a> {
|
|||
|
||||
/// Checks if two captured layouts are equivalent under the current lambda set.
|
||||
/// Resolves recursive pointers to the layout of the lambda set.
|
||||
fn capture_layouts_eq<I>(&self, interner: &I, left: &Layout, right: &Layout) -> bool
|
||||
fn capture_layouts_eq<I>(&self, interner: &I, left: &InLayout<'a>, right: &Layout) -> bool
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let left = interner.get(*left);
|
||||
if left == right {
|
||||
return true;
|
||||
}
|
||||
|
@ -1485,15 +1498,15 @@ impl<'a> LambdaSet<'a> {
|
|||
fn layout_for_member<I, F>(&self, interner: &I, comparator: F) -> ClosureRepresentation<'a>
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
F: Fn(Symbol, &[Layout]) -> bool,
|
||||
F: Fn(Symbol, &[InLayout]) -> bool,
|
||||
{
|
||||
let repr = interner.get(self.representation);
|
||||
|
||||
if self.has_unwrapped_capture_repr() {
|
||||
// Only one function, that captures one identifier.
|
||||
return ClosureRepresentation::UnwrappedCapture(*repr);
|
||||
return ClosureRepresentation::UnwrappedCapture(self.representation);
|
||||
}
|
||||
|
||||
let repr = interner.get(self.representation);
|
||||
|
||||
match repr {
|
||||
Layout::Union(union) => {
|
||||
// here we rely on the fact that a union in a closure would be stored in a one-element record.
|
||||
|
@ -1721,7 +1734,7 @@ impl<'a> LambdaSet<'a> {
|
|||
// sort the tags; make sure ordering stays intact!
|
||||
lambdas.sort_by_key(|(sym, _)| *sym);
|
||||
|
||||
let mut set: Vec<(Symbol, &[Layout])> =
|
||||
let mut set: Vec<(Symbol, &[InLayout])> =
|
||||
Vec::with_capacity_in(lambdas.len(), env.arena);
|
||||
let mut set_with_variables: std::vec::Vec<(&Symbol, &[Variable])> =
|
||||
std::vec::Vec::with_capacity(lambdas.len());
|
||||
|
@ -1742,7 +1755,8 @@ impl<'a> LambdaSet<'a> {
|
|||
// representation, so here the criteria doesn't matter.
|
||||
let mut criteria = CACHEABLE;
|
||||
let arg = cached!(Layout::from_var(env, *var), criteria);
|
||||
arguments.push(arg);
|
||||
let arg_in = env.cache.interner.insert(env.arena.alloc(arg));
|
||||
arguments.push(arg_in);
|
||||
}
|
||||
|
||||
let arguments = arguments.into_bump_slice();
|
||||
|
@ -2375,41 +2389,6 @@ impl<'a> Layout<'a> {
|
|||
false // TODO this should use is_zero_sized once doing so doesn't break things!
|
||||
}
|
||||
|
||||
/// Like stack_size, but doesn't require target info because
|
||||
/// whether something is zero sized is not target-dependent.
|
||||
#[allow(dead_code)]
|
||||
fn is_zero_sized(&self) -> bool {
|
||||
match self {
|
||||
// There are no zero-sized builtins
|
||||
Layout::Builtin(_) => false,
|
||||
// Functions are never zero-sized
|
||||
Layout::LambdaSet(_) => false,
|
||||
// Empty structs, or structs with all zero-sized fields, are zero-sized
|
||||
Layout::Struct { field_layouts, .. } => field_layouts.iter().all(Self::is_zero_sized),
|
||||
// A Box that points to nothing should be unwrapped
|
||||
Layout::Boxed(content) => content.is_zero_sized(),
|
||||
Layout::Union(union_layout) => match union_layout {
|
||||
UnionLayout::NonRecursive(tags)
|
||||
| UnionLayout::Recursive(tags)
|
||||
| UnionLayout::NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => tags
|
||||
.iter()
|
||||
.all(|payloads| payloads.iter().all(Self::is_zero_sized)),
|
||||
UnionLayout::NonNullableUnwrapped(tags)
|
||||
| UnionLayout::NullableUnwrapped {
|
||||
other_fields: tags, ..
|
||||
} => tags.iter().all(Self::is_zero_sized),
|
||||
},
|
||||
// Recursive pointers are considered zero-sized because
|
||||
// if you have a recursive data structure where everything
|
||||
// else but the recutsive pointer is zero-sized, then
|
||||
// the whole thing is unnecessary at runtime and should
|
||||
// be zero-sized.
|
||||
Layout::RecursivePointer => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_passed_by_reference<I>(&self, interner: &I, target_info: TargetInfo) -> bool
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
|
@ -2553,7 +2532,9 @@ impl<'a> Layout<'a> {
|
|||
.runtime_representation(interner)
|
||||
.allocation_alignment_bytes(interner, target_info),
|
||||
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
|
||||
Layout::Boxed(inner) => inner.allocation_alignment_bytes(interner, target_info),
|
||||
Layout::Boxed(inner) => interner
|
||||
.get(*inner)
|
||||
.allocation_alignment_bytes(interner, target_info),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2671,7 +2652,7 @@ impl<'a> Layout<'a> {
|
|||
RecursivePointer => alloc.text("*self"),
|
||||
Boxed(inner) => alloc
|
||||
.text("Boxed(")
|
||||
.append(inner.to_doc(alloc, interner, parens))
|
||||
.append(interner.get(inner).to_doc(alloc, interner, parens))
|
||||
.append(")"),
|
||||
}
|
||||
}
|
||||
|
@ -3083,8 +3064,9 @@ fn layout_from_flat_type<'a>(
|
|||
|
||||
let inner_var = args[0];
|
||||
let inner_layout = cached!(Layout::from_var(env, inner_var), criteria);
|
||||
let inner_layout = env.cache.put_in(env.arena.alloc(inner_layout));
|
||||
|
||||
Cacheable(Ok(Layout::Boxed(env.arena.alloc(inner_layout))), criteria)
|
||||
Cacheable(Ok(Layout::Boxed(inner_layout)), criteria)
|
||||
}
|
||||
_ => {
|
||||
panic!(
|
||||
|
|
|
@ -77,7 +77,7 @@ pub fn helper(
|
|||
procedures,
|
||||
mut interns,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
|
@ -188,7 +188,6 @@ pub fn helper(
|
|||
|
||||
let env = roc_gen_dev::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
module_id,
|
||||
exposed_to_host: exposed_to_host.values.keys().copied().collect(),
|
||||
lazy_literals,
|
||||
|
@ -196,7 +195,13 @@ pub fn helper(
|
|||
};
|
||||
|
||||
let target = target_lexicon::Triple::host();
|
||||
let module_object = roc_gen_dev::build_module(&env, &mut interns, &target, procedures);
|
||||
let module_object = roc_gen_dev::build_module(
|
||||
&env,
|
||||
&mut interns,
|
||||
&mut layout_interner,
|
||||
&target,
|
||||
procedures,
|
||||
);
|
||||
|
||||
let module_out = module_object
|
||||
.write()
|
||||
|
|
|
@ -111,7 +111,7 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
|
|||
procedures,
|
||||
mut interns,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
|
@ -125,7 +125,6 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
|
|||
|
||||
let env = roc_gen_wasm::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
module_id,
|
||||
exposed_to_host,
|
||||
stack_bytes: roc_gen_wasm::Env::DEFAULT_STACK_BYTES,
|
||||
|
@ -140,8 +139,13 @@ fn compile_roc_to_wasm_bytes<'a, T: Wasm32Result>(
|
|||
)
|
||||
});
|
||||
|
||||
let (mut module, mut called_fns, main_fn_index) =
|
||||
roc_gen_wasm::build_app_module(&env, &mut interns, host_module, procedures);
|
||||
let (mut module, mut called_fns, main_fn_index) = roc_gen_wasm::build_app_module(
|
||||
&env,
|
||||
&mut layout_interner,
|
||||
&mut interns,
|
||||
host_module,
|
||||
procedures,
|
||||
);
|
||||
|
||||
T::insert_wrapper(arena, &mut module, TEST_WRAPPER_NAME, main_fn_index);
|
||||
called_fns.push(true);
|
||||
|
|
|
@ -141,7 +141,7 @@ struct BackendInputs<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BackendInputs<'a> {
|
||||
fn new(arena: &'a Bump, layout_interner: &'a STLayoutInterner<'a>) -> Self {
|
||||
fn new(arena: &'a Bump) -> Self {
|
||||
// Compile the host from an external source file
|
||||
let host_bytes = fs::read(LINKING_TEST_HOST_WASM).unwrap();
|
||||
let host_module: WasmModule = roc_gen_wasm::parse_host(arena, &host_bytes).unwrap();
|
||||
|
@ -159,7 +159,6 @@ impl<'a> BackendInputs<'a> {
|
|||
exposed_to_host.insert(roc_main_sym);
|
||||
let env = Env {
|
||||
arena,
|
||||
layout_interner,
|
||||
module_id,
|
||||
exposed_to_host,
|
||||
stack_bytes: Env::DEFAULT_STACK_BYTES,
|
||||
|
@ -263,22 +262,27 @@ fn test_help(
|
|||
dump_filename: &str,
|
||||
) {
|
||||
let arena = Bump::new();
|
||||
let layout_interner = STLayoutInterner::with_capacity(4);
|
||||
let mut layout_interner = STLayoutInterner::with_capacity(4);
|
||||
|
||||
let BackendInputs {
|
||||
env,
|
||||
mut interns,
|
||||
host_module,
|
||||
procedures,
|
||||
} = BackendInputs::new(&arena, &layout_interner);
|
||||
} = BackendInputs::new(&arena);
|
||||
|
||||
let host_import_names = Vec::from_iter(host_module.import.imports.iter().map(|imp| imp.name));
|
||||
assert_eq!(&host_import_names, expected_host_import_names);
|
||||
|
||||
assert!(&host_module.names.function_names.is_empty());
|
||||
|
||||
let (mut final_module, called_fns, _roc_main_index) =
|
||||
roc_gen_wasm::build_app_module(&env, &mut interns, host_module, procedures);
|
||||
let (mut final_module, called_fns, _roc_main_index) = roc_gen_wasm::build_app_module(
|
||||
&env,
|
||||
&mut layout_interner,
|
||||
&mut interns,
|
||||
host_module,
|
||||
procedures,
|
||||
);
|
||||
|
||||
if eliminate_dead_code {
|
||||
final_module.eliminate_dead_code(env.arena, called_fns);
|
||||
|
|
|
@ -14,11 +14,11 @@ procedure Test.16 (Test.54):
|
|||
ret Test.56;
|
||||
|
||||
procedure Test.2 (Test.7, Test.8):
|
||||
let Test.30 : [C {} {}, C {} {}] = TagId(0) Test.7 Test.8;
|
||||
let Test.30 : [C {} {}, C {} {}] = TagId(1) Test.7 Test.8;
|
||||
ret Test.30;
|
||||
|
||||
procedure Test.2 (Test.7, Test.8):
|
||||
let Test.44 : [C {} {}, C {} {}] = TagId(1) Test.7 Test.8;
|
||||
let Test.44 : [C {} {}, C {} {}] = TagId(0) Test.7 Test.8;
|
||||
ret Test.44;
|
||||
|
||||
procedure Test.3 (Test.17):
|
||||
|
@ -32,17 +32,6 @@ procedure Test.4 (Test.18):
|
|||
procedure Test.9 (Test.29, #Attr.12):
|
||||
let Test.8 : {} = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
||||
let Test.7 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
let Test.35 : {} = Struct {};
|
||||
let Test.34 : Str = CallByName Test.15 Test.35;
|
||||
let Test.31 : {} = CallByName Test.3 Test.34;
|
||||
dec Test.34;
|
||||
let Test.33 : {} = Struct {};
|
||||
let Test.32 : Str = CallByName Test.11 Test.33;
|
||||
ret Test.32;
|
||||
|
||||
procedure Test.9 (Test.29, #Attr.12):
|
||||
let Test.8 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.49 : {} = Struct {};
|
||||
let Test.48 : Str = CallByName Test.16 Test.49;
|
||||
let Test.45 : Str = CallByName Test.4 Test.48;
|
||||
|
@ -51,6 +40,17 @@ procedure Test.9 (Test.29, #Attr.12):
|
|||
let Test.46 : Str = CallByName Test.13 Test.47 Test.45;
|
||||
ret Test.46;
|
||||
|
||||
procedure Test.9 (Test.29, #Attr.12):
|
||||
let Test.8 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.35 : {} = Struct {};
|
||||
let Test.34 : Str = CallByName Test.15 Test.35;
|
||||
let Test.31 : {} = CallByName Test.3 Test.34;
|
||||
dec Test.34;
|
||||
let Test.33 : {} = Struct {};
|
||||
let Test.32 : Str = CallByName Test.11 Test.33;
|
||||
ret Test.32;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : Int1 = true;
|
||||
joinpoint Test.25 Test.6:
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
procedure Test.1 (Test.5):
|
||||
let Test.19 : [C , C U64, C {}] = TagId(2) Test.5;
|
||||
let Test.19 : [C , C {}, C U64] = TagId(1) Test.5;
|
||||
ret Test.19;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.27 : [C , C U64, C {}] = TagId(1) Test.5;
|
||||
let Test.27 : [C , C {}, C U64] = TagId(2) Test.5;
|
||||
ret Test.27;
|
||||
|
||||
procedure Test.2 (Test.8):
|
||||
|
@ -11,12 +11,12 @@ procedure Test.2 (Test.8):
|
|||
ret Test.24;
|
||||
|
||||
procedure Test.6 (Test.20, #Attr.12):
|
||||
let Test.5 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.5 : U64 = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||
let Test.30 : Str = "";
|
||||
ret Test.30;
|
||||
|
||||
procedure Test.6 (Test.20, #Attr.12):
|
||||
let Test.5 : {} = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.22 : Str = "";
|
||||
ret Test.22;
|
||||
|
||||
|
@ -45,15 +45,15 @@ procedure Test.0 ():
|
|||
switch Test.3:
|
||||
case 0:
|
||||
let Test.18 : {} = Struct {};
|
||||
let Test.17 : [C , C U64, C {}] = CallByName Test.1 Test.18;
|
||||
let Test.17 : [C , C {}, C U64] = CallByName Test.1 Test.18;
|
||||
jump Test.16 Test.17;
|
||||
|
||||
case 1:
|
||||
let Test.23 : [C , C U64, C {}] = TagId(0) ;
|
||||
let Test.23 : [C , C {}, C U64] = TagId(0) ;
|
||||
jump Test.16 Test.23;
|
||||
|
||||
default:
|
||||
let Test.26 : U64 = 1i64;
|
||||
let Test.25 : [C , C U64, C {}] = CallByName Test.1 Test.26;
|
||||
let Test.25 : [C , C {}, C U64] = CallByName Test.1 Test.26;
|
||||
jump Test.16 Test.25;
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
procedure Test.1 (Test.5):
|
||||
let Test.20 : [C U64, C {}, C Str] = TagId(1) Test.5;
|
||||
let Test.20 : [C {}, C U64, C Str] = TagId(0) Test.5;
|
||||
ret Test.20;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.32 : [C U64, C {}, C Str] = TagId(0) Test.5;
|
||||
let Test.32 : [C {}, C U64, C Str] = TagId(1) Test.5;
|
||||
ret Test.32;
|
||||
|
||||
procedure Test.2 (Test.7):
|
||||
let Test.26 : [C U64, C {}, C Str] = TagId(2) Test.7;
|
||||
let Test.26 : [C {}, C U64, C Str] = TagId(2) Test.7;
|
||||
ret Test.26;
|
||||
|
||||
procedure Test.6 (Test.21, #Attr.12):
|
||||
let Test.5 : U64 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
let Test.5 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
dec #Attr.12;
|
||||
let Test.35 : Str = "";
|
||||
ret Test.35;
|
||||
|
||||
procedure Test.6 (Test.21, #Attr.12):
|
||||
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.5 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
dec #Attr.12;
|
||||
let Test.23 : Str = "";
|
||||
ret Test.23;
|
||||
|
@ -53,16 +53,16 @@ procedure Test.0 ():
|
|||
switch Test.3:
|
||||
case 0:
|
||||
let Test.19 : {} = Struct {};
|
||||
let Test.18 : [C U64, C {}, C Str] = CallByName Test.1 Test.19;
|
||||
let Test.18 : [C {}, C U64, C Str] = CallByName Test.1 Test.19;
|
||||
jump Test.17 Test.18;
|
||||
|
||||
case 1:
|
||||
let Test.25 : Str = "foo";
|
||||
let Test.24 : [C U64, C {}, C Str] = CallByName Test.2 Test.25;
|
||||
let Test.24 : [C {}, C U64, C Str] = CallByName Test.2 Test.25;
|
||||
jump Test.17 Test.24;
|
||||
|
||||
default:
|
||||
let Test.31 : U64 = 1i64;
|
||||
let Test.30 : [C U64, C {}, C Str] = CallByName Test.1 Test.31;
|
||||
let Test.30 : [C {}, C U64, C Str] = CallByName Test.1 Test.31;
|
||||
jump Test.17 Test.30;
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ fn compiles_to_ir(test_name: &str, src: &str, mode: &str, no_check: bool) {
|
|||
module_id: home,
|
||||
procedures,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
interns,
|
||||
..
|
||||
} = loaded;
|
||||
|
@ -152,7 +152,7 @@ fn compiles_to_ir(test_name: &str, src: &str, mode: &str, no_check: bool) {
|
|||
let main_fn_symbol = exposed_to_host.values.keys().copied().next();
|
||||
|
||||
if !no_check {
|
||||
check_procedures(arena, &interns, &layout_interner, &procedures);
|
||||
check_procedures(arena, &interns, &mut layout_interner, &procedures);
|
||||
}
|
||||
|
||||
verify_procedures(test_name, layout_interner, procedures, main_fn_symbol);
|
||||
|
@ -161,7 +161,7 @@ fn compiles_to_ir(test_name: &str, src: &str, mode: &str, no_check: bool) {
|
|||
fn check_procedures<'a>(
|
||||
arena: &'a Bump,
|
||||
interns: &Interns,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
interner: &mut STLayoutInterner<'a>,
|
||||
procedures: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) {
|
||||
use roc_mono::debug::{check_procs, format_problems};
|
||||
|
|
|
@ -1455,6 +1455,7 @@ fn add_tag_union<'a>(
|
|||
}
|
||||
}
|
||||
Layout::Boxed(elem_layout) => {
|
||||
let elem_layout = env.layout_cache.get_in(elem_layout);
|
||||
let (tag_name, payload_fields) =
|
||||
single_tag_payload_fields(union_tags, subs, &[*elem_layout], env, types);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_intern::Interner;
|
||||
use roc_types::types::AliasKind;
|
||||
use std::cmp::{max_by_key, min_by_key};
|
||||
|
||||
|
@ -854,6 +855,7 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
|||
let inner_var = env.subs[inner_var_index];
|
||||
|
||||
let addr_of_inner = mem.deref_usize(addr);
|
||||
let inner_layout = env.layout_cache.interner.get(*inner_layout);
|
||||
let inner_expr = addr_to_ast(
|
||||
env,
|
||||
mem,
|
||||
|
|
|
@ -208,7 +208,7 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
|
|||
mut interns,
|
||||
mut subs,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
mut layout_interner,
|
||||
..
|
||||
} = mono;
|
||||
|
||||
|
@ -234,7 +234,6 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
|
|||
let app_module_bytes = {
|
||||
let env = roc_gen_wasm::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
module_id,
|
||||
stack_bytes: roc_gen_wasm::Env::DEFAULT_STACK_BYTES,
|
||||
exposed_to_host: exposed_to_host
|
||||
|
@ -248,6 +247,7 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
|
|||
let host_module = roc_gen_wasm::parse_host(env.arena, PRE_LINKED_BINARY).unwrap();
|
||||
roc_gen_wasm::build_app_module(
|
||||
&env,
|
||||
&mut layout_interner,
|
||||
&mut interns, // NOTE: must drop this mutable ref before jit_to_ast
|
||||
host_module,
|
||||
procedures,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue