Merge remote-tracking branch 'origin/trunk' into gui-example

This commit is contained in:
Richard Feldman 2022-02-23 21:24:27 -05:00
commit 655373dbe7
No known key found for this signature in database
GPG key ID: 7E4127D1E4241798
281 changed files with 11678 additions and 5539 deletions

View file

@ -1,7 +1,8 @@
/// Helpers for interacting with the zig that generates bitcode
use crate::debug_info_init;
use crate::llvm::build::{
load_roc_value, struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX,
complex_bitcast_check_size, load_roc_value, struct_from_fields, to_cc_return, CCReturn, Env,
C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX,
};
use crate::llvm::convert::basic_type_from_layout;
use crate::llvm::refcounting::{
@ -11,9 +12,12 @@ use inkwell::attributes::{Attribute, AttributeLoc};
use inkwell::types::{BasicType, BasicTypeEnum};
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue};
use inkwell::AddressSpace;
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::layout::{LambdaSet, Layout, LayoutIds, UnionLayout};
use std::convert::TryInto;
pub fn call_bitcode_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
@ -30,6 +34,38 @@ pub fn call_bitcode_fn<'a, 'ctx, 'env>(
})
}
pub fn call_list_bitcode_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_help(env, args, fn_name)
.try_as_basic_value()
.left()
.unwrap_or_else(|| {
panic!(
"LLVM error: Did not get return value from bitcode function {:?}",
fn_name
)
})
}
pub fn call_str_bitcode_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_help(env, args, fn_name)
.try_as_basic_value()
.left()
.unwrap_or_else(|| {
panic!(
"LLVM error: Did not get return value from bitcode function {:?}",
fn_name
)
})
}
pub fn call_void_bitcode_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
@ -60,6 +96,63 @@ fn call_bitcode_fn_help<'a, 'ctx, 'env>(
call
}
pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
return_layout: &Layout<'_>,
fn_name: &str,
) -> BasicValueEnum<'ctx> {
// Calling zig bitcode, so we must follow C calling conventions.
let cc_return = to_cc_return(env, return_layout);
match cc_return {
CCReturn::Return => {
// We'll get a return value
call_bitcode_fn(env, args, fn_name)
}
CCReturn::ByPointer => {
// We need to pass the return value by pointer.
let roc_return_type = basic_type_from_layout(env, return_layout);
let cc_ptr_return_type = env
.module
.get_function(fn_name)
.unwrap()
.get_type()
.get_param_types()[0]
.into_pointer_type();
let cc_return_type: BasicTypeEnum<'ctx> = cc_ptr_return_type
.get_element_type()
.try_into()
.expect("Zig bitcode return type is not a basic type!");
let cc_return_value_ptr = env.builder.build_alloca(cc_return_type, "return_value");
let fixed_args: Vec<BasicValueEnum<'ctx>> = [cc_return_value_ptr.into()]
.iter()
.chain(args)
.copied()
.collect();
call_void_bitcode_fn(env, &fixed_args, fn_name);
let cc_return_value = env.builder.build_load(cc_return_value_ptr, "read_result");
if roc_return_type.size_of() == cc_return_type.size_of() {
cc_return_value
} else {
// We need to convert the C-callconv return type, which may be larger than the Roc
// return type, into the Roc return type.
complex_bitcast_check_size(
env,
cc_return_value,
roc_return_type,
"c_value_to_roc_value",
)
}
}
CCReturn::Void => {
internal_error!("Tried to call valued bitcode function, but it has no return type")
}
}
}
const ARGUMENT_SYMBOLS: [Symbol; 8] = [
Symbol::ARG_1,
Symbol::ARG_2,
@ -281,7 +374,9 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
}
match closure_data_layout.runtime_representation() {
Layout::Struct(&[]) => {
Layout::Struct {
field_layouts: &[], ..
} => {
// nothing to add
}
other => {
@ -601,7 +696,9 @@ 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(&[]) => {
Layout::Struct {
field_layouts: &[], ..
} => {
// nothing to add
&default
}

View file

@ -1,7 +1,9 @@
use std::convert::TryFrom;
use std::path::Path;
use crate::llvm::bitcode::{call_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::bitcode::{
call_bitcode_fn, call_bitcode_fn_fixing_for_convention, call_void_bitcode_fn,
};
use crate::llvm::build_dict::{
self, dict_contains, dict_difference, dict_empty, dict_get, dict_insert, dict_intersection,
dict_keys, dict_len, dict_remove, dict_union, dict_values, dict_walk, set_from_list,
@ -53,7 +55,7 @@ use morphic_lib::{
CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar,
};
use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName};
use roc_builtins::{float_intrinsic, int_intrinsic};
use roc_builtins::{float_intrinsic, llvm_int_intrinsic};
use roc_collections::all::{ImMap, MutMap, MutSet};
use roc_error_macros::internal_error;
use roc_module::low_level::LowLevel;
@ -609,14 +611,14 @@ static LLVM_SETJMP: &str = "llvm.eh.sjlj.setjmp";
pub static LLVM_LONGJMP: &str = "llvm.eh.sjlj.longjmp";
const LLVM_ADD_WITH_OVERFLOW: IntrinsicName =
int_intrinsic!("llvm.sadd.with.overflow", "llvm.uadd.with.overflow");
llvm_int_intrinsic!("llvm.sadd.with.overflow", "llvm.uadd.with.overflow");
const LLVM_SUB_WITH_OVERFLOW: IntrinsicName =
int_intrinsic!("llvm.ssub.with.overflow", "llvm.usub.with.overflow");
llvm_int_intrinsic!("llvm.ssub.with.overflow", "llvm.usub.with.overflow");
const LLVM_MUL_WITH_OVERFLOW: IntrinsicName =
int_intrinsic!("llvm.smul.with.overflow", "llvm.umul.with.overflow");
llvm_int_intrinsic!("llvm.smul.with.overflow", "llvm.umul.with.overflow");
const LLVM_ADD_SATURATED: IntrinsicName = int_intrinsic!("llvm.sadd.sat", "llvm.uadd.sat");
const LLVM_SUB_SATURATED: IntrinsicName = int_intrinsic!("llvm.ssub.sat", "llvm.usub.sat");
const LLVM_ADD_SATURATED: IntrinsicName = llvm_int_intrinsic!("llvm.sadd.sat", "llvm.uadd.sat");
const LLVM_SUB_SATURATED: IntrinsicName = llvm_int_intrinsic!("llvm.ssub.sat", "llvm.usub.sat");
fn add_intrinsic<'ctx>(
module: &Module<'ctx>,
@ -712,8 +714,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
);
// NOTE fake layout; it is only used for debug prints
let roc_main_fn =
function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::Struct(&[]));
let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::UNIT);
let main_fn_name = "$Test.main";
@ -1186,8 +1187,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
// extract field from a record
match (value, layout) {
(StructValue(argument), Layout::Struct(fields)) => {
debug_assert!(!fields.is_empty());
(StructValue(argument), Layout::Struct { field_layouts, .. }) => {
debug_assert!(!field_layouts.is_empty());
let field_value = env
.builder
@ -1199,14 +1200,14 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
)
.unwrap();
let field_layout = fields[*index as usize];
let field_layout = field_layouts[*index as usize];
use_roc_value(env, field_layout, field_value, "struct_field_tag")
}
(
PointerValue(argument),
Layout::Union(UnionLayout::NonNullableUnwrapped(fields)),
) => {
let struct_layout = Layout::Struct(fields);
let struct_layout = Layout::struct_no_name_order(fields);
let struct_type = basic_type_from_layout(env, &struct_layout);
let cast_argument = env
@ -1290,7 +1291,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
)
}
UnionLayout::NonNullableUnwrapped(field_layouts) => {
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let struct_type = basic_type_from_layout(env, &struct_layout);
@ -1339,7 +1340,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
debug_assert_ne!(*tag_id != 0, *nullable_id);
let field_layouts = other_fields;
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let struct_type = basic_type_from_layout(env, &struct_layout);
@ -2022,7 +2023,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let struct_type = basic_type_from_layout(env, &struct_layout);
let wrapper_type = env
@ -2921,7 +2922,7 @@ pub fn complex_bitcast<'ctx>(
/// Check the size of the input and output types. Pretending we have more bytes at a pointer than
/// we actually do can lead to faulty optimizations and weird segfaults/crashes
fn complex_bitcast_check_size<'a, 'ctx, 'env>(
pub fn complex_bitcast_check_size<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
@ -3520,7 +3521,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
call_roc_function(
env,
roc_wrapper_function,
&Layout::Struct(&[Layout::u64(), return_layout]),
&Layout::struct_no_name_order(&[Layout::u64(), return_layout]),
arguments_for_call,
)
};
@ -3600,11 +3601,14 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
let param_types = Vec::from_iter_in(roc_function.get_type().get_param_types(), env.arena);
// drop the "return pointer" if it exists on the roc function
// and the c function does not return via pointer
let param_types = match (&roc_return, &cc_return) {
(RocReturn::ByPointer, CCReturn::Return) => &param_types[1..],
_ => &param_types,
let (params, param_types) = match (&roc_return, &cc_return) {
// Drop the "return pointer" if it exists on the roc function
// and the c function does not return via pointer
(RocReturn::ByPointer, CCReturn::Return) => (&params[..], &param_types[1..]),
// Drop the return pointer the other way, if the C function returns by pointer but Roc
// doesn't
(RocReturn::Return, CCReturn::ByPointer) => (&params[1..], &param_types[..]),
_ => (&params[..], &param_types[..]),
};
debug_assert!(
@ -3903,7 +3907,7 @@ fn roc_result_layout<'a>(
) -> Layout<'a> {
let elements = [Layout::u64(), Layout::usize(target_info), return_layout];
Layout::Struct(arena.alloc(elements))
Layout::struct_no_name_order(arena.alloc(elements))
}
fn roc_result_type<'a, 'ctx, 'env>(
@ -4075,7 +4079,13 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>(
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, None);
let mod_solutions = build_procedures_help(
env,
opt_level,
procedures,
entry_point,
Some(Path::new("/tmp/test.ll")),
);
promote_to_main_function(env, mod_solutions, entry_point.symbol, entry_point.layout)
}
@ -5016,7 +5026,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
}
}
ListMapWithIndex { xs } => {
// List.mapWithIndex : List before, (Nat, before -> after) -> List after
// List.mapWithIndex : List before, (before, Nat -> after) -> List after
let (list, list_layout) = load_symbol_and_layout(scope, xs);
let (function, closure, closure_layout) = function_details!();
@ -5026,7 +5036,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_layout)),
) => {
let argument_layouts = &[Layout::usize(env.target_info), **element_layout];
let argument_layouts = &[**element_layout, Layout::usize(env.target_info)];
let roc_function_call = roc_function_call(
env,
@ -5357,7 +5367,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let (string, _string_layout) = load_symbol_and_layout(scope, &args[0]);
let number_layout = match layout {
Layout::Struct(fields) => fields[0], // TODO: why is it sometimes a struct?
Layout::Struct { field_layouts, .. } => field_layouts[0], // TODO: why is it sometimes a struct?
_ => unreachable!(),
};
@ -5486,13 +5496,13 @@ fn run_low_level<'a, 'ctx, 'env>(
list_single(env, arg, arg_layout)
}
ListRepeat => {
// List.repeat : Int, elem -> List elem
// List.repeat : elem, Nat -> List elem
debug_assert_eq!(args.len(), 2);
let list_len = load_symbol(scope, &args[0]).into_int_value();
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[0]);
let list_len = load_symbol(scope, &args[1]).into_int_value();
list_repeat(env, layout_ids, list_len, elem, elem_layout)
list_repeat(env, layout_ids, elem, elem_layout, list_len)
}
ListReverse => {
// List.reverse : List elem -> List elem
@ -5682,7 +5692,8 @@ fn run_low_level<'a, 'ctx, 'env>(
}
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
| NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin => {
| NumCeiling | NumFloor | NumToFloat | NumIsFinite | NumAtan | NumAcos | NumAsin
| NumToIntChecked => {
debug_assert_eq!(args.len(), 1);
let (arg, arg_layout) = load_symbol_and_layout(scope, &args[0]);
@ -5694,7 +5705,14 @@ fn run_low_level<'a, 'ctx, 'env>(
match arg_builtin {
Int(int_width) => {
let int_type = convert::int_type_from_int_width(env, *int_width);
build_int_unary_op(env, arg.into_int_value(), int_type, op)
build_int_unary_op(
env,
arg.into_int_value(),
*int_width,
int_type,
op,
layout,
)
}
Float(float_width) => build_float_unary_op(
env,
@ -6188,7 +6206,7 @@ impl RocReturn {
}
#[derive(Debug)]
enum CCReturn {
pub enum CCReturn {
/// Return as normal
Return,
/// require an extra argument, a pointer
@ -6230,7 +6248,7 @@ impl CCReturn {
}
/// According to the C ABI, how should we return a value with the given layout?
fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn {
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 pass_result_by_pointer = return_size > 2 * env.target_info.ptr_width() as u32;
@ -6924,8 +6942,10 @@ fn int_type_signed_min(int_type: IntType) -> IntValue {
fn build_int_unary_op<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
arg: IntValue<'ctx>,
int_type: IntType<'ctx>,
arg_width: IntWidth,
arg_int_type: IntType<'ctx>,
op: LowLevel,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
use roc_module::low_level::LowLevel::*;
@ -6934,22 +6954,98 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
match op {
NumNeg => {
// integer abs overflows when applied to the minimum value of a signed type
int_neg_raise_on_overflow(env, arg, int_type)
int_neg_raise_on_overflow(env, arg, arg_int_type)
}
NumAbs => {
// integer abs overflows when applied to the minimum value of a signed type
int_abs_raise_on_overflow(env, arg, int_type)
int_abs_raise_on_overflow(env, arg, arg_int_type)
}
NumToFloat => {
// TODO: Handle different sized numbers
// This is an Int, so we need to convert it.
let target_float_type = match return_layout {
Layout::Builtin(Builtin::Float(float_width)) => {
convert::float_type_from_float_width(env, *float_width)
}
_ => internal_error!("There can only be floats here!"),
};
bd.build_cast(
InstructionOpcode::SIToFP,
arg,
env.context.f64_type(),
target_float_type,
"i64_to_f64",
)
}
NumToIntChecked => {
// return_layout : Result N [ OutOfBounds ]* ~ { result: N, out_of_bounds: bool }
let target_int_width = match return_layout {
Layout::Struct { field_layouts, .. } if field_layouts.len() == 2 => {
debug_assert!(matches!(field_layouts[1], Layout::Builtin(Builtin::Bool)));
match field_layouts[0] {
Layout::Builtin(Builtin::Int(iw)) => iw,
layout => internal_error!(
"There can only be an int layout here, found {:?}!",
layout
),
}
}
layout => internal_error!(
"There can only be a result layout here, found {:?}!",
layout
),
};
let arg_always_fits_in_target = (arg_width.stack_size() < target_int_width.stack_size()
&& (
// If the arg is unsigned, it will always fit in either a signed or unsigned
// int of a larger width.
!arg_width.is_signed()
||
// Otherwise if the arg is signed, it will always fit in a signed int of a
// larger width.
(target_int_width.is_signed() )
) )
|| // Or if the two types are the same, they trivially fit.
arg_width == target_int_width;
if arg_always_fits_in_target {
// This is guaranteed to succeed so we can just make it an int cast and let LLVM
// optimize it away.
let target_int_type = convert::int_type_from_int_width(env, target_int_width);
let target_int_val: BasicValueEnum<'ctx> = env
.builder
.build_int_cast(arg, target_int_type, "int_cast")
.into();
let return_type =
convert::basic_type_from_layout(env, return_layout).into_struct_type();
let r = return_type.const_zero();
let r = bd
.build_insert_value(r, target_int_val, 0, "converted_int")
.unwrap();
let r = bd
.build_insert_value(r, env.context.bool_type().const_zero(), 1, "out_of_bounds")
.unwrap();
r.into_struct_value().into()
} else {
let bitcode_fn = if !arg_width.is_signed() {
// We are trying to convert from unsigned to signed/unsigned of same or lesser width, e.g.
// u16 -> i16, u16 -> i8, or u16 -> u8. We only need to check that the argument
// value fits in the MAX target type value.
&bitcode::NUM_INT_TO_INT_CHECKING_MAX[target_int_width][arg_width]
} else {
// We are trying to convert from signed to signed/unsigned of same or lesser width, e.g.
// i16 -> u16, i16 -> i8, or i16 -> u8. We need to check that the argument value fits in
// the MAX and MIN target type.
&bitcode::NUM_INT_TO_INT_CHECKING_MAX_AND_MIN[target_int_width][arg_width]
};
call_bitcode_fn_fixing_for_convention(env, &[arg.into()], return_layout, bitcode_fn)
}
}
_ => {
unreachable!("Unrecognized int unary operation: {:?}", op);
}

View file

@ -735,8 +735,7 @@ pub fn set_from_list<'a, 'ctx, 'env>(
let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca");
let alignment =
Alignment::from_key_value_layout(key_layout, &Layout::Struct(&[]), env.target_info);
let alignment = Alignment::from_key_value_layout(key_layout, &Layout::UNIT, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);

View file

@ -50,10 +50,10 @@ fn build_hash_layout<'a, 'ctx, 'env>(
hash_builtin(env, layout_ids, seed, val, layout, builtin, when_recursive)
}
Layout::Struct(fields) => build_hash_struct(
Layout::Struct { field_layouts, .. } => build_hash_struct(
env,
layout_ids,
fields,
field_layouts,
when_recursive,
seed,
val.into_struct_value(),
@ -166,7 +166,7 @@ fn build_hash_struct<'a, 'ctx, 'env>(
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let symbol = Symbol::GENERIC_HASH;
let fn_name = layout_ids
@ -248,7 +248,7 @@ fn hash_struct<'a, 'ctx, 'env>(
) -> IntValue<'ctx> {
let ptr_bytes = env.target_info;
let layout = Layout::Struct(field_layouts);
let layout = Layout::struct_no_name_order(field_layouts);
// Optimization: if the bit representation of equal values is the same
// just hash the bits. Caveat here is tags: e.g. `Nothing` in `Just a`
@ -818,7 +818,7 @@ fn hash_ptr_to_struct<'a, 'ctx, 'env>(
.build_struct_gep(wrapper_ptr, TAG_DATA_INDEX, "get_tag_data")
.unwrap();
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let struct_type = basic_type_from_layout(env, &struct_layout);
let struct_ptr = env
.builder

View file

@ -1,7 +1,7 @@
#![allow(clippy::too_many_arguments)]
use crate::llvm::bitcode::{
build_dec_wrapper, build_eq_wrapper, build_has_tag_id, build_inc_n_wrapper, build_inc_wrapper,
call_bitcode_fn, call_void_bitcode_fn,
call_bitcode_fn, call_list_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::build::{
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, RocFunctionCall,
@ -29,29 +29,6 @@ pub fn pass_update_mode<'a, 'ctx, 'env>(
}
}
fn list_returned_from_zig<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
output: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
// per the C ABI, our list objects are passed between functions as an i128/i64
complex_bitcast(
env.builder,
output,
super::convert::zig_list_type(env).into(),
"from_str_list_int",
)
}
pub fn call_bitcode_fn_returns_list<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
let value = call_bitcode_fn(env, args, fn_name);
list_returned_from_zig(env, value)
}
fn pass_element_as_opaque<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
element: BasicValueEnum<'ctx>,
@ -108,7 +85,7 @@ pub fn list_single<'a, 'ctx, 'env>(
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
env.alignment_intvalue(element_layout),
@ -119,17 +96,17 @@ pub fn list_single<'a, 'ctx, 'env>(
)
}
/// List.repeat : Int, elem -> List elem
/// List.repeat : elem, Nat -> List elem
pub fn list_repeat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
list_len: IntValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
list_len: IntValue<'ctx>,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_n_wrapper(env, layout_ids, element_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
list_len.into(),
@ -148,7 +125,7 @@ pub fn list_join<'a, 'ctx, 'env>(
outer_list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, outer_list),
@ -166,7 +143,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
@ -213,7 +190,7 @@ pub fn list_append<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
@ -233,7 +210,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
@ -254,7 +231,7 @@ pub fn list_swap<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
@ -278,7 +255,7 @@ pub fn list_sublist<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
@ -301,7 +278,7 @@ pub fn list_drop_at<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
@ -543,7 +520,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
@ -672,7 +649,7 @@ pub fn list_sort_with<'a, 'ctx, 'env>(
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
@ -687,7 +664,7 @@ pub fn list_sort_with<'a, 'ctx, 'env>(
)
}
/// List.mapWithIndex : List before, (Nat, before -> after) -> List after
/// List.mapWithIndex : List before, (before, Nat -> after) -> List after
pub fn list_map_with_index<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
roc_function_call: RocFunctionCall<'ctx>,
@ -695,7 +672,7 @@ pub fn list_map_with_index<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
@ -719,7 +696,7 @@ pub fn list_map<'a, 'ctx, 'env>(
element_layout: &Layout<'a>,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
@ -784,7 +761,7 @@ pub fn list_map3<'a, 'ctx, 'env>(
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list1),
@ -826,7 +803,7 @@ pub fn list_map4<'a, 'ctx, 'env>(
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
let dec_d = build_dec_wrapper(env, layout_ids, element4_layout);
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list1),
@ -859,7 +836,7 @@ pub fn list_concat<'a, 'ctx, 'env>(
second_list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, first_list),

View file

@ -1,8 +1,8 @@
use crate::llvm::bitcode::{call_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::build::{complex_bitcast, Env, Scope};
use crate::llvm::build_list::{
allocate_list, call_bitcode_fn_returns_list, pass_update_mode, store_list,
use crate::llvm::bitcode::{
call_bitcode_fn, call_list_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::build::{complex_bitcast, Env, Scope};
use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list};
use inkwell::builder::Builder;
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::AddressSpace;
@ -25,7 +25,7 @@ pub fn str_repeat<'a, 'ctx, 'env>(
) -> BasicValueEnum<'ctx> {
let str_c_abi = str_symbol_to_c_abi(env, scope, str_symbol);
let count = load_symbol(scope, &count_symbol);
call_bitcode_fn(env, &[str_c_abi.into(), count], bitcode::STR_REPEAT)
call_str_bitcode_fn(env, &[str_c_abi.into(), count], bitcode::STR_REPEAT)
}
/// Str.split : Str, Str -> List Str
@ -40,7 +40,7 @@ pub fn str_split<'a, 'ctx, 'env>(
let str_c_abi = str_symbol_to_c_abi(env, scope, str_symbol);
let delim_c_abi = str_symbol_to_c_abi(env, scope, delimiter_symbol);
let segment_count = call_bitcode_fn(
let segment_count = call_list_bitcode_fn(
env,
&[str_c_abi.into(), delim_c_abi.into()],
bitcode::STR_COUNT_SEGMENTS,
@ -140,7 +140,7 @@ pub fn str_concat<'a, 'ctx, 'env>(
let str1_c_abi = str_symbol_to_c_abi(env, scope, str1_symbol);
let str2_c_abi = str_symbol_to_c_abi(env, scope, str2_symbol);
call_bitcode_fn(
call_str_bitcode_fn(
env,
&[str1_c_abi.into(), str2_c_abi.into()],
bitcode::STR_CONCAT,
@ -159,7 +159,7 @@ pub fn str_join_with<'a, 'ctx, 'env>(
let list_i128 = str_symbol_to_c_abi(env, scope, list_symbol);
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_bitcode_fn(
call_str_bitcode_fn(
env,
&[list_i128.into(), str_i128.into()],
bitcode::STR_JOIN_WITH,
@ -255,7 +255,7 @@ pub fn str_trim<'a, 'ctx, 'env>(
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM)
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM)
}
/// Str.trimLeft : Str -> Str
@ -265,7 +265,7 @@ pub fn str_trim_left<'a, 'ctx, 'env>(
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_LEFT)
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_LEFT)
}
/// Str.trimRight : Str -> Str
@ -275,7 +275,7 @@ pub fn str_trim_right<'a, 'ctx, 'env>(
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_RIGHT)
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_RIGHT)
}
/// Str.fromInt : Int -> Str
@ -284,7 +284,7 @@ pub fn str_from_int<'a, 'ctx, 'env>(
value: IntValue<'ctx>,
int_width: IntWidth,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn(env, &[value.into()], &bitcode::STR_FROM_INT[int_width])
call_str_bitcode_fn(env, &[value.into()], &bitcode::STR_FROM_INT[int_width])
}
/// Str.toUtf8 : Str -> List U8
@ -299,7 +299,7 @@ pub fn str_to_utf8<'a, 'ctx, 'env>(
"to_utf8",
);
call_bitcode_fn_returns_list(env, &[string], bitcode::STR_TO_UTF8)
call_list_bitcode_fn(env, &[string], bitcode::STR_TO_UTF8)
}
fn decode_from_utf8_result<'a, 'ctx, 'env>(
@ -411,7 +411,7 @@ pub fn str_from_float<'a, 'ctx, 'env>(
) -> BasicValueEnum<'ctx> {
let float = load_symbol(scope, &int_symbol);
call_bitcode_fn(env, &[float], bitcode::STR_FROM_FLOAT)
call_str_bitcode_fn(env, &[float], bitcode::STR_FROM_FLOAT)
}
/// Str.equal : Str, Str -> Bool

View file

@ -161,10 +161,10 @@ fn build_eq<'a, 'ctx, 'env>(
build_eq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
}
Layout::Struct(fields) => build_struct_eq(
Layout::Struct { field_layouts, .. } => build_struct_eq(
env,
layout_ids,
fields,
field_layouts,
when_recursive,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
@ -330,11 +330,11 @@ fn build_neq<'a, 'ctx, 'env>(
build_neq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
}
Layout::Struct(fields) => {
Layout::Struct { field_layouts, .. } => {
let is_equal = build_struct_eq(
env,
layout_ids,
fields,
field_layouts,
when_recursive,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
@ -587,7 +587,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let symbol = Symbol::GENERIC_EQ;
let fn_name = layout_ids
@ -1208,7 +1208,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
tag1: PointerValue<'ctx>,
tag2: PointerValue<'ctx>,
) -> IntValue<'ctx> {
let struct_layout = Layout::Struct(field_layouts);
let struct_layout = Layout::struct_no_name_order(field_layouts);
let wrapper_type = basic_type_from_layout(env, &struct_layout);
debug_assert!(wrapper_type.is_struct_type());

View file

@ -28,7 +28,10 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
use Layout::*;
match layout {
Struct(sorted_fields) => basic_type_from_record(env, sorted_fields),
Struct {
field_layouts: sorted_fields,
..
} => basic_type_from_record(env, sorted_fields),
LambdaSet(lambda_set) => basic_type_from_layout(env, &lambda_set.runtime_representation()),
Union(union_layout) => {
use UnionLayout::*;
@ -86,7 +89,10 @@ pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
use Layout::*;
match layout {
Struct(sorted_fields) => basic_type_from_record(env, sorted_fields),
Struct {
field_layouts: sorted_fields,
..
} => basic_type_from_record(env, sorted_fields),
LambdaSet(lambda_set) => {
basic_type_from_layout_1(env, &lambda_set.runtime_representation())
}

View file

@ -280,7 +280,7 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let layout = Layout::Struct(layouts);
let layout = Layout::struct_no_name_order(layouts);
let (_, fn_name) = function_name_from_mode(
layout_ids,
@ -440,7 +440,7 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
}
Set(element_layout) => {
let key_layout = element_layout;
let value_layout = &Layout::Struct(&[]);
let value_layout = &Layout::UNIT;
let function = modify_refcount_dict(
env,
@ -619,8 +619,9 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
}
}
Struct(layouts) => {
let function = modify_refcount_struct(env, layout_ids, layouts, mode, when_recursive);
Struct { field_layouts, .. } => {
let function =
modify_refcount_struct(env, layout_ids, field_layouts, mode, when_recursive);
Some(function)
}
@ -1312,7 +1313,8 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
env.builder.position_at_end(block);
let wrapper_type = basic_type_from_layout(env, &Layout::Struct(field_layouts));
let wrapper_type =
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
// cast the opaque pointer to a pointer of the correct shape
let struct_ptr = env
@ -1720,7 +1722,8 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
let block = env.context.append_basic_block(parent, "tag_id_modify");
env.builder.position_at_end(block);
let wrapper_type = basic_type_from_layout(env, &Layout::Struct(field_layouts));
let wrapper_type =
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
debug_assert!(wrapper_type.is_struct_type());
let opaque_tag_data_ptr = env