diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index d39906df19..19da388c9f 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -11,13 +11,13 @@ use crate::llvm::build_list::{ list_set, list_single, list_sort_with, list_walk_help, }; use crate::llvm::build_str::{ - str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, str_from_utf8, - str_join_with, str_number_of_bytes, str_split, str_starts_with, str_to_bytes, + empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, + str_from_utf8, str_join_with, str_number_of_bytes, str_split, str_starts_with, str_to_bytes, }; use crate::llvm::compare::{generic_eq, generic_neq}; use crate::llvm::convert::{ basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices, - collection, get_fn_type, get_ptr_type, ptr_int, + get_fn_type, get_ptr_type, ptr_int, }; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_refcount_layout, refcount_is_one_comparison, @@ -641,12 +641,13 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(), Str(str_literal) => { if str_literal.is_empty() { - empty_list(env) + empty_str(env) } else { let ctx = env.context; let builder = env.builder; let number_of_chars = str_literal.len() as u64; - let ptr_bytes = env.ptr_bytes; + + let str_type = super::convert::zig_str_type(env); if str_literal.len() < env.small_str_bytes() as usize { // TODO support big endian systems @@ -711,7 +712,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( builder .build_bitcast( array_alloca, - collection(ctx, ptr_bytes).ptr_type(AddressSpace::Generic), + str_type.ptr_type(AddressSpace::Generic), "cast_collection", ) .into_pointer_value(), @@ -721,7 +722,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( let ptr = define_global_str_literal_ptr(env, *str_literal); let number_of_elements = env.ptr_int().const_int(number_of_chars, false); - let struct_type = collection(ctx, ptr_bytes); + let struct_type = str_type; let mut struct_val; @@ -747,7 +748,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( builder.build_bitcast( struct_val.into_struct_value(), - collection(ctx, ptr_bytes), + str_type, "cast_collection", ) } @@ -1849,12 +1850,10 @@ fn list_literal<'a, 'ctx, 'env>( builder.build_store(elem_ptr, val); } - let ptr_bytes = env.ptr_bytes; - let u8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic); let generic_ptr = builder.build_bitcast(ptr, u8_ptr_type, "to_generic_ptr"); - let struct_type = collection(ctx, ptr_bytes); + let struct_type = super::convert::zig_list_type(env); let len = BasicValueEnum::IntValue(env.ptr_int().const_int(len_u64, false)); let mut struct_val; @@ -1876,7 +1875,7 @@ fn list_literal<'a, 'ctx, 'env>( // Bitcast to an array of raw bytes builder.build_bitcast( struct_val.into_struct_value(), - collection(ctx, ptr_bytes), + super::convert::zig_list_type(env), "cast_collection", ) } diff --git a/compiler/gen/src/llvm/build_dict.rs b/compiler/gen/src/llvm/build_dict.rs index f7ef5ca3e9..7ef54fd055 100644 --- a/compiler/gen/src/llvm/build_dict.rs +++ b/compiler/gen/src/llvm/build_dict.rs @@ -6,7 +6,7 @@ use crate::llvm::bitcode::{ use crate::llvm::build::{ complex_bitcast, load_symbol, load_symbol_and_layout, set_name, Env, Scope, }; -use crate::llvm::convert::{as_const_zero, basic_type_from_layout, collection}; +use crate::llvm::convert::{as_const_zero, basic_type_from_layout}; use crate::llvm::refcounting::Mode; use inkwell::attributes::{Attribute, AttributeLoc}; use inkwell::types::BasicType; @@ -463,7 +463,7 @@ pub fn dict_keys<'a, 'ctx, 'env>( .builder .build_bitcast( list_ptr, - collection(env.context, env.ptr_bytes).ptr_type(AddressSpace::Generic), + super::convert::zig_list_type(env).ptr_type(AddressSpace::Generic), "to_roc_list", ) .into_pointer_value(); @@ -715,8 +715,8 @@ pub fn dict_values<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { let builder = env.builder; - let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap(); - let zig_list_type = env.module.get_struct_type("list.RocList").unwrap(); + let zig_dict_type = super::convert::zig_dict_type(env); + let zig_list_type = super::convert::zig_list_type(env); let dict_ptr = builder.build_alloca(zig_dict_type, "dict_ptr"); env.builder.build_store(dict_ptr, dict); @@ -753,7 +753,7 @@ pub fn dict_values<'a, 'ctx, 'env>( .builder .build_bitcast( list_ptr, - collection(env.context, env.ptr_bytes).ptr_type(AddressSpace::Generic), + super::convert::zig_list_type(env).ptr_type(AddressSpace::Generic), "to_roc_list", ) .into_pointer_value(); diff --git a/compiler/gen/src/llvm/build_list.rs b/compiler/gen/src/llvm/build_list.rs index 8d05ae309c..c0ecccb3b3 100644 --- a/compiler/gen/src/llvm/build_list.rs +++ b/compiler/gen/src/llvm/build_list.rs @@ -6,7 +6,7 @@ use crate::llvm::bitcode::{ use crate::llvm::build::{ allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, InPlace, }; -use crate::llvm::convert::{basic_type_from_layout, collection, get_ptr_type}; +use crate::llvm::convert::{basic_type_from_layout, get_ptr_type}; use crate::llvm::refcounting::{ increment_refcount_layout, refcount_is_one_comparison, PointerToRefcount, }; @@ -88,7 +88,7 @@ pub fn list_repeat<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -317,7 +317,7 @@ pub fn list_join<'a, 'ctx, 'env>( let build_else = || empty_list(env); - let struct_type = collection(ctx, env.ptr_bytes); + let struct_type = super::convert::zig_list_type(env); build_basic_phi2( env, @@ -377,7 +377,7 @@ pub fn list_reverse<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -464,7 +464,7 @@ pub fn list_append<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -790,7 +790,7 @@ pub fn list_range<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -881,7 +881,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -998,7 +998,7 @@ pub fn list_keep_result<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -1044,7 +1044,7 @@ pub fn list_sort_with<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -1149,7 +1149,7 @@ fn list_map_generic<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -1236,7 +1236,7 @@ pub fn list_map2<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -1340,7 +1340,7 @@ pub fn list_map3<'a, 'ctx, 'env>( complex_bitcast( env.builder, output, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "from_i128", ) } @@ -1405,7 +1405,7 @@ pub fn list_concat<'a, 'ctx, 'env>( second_list_length_comparison, build_second_list_then, build_second_list_else, - BasicTypeEnum::StructType(collection(ctx, env.ptr_bytes)), + BasicTypeEnum::StructType(super::convert::zig_list_type(env)), ) }; @@ -1520,7 +1520,7 @@ pub fn list_concat<'a, 'ctx, 'env>( second_list_length_comparison, if_second_list_is_not_empty, if_second_list_is_empty, - BasicTypeEnum::StructType(collection(ctx, env.ptr_bytes)), + BasicTypeEnum::StructType(super::convert::zig_list_type(env)), ) }; @@ -1530,7 +1530,7 @@ pub fn list_concat<'a, 'ctx, 'env>( first_list_length_comparison, if_first_list_is_not_empty, if_first_list_is_empty, - BasicTypeEnum::StructType(collection(ctx, env.ptr_bytes)), + BasicTypeEnum::StructType(super::convert::zig_list_type(env)), ) } _ => { @@ -1732,9 +1732,7 @@ where } pub fn empty_polymorphic_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> { - let ctx = env.context; - - let struct_type = collection(ctx, env.ptr_bytes); + let struct_type = super::convert::zig_list_type(env); // The pointer should be null (aka zero) and the length should be zero, // so the whole struct should be a const_zero @@ -1743,9 +1741,7 @@ pub fn empty_polymorphic_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> Basi // TODO investigate: does this cause problems when the layout is known? this value is now not refcounted! pub fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> { - let ctx = env.context; - - let struct_type = collection(ctx, env.ptr_bytes); + let struct_type = super::convert::zig_list_type(env); // The pointer should be null (aka zero) and the length should be zero, // so the whole struct should be a const_zero @@ -1832,7 +1828,7 @@ pub fn clone_nonempty_list<'a, 'ctx, 'env>( let u8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic); let generic_ptr = cast_basic_basic(builder, clone_ptr.into(), u8_ptr_type.into()); - let struct_type = collection(ctx, env.ptr_bytes); + let struct_type = super::convert::zig_list_type(env); let mut struct_val; // Store the pointer @@ -1853,7 +1849,7 @@ pub fn clone_nonempty_list<'a, 'ctx, 'env>( let answer = builder .build_bitcast( struct_val.into_struct_value(), - collection(ctx, ptr_bytes), + super::convert::zig_list_type(env), "cast_collection", ) .into_struct_value(); @@ -1924,8 +1920,7 @@ pub fn store_list<'a, 'ctx, 'env>( let ctx = env.context; let builder = env.builder; - let ptr_bytes = env.ptr_bytes; - let struct_type = collection(ctx, ptr_bytes); + let struct_type = super::convert::zig_list_type(env); let u8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic); let generic_ptr = @@ -1950,7 +1945,7 @@ pub fn store_list<'a, 'ctx, 'env>( builder.build_bitcast( struct_val.into_struct_value(), - collection(ctx, ptr_bytes), + super::convert::zig_list_type(env), "cast_collection", ) } diff --git a/compiler/gen/src/llvm/build_str.rs b/compiler/gen/src/llvm/build_str.rs index 514d483c06..79e60bc4ac 100644 --- a/compiler/gen/src/llvm/build_str.rs +++ b/compiler/gen/src/llvm/build_str.rs @@ -1,9 +1,7 @@ use crate::llvm::bitcode::{call_bitcode_fn, call_void_bitcode_fn}; use crate::llvm::build::{complex_bitcast, Env, InPlace, Scope}; use crate::llvm::build_list::{allocate_list, store_list}; -use crate::llvm::convert::collection; use inkwell::builder::Builder; -use inkwell::types::BasicTypeEnum; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue}; use inkwell::AddressSpace; use roc_builtins::bitcode; @@ -90,41 +88,6 @@ pub fn str_to_i128<'a, 'ctx, 'env>( .into_int_value() } -fn zig_str_to_struct<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - zig_str: StructValue<'ctx>, -) -> StructValue<'ctx> { - let builder = env.builder; - - // get the RocStr type defined by zig - let zig_str_type = env.module.get_struct_type("str.RocStr").unwrap(); - - let ret_type = BasicTypeEnum::StructType(collection(env.context, env.ptr_bytes)); - - // a roundabout way of casting (LLVM does not accept a standard bitcast) - let allocation = builder.build_alloca(zig_str_type, "zig_result"); - - builder.build_store(allocation, zig_str); - - let ptr3 = builder - .build_bitcast( - allocation, - env.context.i128_type().ptr_type(AddressSpace::Generic), - "cast", - ) - .into_pointer_value(); - - let ptr4 = builder - .build_bitcast( - ptr3, - ret_type.into_struct_type().ptr_type(AddressSpace::Generic), - "cast", - ) - .into_pointer_value(); - - builder.build_load(ptr4, "load").into_struct_value() -} - pub fn destructure<'ctx>( builder: &Builder<'ctx>, wrapper_struct: StructValue<'ctx>, @@ -155,7 +118,7 @@ pub fn str_concat<'a, 'ctx, 'env>( let str1_i128 = str_symbol_to_i128(env, scope, str1_symbol); let str2_i128 = str_symbol_to_i128(env, scope, str2_symbol); - let zig_result = call_bitcode_fn( + call_bitcode_fn( env, &[ env.context @@ -167,9 +130,6 @@ pub fn str_concat<'a, 'ctx, 'env>( ], &bitcode::STR_CONCAT, ) - .into_struct_value(); - - zig_str_to_struct(env, zig_result).into() } /// Str.join : List Str, Str -> Str @@ -185,14 +145,11 @@ pub fn str_join_with<'a, 'ctx, 'env>( let list_i128 = str_symbol_to_i128(env, scope, list_symbol); let str_i128 = str_symbol_to_i128(env, scope, str_symbol); - let zig_result = call_bitcode_fn( + call_bitcode_fn( env, &[list_i128.into(), str_i128.into()], &bitcode::STR_JOIN_WITH, ) - .into_struct_value(); - - zig_str_to_struct(env, zig_result).into() } pub fn str_number_of_bytes<'a, 'ctx, 'env>( @@ -268,9 +225,7 @@ pub fn str_from_int<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { let int = load_symbol(scope, &int_symbol); - let zig_result = call_bitcode_fn(env, &[int], &bitcode::STR_FROM_INT).into_struct_value(); - - zig_str_to_struct(env, zig_result).into() + call_bitcode_fn(env, &[int], &bitcode::STR_FROM_INT) } /// Str.toBytes : Str -> List U8 @@ -290,7 +245,7 @@ pub fn str_to_bytes<'a, 'ctx, 'env>( complex_bitcast( env.builder, zig_result, - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_list_type(env).into(), "to_bytes", ) } @@ -324,7 +279,7 @@ pub fn str_from_utf8<'a, 'ctx, 'env>( let record_type = env.context.struct_type( &[ env.ptr_int().into(), - collection(env.context, env.ptr_bytes).into(), + super::convert::zig_str_type(env).into(), env.context.bool_type().into(), ctx.i8_type().into(), ], @@ -351,9 +306,7 @@ pub fn str_from_float<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { let float = load_symbol(scope, &int_symbol); - let zig_result = call_bitcode_fn(env, &[float], &bitcode::STR_FROM_FLOAT).into_struct_value(); - - zig_str_to_struct(env, zig_result).into() + call_bitcode_fn(env, &[float], &bitcode::STR_FROM_FLOAT) } /// Str.equal : Str, Str -> Bool @@ -371,3 +324,12 @@ pub fn str_equal<'a, 'ctx, 'env>( &bitcode::STR_EQUAL, ) } + +// TODO investigate: does this cause problems when the layout is known? this value is now not refcounted! +pub fn empty_str<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> { + let struct_type = super::convert::zig_str_type(env); + + // The pointer should be null (aka zero) and the length should be zero, + // so the whole struct should be a const_zero + BasicValueEnum::StructValue(struct_type.const_zero()) +} diff --git a/compiler/gen/src/llvm/convert.rs b/compiler/gen/src/llvm/convert.rs index 4e78b10adc..878805a534 100644 --- a/compiler/gen/src/llvm/convert.rs +++ b/compiler/gen/src/llvm/convert.rs @@ -164,8 +164,6 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>( ) -> BasicTypeEnum<'ctx> { use Builtin::*; - let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap(); - let context = env.context; let ptr_bytes = env.ptr_bytes; @@ -181,10 +179,10 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>( Float64 => context.f64_type().as_basic_type_enum(), Float32 => context.f32_type().as_basic_type_enum(), Float16 => context.f16_type().as_basic_type_enum(), - Dict(_, _) | EmptyDict => zig_dict_type.into(), - Set(_) | EmptySet => zig_dict_type.into(), - List(_, _) | Str | EmptyStr => collection(context, ptr_bytes).into(), - EmptyList => BasicTypeEnum::StructType(collection(context, ptr_bytes)), + Dict(_, _) | EmptyDict => zig_dict_type(env).into(), + Set(_) | EmptySet => zig_dict_type(env).into(), + List(_, _) | EmptyList => zig_list_type(env).into(), + Str | EmptyStr => zig_str_type(env).into(), } } @@ -245,17 +243,6 @@ fn block_of_memory_help(context: &Context, union_size: u32) -> BasicTypeEnum<'_> } } -/// Two usize values. Could be a wrapper for a List or a Str. -/// -/// This way, we always initialize it to (*mut u8, usize), and may have to cast the pointer type -/// for lists. -pub fn collection(ctx: &Context, ptr_bytes: u32) -> StructType<'_> { - let usize_type = ptr_int(ctx, ptr_bytes); - let u8_ptr = ctx.i8_type().ptr_type(AddressSpace::Generic); - - ctx.struct_type(&[u8_ptr.into(), usize_type.into()], false) -} - pub fn ptr_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> { match ptr_bytes { 1 => ctx.i8_type(), @@ -268,3 +255,21 @@ pub fn ptr_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> { ), } } + +pub fn zig_dict_type<'a, 'ctx, 'env>( + env: &crate::llvm::build::Env<'a, 'ctx, 'env>, +) -> StructType<'ctx> { + env.module.get_struct_type("dict.RocDict").unwrap() +} + +pub fn zig_list_type<'a, 'ctx, 'env>( + env: &crate::llvm::build::Env<'a, 'ctx, 'env>, +) -> StructType<'ctx> { + env.module.get_struct_type("list.RocList").unwrap() +} + +pub fn zig_str_type<'a, 'ctx, 'env>( + env: &crate::llvm::build::Env<'a, 'ctx, 'env>, +) -> StructType<'ctx> { + env.module.get_struct_type("str.RocStr").unwrap() +}