mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
use generic function to define the stepper wrapper
This commit is contained in:
parent
3fe80b1a1e
commit
619749c954
3 changed files with 38 additions and 142 deletions
|
@ -747,7 +747,7 @@ pub fn setFromList(list: RocList, alignment: Alignment, key_width: usize, value_
|
||||||
decref(std.heap.c_allocator, alignment, list.bytes, data_bytes);
|
decref(std.heap.c_allocator, alignment, list.bytes, data_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const StepperCaller = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
const StepperCaller = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||||
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, output: Opaque) callconv(.C) void {
|
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, output: Opaque) callconv(.C) void {
|
||||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||||
|
|
||||||
|
@ -759,7 +759,7 @@ pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, a
|
||||||
const key = dict.getKey(i, alignment, key_width, value_width);
|
const key = dict.getKey(i, alignment, key_width, value_width);
|
||||||
const value = dict.getValue(i, alignment, key_width, value_width);
|
const value = dict.getValue(i, alignment, key_width, value_width);
|
||||||
|
|
||||||
stepper_caller(stepper, key, value, output);
|
stepper_caller(stepper, key, value, output, output);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -688,7 +688,7 @@ fn dict_intersect_or_difference<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn dict_walk<'a, 'ctx, 'env>(
|
pub fn dict_walk<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
_layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
dict: BasicValueEnum<'ctx>,
|
dict: BasicValueEnum<'ctx>,
|
||||||
stepper: BasicValueEnum<'ctx>,
|
stepper: BasicValueEnum<'ctx>,
|
||||||
accum: BasicValueEnum<'ctx>,
|
accum: BasicValueEnum<'ctx>,
|
||||||
|
@ -709,10 +709,23 @@ pub fn dict_walk<'a, 'ctx, 'env>(
|
||||||
let stepper_ptr = builder.build_alloca(stepper.get_type(), "stepper_ptr");
|
let stepper_ptr = builder.build_alloca(stepper.get_type(), "stepper_ptr");
|
||||||
env.builder.build_store(stepper_ptr, stepper);
|
env.builder.build_store(stepper_ptr, stepper);
|
||||||
|
|
||||||
let stepper_caller =
|
// let stepper_caller =
|
||||||
build_stepper_caller(env, stepper_layout, key_layout, value_layout, accum_layout)
|
// build_stepper_caller(env, stepper_layout, key_layout, value_layout, accum_layout)
|
||||||
.as_global_value()
|
// .as_global_value()
|
||||||
.as_pointer_value();
|
// .as_pointer_value();
|
||||||
|
|
||||||
|
let stepper_caller = crate::llvm::build_list::build_transform_caller(
|
||||||
|
env,
|
||||||
|
layout_ids,
|
||||||
|
stepper_layout,
|
||||||
|
&[
|
||||||
|
key_layout.clone(),
|
||||||
|
value_layout.clone(),
|
||||||
|
accum_layout.clone(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.as_global_value()
|
||||||
|
.as_pointer_value();
|
||||||
|
|
||||||
let accum_bt = basic_type_from_layout(env.arena, env.context, accum_layout, env.ptr_bytes);
|
let accum_bt = basic_type_from_layout(env.arena, env.context, accum_layout, env.ptr_bytes);
|
||||||
let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
|
let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
|
||||||
|
@ -1094,134 +1107,6 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
function_value
|
function_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stepper_caller<'a, 'ctx, 'env>(
|
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
|
||||||
stepper_layout: &Layout<'a>,
|
|
||||||
key_layout: &Layout<'a>,
|
|
||||||
value_layout: &Layout<'a>,
|
|
||||||
accum_layout: &Layout<'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 fn_name = "dict_stepper_caller";
|
|
||||||
|
|
||||||
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(),
|
|
||||||
arg_type.into(),
|
|
||||||
arg_type.into(),
|
|
||||||
arg_type.into(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
|
||||||
debug_assert!(kind_id > 0);
|
|
||||||
let attr = env.context.create_enum_attribute(kind_id, 1);
|
|
||||||
function_value.add_attribute(AttributeLoc::Function, attr);
|
|
||||||
|
|
||||||
let entry = env.context.append_basic_block(function_value, "entry");
|
|
||||||
env.builder.position_at_end(entry);
|
|
||||||
|
|
||||||
debug_info_init!(env, function_value);
|
|
||||||
|
|
||||||
let mut it = function_value.get_param_iter();
|
|
||||||
let closure_ptr = it.next().unwrap().into_pointer_value();
|
|
||||||
let key_ptr = it.next().unwrap().into_pointer_value();
|
|
||||||
let value_ptr = it.next().unwrap().into_pointer_value();
|
|
||||||
let accum_ptr = it.next().unwrap().into_pointer_value();
|
|
||||||
|
|
||||||
set_name(closure_ptr.into(), Symbol::ARG_1.ident_string(&env.interns));
|
|
||||||
set_name(key_ptr.into(), Symbol::ARG_2.ident_string(&env.interns));
|
|
||||||
set_name(value_ptr.into(), Symbol::ARG_3.ident_string(&env.interns));
|
|
||||||
set_name(accum_ptr.into(), Symbol::ARG_4.ident_string(&env.interns));
|
|
||||||
|
|
||||||
let closure_type =
|
|
||||||
basic_type_from_layout(env.arena, env.context, stepper_layout, env.ptr_bytes)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let key_type = basic_type_from_layout(env.arena, env.context, key_layout, env.ptr_bytes)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let value_type = basic_type_from_layout(env.arena, env.context, value_layout, env.ptr_bytes)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let accum_type = basic_type_from_layout(env.arena, env.context, accum_layout, env.ptr_bytes)
|
|
||||||
.ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let closure_cast = env
|
|
||||||
.builder
|
|
||||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let key_cast = env
|
|
||||||
.builder
|
|
||||||
.build_bitcast(key_ptr, key_type, "load_opaque")
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let value_cast = env
|
|
||||||
.builder
|
|
||||||
.build_bitcast(value_ptr, value_type, "load_opaque")
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let accum_cast = env
|
|
||||||
.builder
|
|
||||||
.build_bitcast(accum_ptr, accum_type, "load_opaque")
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let fpointer = env.builder.build_load(closure_cast, "load_opaque");
|
|
||||||
let key = env.builder.build_load(key_cast, "load_opaque");
|
|
||||||
let value = env.builder.build_load(value_cast, "load_opaque");
|
|
||||||
let accum = env.builder.build_load(accum_cast, "load_opaque");
|
|
||||||
|
|
||||||
let call = match stepper_layout {
|
|
||||||
Layout::FunctionPointer(_, _) => {
|
|
||||||
env.builder
|
|
||||||
.build_call(fpointer.into_pointer_value(), &[key, value, accum], "tmp")
|
|
||||||
}
|
|
||||||
Layout::Closure(_, _, _) | Layout::Struct(_) => {
|
|
||||||
let pair = fpointer.into_struct_value();
|
|
||||||
|
|
||||||
let fpointer = env
|
|
||||||
.builder
|
|
||||||
.build_extract_value(pair, 0, "get_fpointer")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let closure_data = env
|
|
||||||
.builder
|
|
||||||
.build_extract_value(pair, 1, "get_closure_data")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
env.builder.build_call(
|
|
||||||
fpointer.into_pointer_value(),
|
|
||||||
&[key, value, accum, closure_data],
|
|
||||||
"tmp",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => unreachable!("layout is not callable {:?}", stepper_layout),
|
|
||||||
};
|
|
||||||
call.set_call_convention(FAST_CALL_CONV);
|
|
||||||
|
|
||||||
let result = call
|
|
||||||
.try_as_basic_value()
|
|
||||||
.left()
|
|
||||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."));
|
|
||||||
|
|
||||||
env.builder.build_store(accum_cast, result);
|
|
||||||
env.builder.build_return(None);
|
|
||||||
|
|
||||||
env.builder.position_at_end(block);
|
|
||||||
env.builder
|
|
||||||
.set_current_debug_location(env.context, di_location);
|
|
||||||
|
|
||||||
function_value
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dict_symbol_to_zig_dict<'a, 'ctx, 'env>(
|
fn dict_symbol_to_zig_dict<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
|
|
|
@ -1328,22 +1328,33 @@ const ARGUMENT_SYMBOLS: [Symbol; 8] = [
|
||||||
Symbol::ARG_8,
|
Symbol::ARG_8,
|
||||||
];
|
];
|
||||||
|
|
||||||
fn build_transform_caller<'a, 'ctx, 'env>(
|
pub fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
function_layout: &Layout<'a>,
|
function_layout: &Layout<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
debug_assert!(argument_layouts.len() <= 7);
|
|
||||||
|
|
||||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
|
||||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
|
||||||
|
|
||||||
let symbol = Symbol::ZIG_FUNCTION_CALLER;
|
let symbol = Symbol::ZIG_FUNCTION_CALLER;
|
||||||
let fn_name = layout_ids
|
let fn_name = layout_ids
|
||||||
.get(symbol, &function_layout)
|
.get(symbol, &function_layout)
|
||||||
.to_symbol_string(symbol, &env.interns);
|
.to_symbol_string(symbol, &env.interns);
|
||||||
let fn_name = format!("transform_caller_{}", fn_name);
|
|
||||||
|
match env.module.get_function(fn_name.as_str()) {
|
||||||
|
Some(function_value) => function_value,
|
||||||
|
None => build_transform_caller_help(env, function_layout, argument_layouts, &fn_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
function_layout: &Layout<'a>,
|
||||||
|
argument_layouts: &[Layout<'a>],
|
||||||
|
fn_name: &str,
|
||||||
|
) -> FunctionValue<'ctx> {
|
||||||
|
debug_assert!(argument_layouts.len() <= 7);
|
||||||
|
|
||||||
|
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
|
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||||
|
|
||||||
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue