mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
Merge pull request #3945 from roc-lang/i3942
Adds lambda set layout interning
This commit is contained in:
commit
93ace1d6f3
53 changed files with 1869 additions and 775 deletions
|
@ -247,7 +247,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
|
||||
let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let argument = if layout.is_passed_by_reference(env.target_info) {
|
||||
let argument = if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
argument_ptr.into_pointer_value(),
|
||||
|
@ -268,8 +268,10 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
match (
|
||||
closure_data_layout.is_represented().is_some(),
|
||||
closure_data_layout.runtime_representation(),
|
||||
closure_data_layout
|
||||
.is_represented(env.layout_interner)
|
||||
.is_some(),
|
||||
closure_data_layout.runtime_representation(env.layout_interner),
|
||||
) {
|
||||
(false, _) => {
|
||||
// the function doesn't expect a closure argument, nothing to add
|
||||
|
@ -402,7 +404,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value = if layout.is_passed_by_reference(env.target_info) {
|
||||
let value = if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
env.builder
|
||||
.build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag_build_rc_wrapper")
|
||||
.into()
|
||||
|
@ -590,29 +592,30 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
let default = [value1.into(), value2.into()];
|
||||
|
||||
let arguments_cast = match closure_data_layout.runtime_representation() {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// nothing to add
|
||||
&default
|
||||
}
|
||||
other => {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &other).ptr_type(AddressSpace::Generic);
|
||||
let arguments_cast =
|
||||
match closure_data_layout.runtime_representation(env.layout_interner) {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// nothing to add
|
||||
&default
|
||||
}
|
||||
other => {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &other).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
|
||||
env.arena
|
||||
.alloc([value1.into(), value2.into(), closure_data.into()])
|
||||
as &[_]
|
||||
}
|
||||
};
|
||||
env.arena
|
||||
.alloc([value1.into(), value2.into(), closure_data.into()])
|
||||
as &[_]
|
||||
}
|
||||
};
|
||||
|
||||
let call = env.builder.build_call(
|
||||
roc_function,
|
||||
|
|
|
@ -57,7 +57,7 @@ use roc_mono::ir::{
|
|||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, RawFunctionLayout,
|
||||
TagIdIntType, UnionLayout,
|
||||
STLayoutInterner, TagIdIntType, UnionLayout,
|
||||
};
|
||||
use roc_std::RocDec;
|
||||
use roc_target::{PtrWidth, TargetInfo};
|
||||
|
@ -203,6 +203,7 @@ impl LlvmBackendMode {
|
|||
|
||||
pub struct Env<'a, 'ctx, 'env> {
|
||||
pub arena: &'a Bump,
|
||||
pub layout_interner: &'env STLayoutInterner<'a>,
|
||||
pub context: &'ctx Context,
|
||||
pub builder: &'env Builder<'ctx>,
|
||||
pub dibuilder: &'env DebugInfoBuilder<'ctx>,
|
||||
|
@ -311,7 +312,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
|||
}
|
||||
|
||||
pub fn alignment_intvalue(&self, element_layout: &Layout<'a>) -> BasicValueEnum<'ctx> {
|
||||
let alignment = element_layout.alignment_bytes(self.target_info);
|
||||
let alignment = element_layout.alignment_bytes(self.layout_interner, self.target_info);
|
||||
let alignment_iv = self.alignment_const(alignment);
|
||||
|
||||
alignment_iv.into()
|
||||
|
@ -880,7 +881,9 @@ fn promote_to_wasm_test_wrapper<'a, 'ctx, 'env>(
|
|||
let roc_main_fn_result = call_roc_function(env, roc_main_fn, &top_level.result, &[]);
|
||||
|
||||
// For consistency, we always return with a heap-allocated value
|
||||
let (size, alignment) = top_level.result.stack_size_and_alignment(env.target_info);
|
||||
let (size, alignment) = top_level
|
||||
.result
|
||||
.stack_size_and_alignment(env.layout_interner, env.target_info);
|
||||
let number_of_bytes = env.ptr_int().const_int(size as _, false);
|
||||
let void_ptr = env.call_alloc(number_of_bytes, alignment);
|
||||
|
||||
|
@ -1249,8 +1252,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
let allocation = reserve_with_refcount_help(
|
||||
env,
|
||||
basic_type,
|
||||
layout.stack_size(env.target_info),
|
||||
layout.alignment_bytes(env.target_info),
|
||||
layout.stack_size(env.layout_interner, env.target_info),
|
||||
layout.alignment_bytes(env.layout_interner, env.target_info),
|
||||
);
|
||||
|
||||
store_roc_value(env, *layout, allocation, value);
|
||||
|
@ -1328,7 +1331,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
let (value, layout) = load_symbol_and_layout(scope, structure);
|
||||
|
||||
let layout = if let Layout::LambdaSet(lambda_set) = layout {
|
||||
lambda_set.runtime_representation()
|
||||
lambda_set.runtime_representation(env.layout_interner)
|
||||
} else {
|
||||
*layout
|
||||
};
|
||||
|
@ -1600,7 +1603,7 @@ fn build_tag_field_value<'a, 'ctx, 'env>(
|
|||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
)
|
||||
} else if tag_field_layout.is_passed_by_reference(env.target_info) {
|
||||
} else if tag_field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
// NOTE: we rely on this being passed to `store_roc_value` so that
|
||||
|
@ -1661,7 +1664,7 @@ fn build_struct<'a, 'ctx, 'env>(
|
|||
if !field_layout.is_dropped_because_empty() {
|
||||
field_types.push(basic_type_from_layout(env, field_layout));
|
||||
|
||||
if field_layout.is_passed_by_reference(env.target_info) {
|
||||
if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let field_value = env
|
||||
.builder
|
||||
.build_load(field_expr.into_pointer_value(), "load_tag_to_put_in_struct");
|
||||
|
@ -1697,7 +1700,12 @@ fn build_tag<'a, 'ctx, 'env>(
|
|||
|
||||
let data = build_struct(env, scope, arguments);
|
||||
|
||||
let roc_union = RocUnion::tagged_from_slices(env.context, tags, env.target_info);
|
||||
let roc_union = RocUnion::tagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
tags,
|
||||
env.target_info,
|
||||
);
|
||||
let value = roc_union.as_struct_value(env, data, Some(tag_id as _));
|
||||
|
||||
let alloca = create_entry_block_alloca(
|
||||
|
@ -1788,8 +1796,12 @@ fn build_tag<'a, 'ctx, 'env>(
|
|||
nullable_id,
|
||||
other_fields,
|
||||
} => {
|
||||
let roc_union =
|
||||
RocUnion::untagged_from_slices(env.context, &[other_fields], env.target_info);
|
||||
let roc_union = RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[other_fields],
|
||||
env.target_info,
|
||||
);
|
||||
|
||||
if tag_id == *nullable_id as _ {
|
||||
let output_type = roc_union.struct_type().ptr_type(AddressSpace::Generic);
|
||||
|
@ -2104,8 +2116,8 @@ pub fn reserve_with_refcount<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'a>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let stack_size = layout.stack_size(env.target_info);
|
||||
let alignment_bytes = layout.alignment_bytes(env.target_info);
|
||||
let stack_size = layout.stack_size(env.layout_interner, env.target_info);
|
||||
let alignment_bytes = layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
|
||||
|
@ -2120,9 +2132,9 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
|
|||
let ptr_bytes = env.target_info;
|
||||
|
||||
let roc_union = if union_layout.stores_tag_id_as_data(ptr_bytes) {
|
||||
RocUnion::tagged_from_slices(env.context, fields, env.target_info)
|
||||
RocUnion::tagged_from_slices(env.layout_interner, env.context, fields, env.target_info)
|
||||
} else {
|
||||
RocUnion::untagged_from_slices(env.context, fields, env.target_info)
|
||||
RocUnion::untagged_from_slices(env.layout_interner, env.context, fields, env.target_info)
|
||||
};
|
||||
|
||||
reserve_with_refcount_help(
|
||||
|
@ -2211,10 +2223,10 @@ fn list_literal<'a, 'ctx, 'env>(
|
|||
// if element_type.is_int_type() {
|
||||
if false {
|
||||
let element_type = element_type.into_int_type();
|
||||
let element_width = element_layout.stack_size(env.target_info);
|
||||
let element_width = element_layout.stack_size(env.layout_interner, env.target_info);
|
||||
let size = list_length * element_width as usize;
|
||||
let alignment = element_layout
|
||||
.alignment_bytes(env.target_info)
|
||||
.alignment_bytes(env.layout_interner, env.target_info)
|
||||
.max(env.target_info.ptr_width() as u32);
|
||||
|
||||
let mut is_all_constant = true;
|
||||
|
@ -2351,7 +2363,7 @@ pub fn load_roc_value<'a, 'ctx, 'env>(
|
|||
source: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
if layout.is_passed_by_reference(env.target_info) {
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let alloca = entry_block_alloca_zerofill(env, basic_type_from_layout(env, &layout), name);
|
||||
|
||||
store_roc_value(env, layout, alloca, source.into());
|
||||
|
@ -2368,7 +2380,7 @@ pub fn use_roc_value<'a, 'ctx, 'env>(
|
|||
source: BasicValueEnum<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
if layout.is_passed_by_reference(env.target_info) {
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let alloca = entry_block_alloca_zerofill(env, basic_type_from_layout(env, &layout), name);
|
||||
|
||||
env.builder.build_store(alloca, source);
|
||||
|
@ -2399,15 +2411,16 @@ pub fn store_roc_value<'a, 'ctx, 'env>(
|
|||
destination: PointerValue<'ctx>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
) {
|
||||
if layout.is_passed_by_reference(env.target_info) {
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
let align_bytes = layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false);
|
||||
let size = env.ptr_int().const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
|
@ -2502,8 +2515,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
// store_roc_value(env, *layout, out_parameter.into_pointer_value(), value);
|
||||
|
||||
let destination = out_parameter.into_pointer_value();
|
||||
if layout.is_passed_by_reference(env.target_info) {
|
||||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let align_bytes =
|
||||
layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
debug_assert!(
|
||||
|
@ -2534,7 +2548,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
// Hence, we explicitly memcpy source to destination, and rely on
|
||||
// LLVM optimizing away any inefficiencies.
|
||||
let target_info = env.target_info;
|
||||
let width = layout.stack_size(target_info);
|
||||
let width = layout.stack_size(env.layout_interner, target_info);
|
||||
let size = env.ptr_int().const_int(width as _, false);
|
||||
|
||||
env.builder
|
||||
|
@ -2614,7 +2628,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
for param in parameters.iter() {
|
||||
let basic_type = basic_type_from_layout(env, ¶m.layout);
|
||||
|
||||
let phi_type = if param.layout.is_passed_by_reference(env.target_info) {
|
||||
let phi_type = if param
|
||||
.layout
|
||||
.is_passed_by_reference(env.layout_interner, env.target_info)
|
||||
{
|
||||
basic_type.ptr_type(AddressSpace::Generic).into()
|
||||
} else {
|
||||
basic_type
|
||||
|
@ -2697,7 +2714,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
let (value, layout) = load_symbol_and_layout(scope, symbol);
|
||||
let layout = *layout;
|
||||
|
||||
if layout.contains_refcounted() {
|
||||
if layout.contains_refcounted(env.layout_interner) {
|
||||
increment_refcount_layout(
|
||||
env,
|
||||
parent,
|
||||
|
@ -2713,7 +2730,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
Dec(symbol) => {
|
||||
let (value, layout) = load_symbol_and_layout(scope, symbol);
|
||||
|
||||
if layout.contains_refcounted() {
|
||||
if layout.contains_refcounted(env.layout_interner) {
|
||||
decrement_refcount_layout(env, parent, layout_ids, value, layout);
|
||||
}
|
||||
|
||||
|
@ -2726,7 +2743,8 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::Str) => todo!(),
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
debug_assert!(value.is_struct_value());
|
||||
let alignment = element_layout.alignment_bytes(env.target_info);
|
||||
let alignment = element_layout
|
||||
.alignment_bytes(env.layout_interner, env.target_info);
|
||||
|
||||
build_list::decref(env, value.into_struct_value(), alignment);
|
||||
}
|
||||
|
@ -4155,7 +4173,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
|||
.build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error")
|
||||
.unwrap();
|
||||
|
||||
let v3 = if return_layout.is_passed_by_reference(env.target_info) {
|
||||
let v3 = if return_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let loaded = env.builder.build_load(
|
||||
return_value.into_pointer_value(),
|
||||
"load_call_result_passed_by_ptr",
|
||||
|
@ -4418,10 +4436,12 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
|
||||
let it = procedures.iter().map(|x| x.1);
|
||||
|
||||
let solutions = match roc_alias_analysis::spec_program(opt_level, opt_entry_point, it) {
|
||||
Err(e) => panic!("Error in alias analysis: {}", e),
|
||||
Ok(solutions) => solutions,
|
||||
};
|
||||
let solutions =
|
||||
match roc_alias_analysis::spec_program(env.layout_interner, opt_level, opt_entry_point, it)
|
||||
{
|
||||
Err(e) => panic!("Error in alias analysis: {}", e),
|
||||
Ok(solutions) => solutions,
|
||||
};
|
||||
|
||||
let solutions = env.arena.alloc(solutions);
|
||||
|
||||
|
@ -4687,7 +4707,8 @@ fn build_closure_caller<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
let closure_argument_type = {
|
||||
let basic_type = basic_type_from_layout(env, &lambda_set.runtime_representation());
|
||||
let basic_type =
|
||||
basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner));
|
||||
|
||||
basic_type.ptr_type(AddressSpace::Generic)
|
||||
};
|
||||
|
@ -4734,10 +4755,12 @@ fn build_closure_caller<'a, 'ctx, 'env>(
|
|||
|
||||
// NOTE this may be incorrect in the long run
|
||||
// here we load any argument that is a pointer
|
||||
let closure_layout = lambda_set.runtime_representation();
|
||||
let closure_layout = lambda_set.runtime_representation(env.layout_interner);
|
||||
let layouts_it = arguments.iter().chain(std::iter::once(&closure_layout));
|
||||
for (param, layout) in evaluator_arguments.iter_mut().zip(layouts_it) {
|
||||
if param.is_pointer_value() && !layout.is_passed_by_reference(env.target_info) {
|
||||
if param.is_pointer_value()
|
||||
&& !layout.is_passed_by_reference(env.layout_interner, env.target_info)
|
||||
{
|
||||
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||
}
|
||||
}
|
||||
|
@ -4755,13 +4778,14 @@ fn build_closure_caller<'a, 'ctx, 'env>(
|
|||
} else {
|
||||
let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments);
|
||||
|
||||
if return_layout.is_passed_by_reference(env.target_info) {
|
||||
let align_bytes = return_layout.alignment_bytes(env.target_info);
|
||||
if return_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let align_bytes = return_layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
let size = env
|
||||
.ptr_int()
|
||||
.const_int(return_layout.stack_size(env.target_info) as u64, false);
|
||||
let size = env.ptr_int().const_int(
|
||||
return_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_memcpy(
|
||||
|
@ -4788,7 +4812,7 @@ fn build_closure_caller<'a, 'ctx, 'env>(
|
|||
env,
|
||||
def_name,
|
||||
alias_symbol,
|
||||
lambda_set.runtime_representation(),
|
||||
lambda_set.runtime_representation(env.layout_interner),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5058,7 +5082,7 @@ pub fn call_roc_function<'a, 'ctx, 'env>(
|
|||
debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV);
|
||||
call.set_call_convention(FAST_CALL_CONV);
|
||||
|
||||
if result_layout.is_passed_by_reference(env.target_info) {
|
||||
if result_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
result_alloca.into()
|
||||
} else {
|
||||
env.builder
|
||||
|
@ -5140,10 +5164,13 @@ fn roc_function_call<'a, 'ctx, 'env>(
|
|||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let inc_closure_data =
|
||||
build_inc_n_wrapper(env, layout_ids, &lambda_set.runtime_representation())
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
let inc_closure_data = build_inc_n_wrapper(
|
||||
env,
|
||||
layout_ids,
|
||||
&lambda_set.runtime_representation(env.layout_interner),
|
||||
)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let closure_data_is_owned = env
|
||||
.context
|
||||
|
@ -6482,7 +6509,7 @@ fn to_cc_type<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'a>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
match layout.runtime_representation() {
|
||||
match layout.runtime_representation(env.layout_interner) {
|
||||
Layout::Builtin(builtin) => to_cc_type_builtin(env, &builtin),
|
||||
layout => {
|
||||
// TODO this is almost certainly incorrect for bigger structs
|
||||
|
@ -6524,7 +6551,11 @@ enum RocReturn {
|
|||
}
|
||||
|
||||
impl RocReturn {
|
||||
fn roc_return_by_pointer(target_info: TargetInfo, layout: Layout) -> bool {
|
||||
fn roc_return_by_pointer(
|
||||
interner: &STLayoutInterner,
|
||||
target_info: TargetInfo,
|
||||
layout: Layout,
|
||||
) -> bool {
|
||||
match layout {
|
||||
Layout::Builtin(builtin) => {
|
||||
use Builtin::*;
|
||||
|
@ -6539,15 +6570,17 @@ impl RocReturn {
|
|||
}
|
||||
}
|
||||
Layout::Union(UnionLayout::NonRecursive(_)) => true,
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
RocReturn::roc_return_by_pointer(target_info, lambda_set.runtime_representation())
|
||||
}
|
||||
Layout::LambdaSet(lambda_set) => RocReturn::roc_return_by_pointer(
|
||||
interner,
|
||||
target_info,
|
||||
lambda_set.runtime_representation(interner),
|
||||
),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_layout<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> Self {
|
||||
if Self::roc_return_by_pointer(env.target_info, *layout) {
|
||||
if Self::roc_return_by_pointer(env.layout_interner, env.target_info, *layout) {
|
||||
RocReturn::ByPointer
|
||||
} else {
|
||||
RocReturn::Return
|
||||
|
@ -6685,7 +6718,7 @@ impl<'ctx> FunctionSpec<'ctx> {
|
|||
|
||||
/// According to the C ABI, how should we return a value with the given layout?
|
||||
pub fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn {
|
||||
let return_size = layout.stack_size(env.target_info);
|
||||
let return_size = layout.stack_size(env.layout_interner, env.target_info);
|
||||
let pass_result_by_pointer = return_size > 2 * env.target_info.ptr_width() as u32;
|
||||
|
||||
if return_size == 0 {
|
||||
|
|
|
@ -82,7 +82,10 @@ pub(crate) fn layout_width<'a, 'ctx, 'env>(
|
|||
layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
env.ptr_int()
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false)
|
||||
.const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
@ -317,7 +320,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
|||
|
||||
// the list has the same alignment as a usize / ptr. The element comes first in the struct if
|
||||
// its alignment is bigger than that of a list.
|
||||
let element_align = element_layout.alignment_bytes(env.target_info);
|
||||
let element_align = element_layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
let element_first = element_align > env.target_info.ptr_width() as u32;
|
||||
|
||||
let fields = if element_first {
|
||||
|
@ -715,13 +718,13 @@ pub(crate) fn allocate_list<'a, 'ctx, 'env>(
|
|||
let builder = env.builder;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
|
||||
let elem_bytes = elem_layout.stack_size(env.layout_interner, env.target_info) as u64;
|
||||
let bytes_per_element = len_type.const_int(elem_bytes, false);
|
||||
let number_of_data_bytes =
|
||||
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
||||
|
||||
let basic_type = basic_type_from_layout(env, elem_layout);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
|||
use inkwell::values::StructValue;
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_mono::layout::{round_up_to_alignment, Builtin, Layout, UnionLayout};
|
||||
use roc_mono::layout::{round_up_to_alignment, Builtin, Layout, STLayoutInterner, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||
|
@ -34,7 +34,9 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
field_layouts: sorted_fields,
|
||||
..
|
||||
} => basic_type_from_record(env, sorted_fields),
|
||||
LambdaSet(lambda_set) => basic_type_from_layout(env, &lambda_set.runtime_representation()),
|
||||
LambdaSet(lambda_set) => {
|
||||
basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
||||
}
|
||||
Boxed(inner_layout) => {
|
||||
let inner_type = basic_type_from_layout(env, inner_layout);
|
||||
|
||||
|
@ -60,7 +62,7 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
|||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
//
|
||||
RocUnion::tagged_from_slices(env.context, tags, env.target_info)
|
||||
RocUnion::tagged_from_slices(env.layout_interner, env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
.into()
|
||||
}
|
||||
|
@ -69,29 +71,45 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
|||
other_tags: tags, ..
|
||||
} => {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
RocUnion::tagged_from_slices(env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
RocUnion::tagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
tags,
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
} else {
|
||||
RocUnion::untagged_from_slices(env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
tags,
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
RocUnion::untagged_from_slices(env.context, &[other_fields], env.target_info)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
RocUnion::untagged_from_slices(env.context, &[fields], env.target_info)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[other_fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,13 +150,13 @@ pub fn argument_type_from_layout<'a, 'ctx, 'env>(
|
|||
|
||||
match layout {
|
||||
LambdaSet(lambda_set) => {
|
||||
argument_type_from_layout(env, &lambda_set.runtime_representation())
|
||||
argument_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
||||
}
|
||||
Union(union_layout) => argument_type_from_union_layout(env, union_layout),
|
||||
Builtin(_) => {
|
||||
let base = basic_type_from_layout(env, layout);
|
||||
|
||||
if layout.is_passed_by_reference(env.target_info) {
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
base.ptr_type(AddressSpace::Generic).into()
|
||||
} else {
|
||||
base
|
||||
|
@ -275,6 +293,7 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
}
|
||||
|
||||
pub fn tagged_from_slices(
|
||||
interner: &STLayoutInterner,
|
||||
context: &'ctx Context,
|
||||
layouts: &[&[Layout<'_>]],
|
||||
target_info: TargetInfo,
|
||||
|
@ -285,18 +304,19 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
};
|
||||
|
||||
let (data_width, data_align) =
|
||||
Layout::stack_size_and_alignment_slices(layouts, target_info);
|
||||
Layout::stack_size_and_alignment_slices(interner, layouts, target_info);
|
||||
|
||||
Self::new(context, target_info, data_align, data_width, Some(tag_type))
|
||||
}
|
||||
|
||||
pub fn untagged_from_slices(
|
||||
interner: &STLayoutInterner,
|
||||
context: &'ctx Context,
|
||||
layouts: &[&[Layout<'_>]],
|
||||
target_info: TargetInfo,
|
||||
) -> Self {
|
||||
let (data_width, data_align) =
|
||||
Layout::stack_size_and_alignment_slices(layouts, target_info);
|
||||
Layout::stack_size_and_alignment_slices(interner, layouts, target_info);
|
||||
|
||||
Self::new(context, target_info, data_align, data_width, None)
|
||||
}
|
||||
|
|
|
@ -137,9 +137,10 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
|
||||
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
||||
|
||||
let stack_size = env
|
||||
.ptr_int()
|
||||
.const_int(layout.stack_size(env.target_info) as u64, false);
|
||||
let stack_size = env.ptr_int().const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
let mut extra_offset = env.builder.build_int_add(offset, stack_size, "offset");
|
||||
|
||||
|
@ -221,7 +222,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
Layout::LambdaSet(_) => unreachable!("cannot compare closures"),
|
||||
|
||||
Layout::Union(union_layout) => {
|
||||
if layout.safe_to_memcpy() {
|
||||
if layout.safe_to_memcpy(env.layout_interner) {
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(ptr, &[cursors.offset], "at_current_offset")
|
||||
|
@ -255,9 +256,10 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
let source = value.into_pointer_value();
|
||||
let value = load_roc_value(env, *inner_layout, source, "inner");
|
||||
|
||||
let inner_width = env
|
||||
.ptr_int()
|
||||
.const_int(inner_layout.stack_size(env.target_info) as u64, false);
|
||||
let inner_width = env.ptr_int().const_int(
|
||||
inner_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
let new_extra = env
|
||||
.builder
|
||||
|
@ -318,7 +320,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
) -> IntValue<'ctx> {
|
||||
let layout = Layout::struct_no_name_order(field_layouts);
|
||||
|
||||
if layout.safe_to_memcpy() {
|
||||
if layout.safe_to_memcpy(env.layout_interner) {
|
||||
build_copy(env, ptr, cursors.offset, value)
|
||||
} else {
|
||||
let mut cursors = cursors;
|
||||
|
@ -343,9 +345,10 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
when_recursive,
|
||||
);
|
||||
|
||||
let field_width = env
|
||||
.ptr_int()
|
||||
.const_int(field_layout.stack_size(env.target_info) as u64, false);
|
||||
let field_width = env.ptr_int().const_int(
|
||||
field_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
cursors.extra_offset = new_extra;
|
||||
cursors.offset = env
|
||||
|
@ -576,7 +579,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
|
||||
let (width, _) = union_layout.data_size_and_alignment(env.target_info);
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -618,7 +622,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
let layout = Layout::struct_no_name_order(fields);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
|
||||
let (width, _) = union_layout.data_size_and_alignment(env.target_info);
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -686,7 +691,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
let layout = Layout::struct_no_name_order(fields);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
|
||||
let (width, _) = union_layout.data_size_and_alignment(env.target_info);
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -776,8 +782,10 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
offset: extra_offset,
|
||||
extra_offset: env.builder.build_int_add(
|
||||
extra_offset,
|
||||
env.ptr_int()
|
||||
.const_int(layout.stack_size(env.target_info) as _, false),
|
||||
env.ptr_int().const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as _,
|
||||
false,
|
||||
),
|
||||
"new_offset",
|
||||
),
|
||||
};
|
||||
|
@ -907,12 +915,13 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
offset = build_copy(env, ptr, offset, len.into());
|
||||
offset = build_copy(env, ptr, offset, len.into());
|
||||
|
||||
let (element_width, _element_align) = elem.stack_size_and_alignment(env.target_info);
|
||||
let (element_width, _element_align) =
|
||||
elem.stack_size_and_alignment(env.layout_interner, env.target_info);
|
||||
let element_width = env.ptr_int().const_int(element_width as _, false);
|
||||
|
||||
let elements_width = bd.build_int_mul(element_width, len, "elements_width");
|
||||
|
||||
if elem.safe_to_memcpy() {
|
||||
if elem.safe_to_memcpy(env.layout_interner) {
|
||||
// NOTE we are not actually sure the dest is properly aligned
|
||||
let dest = pointer_at_offset(bd, ptr, offset);
|
||||
let src = bd.build_pointer_cast(
|
||||
|
@ -936,9 +945,10 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
// if the element has any pointers, we clone them to this offset
|
||||
let rest_offset = bd.build_alloca(env.ptr_int(), "rest_offset");
|
||||
|
||||
let element_stack_size = env
|
||||
.ptr_int()
|
||||
.const_int(elem.stack_size(env.target_info) as u64, false);
|
||||
let element_stack_size = env.ptr_int().const_int(
|
||||
elem.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
let rest_start_offset = bd.build_int_add(
|
||||
cursors.extra_offset,
|
||||
bd.build_int_mul(len, element_stack_size, "elements_width"),
|
||||
|
|
|
@ -16,7 +16,7 @@ use inkwell::values::{
|
|||
use inkwell::{AddressSpace, IntPredicate};
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||
|
||||
use super::build::{load_roc_value, FunctionSpec};
|
||||
use super::convert::{argument_type_from_layout, argument_type_from_union_layout};
|
||||
|
@ -124,7 +124,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
|
||||
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
|
||||
let alignment = layout
|
||||
.allocation_alignment_bytes(env.target_info)
|
||||
.allocation_alignment_bytes(env.layout_interner, env.target_info)
|
||||
.max(env.target_info.ptr_width() as u32);
|
||||
|
||||
let context = env.context;
|
||||
|
@ -332,7 +332,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
|||
let wrapper_struct = arg_val.into_struct_value();
|
||||
|
||||
for (i, field_layout) in layouts.iter().enumerate() {
|
||||
if field_layout.contains_refcounted() {
|
||||
if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let raw_value = env
|
||||
.builder
|
||||
.build_extract_value(wrapper_struct, i as u32, "decrement_struct_field")
|
||||
|
@ -613,7 +613,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
layout_ids,
|
||||
mode,
|
||||
when_recursive,
|
||||
&lambda_set.runtime_representation(),
|
||||
&lambda_set.runtime_representation(env.layout_interner),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -717,7 +717,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(modification_block);
|
||||
|
||||
if element_layout.contains_refcounted() {
|
||||
if element_layout.contains_refcounted(env.layout_interner) {
|
||||
let ptr_type = basic_type_from_layout(env, element_layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
|
||||
|
@ -818,7 +818,9 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
|||
|
||||
let parent = fn_val;
|
||||
|
||||
let arg_val = if Layout::Builtin(Builtin::Str).is_passed_by_reference(env.target_info) {
|
||||
let arg_val = if Layout::Builtin(Builtin::Str)
|
||||
.is_passed_by_reference(env.layout_interner, env.target_info)
|
||||
{
|
||||
env.builder
|
||||
.build_load(arg_val.into_pointer_value(), "load_str_to_stack")
|
||||
} else {
|
||||
|
@ -1178,10 +1180,10 @@ enum DecOrReuse {
|
|||
Reuse,
|
||||
}
|
||||
|
||||
fn fields_need_no_refcounting(field_layouts: &[Layout]) -> bool {
|
||||
fn fields_need_no_refcounting(interner: &STLayoutInterner, field_layouts: &[Layout]) -> bool {
|
||||
!field_layouts
|
||||
.iter()
|
||||
.any(|x| x.is_refcounted() || x.contains_refcounted())
|
||||
.any(|x| x.is_refcounted() || x.contains_refcounted(interner))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -1211,7 +1213,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
|
||||
for (tag_id, field_layouts) in tags.iter().enumerate() {
|
||||
// if none of the fields are or contain anything refcounted, just move on
|
||||
if fields_need_no_refcounting(field_layouts) {
|
||||
if fields_need_no_refcounting(env.layout_interner, field_layouts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1256,7 +1258,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
let recursive_field_ptr = cast_basic_basic(env.builder, ptr_as_i64_ptr, union_type);
|
||||
|
||||
deferred_rec.push(recursive_field_ptr);
|
||||
} else if field_layout.contains_refcounted() {
|
||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
|
||||
|
@ -1620,7 +1622,7 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
// if none of the fields are or contain anything refcounted, just move on
|
||||
if !field_layouts
|
||||
.iter()
|
||||
.any(|x| x.is_refcounted() || x.contains_refcounted())
|
||||
.any(|x| x.is_refcounted() || x.contains_refcounted(env.layout_interner))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -1678,17 +1680,18 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
recursive_ptr_field_value,
|
||||
&Layout::RecursivePointer,
|
||||
)
|
||||
} else if field_layout.contains_refcounted() {
|
||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||
.unwrap();
|
||||
|
||||
let field_value = if field_layout.is_passed_by_reference(env.target_info) {
|
||||
field_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(field_ptr, "field_value")
|
||||
};
|
||||
let field_value =
|
||||
if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
field_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(field_ptr, "field_value")
|
||||
};
|
||||
|
||||
modify_refcount_layout_help(
|
||||
env,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue