mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Merge remote-tracking branch 'origin/main' into windows-c-calling-convention
This commit is contained in:
commit
8175e3a9e2
58 changed files with 2011 additions and 795 deletions
|
@ -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 = match env.target_info.operating_system {
|
||||
roc_target::OperatingSystem::Windows => return_size >= env.target_info.ptr_width() as u32,
|
||||
roc_target::OperatingSystem::Unix => return_size > 2 * env.target_info.ptr_width() as u32,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue