Merge branch 'trunk' into mfonism/rename-num-float-type-to-frac

This commit is contained in:
Richard Feldman 2022-05-08 20:54:33 -04:00 committed by GitHub
commit df7df4ccf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
96 changed files with 4357 additions and 1433 deletions

View file

@ -68,6 +68,8 @@ use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, Unio
use roc_target::{PtrWidth, TargetInfo};
use target_lexicon::{Architecture, OperatingSystem, Triple};
use super::convert::zig_with_overflow_roc_dec;
#[inline(always)]
fn print_fn_verification_output() -> bool {
dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, {
@ -5246,6 +5248,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
argument_layouts,
Layout::Builtin(Builtin::Bool),
);
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
}
_ => unreachable!("invalid list layout"),
@ -5368,7 +5371,17 @@ fn run_low_level<'a, 'ctx, 'env>(
let string = load_symbol(scope, &args[0]);
call_bitcode_fn(env, &[string], intrinsic)
let result = call_bitcode_fn(env, &[string], intrinsic);
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast
let expected_type = basic_type_from_layout(env, layout);
let actual_type = result.get_type();
if expected_type != actual_type {
complex_bitcast_check_size(env, result, expected_type, "str_to_num_cast")
} else {
result
}
}
StrFromInt => {
// Str.fromInt : Int -> Str
@ -7054,6 +7067,76 @@ fn build_float_binop<'a, 'ctx, 'env>(
}
}
fn dec_binop_with_overflow<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> StructValue<'ctx> {
let lhs = lhs.into_int_value();
let rhs = rhs.into_int_value();
let return_type = zig_with_overflow_roc_dec(env);
let return_alloca = env.builder.build_alloca(return_type, "return_alloca");
let int_64 = env.context.i128_type().const_int(64, false);
let int_64_type = env.context.i64_type();
let lhs1 = env
.builder
.build_right_shift(lhs, int_64, false, "lhs_left_bits");
let rhs1 = env
.builder
.build_right_shift(rhs, int_64, false, "rhs_left_bits");
call_void_bitcode_fn(
env,
&[
return_alloca.into(),
env.builder.build_int_cast(lhs, int_64_type, "").into(),
env.builder.build_int_cast(lhs1, int_64_type, "").into(),
env.builder.build_int_cast(rhs, int_64_type, "").into(),
env.builder.build_int_cast(rhs1, int_64_type, "").into(),
],
fn_name,
);
env.builder
.build_load(return_alloca, "load_dec")
.into_struct_value()
}
pub fn dec_binop_with_unchecked<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let lhs = lhs.into_int_value();
let rhs = rhs.into_int_value();
let int_64 = env.context.i128_type().const_int(64, false);
let int_64_type = env.context.i64_type();
let lhs1 = env
.builder
.build_right_shift(lhs, int_64, false, "lhs_left_bits");
let rhs1 = env
.builder
.build_right_shift(rhs, int_64, false, "rhs_left_bits");
call_bitcode_fn(
env,
&[
env.builder.build_int_cast(lhs, int_64_type, "").into(),
env.builder.build_int_cast(lhs1, int_64_type, "").into(),
env.builder.build_int_cast(rhs, int_64_type, "").into(),
env.builder.build_int_cast(rhs1, int_64_type, "").into(),
],
fn_name,
)
}
fn build_dec_binop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
@ -7093,7 +7176,7 @@ fn build_dec_binop<'a, 'ctx, 'env>(
rhs,
"decimal multiplication overflowed",
),
NumDivUnchecked => call_bitcode_fn(env, &[lhs, rhs], bitcode::DEC_DIV),
NumDivUnchecked => dec_binop_with_unchecked(env, bitcode::DEC_DIV, lhs, rhs),
_ => {
unreachable!("Unrecognized int binary operation: {:?}", op);
}
@ -7108,15 +7191,7 @@ fn build_dec_binop_throw_on_overflow<'a, 'ctx, 'env>(
rhs: BasicValueEnum<'ctx>,
message: &str,
) -> BasicValueEnum<'ctx> {
let overflow_type = crate::llvm::convert::zig_with_overflow_roc_dec(env);
let result_ptr = env.builder.build_alloca(overflow_type, "result_ptr");
call_void_bitcode_fn(env, &[result_ptr.into(), lhs, rhs], operation);
let result = env
.builder
.build_load(result_ptr, "load_overflow")
.into_struct_value();
let result = dec_binop_with_overflow(env, operation, lhs, rhs);
let value = throw_on_overflow(env, parent, result, message).into_struct_value();
@ -7211,6 +7286,9 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|| // Or if the two types are the same, they trivially fit.
arg_width == target_int_width;
let return_type =
convert::basic_type_from_layout(env, return_layout).into_struct_type();
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.
@ -7225,8 +7303,6 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
)
.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")
@ -7249,7 +7325,14 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
&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)
let result = call_bitcode_fn_fixing_for_convention(
env,
&[arg.into()],
return_layout,
bitcode_fn,
);
complex_bitcast_check_size(env, result, return_type.into(), "cast_bitpacked")
}
}
_ => {

View file

@ -283,6 +283,8 @@ pub fn dict_get<'a, 'ctx, 'env>(
.ptr_int()
.const_int(value_layout.stack_size(env.target_info) as u64, false);
let value_bt = basic_type_from_layout(env, value_layout);
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
let alignment_iv = alignment.as_int_value(env.context);
@ -308,17 +310,26 @@ pub fn dict_get<'a, 'ctx, 'env>(
)
.into_struct_value();
let flag = env
let flag_u8 = env
.builder
.build_extract_value(result, 1, "get_flag")
.unwrap()
.into_int_value();
let flag = env
.builder
.build_int_cast(flag_u8, env.context.bool_type(), "to_bool");
let value_u8_ptr_int = env
.builder
.build_extract_value(result, 0, "get_value_ptr_int")
.unwrap()
.into_int_value();
let ptr_type = value_bt.ptr_type(AddressSpace::Generic);
let value_u8_ptr = env
.builder
.build_extract_value(result, 0, "get_value_ptr")
.unwrap()
.into_pointer_value();
.build_int_to_ptr(value_u8_ptr_int, ptr_type, "opaque_value_ptr");
let start_block = env.builder.get_insert_block().unwrap();
let parent = start_block.get_parent().unwrap();
@ -326,7 +337,6 @@ pub fn dict_get<'a, 'ctx, 'env>(
let if_not_null = env.context.append_basic_block(parent, "if_not_null");
let done_block = env.context.append_basic_block(parent, "done");
let value_bt = basic_type_from_layout(env, value_layout);
let default = value_bt.const_zero();
env.builder

View file

@ -494,7 +494,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
layout_width(env, element_layout),
layout_width(env, function_call_return_layout),
layout_width(env, default_layout),
has_tag_id.as_global_value().as_pointer_value().into(),
has_tag_id_helper(env, has_tag_id).into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
pass_as_opaque(env, result_ptr),
],
@ -603,6 +603,30 @@ fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx>
BasicValueEnum::StructValue(struct_type.const_zero())
}
fn has_tag_id_helper<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
has_tag_id: FunctionValue<'ctx>,
) -> PointerValue<'ctx> {
let u8_t = env.context.i8_type();
let u16_t = env.context.i16_type();
let u8_ptr_t = u8_t.ptr_type(AddressSpace::Generic);
let struct_t = env
.context
.struct_type(&[u8_t.into(), env.ptr_int().into()], false);
let has_tag_id_type = struct_t
.fn_type(&[u16_t.into(), u8_ptr_t.into()], false)
.ptr_type(AddressSpace::Generic);
env.builder.build_pointer_cast(
has_tag_id.as_global_value().as_pointer_value(),
has_tag_id_type,
"has_tag_id_cast",
)
}
/// List.keepOks : List before, (before -> Result after *) -> List after
pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -626,7 +650,7 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
let has_tag_id = match result_layout {
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
Layout::Builtin(Builtin::Bool) => {
// a `Result [] whatever`, so there is nothing to keep
// a `Result whatever []`, so there is nothing to keep
return empty_list(env);
}
_ => unreachable!(),
@ -644,7 +668,7 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
layout_width(env, before_layout),
layout_width(env, result_layout),
layout_width(env, after_layout),
has_tag_id.as_global_value().as_pointer_value().into(),
has_tag_id_helper(env, has_tag_id).into(),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_KEEP_OKS,
@ -692,7 +716,7 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
layout_width(env, before_layout),
layout_width(env, result_layout),
layout_width(env, after_layout),
has_tag_id.as_global_value().as_pointer_value().into(),
has_tag_id_helper(env, has_tag_id).into(),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_KEEP_ERRS,
@ -968,7 +992,6 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
@ -982,18 +1005,22 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
// in the Zig definition called above, because we don't know the size of the
// element until user compile time, which is later than the compile time of bitcode defs.
let value_u8_ptr = env
let value_u8_ptr_int = env
.builder
.build_extract_value(result, 0, "get_value_ptr")
.build_extract_value(result, 0, "get_value_ptr_int")
.unwrap()
.into_pointer_value();
.into_int_value();
let found = env
let found_u8 = env
.builder
.build_extract_value(result, 1, "get_found")
.unwrap()
.into_int_value();
let found = env
.builder
.build_int_cast(found_u8, env.context.bool_type(), "found_as_bool");
let start_block = env.builder.get_insert_block().unwrap();
let parent = start_block.get_parent().unwrap();
@ -1007,14 +1034,13 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
.build_conditional_branch(found, if_not_null, done_block);
env.builder.position_at_end(if_not_null);
let value_ptr = env
.builder
.build_bitcast(
value_u8_ptr,
value_bt.ptr_type(AddressSpace::Generic),
"from_opaque",
)
.into_pointer_value();
let value_ptr = env.builder.build_int_to_ptr(
value_u8_ptr_int,
value_bt.ptr_type(AddressSpace::Generic),
"get_value_ptr",
);
let loaded = env.builder.build_load(value_ptr, "load_value");
env.builder.build_unconditional_branch(done_block);

View file

@ -1,5 +1,5 @@
use crate::llvm::bitcode::{call_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::build::{complex_bitcast, Env, Scope};
use crate::llvm::build::{Env, Scope};
use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list};
use inkwell::builder::Builder;
use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue};
@ -155,16 +155,22 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>(
let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap();
let result_ptr = builder.build_alloca(result_type, "alloca_utf8_validate_bytes_result");
let count = env
.builder
.build_extract_value(count_and_start, 0, "get_count")
.unwrap();
let start = env
.builder
.build_extract_value(count_and_start, 1, "get_start")
.unwrap();
call_void_bitcode_fn(
env,
&[
list_symbol_to_c_abi(env, scope, list).into(),
complex_bitcast(
env.builder,
count_and_start.into(),
env.twice_ptr_int().into(),
"to_i128",
),
count,
start,
result_ptr.into(),
],
bitcode::STR_FROM_UTF8_RANGE,

View file

@ -1,4 +1,3 @@
use crate::llvm::bitcode::call_bitcode_fn;
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
use crate::llvm::build_list::{list_len, load_list_ptr};
use crate::llvm::build_str::str_equal;
@ -14,7 +13,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use super::build::{load_roc_value, use_roc_value};
use super::build::{dec_binop_with_unchecked, load_roc_value, use_roc_value};
use super::convert::argument_type_from_union_layout;
#[derive(Clone, Debug)]
@ -124,7 +123,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
}
Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"),
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_EQ),
Builtin::Decimal => dec_binop_with_unchecked(env, bitcode::DEC_EQ, lhs_val, rhs_val),
Builtin::Str => str_equal(env, lhs_val, rhs_val),
Builtin::List(elem) => build_list_eq(
@ -289,7 +288,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
}
Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"),
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_NEQ),
Builtin::Decimal => dec_binop_with_unchecked(env, bitcode::DEC_NEQ, lhs_val, rhs_val),
Builtin::Str => {
let is_equal = str_equal(env, lhs_val, rhs_val).into_int_value();

View file

@ -273,7 +273,10 @@ pub fn zig_str_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ct
}
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
env.module.get_struct_type("list.HasTagId").unwrap()
let u8_ptr_t = env.context.i8_type().ptr_type(AddressSpace::Generic);
env.context
.struct_type(&[env.context.bool_type().into(), u8_ptr_t.into()], false)
}
pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {