Merge pull request #1422 from rtfeldman/raw-function-layout

remove FunctionPointer layout variant
This commit is contained in:
Richard Feldman 2021-06-19 20:42:56 -04:00 committed by GitHub
commit f08c764cad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 467 additions and 799 deletions

View file

@ -6,7 +6,7 @@ use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type};
use roc_module::ident::{Lowercase, TagName};
use roc_module::operator::CalledVia;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::ir::TopLevelFunctionLayout;
use roc_mono::ir::ProcLayout;
use roc_mono::layout::{union_sorted_tags_help, Builtin, Layout, UnionLayout, UnionVariant};
use roc_parse::ast::{AssignedField, Expr, StrLiteral};
use roc_region::all::{Located, Region};
@ -38,7 +38,7 @@ pub unsafe fn jit_to_ast<'a>(
arena: &'a Bump,
lib: Library,
main_fn_name: &str,
layout: TopLevelFunctionLayout<'a>,
layout: ProcLayout<'a>,
content: &Content,
interns: &Interns,
home: ModuleId,
@ -54,7 +54,7 @@ pub unsafe fn jit_to_ast<'a>(
};
match layout {
TopLevelFunctionLayout {
ProcLayout {
arguments: [],
result,
} => {
@ -153,20 +153,30 @@ fn jit_to_ast_help<'a>(
Layout::Struct(field_layouts) => {
let ptr_to_ast = |ptr: *const u8| match content {
Content::Structure(FlatType::Record(fields, _)) => {
struct_to_ast(env, ptr, field_layouts, fields)
Ok(struct_to_ast(env, ptr, field_layouts, fields))
}
Content::Structure(FlatType::EmptyRecord) => {
struct_to_ast(env, ptr, field_layouts, &MutMap::default())
Ok(struct_to_ast(env, ptr, field_layouts, &MutMap::default()))
}
Content::Structure(FlatType::TagUnion(tags, _)) => {
debug_assert_eq!(tags.len(), 1);
let (tag_name, payload_vars) = tags.iter().next().unwrap();
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars)
Ok(single_tag_union_to_ast(
env,
ptr,
field_layouts,
tag_name.clone(),
payload_vars,
))
}
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[])
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => Ok(
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[]),
),
Content::Structure(FlatType::Func(_, _, _)) => {
// a function with a struct as the closure environment
Err(ToAstProblem::FunctionLayout)
}
other => {
unreachable!(
@ -181,12 +191,12 @@ fn jit_to_ast_help<'a>(
let result_stack_size = layout.stack_size(env.ptr_bytes);
Ok(run_jit_function_dynamic_type!(
run_jit_function_dynamic_type!(
lib,
main_fn_name,
result_stack_size as usize,
|bytes: *const u8| { ptr_to_ast(bytes as *const u8) }
))
)
}
Layout::Union(UnionLayout::NonRecursive(union_layouts)) => match content {
Content::Structure(FlatType::TagUnion(tags, _)) => {
@ -265,7 +275,6 @@ fn jit_to_ast_help<'a>(
}
Layout::Closure(_, _, _) => Err(ToAstProblem::FunctionLayout),
Layout::FunctionPointer(_, _) => Err(ToAstProblem::FunctionLayout),
}
}

View file

@ -910,13 +910,14 @@ test "endsWith: hello world ends with world" {
}
// Str.concat
pub fn strConcatC(result_in_place: InPlace, arg1: RocStr, arg2: RocStr) callconv(.C) RocStr {
return @call(.{ .modifier = always_inline }, strConcat, .{ result_in_place, arg1, arg2 });
pub fn strConcatC(arg1: RocStr, arg2: RocStr) callconv(.C) RocStr {
return @call(.{ .modifier = always_inline }, strConcat, .{ arg1, arg2 });
}
fn strConcat(result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
fn strConcat(arg1: RocStr, arg2: RocStr) RocStr {
if (arg1.isEmpty()) {
// the second argument is borrowed, so we must increment its refcount before returning
const result_in_place = InPlace.Clone;
return RocStr.clone(result_in_place, arg2);
} else if (arg2.isEmpty()) {
// the first argument is owned, so we can return it without cloning
@ -974,7 +975,7 @@ test "RocStr.concat: small concat small" {
roc_str3.deinit();
}
const result = strConcat(InPlace.Clone, roc_str1, roc_str2);
const result = strConcat(roc_str1, roc_str2);
defer result.deinit();

View file

@ -9,7 +9,7 @@ use object::{
};
use roc_collections::all::MutMap;
use roc_module::symbol;
use roc_mono::ir::{Proc, TopLevelFunctionLayout};
use roc_mono::ir::{Proc, ProcLayout};
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
// This is used by some code below which is currently commented out.
@ -21,7 +21,7 @@ use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Tripl
pub fn build_module<'a>(
env: &'a Env,
target: &Triple,
procedures: MutMap<(symbol::Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
) -> Result<Object, String> {
match target {
Triple {
@ -144,7 +144,7 @@ fn generate_wrapper<'a, B: Backend<'a>>(
fn build_object<'a, B: Backend<'a>>(
env: &'a Env,
procedures: MutMap<(symbol::Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
mut backend: B,
mut output: Object,
) -> Result<Object, String> {

View file

@ -151,9 +151,6 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
}
match closure_data_layout {
Layout::FunctionPointer(_, _) => {
// do nothing
}
Layout::Closure(_, lambda_set, _) => {
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
// do nothing
@ -508,7 +505,6 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
let default = [value1, value2];
let arguments_cast = match closure_data_layout {
Layout::FunctionPointer(_, _) => &default,
Layout::Closure(_, lambda_set, _) => {
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
&default

View file

@ -17,8 +17,8 @@ use crate::llvm::build_str::{
};
use crate::llvm::compare::{generic_eq, generic_neq};
use crate::llvm::convert::{
basic_type_from_builtin, basic_type_from_function_layout, basic_type_from_layout,
block_of_memory, block_of_memory_slices, ptr_int,
basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices,
ptr_int,
};
use crate::llvm::refcounting::{
decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
@ -49,11 +49,10 @@ use roc_module::ident::TagName;
use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::ir::{
BranchInfo, CallType, EntryPoint, ExceptionId, JoinPointId, ModifyRc, OptLevel,
TopLevelFunctionLayout, Wrapped,
BranchInfo, CallType, EntryPoint, ExceptionId, JoinPointId, ModifyRc, OptLevel, ProcLayout,
Wrapped,
};
use roc_mono::layout::{Builtin, InPlace, LambdaSet, Layout, LayoutIds, UnionLayout};
use std::convert::TryFrom;
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, UnionLayout};
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
/// output in debug builds, but we don't want it to print to stdout in release builds!
@ -118,7 +117,7 @@ impl<'ctx> Iterator for FunctionIterator<'ctx> {
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Scope<'a, 'ctx> {
symbols: ImMap<Symbol, (Layout<'a>, BasicValueEnum<'ctx>)>,
pub top_level_thunks: ImMap<Symbol, (TopLevelFunctionLayout<'a>, FunctionValue<'ctx>)>,
pub top_level_thunks: ImMap<Symbol, (ProcLayout<'a>, FunctionValue<'ctx>)>,
join_points: ImMap<JoinPointId, (BasicBlock<'ctx>, &'a [PointerValue<'ctx>])>,
}
@ -132,7 +131,7 @@ impl<'a, 'ctx> Scope<'a, 'ctx> {
pub fn insert_top_level_thunk(
&mut self,
symbol: Symbol,
layout: &'a TopLevelFunctionLayout<'a>,
layout: &'a ProcLayout<'a>,
function_value: FunctionValue<'ctx>,
) {
self.top_level_thunks
@ -588,7 +587,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
mod_solutions: &'a ModSolutions,
symbol: Symbol,
top_level: TopLevelFunctionLayout<'a>,
top_level: ProcLayout<'a>,
) -> (&'static str, FunctionValue<'ctx>) {
let it = top_level.arguments.iter().copied();
let bytes = roc_mono::alias_analysis::func_name_bytes_help(symbol, it, top_level.result);
@ -1638,9 +1637,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
}
}
EmptyArray => empty_polymorphic_list(env),
Array { elem_layout, elems } => {
list_literal(env, layout.in_place(), scope, elem_layout, elems)
}
Array { elem_layout, elems } => list_literal(env, scope, elem_layout, elems),
RuntimeErrorFunction(_) => todo!(),
}
}
@ -1794,7 +1791,6 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
fn list_literal<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
scope: &Scope<'a, 'ctx>,
elem_layout: &Layout<'a>,
elems: &&[Symbol],
@ -1808,7 +1804,7 @@ fn list_literal<'a, 'ctx, 'env>(
let len_type = env.ptr_int();
let len = len_type.const_int(len_u64, false);
allocate_list(env, inplace, elem_layout, len)
allocate_list(env, elem_layout, len)
};
// Copy the elements from the list literal into the array
@ -3102,7 +3098,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
pub fn build_proc_headers<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
mod_solutions: &'a ModSolutions,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>,
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
scope: &mut Scope<'a, 'ctx>,
// alias_analysis_solutions: AliasAnalysisSolutions,
) -> Vec<
@ -3144,7 +3140,7 @@ pub fn build_proc_headers<'a, 'ctx, 'env>(
pub fn build_procedures<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
opt_level: OptLevel,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>,
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
entry_point: EntryPoint<'a>,
) {
build_procedures_help(env, opt_level, procedures, entry_point);
@ -3153,7 +3149,7 @@ pub fn build_procedures<'a, 'ctx, 'env>(
pub fn build_procedures_return_main<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
opt_level: OptLevel,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>,
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
entry_point: EntryPoint<'a>,
) -> (&'static str, FunctionValue<'ctx>) {
let mod_solutions = build_procedures_help(env, opt_level, procedures, entry_point);
@ -3164,7 +3160,7 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>(
fn build_procedures_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
opt_level: OptLevel,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), roc_mono::ir::Proc<'a>>,
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
entry_point: EntryPoint<'a>,
) -> &'a ModSolutions {
let mut layout_ids = roc_mono::layout::LayoutIds::default();
@ -3400,122 +3396,6 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
build_host_exposed_alias_size(env, def_name, alias_symbol, layout);
}
fn build_function_caller<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
def_name: &str,
alias_symbol: Symbol,
arguments: &[Layout<'a>],
result: &Layout<'a>,
) {
let context = &env.context;
let builder = env.builder;
// STEP 1: build function header
// e.g. `roc__main_1_Fx_caller`
let function_name = format!(
"roc_{}_{}_caller",
def_name,
alias_symbol.ident_string(&env.interns)
);
let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena);
for layout in arguments {
let arg_type = basic_type_from_layout(env, layout);
let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic);
argument_types.push(arg_ptr_type.into());
}
let function_pointer_type = {
let mut args = Vec::new_in(env.arena);
args.extend(arguments.iter().cloned());
// pretend the closure layout is empty
args.push(Layout::Struct(&[]));
// this is already a (function) pointer type
basic_type_from_function_layout(env, &args, result)
};
argument_types.push(function_pointer_type);
let closure_argument_type = {
let basic_type = basic_type_from_layout(env, &Layout::Struct(&[]));
basic_type.ptr_type(AddressSpace::Generic)
};
argument_types.push(closure_argument_type.into());
let result_type = basic_type_from_layout(env, result);
let roc_call_result_type =
context.struct_type(&[context.i64_type().into(), result_type], false);
let output_type = { roc_call_result_type.ptr_type(AddressSpace::Generic) };
argument_types.push(output_type.into());
let function_type = context.void_type().fn_type(&argument_types, false);
let function_value = add_func(
env.module,
function_name.as_str(),
function_type,
Linkage::External,
C_CALL_CONV,
);
// STEP 2: build function body
let entry = context.append_basic_block(function_value, "entry");
builder.position_at_end(entry);
let mut parameters = function_value.get_params();
let output = parameters.pop().unwrap().into_pointer_value();
let _closure_data_ptr = parameters.pop().unwrap().into_pointer_value();
let function_ptr = parameters.pop().unwrap().into_pointer_value();
let actual_function_type = basic_type_from_function_layout(env, arguments, result);
let function_ptr = builder
.build_bitcast(function_ptr, actual_function_type, "cast")
.into_pointer_value();
let mut parameters = parameters;
for param in parameters.iter_mut() {
debug_assert!(param.is_pointer_value());
*param = builder.build_load(param.into_pointer_value(), "load_param");
}
let call_result = invoke_and_catch(
env,
function_value,
CallableValue::try_from(function_ptr).unwrap(),
C_CALL_CONV,
&parameters,
result_type,
);
builder.build_store(output, call_result);
builder.build_return(None);
// STEP 3: build a {} -> u64 function that gives the size of the return type
build_host_exposed_alias_size_help(
env,
def_name,
alias_symbol,
Some("result"),
roc_call_result_type.into(),
);
// STEP 4: build a {} -> u64 function that gives the size of the function
let layout = Layout::Struct(&[]);
build_host_exposed_alias_size(env, def_name, alias_symbol, layout);
}
fn build_host_exposed_alias_size<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
def_name: &str,
@ -3583,14 +3463,14 @@ pub fn build_proc<'a, 'ctx, 'env>(
fn_val: FunctionValue<'ctx>,
) {
use roc_mono::ir::HostExposedLayouts;
use roc_mono::layout::RawFunctionLayout;
let copy = proc.host_exposed_layouts.clone();
let fn_name = fn_val.get_name().to_string_lossy();
match copy {
HostExposedLayouts::NotHostExposed => {}
HostExposedLayouts::HostExposed { rigids: _, aliases } => {
for (name, (symbol, top_level, layout)) in aliases {
match layout {
Layout::Closure(arguments, closure, result) => {
RawFunctionLayout::Function(arguments, closure, result) => {
// define closure size and return value size, e.g.
//
// * roc__mainForHost_1_Update_size() -> i64
@ -3627,18 +3507,10 @@ pub fn build_proc<'a, 'ctx, 'env>(
env, &fn_name, evaluator, name, arguments, closure, result,
)
}
Layout::FunctionPointer(arguments, result) => {
// define function size (equal to pointer size) and return value size, e.g.
//
// * roc__mainForHost_1_Update_size() -> i64
// * roc__mainForHost_1_Update_result_size() -> i64
build_function_caller(env, &fn_name, name, arguments, result)
}
Layout::Builtin(_) => {}
Layout::Struct(_) => {}
Layout::Union(_) => {}
Layout::RecursivePointer => {}
RawFunctionLayout::ZeroArgumentThunk(_) => {
// do nothing
}
}
}
}
@ -4289,13 +4161,13 @@ fn run_low_level<'a, 'ctx, 'env>(
// Str.concat : Str, Str -> Str
debug_assert_eq!(args.len(), 2);
str_concat(env, layout.in_place(), scope, args[0], args[1])
str_concat(env, scope, args[0], args[1])
}
StrJoinWith => {
// Str.joinWith : List Str, Str -> Str
debug_assert_eq!(args.len(), 2);
str_join_with(env, layout.in_place(), scope, args[0], args[1])
str_join_with(env, scope, args[0], args[1])
}
StrStartsWith => {
// Str.startsWith : Str, Str -> Bool
@ -4349,7 +4221,7 @@ fn run_low_level<'a, 'ctx, 'env>(
// Str.split : Str, Str -> List Str
debug_assert_eq!(args.len(), 2);
str_split(env, scope, layout.in_place(), args[0], args[1])
str_split(env, scope, args[0], args[1])
}
StrIsEmpty => {
// Str.isEmpty : Str -> Str
@ -4384,7 +4256,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let (arg, arg_layout) = load_symbol_and_layout(scope, &args[0]);
list_single(env, layout.in_place(), arg, arg_layout)
list_single(env, arg, arg_layout)
}
ListRepeat => {
// List.repeat : Int, elem -> List elem
@ -4401,7 +4273,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
list_reverse(env, layout.in_place(), list, list_layout)
list_reverse(env, list, list_layout)
}
ListConcat => {
debug_assert_eq!(args.len(), 2);
@ -4410,14 +4282,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let second_list = load_symbol(scope, &args[1]);
list_concat(
env,
layout.in_place(),
parent,
first_list,
second_list,
list_layout,
)
list_concat(env, parent, first_list, second_list, list_layout)
}
ListContains => {
// List.contains : List elem, elem -> Bool
@ -4450,7 +4315,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
list_append(env, layout.in_place(), original_wrapper, elem, elem_layout)
list_append(env, original_wrapper, elem, elem_layout)
}
ListSwap => {
// List.swap : List elem, Nat, Nat -> List elem
@ -4502,7 +4367,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
list_prepend(env, layout.in_place(), original_wrapper, elem, elem_layout)
list_prepend(env, original_wrapper, elem, elem_layout)
}
ListJoin => {
// List.join : List (List elem) -> List elem
@ -4510,7 +4375,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let (list, outer_list_layout) = load_symbol_and_layout(scope, &args[0]);
list_join(env, layout.in_place(), parent, list, outer_list_layout)
list_join(env, parent, list, outer_list_layout)
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
| NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => {

View file

@ -88,7 +88,7 @@ fn build_hash_layout<'a, 'ctx, 'env>(
}
},
Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => {
Layout::Closure(_, _, _) => {
unreachable!("the type system will guarantee these are never hashed")
}
}

View file

@ -1,7 +1,7 @@
#![allow(clippy::too_many_arguments)]
use crate::llvm::bitcode::{
build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper,
build_transform_caller, call_bitcode_fn, call_void_bitcode_fn,
build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper, call_bitcode_fn,
call_void_bitcode_fn,
};
use crate::llvm::build::{
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, RocFunctionCall,
@ -14,7 +14,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, PointerType};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::{AddressSpace, IntPredicate};
use roc_builtins::bitcode;
use roc_mono::layout::{Builtin, InPlace, Layout, LayoutIds};
use roc_mono::layout::{Builtin, Layout, LayoutIds};
fn list_returned_from_zig<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -83,7 +83,6 @@ pub fn pass_as_opaque<'a, 'ctx, 'env>(
/// List.single : a -> List a
pub fn list_single<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_inplace: InPlace,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
@ -124,7 +123,6 @@ pub fn list_repeat<'a, 'ctx, 'env>(
/// List.prepend : List elem, elem -> List elem
pub fn list_prepend<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
original_wrapper: StructValue<'ctx>,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
@ -146,7 +144,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
);
// Allocate space for the new array that we'll copy into.
let clone_ptr = allocate_list(env, inplace, elem_layout, new_list_len);
let clone_ptr = allocate_list(env, elem_layout, new_list_len);
builder.build_store(clone_ptr, elem);
@ -189,7 +187,6 @@ pub fn list_prepend<'a, 'ctx, 'env>(
/// List.join : List (List elem) -> List elem
pub fn list_join<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_inplace: InPlace,
_parent: FunctionValue<'ctx>,
outer_list: BasicValueEnum<'ctx>,
outer_list_layout: &Layout<'a>,
@ -221,17 +218,16 @@ pub fn list_join<'a, 'ctx, 'env>(
/// List.reverse : List elem -> List elem
pub fn list_reverse<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_output_inplace: InPlace,
list: BasicValueEnum<'ctx>,
list_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let (_, element_layout) = match *list_layout {
Layout::Builtin(Builtin::EmptyList) => (
InPlace::InPlace,
let element_layout = match *list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// this pointer will never actually be dereferenced
Layout::Builtin(Builtin::Int64),
),
Layout::Builtin(Builtin::List(elem_layout)) => (InPlace::Clone, *elem_layout),
Layout::Builtin(Builtin::Int64)
}
Layout::Builtin(Builtin::List(elem_layout)) => *elem_layout,
_ => unreachable!("Invalid layout {:?} in List.reverse", list_layout),
};
@ -287,7 +283,6 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
/// List.append : List elem, elem -> List elem
pub fn list_append<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_inplace: InPlace,
original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
@ -658,54 +653,6 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
)
}
pub fn list_keep_result<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: FunctionValue<'ctx>,
transform_layout: Layout<'a>,
closure_data: BasicValueEnum<'ctx>,
closure_data_layout: Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
op: &str,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let result_layout = match transform_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let closure_data_ptr = builder.build_alloca(closure_data.get_type(), "closure_data_ptr");
env.builder.build_store(closure_data_ptr, closure_data);
let stepper_caller =
build_transform_caller(env, transform, closure_data_layout, &[*before_layout])
.as_global_value()
.as_pointer_value();
let inc_closure = build_inc_wrapper(env, layout_ids, &transform_layout);
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, closure_data_ptr),
stepper_caller.into(),
env.alignment_intvalue(&before_layout),
layout_width(env, before_layout),
layout_width(env, after_layout),
layout_width(env, result_layout),
inc_closure.as_global_value().as_pointer_value().into(),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
op,
)
}
/// List.sortWith : List a, (a, a -> Ordering) -> List a
pub fn list_sort_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -852,7 +799,6 @@ pub fn list_map3<'a, 'ctx, 'env>(
/// List.concat : List elem, List elem -> List elem
pub fn list_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_inplace: InPlace,
_parent: FunctionValue<'ctx>,
first_list: BasicValueEnum<'ctx>,
second_list: BasicValueEnum<'ctx>,
@ -1118,7 +1064,6 @@ pub fn load_list_ptr<'ctx>(
pub fn allocate_list<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
elem_layout: &Layout<'a>,
number_of_elements: IntValue<'ctx>,
) -> PointerValue<'ctx> {
@ -1131,14 +1076,9 @@ pub fn allocate_list<'a, 'ctx, 'env>(
let number_of_data_bytes =
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
let rc1 = match inplace {
InPlace::InPlace => number_of_elements,
InPlace::Clone => {
// the refcount of a new list is initially 1
// we assume that the list is indeed used (dead variables are eliminated)
crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes)
}
};
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
allocate_with_refcount_help(env, elem_layout, number_of_data_bytes, rc1)
}

View file

@ -6,7 +6,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str
use inkwell::AddressSpace;
use roc_builtins::bitcode;
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, InPlace, Layout};
use roc_mono::layout::{Builtin, Layout};
use super::build::load_symbol;
@ -16,7 +16,6 @@ pub static CHAR_LAYOUT: Layout = Layout::Builtin(Builtin::Int8);
pub fn str_split<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
inplace: InPlace,
str_symbol: Symbol,
delimiter_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
@ -33,7 +32,7 @@ pub fn str_split<'a, 'ctx, 'env>(
.into_int_value();
// a pointer to the elements
let ret_list_ptr = allocate_list(env, inplace, &Layout::Builtin(Builtin::Str), segment_count);
let ret_list_ptr = allocate_list(env, &Layout::Builtin(Builtin::Str), segment_count);
// get the RocStr type defined by zig
let roc_str_type = env.module.get_struct_type("str.RocStr").unwrap();
@ -109,7 +108,6 @@ pub fn destructure<'ctx>(
/// Str.concat : Str, Str -> Str
pub fn str_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
scope: &Scope<'a, 'ctx>,
str1_symbol: Symbol,
str2_symbol: Symbol,
@ -120,14 +118,7 @@ pub fn str_concat<'a, 'ctx, 'env>(
call_bitcode_fn(
env,
&[
env.context
.i8_type()
.const_int(inplace as u64, false)
.into(),
str1_i128.into(),
str2_i128.into(),
],
&[str1_i128.into(), str2_i128.into()],
&bitcode::STR_CONCAT,
)
}
@ -135,7 +126,6 @@ pub fn str_concat<'a, 'ctx, 'env>(
/// Str.join : List Str, Str -> Str
pub fn str_join_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_inplace: InPlace,
scope: &Scope<'a, 'ctx>,
list_symbol: Symbol,
str_symbol: Symbol,

View file

@ -195,7 +195,7 @@ fn build_eq<'a, 'ctx, 'env>(
}
},
Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => {
Layout::Closure(_, _, _) => {
unreachable!("the type system will guarantee these are never compared")
}
}
@ -336,7 +336,7 @@ fn build_neq<'a, 'ctx, 'env>(
unreachable!("recursion pointers should never be compared directly")
}
Layout::FunctionPointer(_, _) | Layout::Closure(_, _, _) => {
Layout::Closure(_, _, _) => {
unreachable!("the type system will guarantee these are never compared")
}
}

View file

@ -4,24 +4,6 @@ use inkwell::types::{BasicType, BasicTypeEnum, IntType, StructType};
use inkwell::AddressSpace;
use roc_mono::layout::{Builtin, Layout, UnionLayout};
pub fn basic_type_from_function_layout<'a, 'ctx, 'env>(
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
args: &[Layout<'_>],
ret_layout: &Layout<'_>,
) -> BasicTypeEnum<'ctx> {
let ret_type = basic_type_from_layout(env, &ret_layout);
let mut arg_basic_types = Vec::with_capacity_in(args.len(), env.arena);
for arg_layout in args.iter() {
arg_basic_types.push(basic_type_from_layout(env, arg_layout));
}
let fn_type = ret_type.fn_type(arg_basic_types.into_bump_slice(), false);
let ptr_type = fn_type.ptr_type(AddressSpace::Generic);
ptr_type.as_basic_type_enum()
}
fn basic_type_from_record<'a, 'ctx, 'env>(
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
fields: &[Layout<'_>],
@ -44,7 +26,6 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
use Layout::*;
match layout {
FunctionPointer(args, ret_layout) => basic_type_from_function_layout(env, args, ret_layout),
Closure(_args, closure_layout, _ret_layout) => {
let closure_data_layout = closure_layout.runtime_representation();
basic_type_from_layout(env, &closure_data_layout)

View file

@ -750,8 +750,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
Some(function)
}
},
FunctionPointer(_, _) => None,
}
}

View file

@ -20,7 +20,7 @@ use roc_module::symbol::{
};
use roc_mono::ir::{
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, PendingSpecialization, Proc,
Procs, TopLevelFunctionLayout,
ProcLayout, Procs,
};
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
@ -708,7 +708,7 @@ pub struct MonomorphizedModule<'a> {
pub can_problems: MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
pub type_problems: MutMap<ModuleId, Vec<solve::TypeError>>,
pub mono_problems: MutMap<ModuleId, Vec<roc_mono::ir::MonoProblem>>,
pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
pub entry_point: EntryPoint<'a>,
pub exposed_to_host: MutMap<Symbol, Variable>,
pub header_sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
@ -781,7 +781,7 @@ enum Msg<'a> {
ident_ids: IdentIds,
layout_cache: LayoutCache<'a>,
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations<'a>>,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
problems: Vec<roc_mono::ir::MonoProblem>,
module_timing: ModuleTiming,
subs: Subs,
@ -829,7 +829,7 @@ struct State<'a> {
pub module_cache: ModuleCache<'a>,
pub dependencies: Dependencies<'a>,
pub procedures: MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
pub procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
pub exposed_to_host: MutMap<Symbol, Variable>,
/// This is the "final" list of IdentIds, after canonicalization and constraint gen
@ -860,7 +860,7 @@ struct State<'a> {
pub needs_specialization: MutSet<ModuleId>,
pub all_pending_specializations:
MutMap<Symbol, MutMap<TopLevelFunctionLayout<'a>, PendingSpecialization<'a>>>,
MutMap<Symbol, MutMap<ProcLayout<'a>, PendingSpecialization<'a>>>,
pub specializations_in_flight: u32,
@ -2065,8 +2065,6 @@ fn update<'a>(
&& state.dependencies.solved_all()
&& state.goal_phase == Phase::MakeSpecializations
{
Proc::insert_refcount_operations(arena, &mut state.procedures);
// display the mono IR of the module, for debug purposes
if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS {
let procs_string = state
@ -2080,6 +2078,8 @@ fn update<'a>(
println!("{}", result);
}
Proc::insert_refcount_operations(arena, &mut state.procedures);
// This is not safe with the new non-recursive RC updates that we do for tag unions
//
// Proc::optimize_refcount_operations(
@ -2237,7 +2237,7 @@ fn finish_specialization(
// the entry point is not specialized. This can happen if the repl output
// is a function value
EntryPoint {
layout: roc_mono::ir::TopLevelFunctionLayout {
layout: roc_mono::ir::ProcLayout {
arguments: &[],
result: Layout::Struct(&[]),
},
@ -4056,7 +4056,7 @@ fn add_def_to_module<'a>(
procs.insert_exposed(
symbol,
TopLevelFunctionLayout::from_layout(mono_env.arena, layout),
ProcLayout::from_layout(mono_env.arena, layout),
mono_env.arena,
mono_env.subs,
def.annotation,
@ -4087,14 +4087,14 @@ fn add_def_to_module<'a>(
if is_exposed {
let annotation = def.expr_var;
let layout = match layout_cache.from_var(
let top_level = match layout_cache.from_var(
mono_env.arena,
annotation,
mono_env.subs,
) {
Ok(l) => {
// remember, this is a 0-argument thunk
Layout::FunctionPointer(&[], mono_env.arena.alloc(l))
ProcLayout::new(mono_env.arena, &[], l)
}
Err(LayoutProblem::Erroneous) => {
let message = "top level function has erroneous type";
@ -4115,7 +4115,7 @@ fn add_def_to_module<'a>(
procs.insert_exposed(
symbol,
TopLevelFunctionLayout::from_layout(mono_env.arena, layout),
top_level,
mono_env.arena,
mono_env.subs,
def.annotation,

View file

@ -396,17 +396,15 @@ impl<'a> PackageModuleIds<'a> {
fn insert_debug_name(module_id: ModuleId, module_name: &PQModuleName) {
let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked.");
if !names.contains_key(&module_id.0) {
match module_name {
PQModuleName::Unqualified(module) => {
names.insert(module_id.0, module.to_string().into());
}
names
.entry(module_id.0)
.or_insert_with(|| match module_name {
PQModuleName::Unqualified(module) => module.to_string().into(),
PQModuleName::Qualified(package, module) => {
let name = format!("{}.{}", package, module).into();
names.insert(module_id.0, name);
}
}
name
}
});
}
#[cfg(not(debug_assertions))]
@ -464,9 +462,9 @@ impl ModuleIds {
let mut names = DEBUG_MODULE_ID_NAMES.lock().expect("Failed to acquire lock for Debug interning into DEBUG_MODULE_ID_NAMES, presumably because a thread panicked.");
// TODO make sure modules are never added more than once!
if !names.contains_key(&module_id.0) {
names.insert(module_id.0, module_name.to_string().into());
}
names
.entry(module_id.0)
.or_insert_with(|| module_name.to_string().into());
}
#[cfg(not(debug_assertions))]

View file

@ -144,7 +144,7 @@ where
"{:?}: {:?} with {:?} args",
proc.name,
bytes_as_ascii(&bytes),
proc.args.len()
(proc.args, proc.ret_layout),
);
}
@ -173,10 +173,7 @@ where
morphic_lib::solve(program)
}
fn build_entry_point(
layout: crate::ir::TopLevelFunctionLayout,
func_name: FuncName,
) -> Result<FuncDef> {
fn build_entry_point(layout: crate::ir::ProcLayout, func_name: FuncName) -> Result<FuncDef> {
let mut builder = FuncDefBuilder::new();
let block = builder.add_block();
@ -976,7 +973,6 @@ fn layout_spec(builder: &mut FuncDefBuilder, layout: &Layout) -> Result<TypeId>
} => worst_case_type(builder),
},
RecursivePointer => worst_case_type(builder),
FunctionPointer(_, _) => todo!(),
Closure(_, lambda_set, _) => layout_spec(builder, &lambda_set.runtime_representation()),
}
}

View file

@ -1,4 +1,4 @@
use crate::ir::{Expr, JoinPointId, Param, Proc, Stmt, TopLevelFunctionLayout};
use crate::ir::{Expr, JoinPointId, Param, Proc, ProcLayout, Stmt};
use crate::layout::Layout;
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -18,7 +18,7 @@ fn should_borrow_layout(layout: &Layout) -> bool {
pub fn infer_borrow<'a>(
arena: &'a Bump,
procs: &MutMap<(Symbol, TopLevelFunctionLayout<'a>), Proc<'a>>,
procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
) -> ParamMap<'a> {
let mut param_map = ParamMap {
items: MutMap::default(),
@ -67,7 +67,7 @@ pub fn infer_borrow<'a>(
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Key<'a> {
Declaration(Symbol, TopLevelFunctionLayout<'a>),
Declaration(Symbol, ProcLayout<'a>),
JoinPoint(JoinPointId),
}
@ -96,11 +96,7 @@ impl<'a> IntoIterator for &'a ParamMap<'a> {
}
impl<'a> ParamMap<'a> {
pub fn get_symbol(
&self,
symbol: Symbol,
layout: TopLevelFunctionLayout<'a>,
) -> Option<&'a [Param<'a>]> {
pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> {
let key = Key::Declaration(symbol, layout);
self.items.get(&key).copied()
@ -155,12 +151,7 @@ impl<'a> ParamMap<'a> {
.into_bump_slice()
}
fn visit_proc(
&mut self,
arena: &'a Bump,
proc: &Proc<'a>,
key: (Symbol, TopLevelFunctionLayout<'a>),
) {
fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, ProcLayout<'a>)) {
if proc.must_own_arguments {
self.visit_proc_always_owned(arena, proc, key);
return;
@ -178,7 +169,7 @@ impl<'a> ParamMap<'a> {
&mut self,
arena: &'a Bump,
proc: &Proc<'a>,
key: (Symbol, TopLevelFunctionLayout<'a>),
key: (Symbol, ProcLayout<'a>),
) {
let already_in_there = self.items.insert(
Key::Declaration(proc.name, key.1),
@ -371,7 +362,7 @@ impl<'a> BorrowInfState<'a> {
arg_layouts,
..
} => {
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout);
// get the borrow signature of the applied function
let ps = self
@ -414,7 +405,7 @@ impl<'a> BorrowInfState<'a> {
debug_assert!(op.is_higher_order());
let closure_layout = TopLevelFunctionLayout {
let closure_layout = ProcLayout {
arguments: arg_layouts,
result: *ret_layout,
};
@ -609,7 +600,7 @@ impl<'a> BorrowInfState<'a> {
Stmt::Ret(z),
) = (v, b)
{
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout);
if self.current_proc == *g && x == *z {
// anonymous functions (for which the ps may not be known)
@ -702,7 +693,7 @@ impl<'a> BorrowInfState<'a> {
}
}
fn collect_proc(&mut self, proc: &Proc<'a>, layout: TopLevelFunctionLayout<'a>) {
fn collect_proc(&mut self, proc: &Proc<'a>, layout: ProcLayout<'a>) {
let old = self.param_set.clone();
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();

View file

@ -1,5 +1,5 @@
use crate::borrow::{ParamMap, BORROWED, OWNED};
use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, Stmt, TopLevelFunctionLayout};
use crate::ir::{Expr, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt};
use crate::layout::Layout;
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -497,7 +497,7 @@ impl<'a> Context<'a> {
const FUNCTION: bool = BORROWED;
const CLOSURE_DATA: bool = BORROWED;
let function_layout = TopLevelFunctionLayout {
let function_layout = ProcLayout {
arguments: arg_layouts,
result: *ret_layout,
};
@ -687,7 +687,7 @@ impl<'a> Context<'a> {
arg_layouts,
..
} => {
let top_level = TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout);
// get the borrow signature
let ps = self
@ -976,8 +976,7 @@ impl<'a> Context<'a> {
arg_layouts,
..
} => {
let top_level =
TopLevelFunctionLayout::new(self.arena, arg_layouts, *ret_layout);
let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout);
// get the borrow signature
let ps = self
@ -1236,7 +1235,7 @@ pub fn visit_proc<'a>(
arena: &'a Bump,
param_map: &'a ParamMap<'a>,
proc: &mut Proc<'a>,
layout: TopLevelFunctionLayout<'a>,
layout: ProcLayout<'a>,
) {
let ctx = Context::new(arena, param_map);

File diff suppressed because it is too large Load diff

View file

@ -20,19 +20,24 @@ impl Layout<'_> {
pub const TAG_SIZE: Layout<'static> = Layout::Builtin(Builtin::Int64);
}
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum InPlace {
InPlace,
Clone,
}
#[derive(Debug, Clone)]
pub enum LayoutProblem {
UnresolvedTypeVar(Variable),
Erroneous,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RawFunctionLayout<'a> {
Function(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>),
ZeroArgumentThunk(Layout<'a>),
}
impl RawFunctionLayout<'_> {
pub fn is_zero_argument_thunk(&self) -> bool {
matches!(self, RawFunctionLayout::ZeroArgumentThunk(_))
}
}
/// Types for code gen must be monomorphic. No type variables allowed!
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Layout<'a> {
@ -45,23 +50,9 @@ pub enum Layout<'a> {
RecursivePointer,
/// A function. The types of its arguments, then the type of its return value.
FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>),
Closure(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>),
}
impl<'a> Layout<'a> {
pub fn in_place(&self) -> InPlace {
match self {
Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace,
Layout::Builtin(Builtin::List(_)) => InPlace::Clone,
Layout::Builtin(Builtin::EmptyStr) => InPlace::InPlace,
Layout::Builtin(Builtin::Str) => InPlace::Clone,
Layout::Builtin(Builtin::Int1) => InPlace::Clone,
_ => unreachable!("Layout {:?} does not have an inplace", self),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum UnionLayout<'a> {
/// A non-recursive tag union
@ -89,9 +80,9 @@ pub enum UnionLayout<'a> {
}
impl<'a> UnionLayout<'a> {
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _parens: Parens) -> DocBuilder<'b, D, A>
pub fn to_doc<D, A>(self, alloc: &'a D, _parens: Parens) -> DocBuilder<'a, D, A>
where
D: DocAllocator<'b, A>,
D: DocAllocator<'a, A>,
D::Doc: Clone,
A: Clone,
{
@ -192,32 +183,31 @@ impl<'a> LambdaSet<'a> {
}
}
pub fn extend_function_layout(
pub fn extend_argument_list(
&self,
arena: &'a Bump,
argument_layouts: &'a [Layout<'a>],
ret_layout: &'a Layout<'a>,
) -> Layout<'a> {
) -> &'a [Layout<'a>] {
if let [] = self.set {
// TERRIBLE HACK for builting functions
Layout::FunctionPointer(argument_layouts, ret_layout)
argument_layouts
} else {
match self.representation {
Layout::Struct(&[]) => {
// this function does not have anything in its closure, and the lambda set is a
// singleton, so we pass no extra argument
Layout::FunctionPointer(argument_layouts, ret_layout)
argument_layouts
}
Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => {
// we don't pass this along either
Layout::FunctionPointer(argument_layouts, ret_layout)
argument_layouts
}
_ => {
let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena);
arguments.extend(argument_layouts);
arguments.push(self.runtime_representation());
Layout::FunctionPointer(arguments.into_bump_slice(), ret_layout)
arguments.into_bump_slice()
}
}
}
@ -503,10 +493,6 @@ impl<'a> Layout<'a> {
}
}
}
FunctionPointer(_, _) => {
// Function pointers are immutable and can always be safely copied
true
}
Closure(_, closure_layout, _) => closure_layout.safe_to_memcpy(),
RecursivePointer => {
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
@ -558,7 +544,6 @@ impl<'a> Layout<'a> {
}
}
Closure(_, lambda_set, _) => lambda_set.stack_size(pointer_size),
FunctionPointer(_, _) => pointer_size,
RecursivePointer => pointer_size,
}
}
@ -590,7 +575,6 @@ impl<'a> Layout<'a> {
}
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size),
Layout::RecursivePointer => pointer_size,
Layout::FunctionPointer(_, _) => pointer_size,
Layout::Closure(_, captured, _) => {
pointer_size.max(captured.alignment_bytes(pointer_size))
}
@ -645,13 +629,12 @@ impl<'a> Layout<'a> {
}
RecursivePointer => true,
Closure(_, closure_layout, _) => closure_layout.contains_refcounted(),
FunctionPointer(_, _) => false,
}
}
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, parens: Parens) -> DocBuilder<'b, D, A>
pub fn to_doc<D, A>(self, alloc: &'a D, parens: Parens) -> DocBuilder<'a, D, A>
where
D: DocAllocator<'b, A>,
D: DocAllocator<'a, A>,
D::Doc: Clone,
A: Clone,
{
@ -669,14 +652,6 @@ impl<'a> Layout<'a> {
}
Union(union_layout) => union_layout.to_doc(alloc, parens),
RecursivePointer => alloc.text("*self"),
FunctionPointer(args, result) => {
let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction));
alloc
.intersperse(args_doc, ", ")
.append(alloc.text(" -> "))
.append(result.to_doc(alloc, Parens::InFunction))
}
Closure(args, closure_layout, result) => {
let args_doc = args.iter().map(|x| x.to_doc(alloc, Parens::InFunction));
@ -725,8 +700,6 @@ impl<'a> CachedVariable<'a> {
}
}
// use ven_ena::unify::{InPlace, Snapshot, UnificationTable, UnifyKey};
impl<'a> ven_ena::unify::UnifyKey for CachedVariable<'a> {
type Value = CachedLayout<'a>;
@ -796,7 +769,7 @@ impl<'a> LayoutCache<'a> {
arena: &'a Bump,
var: Variable,
subs: &Subs,
) -> Result<Layout<'a>, LayoutProblem> {
) -> Result<RawFunctionLayout<'a>, LayoutProblem> {
// Store things according to the root Variable, to avoid duplicate work.
let var = subs.get_root_key_without_compacting(var);
@ -806,31 +779,18 @@ impl<'a> LayoutCache<'a> {
use CachedLayout::*;
match self.layouts.probe_value(cached_var) {
Cached(result) => Ok(result),
Problem(problem) => Err(problem),
NotCached => {
Cached(_) | NotCached => {
let mut env = Env {
arena,
subs,
seen: MutSet::default(),
};
let result = Layout::from_var(&mut env, var);
// Don't actually cache. The layout cache is very hard to get right in the presence
// of specialization, it's turned of for now so an invalid cache is never the cause
// of a problem
if false {
let cached_layout = match &result {
Ok(layout) => Cached(*layout),
Err(problem) => Problem(problem.clone()),
};
self.layouts
.update_value(cached_var, |existing| existing.value = cached_layout);
}
result
Layout::from_var(&mut env, var).map(|l| match l {
Layout::Closure(a, b, c) => RawFunctionLayout::Function(a, b, c),
other => RawFunctionLayout::ZeroArgumentThunk(other),
})
}
}
}
@ -959,9 +919,9 @@ impl<'a> Builtin<'a> {
}
}
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _parens: Parens) -> DocBuilder<'b, D, A>
pub fn to_doc<D, A>(self, alloc: &'a D, _parens: Parens) -> DocBuilder<'a, D, A>
where
D: DocAllocator<'b, A>,
D: DocAllocator<'a, A>,
D::Doc: Clone,
A: Clone,
{
@ -1953,7 +1913,7 @@ impl LayoutId {
struct IdsByLayout<'a> {
by_id: MutMap<Layout<'a>, u32>,
toplevels_by_id: MutMap<crate::ir::TopLevelFunctionLayout<'a>, u32>,
toplevels_by_id: MutMap<crate::ir::ProcLayout<'a>, u32>,
next_id: u32,
}
@ -1993,7 +1953,7 @@ impl<'a> LayoutIds<'a> {
pub fn get_toplevel<'b>(
&mut self,
symbol: Symbol,
layout: &'b crate::ir::TopLevelFunctionLayout<'a>,
layout: &'b crate::ir::ProcLayout<'a>,
) -> LayoutId {
// Note: this function does some weird stuff to satisfy the borrow checker.
// There's probably a nicer way to write it that still works.

View file

@ -23,7 +23,7 @@ use roc_collections::all::MutMap;
use roc_module::symbol::Symbol;
use roc_mono::ir::Proc;
use roc_mono::ir::TopLevelFunctionLayout;
use roc_mono::ir::ProcLayout;
/// Without this, some tests pass in `cargo test --release` but fail without
/// the --release flag because they run out of stack space. This increases
@ -146,7 +146,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
#[cfg(debug_assertions)]
fn verify_procedures(
test_name: &str,
procedures: MutMap<(Symbol, TopLevelFunctionLayout<'_>), Proc<'_>>,
procedures: MutMap<(Symbol, ProcLayout<'_>), Proc<'_>>,
main_fn_symbol: Symbol,
) {
let index = procedures
@ -205,7 +205,7 @@ fn verify_procedures(
#[cfg(not(debug_assertions))]
fn verify_procedures(
_expected: &str,
_procedures: MutMap<(Symbol, TopLevelFunctionLayout<'_>), Proc<'_>>,
_procedures: MutMap<(Symbol, ProcLayout<'_>), Proc<'_>>,
_main_fn_symbol: Symbol,
) {
// Do nothing