From febb5787739c919fea3b7c97416123e73b829177 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 16 May 2021 16:15:27 +0200 Subject: [PATCH 1/4] rework refcount code gen to accept unknown inc values --- compiler/gen/src/llvm/bitcode.rs | 13 +- compiler/gen/src/llvm/refcounting.rs | 301 ++++++++++++++++++++------- 2 files changed, 236 insertions(+), 78 deletions(-) diff --git a/compiler/gen/src/llvm/bitcode.rs b/compiler/gen/src/llvm/bitcode.rs index b80f51375e..4a20cec722 100644 --- a/compiler/gen/src/llvm/bitcode.rs +++ b/compiler/gen/src/llvm/bitcode.rs @@ -204,13 +204,14 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( function_value } -pub fn build_inc_n_wrapper<'a, 'ctx, 'env>( +fn build_inc_n_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, n: u64, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::Inc(n)) + // build_rc_wrapper(env, layout_ids, layout, Mode::Inc(n)) + todo!() } pub fn build_inc_wrapper<'a, 'ctx, 'env>( @@ -218,7 +219,7 @@ pub fn build_inc_wrapper<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::Inc(1)) + build_rc_wrapper(env, layout_ids, layout, Mode::Inc) } pub fn build_dec_wrapper<'a, 'ctx, 'env>( @@ -244,7 +245,7 @@ pub fn build_rc_wrapper<'a, 'ctx, 'env>( .to_symbol_string(symbol, &env.interns); let fn_name = match rc_operation { - Mode::Inc(n) => format!("{}_inc_{}", fn_name, n), + Mode::Inc => format!("{}_inc", fn_name), Mode::Dec => format!("{}_dec", fn_name), }; @@ -285,7 +286,9 @@ pub fn build_rc_wrapper<'a, 'ctx, 'env>( let value = env.builder.build_load(value_cast, "load_opaque"); match rc_operation { - Mode::Inc(n) => { + Mode::Inc => { + // we hardcode the 1 here + let n = 1; increment_refcount_layout(env, function_value, layout_ids, n, value, layout); } Mode::Dec => { diff --git a/compiler/gen/src/llvm/refcounting.rs b/compiler/gen/src/llvm/refcounting.rs index ad6c1d24de..d69ea7b590 100644 --- a/compiler/gen/src/llvm/refcounting.rs +++ b/compiler/gen/src/llvm/refcounting.rs @@ -109,7 +109,7 @@ impl<'ctx> PointerToRefcount<'ctx> { env: &Env<'a, 'ctx, 'env>, ) { match mode { - CallMode::Inc(_, inc_amount) => self.increment(inc_amount, env), + CallMode::Inc(inc_amount) => self.increment(inc_amount, env), CallMode::Dec => self.decrement(env, layout), } } @@ -318,11 +318,84 @@ fn modify_refcount_struct<'a, 'ctx, 'env>( parent: FunctionValue<'ctx>, layout_ids: &mut LayoutIds<'a>, value: BasicValueEnum<'ctx>, - layouts: &[Layout<'a>], + layouts: &'a [Layout<'a>], mode: Mode, when_recursive: &WhenRecursive<'a>, +) -> FunctionValue<'ctx> { + 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 (call_name, fn_name) = function_name_from_mode( + layout_ids, + &env.interns, + "increment_struct", + "decrement_struct", + &layout, + mode, + ); + + let function = match env.module.get_function(fn_name.as_str()) { + Some(function_value) => function_value, + None => { + let basic_type = basic_type_from_layout(env, &layout); + let function_value = build_header(env, basic_type, mode, &fn_name); + + modify_refcount_struct_help( + env, + layout_ids, + mode, + when_recursive, + layouts, + function_value, + ); + + function_value + } + }; + + env.builder.position_at_end(block); + env.builder + .set_current_debug_location(env.context, di_location); + + function +} + +#[allow(clippy::too_many_arguments)] +fn modify_refcount_struct_help<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout_ids: &mut LayoutIds<'a>, + mode: Mode, + when_recursive: &WhenRecursive<'a>, + layouts: &[Layout<'a>], + fn_val: FunctionValue<'ctx>, ) { - let wrapper_struct = value.into_struct_value(); + debug_assert_eq!( + when_recursive, + &WhenRecursive::Unreachable, + "TODO pipe when_recursive through the dict key/value inc/dec" + ); + + let builder = env.builder; + let ctx = env.context; + + // Add a basic block for the entry point + let entry = ctx.append_basic_block(fn_val, "entry"); + + builder.position_at_end(entry); + + debug_info_init!(env, fn_val); + + // Add args to scope + let arg_symbol = Symbol::ARG_1; + let arg_val = fn_val.get_param_iter().next().unwrap(); + + set_name(arg_val, arg_symbol.ident_string(&env.interns)); + + let parent = fn_val; + + let wrapper_struct = arg_val.into_struct_value(); for (i, field_layout) in layouts.iter().enumerate() { if field_layout.contains_refcounted() { @@ -335,13 +408,15 @@ fn modify_refcount_struct<'a, 'ctx, 'env>( env, parent, layout_ids, - mode, + mode.to_call_mode(fn_val), when_recursive, field_ptr, field_layout, ); } } + // this function returns void + builder.build_return(None); } pub fn increment_refcount_layout<'a, 'ctx, 'env>( @@ -352,11 +427,12 @@ pub fn increment_refcount_layout<'a, 'ctx, 'env>( value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { + let amount = env.ptr_int().const_int(inc_amount, false); modify_refcount_layout( env, parent, layout_ids, - Mode::Inc(inc_amount), + CallMode::Inc(amount), value, layout, ); @@ -369,7 +445,7 @@ pub fn decrement_refcount_layout<'a, 'ctx, 'env>( value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { - modify_refcount_layout(env, parent, layout_ids, Mode::Dec, value, layout); + modify_refcount_layout(env, parent, layout_ids, CallMode::Dec, value, layout); } fn modify_refcount_builtin<'a, 'ctx, 'env>( @@ -380,7 +456,7 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( value: BasicValueEnum<'ctx>, layout: &Layout<'a>, builtin: &Builtin<'a>, -) { +) -> Option> { use Builtin::*; match builtin { @@ -388,7 +464,7 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( let wrapper_struct = value.into_struct_value(); if let MemoryMode::Refcounted = memory_mode { - modify_refcount_list( + let function = modify_refcount_list( env, layout_ids, mode, @@ -397,17 +473,19 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( element_layout, wrapper_struct, ); + + Some(function) + } else { + None } } Set(element_layout) => { - if element_layout.contains_refcounted() { - // TODO decrement all values - } - todo!(); - } - Dict(key_layout, value_layout) => { let wrapper_struct = value.into_struct_value(); - modify_refcount_dict( + + let key_layout = &Layout::Struct(&[]); + let value_layout = element_layout; + + let function = modify_refcount_dict( env, layout_ids, mode, @@ -417,14 +495,34 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( value_layout, wrapper_struct, ); + + Some(function) + } + Dict(key_layout, value_layout) => { + let wrapper_struct = value.into_struct_value(); + let function = modify_refcount_dict( + env, + layout_ids, + mode, + when_recursive, + layout, + key_layout, + value_layout, + wrapper_struct, + ); + + Some(function) } Str => { let wrapper_struct = value.into_struct_value(); - modify_refcount_str(env, layout_ids, mode, layout, wrapper_struct); + let function = modify_refcount_str(env, layout_ids, mode, layout, wrapper_struct); + + Some(function) } _ => { debug_assert!(!builtin.is_refcounted()); + None } } } @@ -433,7 +531,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, layout_ids: &mut LayoutIds<'a>, - mode: Mode, + call_mode: CallMode<'ctx>, value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { @@ -441,7 +539,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>( env, parent, layout_ids, - mode, + call_mode, &WhenRecursive::Unreachable, value, layout, @@ -458,11 +556,60 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, layout_ids: &mut LayoutIds<'a>, - mode: Mode, + call_mode: CallMode<'ctx>, when_recursive: &WhenRecursive<'a>, value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { + let mode = match call_mode { + CallMode::Inc(_) => Mode::Inc, + CallMode::Dec => Mode::Dec, + }; + + let function = match modify_refcount_layout_build_function( + env, + parent, + layout_ids, + mode, + when_recursive, + value, + layout, + ) { + Some(f) => f, + None => return, + }; + + call_help(env, function, call_mode, value); +} + +fn call_help<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + function: FunctionValue<'ctx>, + call_mode: CallMode<'ctx>, + value: BasicValueEnum<'ctx>, +) -> inkwell::values::CallSiteValue<'ctx> { + let call = match call_mode { + CallMode::Inc(inc_amount) => { + env.builder + .build_call(function, &[value, inc_amount.into()], "increment") + } + CallMode::Dec => env.builder.build_call(function, &[value], "decrement"), + }; + + call.set_call_convention(FAST_CALL_CONV); + + call +} + +fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + parent: FunctionValue<'ctx>, + layout_ids: &mut LayoutIds<'a>, + mode: Mode, + when_recursive: &WhenRecursive<'a>, + value: BasicValueEnum<'ctx>, + layout: &Layout<'a>, +) -> Option> { use Layout::*; match layout { @@ -485,7 +632,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( } => { debug_assert!(value.is_pointer_value()); - build_rec_union( + let function = build_rec_union( env, layout_ids, mode, @@ -494,6 +641,8 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( value.into_pointer_value(), true, ); + + Some(function) } NullableUnwrapped { other_fields, .. } => { @@ -501,7 +650,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( let other_fields = &other_fields[1..]; - build_rec_union( + let function = build_rec_union( env, layout_ids, mode, @@ -510,12 +659,14 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( value.into_pointer_value(), true, ); + + Some(function) } NonNullableUnwrapped(fields) => { debug_assert!(value.is_pointer_value()); - build_rec_union( + let function = build_rec_union( env, layout_ids, mode, @@ -524,11 +675,12 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( value.into_pointer_value(), true, ); + Some(function) } Recursive(tags) => { debug_assert!(value.is_pointer_value()); - build_rec_union( + let function = build_rec_union( env, layout_ids, mode, @@ -537,10 +689,14 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( value.into_pointer_value(), false, ); + Some(function) } NonRecursive(tags) => { - modify_refcount_union(env, layout_ids, mode, when_recursive, tags, value) + let function = + modify_refcount_union(env, layout_ids, mode, when_recursive, tags, value); + + Some(function) } } } @@ -553,7 +709,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( .build_extract_value(wrapper_struct, 1, "modify_rc_closure_data") .unwrap(); - modify_refcount_layout_help( + let function = modify_refcount_layout_build_function( env, parent, layout_ids, @@ -561,12 +717,16 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( when_recursive, field_ptr, &closure_layout.as_block_of_memory_layout(), - ) + )?; + + Some(function) + } else { + None } } Struct(layouts) => { - modify_refcount_struct( + let function = modify_refcount_struct( env, parent, layout_ids, @@ -575,9 +735,11 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( mode, when_recursive, ); + + Some(function) } - PhantomEmptyStruct => {} + PhantomEmptyStruct => None, Layout::RecursivePointer => match when_recursive { WhenRecursive::Unreachable => { @@ -594,7 +756,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( .build_bitcast(value, bt, "i64_to_opaque") .into_pointer_value(); - modify_refcount_layout_help( + let function = modify_refcount_layout_build_function( env, parent, layout_ids, @@ -602,11 +764,13 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( when_recursive, field_cast.into(), &layout, - ) + )?; + + Some(function) } }, - FunctionPointer(_, _) | Pointer(_) => {} + FunctionPointer(_, _) | Pointer(_) => None, } } @@ -618,7 +782,7 @@ fn modify_refcount_list<'a, 'ctx, 'env>( layout: &Layout<'a>, element_layout: &Layout<'a>, original_wrapper: StructValue<'ctx>, -) { +) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); @@ -655,13 +819,13 @@ fn modify_refcount_list<'a, 'ctx, 'env>( env.builder .set_current_debug_location(env.context, di_location); - call_help(env, function, mode, original_wrapper.into(), call_name); + function } fn mode_to_call_mode(function: FunctionValue<'_>, mode: Mode) -> CallMode<'_> { match mode { Mode::Dec => CallMode::Dec, - Mode::Inc(num) => CallMode::Inc(num, function.get_nth_param(1).unwrap().into_int_value()), + Mode::Inc => CallMode::Inc(function.get_nth_param(1).unwrap().into_int_value()), } } @@ -720,7 +884,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( env, parent, layout_ids, - mode, + mode.to_call_mode(fn_val), when_recursive, element, element_layout, @@ -756,7 +920,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>( mode: Mode, layout: &Layout<'a>, original_wrapper: StructValue<'ctx>, -) { +) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); @@ -785,7 +949,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>( env.builder .set_current_debug_location(env.context, di_location); - call_help(env, function, mode, original_wrapper.into(), call_name); + function } fn modify_refcount_str_help<'a, 'ctx, 'env>( @@ -856,7 +1020,7 @@ fn modify_refcount_dict<'a, 'ctx, 'env>( key_layout: &Layout<'a>, value_layout: &Layout<'a>, original_wrapper: StructValue<'ctx>, -) { +) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); @@ -894,7 +1058,7 @@ fn modify_refcount_dict<'a, 'ctx, 'env>( env.builder .set_current_debug_location(env.context, di_location); - call_help(env, function, mode, original_wrapper.into(), call_name); + function } #[allow(clippy::too_many_arguments)] @@ -990,7 +1154,7 @@ fn build_header<'a, 'ctx, 'env>( fn_name: &str, ) -> FunctionValue<'ctx> { match mode { - Mode::Inc(_) => build_header_help( + Mode::Inc => build_header_help( env, fn_name, env.context.void_type().into(), @@ -1036,13 +1200,26 @@ pub fn build_header_help<'a, 'ctx, 'env>( #[derive(Clone, Copy)] pub enum Mode { - Inc(u64), + Inc, Dec, } +impl Mode { + fn to_call_mode<'ctx>(&self, function: FunctionValue<'ctx>) -> CallMode<'ctx> { + match self { + Mode::Inc => { + let amount = function.get_nth_param(1).unwrap().into_int_value(); + + CallMode::Inc(amount) + } + Mode::Dec => CallMode::Dec, + } + } +} + #[derive(Clone, Copy)] enum CallMode<'ctx> { - Inc(u64, IntValue<'ctx>), + Inc(IntValue<'ctx>), Dec, } @@ -1054,7 +1231,7 @@ fn build_rec_union<'a, 'ctx, 'env>( fields: &'a [&'a [Layout<'a>]], value: PointerValue<'ctx>, is_nullable: bool, -) { +) -> FunctionValue<'ctx> { let layout = Layout::Union(UnionLayout::Recursive(fields)); let (call_name, fn_name) = function_name_from_mode( @@ -1095,7 +1272,7 @@ fn build_rec_union<'a, 'ctx, 'env>( } }; - call_help(env, function, mode, value.into(), call_name); + function } fn build_rec_union_help<'a, 'ctx, 'env>( @@ -1112,7 +1289,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( let context = &env.context; let builder = env.builder; - let pick = |a, b| if let Mode::Inc(_) = mode { a } else { b }; + let pick = |a, b| if let Mode::Inc = mode { a } else { b }; // Add a basic block for the entry point let entry = context.append_basic_block(fn_val, "entry"); @@ -1258,7 +1435,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( env, parent, layout_ids, - mode, + mode.to_call_mode(fn_val), when_recursive, field, field_layout, @@ -1268,7 +1445,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( let call_name = pick("recursive_tag_increment", "recursive_tag_decrement"); for ptr in deferred_rec { // recursively decrement the field - let call = call_help(env, fn_val, mode, ptr, call_name); + let call = call_help(env, fn_val, mode.to_call_mode(fn_val), ptr); call.set_tail_call(true); } @@ -1331,28 +1508,6 @@ fn rec_union_read_tag<'a, 'ctx, 'env>( .into_int_value() } -fn call_help<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - function: FunctionValue<'ctx>, - mode: Mode, - value: BasicValueEnum<'ctx>, - call_name: &str, -) -> inkwell::values::CallSiteValue<'ctx> { - let call = match mode { - Mode::Inc(inc_amount) => { - let rc_increment = ptr_int(env.context, env.ptr_bytes).const_int(inc_amount, false); - - env.builder - .build_call(function, &[value, rc_increment.into()], call_name) - } - Mode::Dec => env.builder.build_call(function, &[value], call_name), - }; - - call.set_call_convention(FAST_CALL_CONV); - - call -} - fn function_name_from_mode<'a>( layout_ids: &mut LayoutIds<'a>, interns: &Interns, @@ -1368,7 +1523,7 @@ fn function_name_from_mode<'a>( // rather confusing, so now `inc_x` always corresponds to `dec_x` let layout_id = layout_ids.get(Symbol::DEC, layout); match mode { - Mode::Inc(_) => (if_inc, layout_id.to_symbol_string(Symbol::INC, interns)), + Mode::Inc => (if_inc, layout_id.to_symbol_string(Symbol::INC, interns)), Mode::Dec => (if_dec, layout_id.to_symbol_string(Symbol::DEC, interns)), } } @@ -1380,7 +1535,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>( when_recursive: &WhenRecursive<'a>, fields: &'a [&'a [Layout<'a>]], value: BasicValueEnum<'ctx>, -) { +) -> FunctionValue<'ctx> { let layout = Layout::Union(UnionLayout::NonRecursive(fields)); let block = env.builder.get_insert_block().expect("to be in a function"); @@ -1418,7 +1573,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>( env.builder .set_current_debug_location(env.context, di_location); - call_help(env, function, mode, value, call_name); + function } fn modify_refcount_union_help<'a, 'ctx, 'env>( @@ -1509,7 +1664,7 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>( env, parent, layout_ids, - mode, + mode.to_call_mode(fn_val), when_recursive, field_ptr, field_layout, From de7b06e411917e18f3e95271ed9f63e7999c9863 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 16 May 2021 21:17:34 +0200 Subject: [PATCH 2/4] refactor + clippy --- compiler/builtins/bitcode/src/utils.zig | 4 + compiler/gen/src/llvm/bitcode.rs | 8 +- compiler/gen/src/llvm/refcounting.rs | 124 +++++++++--------------- 3 files changed, 54 insertions(+), 82 deletions(-) diff --git a/compiler/builtins/bitcode/src/utils.zig b/compiler/builtins/bitcode/src/utils.zig index f36eee65d5..ab3e6951f7 100644 --- a/compiler/builtins/bitcode/src/utils.zig +++ b/compiler/builtins/bitcode/src/utils.zig @@ -1,6 +1,10 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +pub const Inc = fn (?[*]u8) callconv(.C) void; +pub const IncN = fn (?[*]u8, u64) callconv(.C) void; +pub const Dec = fn (?[*]u8) callconv(.C) void; + const REFCOUNT_MAX_ISIZE: comptime isize = 0; const REFCOUNT_ONE_ISIZE: comptime isize = std.math.minInt(isize); pub const REFCOUNT_ONE: usize = @bitCast(usize, REFCOUNT_ONE_ISIZE); diff --git a/compiler/gen/src/llvm/bitcode.rs b/compiler/gen/src/llvm/bitcode.rs index 4a20cec722..5f9eb5d387 100644 --- a/compiler/gen/src/llvm/bitcode.rs +++ b/compiler/gen/src/llvm/bitcode.rs @@ -204,16 +204,16 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( function_value } -fn build_inc_n_wrapper<'a, 'ctx, 'env>( +/// a functin that accepts two arguments: the value to increment, and an amount to increment by +pub fn build_inc_n_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, - n: u64, ) -> FunctionValue<'ctx> { - // build_rc_wrapper(env, layout_ids, layout, Mode::Inc(n)) - todo!() + build_rc_wrapper(env, layout_ids, layout, Mode::Inc) } +/// a functin that accepts two arguments: the value to increment; increments by 1 pub fn build_inc_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, diff --git a/compiler/gen/src/llvm/refcounting.rs b/compiler/gen/src/llvm/refcounting.rs index d69ea7b590..2cf26f6934 100644 --- a/compiler/gen/src/llvm/refcounting.rs +++ b/compiler/gen/src/llvm/refcounting.rs @@ -315,9 +315,7 @@ impl<'ctx> PointerToRefcount<'ctx> { fn modify_refcount_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - parent: FunctionValue<'ctx>, layout_ids: &mut LayoutIds<'a>, - value: BasicValueEnum<'ctx>, layouts: &'a [Layout<'a>], mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -327,7 +325,7 @@ fn modify_refcount_struct<'a, 'ctx, 'env>( let layout = Layout::Struct(layouts); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_struct", @@ -453,7 +451,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, - value: BasicValueEnum<'ctx>, layout: &Layout<'a>, builtin: &Builtin<'a>, ) -> Option> { @@ -461,8 +458,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( match builtin { List(memory_mode, element_layout) => { - let wrapper_struct = value.into_struct_value(); - if let MemoryMode::Refcounted = memory_mode { let function = modify_refcount_list( env, @@ -471,7 +466,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( when_recursive, layout, element_layout, - wrapper_struct, ); Some(function) @@ -480,8 +474,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( } } Set(element_layout) => { - let wrapper_struct = value.into_struct_value(); - let key_layout = &Layout::Struct(&[]); let value_layout = element_layout; @@ -493,13 +485,11 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( layout, key_layout, value_layout, - wrapper_struct, ); Some(function) } Dict(key_layout, value_layout) => { - let wrapper_struct = value.into_struct_value(); let function = modify_refcount_dict( env, layout_ids, @@ -508,18 +498,13 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( layout, key_layout, value_layout, - wrapper_struct, ); Some(function) } - Str => { - let wrapper_struct = value.into_struct_value(); - let function = modify_refcount_str(env, layout_ids, mode, layout, wrapper_struct); + Str => Some(modify_refcount_str(env, layout_ids, mode, layout)), - Some(function) - } _ => { debug_assert!(!builtin.is_refcounted()); None @@ -572,14 +557,35 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( layout_ids, mode, when_recursive, - value, layout, ) { Some(f) => f, None => return, }; - call_help(env, function, call_mode, value); + match layout { + Layout::RecursivePointer => match when_recursive { + WhenRecursive::Unreachable => { + unreachable!("recursion pointers should never be hashed directly") + } + WhenRecursive::Loop(union_layout) => { + let layout = Layout::Union(*union_layout); + + let bt = basic_type_from_layout(env, &layout); + + // cast the i64 pointer to a pointer to block of memory + let field_cast = env + .builder + .build_bitcast(value, bt, "i64_to_opaque") + .into_pointer_value(); + + call_help(env, function, call_mode, field_cast.into()); + } + }, + _ => { + call_help(env, function, call_mode, value); + } + } } fn call_help<'a, 'ctx, 'env>( @@ -607,21 +613,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, - value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) -> Option> { use Layout::*; match layout { - Builtin(builtin) => modify_refcount_builtin( - env, - layout_ids, - mode, - when_recursive, - value, - layout, - builtin, - ), + Builtin(builtin) => { + modify_refcount_builtin(env, layout_ids, mode, when_recursive, layout, builtin) + } Union(variant) => { use UnionLayout::*; @@ -630,15 +629,12 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( NullableWrapped { other_tags: tags, .. } => { - debug_assert!(value.is_pointer_value()); - let function = build_rec_union( env, layout_ids, mode, &WhenRecursive::Loop(*variant), tags, - value.into_pointer_value(), true, ); @@ -646,8 +642,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } NullableUnwrapped { other_fields, .. } => { - debug_assert!(value.is_pointer_value()); - let other_fields = &other_fields[1..]; let function = build_rec_union( @@ -656,7 +650,6 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( mode, &WhenRecursive::Loop(*variant), &*env.arena.alloc([other_fields]), - value.into_pointer_value(), true, ); @@ -664,29 +657,24 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } NonNullableUnwrapped(fields) => { - debug_assert!(value.is_pointer_value()); - let function = build_rec_union( env, layout_ids, mode, &WhenRecursive::Loop(*variant), &*env.arena.alloc([*fields]), - value.into_pointer_value(), true, ); Some(function) } Recursive(tags) => { - debug_assert!(value.is_pointer_value()); let function = build_rec_union( env, layout_ids, mode, &WhenRecursive::Loop(*variant), tags, - value.into_pointer_value(), false, ); Some(function) @@ -694,20 +682,24 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( NonRecursive(tags) => { let function = - modify_refcount_union(env, layout_ids, mode, when_recursive, tags, value); + modify_refcount_union(env, layout_ids, mode, when_recursive, tags); Some(function) } } } - Closure(_, closure_layout, _) => { + Closure(argument_layouts, closure_layout, return_layout) => { if closure_layout.contains_refcounted() { - let wrapper_struct = value.into_struct_value(); + // Temporary hack to make this work for now. With defunctionalization, none of this + // will matter + let p2 = closure_layout.as_block_of_memory_layout(); + let mut argument_layouts = + Vec::from_iter_in(argument_layouts.iter().copied(), env.arena); + argument_layouts.push(p2); + let argument_layouts = argument_layouts.into_bump_slice(); - let field_ptr = env - .builder - .build_extract_value(wrapper_struct, 1, "modify_rc_closure_data") - .unwrap(); + let p1 = Layout::FunctionPointer(argument_layouts, return_layout); + let actual_layout = Layout::Struct(env.arena.alloc([p1, p2])); let function = modify_refcount_layout_build_function( env, @@ -715,8 +707,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( layout_ids, mode, when_recursive, - field_ptr, - &closure_layout.as_block_of_memory_layout(), + &actual_layout, )?; Some(function) @@ -726,15 +717,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } Struct(layouts) => { - let function = modify_refcount_struct( - env, - parent, - layout_ids, - value, - layouts, - mode, - when_recursive, - ); + let function = modify_refcount_struct(env, layout_ids, layouts, mode, when_recursive); Some(function) } @@ -748,21 +731,12 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( WhenRecursive::Loop(union_layout) => { let layout = Layout::Union(*union_layout); - let bt = basic_type_from_layout(env, &layout); - - // cast the i64 pointer to a pointer to block of memory - let field_cast = env - .builder - .build_bitcast(value, bt, "i64_to_opaque") - .into_pointer_value(); - let function = modify_refcount_layout_build_function( env, parent, layout_ids, mode, when_recursive, - field_cast.into(), &layout, )?; @@ -781,12 +755,11 @@ fn modify_refcount_list<'a, 'ctx, 'env>( when_recursive: &WhenRecursive<'a>, layout: &Layout<'a>, element_layout: &Layout<'a>, - original_wrapper: StructValue<'ctx>, ) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_list", @@ -919,12 +892,11 @@ fn modify_refcount_str<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, mode: Mode, layout: &Layout<'a>, - original_wrapper: StructValue<'ctx>, ) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_str", @@ -1019,12 +991,11 @@ fn modify_refcount_dict<'a, 'ctx, 'env>( layout: &Layout<'a>, key_layout: &Layout<'a>, value_layout: &Layout<'a>, - original_wrapper: StructValue<'ctx>, ) -> FunctionValue<'ctx> { let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_dict", @@ -1229,12 +1200,11 @@ fn build_rec_union<'a, 'ctx, 'env>( mode: Mode, when_recursive: &WhenRecursive<'a>, fields: &'a [&'a [Layout<'a>]], - value: PointerValue<'ctx>, is_nullable: bool, ) -> FunctionValue<'ctx> { let layout = Layout::Union(UnionLayout::Recursive(fields)); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_rec_union", @@ -1442,7 +1412,6 @@ fn build_rec_union_help<'a, 'ctx, 'env>( ); } - let call_name = pick("recursive_tag_increment", "recursive_tag_decrement"); for ptr in deferred_rec { // recursively decrement the field let call = call_help(env, fn_val, mode.to_call_mode(fn_val), ptr); @@ -1534,14 +1503,13 @@ fn modify_refcount_union<'a, 'ctx, 'env>( mode: Mode, when_recursive: &WhenRecursive<'a>, fields: &'a [&'a [Layout<'a>]], - value: BasicValueEnum<'ctx>, ) -> FunctionValue<'ctx> { let layout = Layout::Union(UnionLayout::NonRecursive(fields)); let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let (call_name, fn_name) = function_name_from_mode( + let (_, fn_name) = function_name_from_mode( layout_ids, &env.interns, "increment_union", From 353e161f77ec11ccb7e3d4dbde86b167071e3c35 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 16 May 2021 21:25:47 +0200 Subject: [PATCH 3/4] expose support for multi-increment --- compiler/gen/src/llvm/bitcode.rs | 38 ++++++++++++++++++++++------ compiler/gen/src/llvm/refcounting.rs | 11 ++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/compiler/gen/src/llvm/bitcode.rs b/compiler/gen/src/llvm/bitcode.rs index 5f9eb5d387..c54b458db5 100644 --- a/compiler/gen/src/llvm/bitcode.rs +++ b/compiler/gen/src/llvm/bitcode.rs @@ -2,7 +2,9 @@ use crate::debug_info_init; use crate::llvm::build::{set_name, Env, C_CALL_CONV, FAST_CALL_CONV}; use crate::llvm::convert::basic_type_from_layout; -use crate::llvm::refcounting::{decrement_refcount_layout, increment_refcount_layout, Mode}; +use crate::llvm::refcounting::{ + decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout, +}; use inkwell::attributes::{Attribute, AttributeLoc}; use inkwell::types::{BasicType, BasicTypeEnum}; use inkwell::values::{BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue}; @@ -204,6 +206,12 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( function_value } +enum Mode { + Inc, + IncN, + Dec, +} + /// a functin that accepts two arguments: the value to increment, and an amount to increment by pub fn build_inc_n_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -245,6 +253,7 @@ pub fn build_rc_wrapper<'a, 'ctx, 'env>( .to_symbol_string(symbol, &env.interns); let fn_name = match rc_operation { + Mode::IncN => format!("{}_inc_n", fn_name), Mode::Inc => format!("{}_inc", fn_name), Mode::Dec => format!("{}_dec", fn_name), }; @@ -254,12 +263,20 @@ pub fn build_rc_wrapper<'a, 'ctx, 'env>( None => { let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic); - let function_value = crate::llvm::refcounting::build_header_help( - env, - &fn_name, - env.context.void_type().into(), - &[arg_type.into()], - ); + let function_value = match rc_operation { + Mode::Inc | Mode::Dec => crate::llvm::refcounting::build_header_help( + env, + &fn_name, + env.context.void_type().into(), + &[arg_type.into()], + ), + Mode::IncN => crate::llvm::refcounting::build_header_help( + env, + &fn_name, + env.context.void_type().into(), + &[arg_type.into(), env.ptr_int().into()], + ), + }; let kind_id = Attribute::get_named_enum_kind_id("alwaysinline"); debug_assert!(kind_id > 0); @@ -287,10 +304,15 @@ pub fn build_rc_wrapper<'a, 'ctx, 'env>( match rc_operation { Mode::Inc => { - // we hardcode the 1 here let n = 1; increment_refcount_layout(env, function_value, layout_ids, n, value, layout); } + Mode::IncN => { + let n = it.next().unwrap().into_int_value(); + set_name(n.into(), Symbol::ARG_2.ident_string(&env.interns)); + + increment_n_refcount_layout(env, function_value, layout_ids, n, value, layout); + } Mode::Dec => { decrement_refcount_layout(env, function_value, layout_ids, value, layout); } diff --git a/compiler/gen/src/llvm/refcounting.rs b/compiler/gen/src/llvm/refcounting.rs index 2cf26f6934..a03398322e 100644 --- a/compiler/gen/src/llvm/refcounting.rs +++ b/compiler/gen/src/llvm/refcounting.rs @@ -426,6 +426,17 @@ pub fn increment_refcount_layout<'a, 'ctx, 'env>( layout: &Layout<'a>, ) { let amount = env.ptr_int().const_int(inc_amount, false); + increment_n_refcount_layout(env, parent, layout_ids, amount, value, layout); +} + +pub fn increment_n_refcount_layout<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + parent: FunctionValue<'ctx>, + layout_ids: &mut LayoutIds<'a>, + amount: IntValue<'ctx>, + value: BasicValueEnum<'ctx>, + layout: &Layout<'a>, +) { modify_refcount_layout( env, parent, From 4afd3cfce622b474b616240a3dd10699c340c819 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 16 May 2021 21:32:45 +0200 Subject: [PATCH 4/4] fixup --- compiler/builtins/bitcode/src/list.zig | 12 +++++------- compiler/gen/src/llvm/bitcode.rs | 4 ++-- compiler/gen/src/llvm/build_dict.rs | 17 ++++++++++++----- compiler/gen/src/llvm/build_list.rs | 6 +++--- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/compiler/builtins/bitcode/src/list.zig b/compiler/builtins/bitcode/src/list.zig index b43e329405..1791a8f61b 100644 --- a/compiler/builtins/bitcode/src/list.zig +++ b/compiler/builtins/bitcode/src/list.zig @@ -11,6 +11,7 @@ const CompareFn = fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) u8; const Opaque = ?[*]u8; const Inc = fn (?[*]u8) callconv(.C) void; +const IncN = fn (?[*]u8, usize) callconv(.C) void; const Dec = fn (?[*]u8) callconv(.C) void; pub const RocList = extern struct { @@ -615,7 +616,7 @@ pub fn listContains(list: RocList, key: Opaque, key_width: usize, is_eq: EqFn) c return false; } -pub fn listRepeat(count: usize, alignment: usize, element: Opaque, element_width: usize, inc_n_element: Inc) callconv(.C) RocList { +pub fn listRepeat(count: usize, alignment: usize, element: Opaque, element_width: usize, inc_n_element: IncN) callconv(.C) RocList { if (count == 0) { return RocList.empty(); } @@ -624,18 +625,15 @@ pub fn listRepeat(count: usize, alignment: usize, element: Opaque, element_width var output = RocList.allocate(allocator, alignment, count, element_width); if (output.bytes) |target_ptr| { + // increment the element's RC N times + inc_n_element(element, count); + var i: usize = 0; const source = element orelse unreachable; while (i < count) : (i += 1) { @memcpy(target_ptr + i * element_width, source, element_width); } - // TODO do all increments at once! - i = 0; - while (i < count) : (i += 1) { - inc_n_element(element); - } - return output; } else { unreachable; diff --git a/compiler/gen/src/llvm/bitcode.rs b/compiler/gen/src/llvm/bitcode.rs index c54b458db5..8545e8770a 100644 --- a/compiler/gen/src/llvm/bitcode.rs +++ b/compiler/gen/src/llvm/bitcode.rs @@ -218,7 +218,7 @@ pub fn build_inc_n_wrapper<'a, 'ctx, 'env>( layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::Inc) + build_rc_wrapper(env, layout_ids, layout, Mode::IncN) } /// a functin that accepts two arguments: the value to increment; increments by 1 @@ -238,7 +238,7 @@ pub fn build_dec_wrapper<'a, 'ctx, 'env>( build_rc_wrapper(env, layout_ids, layout, Mode::Dec) } -pub fn build_rc_wrapper<'a, 'ctx, 'env>( +fn build_rc_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, diff --git a/compiler/gen/src/llvm/build_dict.rs b/compiler/gen/src/llvm/build_dict.rs index 7ef54fd055..b282f77ddd 100644 --- a/compiler/gen/src/llvm/build_dict.rs +++ b/compiler/gen/src/llvm/build_dict.rs @@ -397,9 +397,16 @@ pub fn dict_elements_rc<'a, 'ctx, 'env>( let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.ptr_bytes); let alignment_iv = env.context.i8_type().const_int(alignment as u64, false); - use crate::llvm::bitcode::build_rc_wrapper; - let inc_key_fn = build_rc_wrapper(env, layout_ids, key_layout, rc_operation); - let inc_value_fn = build_rc_wrapper(env, layout_ids, value_layout, rc_operation); + let (key_fn, value_fn) = match rc_operation { + Mode::Inc => ( + build_inc_wrapper(env, layout_ids, key_layout), + build_inc_wrapper(env, layout_ids, value_layout), + ), + Mode::Dec => ( + build_dec_wrapper(env, layout_ids, key_layout), + build_dec_wrapper(env, layout_ids, value_layout), + ), + }; call_void_bitcode_fn( env, @@ -408,8 +415,8 @@ pub fn dict_elements_rc<'a, 'ctx, 'env>( alignment_iv.into(), key_width.into(), value_width.into(), - inc_key_fn.as_global_value().as_pointer_value().into(), - inc_value_fn.as_global_value().as_pointer_value().into(), + key_fn.as_global_value().as_pointer_value().into(), + value_fn.as_global_value().as_pointer_value().into(), ], &bitcode::DICT_ELEMENTS_RC, ); diff --git a/compiler/gen/src/llvm/build_list.rs b/compiler/gen/src/llvm/build_list.rs index b3a759e641..6634c51862 100644 --- a/compiler/gen/src/llvm/build_list.rs +++ b/compiler/gen/src/llvm/build_list.rs @@ -1,7 +1,7 @@ #![allow(clippy::too_many_arguments)] use crate::llvm::bitcode::{ - build_compare_wrapper, build_dec_wrapper, build_eq_wrapper, build_inc_wrapper, - build_transform_caller, call_bitcode_fn, call_void_bitcode_fn, + build_compare_wrapper, build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, + build_inc_wrapper, build_transform_caller, call_bitcode_fn, call_void_bitcode_fn, }; use crate::llvm::build::{ allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, InPlace, @@ -118,7 +118,7 @@ pub fn list_repeat<'a, 'ctx, 'env>( element: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout); + let inc_element_fn = build_inc_n_wrapper(env, layout_ids, element_layout); call_bitcode_fn_returns_list( env,