mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Merge pull request #1422 from rtfeldman/raw-function-layout
remove FunctionPointer layout variant
This commit is contained in:
commit
f08c764cad
19 changed files with 467 additions and 799 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
¶meters,
|
||||
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 => {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
// the refcount of a new list is initially 1
|
||||
// we assume that the list is indeed used (dead variables are eliminated)
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
|
||||
|
||||
allocate_with_refcount_help(env, elem_layout, number_of_data_bytes, rc1)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -750,8 +750,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
Some(function)
|
||||
}
|
||||
},
|
||||
|
||||
FunctionPointer(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))]
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue