mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-11 18:58:24 +03:00
Merge pull request #5773 from roc-lang/remaining-dev-backend-lowlevels
Remaining dev backend lowlevels
This commit is contained in:
commit
85c0eaddcb
@ -1962,18 +1962,73 @@ impl<
|
||||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let caller_proc = CallerProc::new(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
let caller_proc = match higher_order.op {
|
||||
HigherOrder::ListMap { .. }
|
||||
| HigherOrder::ListMap2 { .. }
|
||||
| HigherOrder::ListMap3 { .. }
|
||||
| HigherOrder::ListMap4 { .. } => CallerProc::new_list_map(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
),
|
||||
HigherOrder::ListSortWith { .. } => CallerProc::new_compare(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
),
|
||||
};
|
||||
|
||||
let caller = self.debug_symbol("caller");
|
||||
let caller_string = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(caller_proc.proc_symbol),
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
self.caller_procs.push(caller_proc);
|
||||
|
||||
let argument_layouts = match higher_order.closure_env_layout {
|
||||
None => higher_order.passed_function.argument_layouts,
|
||||
Some(_) => &higher_order.passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
// function pointer to a function that takes a pointer, and increments
|
||||
let inc_n_data = if let Some(closure_env_layout) = higher_order.closure_env_layout {
|
||||
self.increment_fn_pointer(closure_env_layout)
|
||||
} else {
|
||||
// null pointer
|
||||
self.load_literal_i64(&Symbol::DEV_TMP, 0);
|
||||
Symbol::DEV_TMP
|
||||
};
|
||||
|
||||
let data = self.debug_symbol("data");
|
||||
if let Some(_closure_data_layout) = higher_order.closure_env_layout {
|
||||
let data_symbol = higher_order.passed_function.captured_environment;
|
||||
self.storage_manager
|
||||
.ensure_symbol_on_stack(&mut self.buf, &data_symbol);
|
||||
let (new_elem_offset, _) = self.storage_manager.stack_offset_and_size(&data_symbol);
|
||||
|
||||
// Load address of output element into register.
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &data);
|
||||
ASM::add_reg64_reg64_imm32(&mut self.buf, reg, CC::BASE_PTR_REG, new_elem_offset);
|
||||
} else {
|
||||
// use a null pointer
|
||||
self.load_literal(&data, &Layout::U64, &Literal::Int(0u128.to_be_bytes()));
|
||||
}
|
||||
|
||||
let ptr = Layout::U64;
|
||||
let usize_ = Layout::U64;
|
||||
|
||||
match higher_order.op {
|
||||
HigherOrder::ListMap { xs } => {
|
||||
let old_element_layout = higher_order.passed_function.argument_layouts[0];
|
||||
let old_element_layout = argument_layouts[0];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
let input_list_layout = LayoutRepr::Builtin(Builtin::List(old_element_layout));
|
||||
@ -1981,8 +2036,6 @@ impl<
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout);
|
||||
|
||||
let caller = self.debug_symbol("caller");
|
||||
let data = self.debug_symbol("data");
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width = self.debug_symbol("old_element_width");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
@ -1992,47 +2045,8 @@ impl<
|
||||
self.load_layout_stack_size(old_element_layout, old_element_width);
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
let caller_string = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(caller_proc.proc_symbol),
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
);
|
||||
|
||||
// self.helper_proc_symbols .extend([(caller_proc.proc_symbol, caller_proc.proc_layout)]);
|
||||
self.caller_procs.push(caller_proc);
|
||||
|
||||
// function pointer to a function that takes a pointer, and increments
|
||||
let inc_n_data = if let Some(closure_env_layout) = higher_order.closure_env_layout {
|
||||
self.increment_fn_pointer(closure_env_layout)
|
||||
} else {
|
||||
// null pointer
|
||||
self.load_literal_i64(&Symbol::DEV_TMP, 0);
|
||||
Symbol::DEV_TMP
|
||||
};
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
if let Some(_closure_data_layout) = higher_order.closure_env_layout {
|
||||
let data_symbol = higher_order.passed_function.captured_environment;
|
||||
self.storage_manager
|
||||
.ensure_symbol_on_stack(&mut self.buf, &data_symbol);
|
||||
let (new_elem_offset, _) =
|
||||
self.storage_manager.stack_offset_and_size(&data_symbol);
|
||||
|
||||
// Load address of output element into register.
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &data);
|
||||
ASM::add_reg64_reg64_imm32(
|
||||
&mut self.buf,
|
||||
reg,
|
||||
CC::BASE_PTR_REG,
|
||||
new_elem_offset,
|
||||
);
|
||||
} else {
|
||||
// use a null pointer
|
||||
self.load_literal(&data, &Layout::U64, &Literal::Int(0u128.to_be_bytes()));
|
||||
}
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
@ -2063,9 +2077,6 @@ impl<
|
||||
new_element_width,
|
||||
];
|
||||
|
||||
let ptr = Layout::U64;
|
||||
let usize_ = Layout::U64;
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout,
|
||||
ptr,
|
||||
@ -2077,37 +2088,398 @@ impl<
|
||||
usize_,
|
||||
];
|
||||
|
||||
// Setup the return location.
|
||||
let base_offset = self
|
||||
.storage_manager
|
||||
.claim_stack_area(dst, self.layout_interner.stack_size(ret_layout));
|
||||
|
||||
self.build_fn_call(
|
||||
&Symbol::DEV_TMP3,
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_MAP.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
&ret_layout,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListMap2 { xs, ys } => {
|
||||
let old_element_layout1 = argument_layouts[0];
|
||||
let old_element_layout2 = argument_layouts[1];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
// Return list value from fn call
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
base_offset,
|
||||
&Symbol::DEV_TMP3,
|
||||
&ret_layout,
|
||||
let input_list_layout1 = LayoutRepr::Builtin(Builtin::List(old_element_layout1));
|
||||
let input_list_in_layout1 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout1);
|
||||
|
||||
let input_list_layout2 = LayoutRepr::Builtin(Builtin::List(old_element_layout2));
|
||||
let input_list_in_layout2 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout2);
|
||||
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width1 = self.debug_symbol("old_element_width1");
|
||||
let old_element_width2 = self.debug_symbol("old_element_width2");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
|
||||
self.load_layout_alignment(new_element_layout, alignment);
|
||||
|
||||
self.load_layout_stack_size(old_element_layout1, old_element_width1);
|
||||
self.load_layout_stack_size(old_element_layout2, old_element_width2);
|
||||
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
let dec1 = self.decrement_fn_pointer(old_element_layout1);
|
||||
let dec2 = self.decrement_fn_pointer(old_element_layout2);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP2,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(data_is_owned),
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP3);
|
||||
// list1: RocList,
|
||||
// list2: RocList,
|
||||
// caller: Caller1,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// old_element_width1: usize,
|
||||
// old_element_width2: usize,
|
||||
// new_element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
ys,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP2,
|
||||
alignment,
|
||||
old_element_width1,
|
||||
old_element_width2,
|
||||
new_element_width,
|
||||
dec1,
|
||||
dec2,
|
||||
];
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout1,
|
||||
input_list_in_layout2,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_,
|
||||
usize_,
|
||||
usize_,
|
||||
ptr, // dec1
|
||||
ptr, // dec2
|
||||
];
|
||||
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_MAP2.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListMap3 { xs, ys, zs } => {
|
||||
let old_element_layout1 = argument_layouts[0];
|
||||
let old_element_layout2 = argument_layouts[1];
|
||||
let old_element_layout3 = argument_layouts[2];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
let input_list_layout1 = LayoutRepr::Builtin(Builtin::List(old_element_layout1));
|
||||
let input_list_in_layout1 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout1);
|
||||
|
||||
let input_list_layout2 = LayoutRepr::Builtin(Builtin::List(old_element_layout2));
|
||||
let input_list_in_layout2 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout2);
|
||||
|
||||
let input_list_layout3 = LayoutRepr::Builtin(Builtin::List(old_element_layout3));
|
||||
let input_list_in_layout3 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout3);
|
||||
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width1 = self.debug_symbol("old_element_width1");
|
||||
let old_element_width2 = self.debug_symbol("old_element_width2");
|
||||
let old_element_width3 = self.debug_symbol("old_element_width3");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
|
||||
self.load_layout_alignment(new_element_layout, alignment);
|
||||
|
||||
self.load_layout_stack_size(old_element_layout1, old_element_width1);
|
||||
self.load_layout_stack_size(old_element_layout2, old_element_width2);
|
||||
self.load_layout_stack_size(old_element_layout3, old_element_width3);
|
||||
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
let dec1 = self.decrement_fn_pointer(old_element_layout1);
|
||||
let dec2 = self.decrement_fn_pointer(old_element_layout2);
|
||||
let dec3 = self.decrement_fn_pointer(old_element_layout3);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP2,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(data_is_owned),
|
||||
);
|
||||
|
||||
// list1: RocList,
|
||||
// list2: RocList,
|
||||
// caller: Caller1,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// old_element_width1: usize,
|
||||
// old_element_width2: usize,
|
||||
// new_element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
ys,
|
||||
zs,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP2,
|
||||
alignment,
|
||||
old_element_width1,
|
||||
old_element_width2,
|
||||
old_element_width3,
|
||||
new_element_width,
|
||||
dec1,
|
||||
dec2,
|
||||
dec3,
|
||||
];
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout1,
|
||||
input_list_in_layout2,
|
||||
input_list_in_layout3,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_, // old_element_width_1
|
||||
usize_, // old_element_width_2
|
||||
usize_, // old_element_width_3
|
||||
usize_, // new_element_width
|
||||
ptr, // dec1
|
||||
ptr, // dec2
|
||||
ptr, // dec3
|
||||
];
|
||||
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_MAP3.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListMap4 { xs, ys, zs, ws } => {
|
||||
let old_element_layout1 = argument_layouts[0];
|
||||
let old_element_layout2 = argument_layouts[1];
|
||||
let old_element_layout3 = argument_layouts[2];
|
||||
let old_element_layout4 = argument_layouts[3];
|
||||
let new_element_layout = higher_order.passed_function.return_layout;
|
||||
|
||||
let input_list_layout1 = LayoutRepr::Builtin(Builtin::List(old_element_layout1));
|
||||
let input_list_in_layout1 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout1);
|
||||
|
||||
let input_list_layout2 = LayoutRepr::Builtin(Builtin::List(old_element_layout2));
|
||||
let input_list_in_layout2 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout2);
|
||||
|
||||
let input_list_layout3 = LayoutRepr::Builtin(Builtin::List(old_element_layout3));
|
||||
let input_list_in_layout3 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout3);
|
||||
|
||||
let input_list_layout4 = LayoutRepr::Builtin(Builtin::List(old_element_layout4));
|
||||
let input_list_in_layout4 = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout4);
|
||||
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let old_element_width1 = self.debug_symbol("old_element_width1");
|
||||
let old_element_width2 = self.debug_symbol("old_element_width2");
|
||||
let old_element_width3 = self.debug_symbol("old_element_width3");
|
||||
let old_element_width4 = self.debug_symbol("old_element_width4");
|
||||
let new_element_width = self.debug_symbol("new_element_width");
|
||||
|
||||
self.load_layout_alignment(new_element_layout, alignment);
|
||||
|
||||
self.load_layout_stack_size(old_element_layout1, old_element_width1);
|
||||
self.load_layout_stack_size(old_element_layout2, old_element_width2);
|
||||
self.load_layout_stack_size(old_element_layout3, old_element_width3);
|
||||
self.load_layout_stack_size(old_element_layout4, old_element_width4);
|
||||
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
let dec1 = self.decrement_fn_pointer(old_element_layout1);
|
||||
let dec2 = self.decrement_fn_pointer(old_element_layout2);
|
||||
let dec3 = self.decrement_fn_pointer(old_element_layout3);
|
||||
let dec4 = self.decrement_fn_pointer(old_element_layout4);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP2,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(data_is_owned),
|
||||
);
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
ys,
|
||||
zs,
|
||||
ws,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP2,
|
||||
alignment,
|
||||
old_element_width1,
|
||||
old_element_width2,
|
||||
old_element_width3,
|
||||
old_element_width4,
|
||||
new_element_width,
|
||||
dec1,
|
||||
dec2,
|
||||
dec3,
|
||||
dec4,
|
||||
];
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout1,
|
||||
input_list_in_layout2,
|
||||
input_list_in_layout3,
|
||||
input_list_in_layout4,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_, // old_element_width_1
|
||||
usize_, // old_element_width_2
|
||||
usize_, // old_element_width_3
|
||||
usize_, // old_element_width_4
|
||||
usize_, // new_element_width
|
||||
ptr, // dec1
|
||||
ptr, // dec2
|
||||
ptr, // dec3
|
||||
ptr, // dec4
|
||||
];
|
||||
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_MAP4.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListSortWith { xs } => {
|
||||
let element_layout = argument_layouts[0];
|
||||
|
||||
let input_list_layout = LayoutRepr::Builtin(Builtin::List(element_layout));
|
||||
let input_list_in_layout = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout);
|
||||
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let element_width = self.debug_symbol("old_element_width");
|
||||
|
||||
self.load_layout_alignment(element_layout, alignment);
|
||||
self.load_layout_stack_size(element_layout, element_width);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP2,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(data_is_owned),
|
||||
);
|
||||
|
||||
// input: RocList,
|
||||
// caller: CompareFn,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP2,
|
||||
alignment,
|
||||
element_width,
|
||||
];
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_,
|
||||
];
|
||||
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_SORT_WITH.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListMap2 { .. } => todo!(),
|
||||
HigherOrder::ListMap3 { .. } => todo!(),
|
||||
HigherOrder::ListMap4 { .. } => todo!(),
|
||||
HigherOrder::ListSortWith { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2622,8 +2994,9 @@ impl<
|
||||
let element_alignment_symbol = Symbol::DEV_TMP2;
|
||||
self.load_layout_alignment(Layout::U32, element_alignment_symbol);
|
||||
|
||||
let allocation_symbol = self.debug_symbol("list_allocation");
|
||||
self.allocate_with_refcount(
|
||||
Symbol::DEV_TMP3,
|
||||
allocation_symbol,
|
||||
data_bytes_symbol,
|
||||
element_alignment_symbol,
|
||||
);
|
||||
@ -2634,7 +3007,7 @@ impl<
|
||||
// The pointer already points to the first element
|
||||
let ptr_reg = self
|
||||
.storage_manager
|
||||
.load_to_general_reg(&mut self.buf, &Symbol::DEV_TMP3);
|
||||
.load_to_general_reg(&mut self.buf, &allocation_symbol);
|
||||
|
||||
// Copy everything into output array.
|
||||
let mut element_offset = 0;
|
||||
@ -2684,7 +3057,7 @@ impl<
|
||||
ASM::mov_base32_reg64(buf, base_offset + 16, tmp_reg);
|
||||
},
|
||||
);
|
||||
self.free_symbol(&Symbol::DEV_TMP3);
|
||||
self.free_symbol(&allocation_symbol);
|
||||
}
|
||||
|
||||
fn create_struct(&mut self, sym: &Symbol, layout: &InLayout<'a>, fields: &'a [Symbol]) {
|
||||
@ -4024,6 +4397,41 @@ impl<
|
||||
CC: CallConv<GeneralReg, FloatReg, ASM>,
|
||||
> Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
fn build_fn_call_stack_return<const N: usize>(
|
||||
&mut self,
|
||||
function_name: String,
|
||||
arguments: &[Symbol; N],
|
||||
layouts: &[InLayout<'a>; N],
|
||||
ret_layout: InLayout<'a>,
|
||||
dst: Symbol,
|
||||
) {
|
||||
// Setup the return location.
|
||||
let base_offset = self
|
||||
.storage_manager
|
||||
.claim_stack_area(&dst, self.layout_interner.stack_size(ret_layout));
|
||||
|
||||
let tmp = self.debug_symbol("call_with_stack_return_result");
|
||||
|
||||
self.build_fn_call(
|
||||
&tmp,
|
||||
function_name,
|
||||
arguments.as_slice(),
|
||||
layouts.as_slice(),
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
// Return list value from fn call
|
||||
self.storage_manager.copy_symbol_to_stack_offset(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
base_offset,
|
||||
&tmp,
|
||||
&ret_layout,
|
||||
);
|
||||
|
||||
self.free_symbol(&tmp);
|
||||
}
|
||||
|
||||
fn clear_tag_id(&mut self, ptr_reg: GeneralReg) -> (Symbol, GeneralReg) {
|
||||
let unmasked_symbol = self.debug_symbol("unmasked");
|
||||
let unmasked_reg = self
|
||||
|
@ -51,7 +51,7 @@ pub fn build_module<'a, 'r>(
|
||||
b".note.GNU-stack".to_vec(),
|
||||
SectionKind::Elf(object::elf::SHT_PROGBITS),
|
||||
);
|
||||
build_object(procedures, backend, object)
|
||||
build_object(env.mode, procedures, backend, object)
|
||||
}
|
||||
Triple {
|
||||
architecture: TargetArch::X86_64,
|
||||
@ -65,6 +65,7 @@ pub fn build_module<'a, 'r>(
|
||||
x86_64::X86_64SystemV,
|
||||
>(env, TargetInfo::default_x86_64(), interns, layout_interner);
|
||||
build_object(
|
||||
env.mode,
|
||||
procedures,
|
||||
backend,
|
||||
Object::new(
|
||||
@ -86,6 +87,7 @@ pub fn build_module<'a, 'r>(
|
||||
x86_64::X86_64WindowsFastcall,
|
||||
>(env, TargetInfo::default_x86_64(), interns, layout_interner);
|
||||
build_object(
|
||||
env.mode,
|
||||
procedures,
|
||||
backend,
|
||||
Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little),
|
||||
@ -104,6 +106,7 @@ pub fn build_module<'a, 'r>(
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns, layout_interner);
|
||||
build_object(
|
||||
env.mode,
|
||||
procedures,
|
||||
backend,
|
||||
Object::new(BinaryFormat::Elf, Architecture::Aarch64, Endianness::Little),
|
||||
@ -122,6 +125,7 @@ pub fn build_module<'a, 'r>(
|
||||
aarch64::AArch64Call,
|
||||
>(env, TargetInfo::default_aarch64(), interns, layout_interner);
|
||||
build_object(
|
||||
env.mode,
|
||||
procedures,
|
||||
backend,
|
||||
Object::new(
|
||||
@ -294,6 +298,7 @@ fn generate_wrapper<'a, B: Backend<'a>>(
|
||||
}
|
||||
|
||||
fn build_object<'a, B: Backend<'a>>(
|
||||
mode: AssemblyBackendMode,
|
||||
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
mut backend: B,
|
||||
mut output: Object<'a>,
|
||||
@ -402,9 +407,11 @@ fn build_object<'a, B: Backend<'a>>(
|
||||
module_id.register_debug_idents(ident_ids);
|
||||
}
|
||||
|
||||
// println!("{}", test_helper.to_pretty(backend.interner(), 200, true));
|
||||
if let AssemblyBackendMode::Test = mode {
|
||||
if false {
|
||||
println!("{}", test_helper.to_pretty(backend.interner(), 200, true));
|
||||
}
|
||||
|
||||
if let AssemblyBackendMode::Test = backend.env().mode {
|
||||
build_proc_symbol(
|
||||
&mut output,
|
||||
&mut layout_ids,
|
||||
|
@ -23,6 +23,9 @@ const LAYOUT_UNIT: InLayout = Layout::UNIT;
|
||||
const ARG_1: Symbol = Symbol::ARG_1;
|
||||
const ARG_2: Symbol = Symbol::ARG_2;
|
||||
const ARG_3: Symbol = Symbol::ARG_3;
|
||||
const ARG_4: Symbol = Symbol::ARG_4;
|
||||
const ARG_5: Symbol = Symbol::ARG_5;
|
||||
const ARG_6: Symbol = Symbol::ARG_6;
|
||||
|
||||
/// "Infinite" reference count, for static values
|
||||
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
|
||||
@ -657,7 +660,7 @@ impl<'a> CallerProc<'a> {
|
||||
Self::create_symbol(home, ident_ids, &debug_name)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
pub fn new_list_map(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
@ -665,6 +668,17 @@ impl<'a> CallerProc<'a> {
|
||||
passed_function: &PassedFunction<'a>,
|
||||
capture_layout: Option<InLayout<'a>>,
|
||||
) -> Self {
|
||||
assert!(passed_function.argument_layouts.len() <= 4);
|
||||
const ARG_SYMBOLS: &[Symbol] = &[ARG_1, ARG_2, ARG_3, ARG_4, ARG_5, ARG_6];
|
||||
|
||||
let argument_layouts = match capture_layout {
|
||||
None => passed_function.argument_layouts,
|
||||
Some(_) => &passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
let capture_symbol = ARG_SYMBOLS[0];
|
||||
let return_symbol = ARG_SYMBOLS[1 + argument_layouts.len()];
|
||||
|
||||
let mut ctx = Context {
|
||||
new_linker_data: Vec::new_in(arena),
|
||||
recursive_union: None,
|
||||
@ -677,14 +691,21 @@ impl<'a> CallerProc<'a> {
|
||||
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(Layout::UNIT))
|
||||
};
|
||||
|
||||
let ptr_argument_layout = layout_interner
|
||||
.insert_direct_no_semantic(LayoutRepr::Ptr(passed_function.argument_layouts[0]));
|
||||
let it = argument_layouts
|
||||
.iter()
|
||||
.map(|l| layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(*l)));
|
||||
let ptr_argument_layouts = Vec::from_iter_in(it, arena);
|
||||
|
||||
let ptr_return_layout = layout_interner
|
||||
.insert_direct_no_semantic(LayoutRepr::Ptr(passed_function.return_layout));
|
||||
|
||||
let mut arguments = Vec::with_capacity_in(1 + ptr_argument_layouts.len() + 1, arena);
|
||||
arguments.push(ptr_capture_layout);
|
||||
arguments.extend(ptr_argument_layouts.iter().copied());
|
||||
arguments.push(ptr_return_layout);
|
||||
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arena.alloc([ptr_capture_layout, ptr_argument_layout, ptr_return_layout]),
|
||||
arguments: arguments.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
niche: Niche::NONE,
|
||||
};
|
||||
@ -694,15 +715,24 @@ impl<'a> CallerProc<'a> {
|
||||
|
||||
ctx.new_linker_data.push((proc_symbol, proc_layout));
|
||||
|
||||
let load_capture = Expr::ptr_load(arena.alloc(Symbol::ARG_1));
|
||||
let load_argument = Expr::ptr_load(arena.alloc(Symbol::ARG_2));
|
||||
let load_capture = Expr::ptr_load(arena.alloc(capture_symbol));
|
||||
|
||||
let loaded_capture = Self::create_symbol(home, ident_ids, "loaded_capture");
|
||||
let loaded_argument = Self::create_symbol(home, ident_ids, "loaded_argument");
|
||||
let call_result = Self::create_symbol(home, ident_ids, "call_result");
|
||||
let unit_symbol = Self::create_symbol(home, ident_ids, "unit_symbol");
|
||||
let ignored = Self::create_symbol(home, ident_ids, "ignored");
|
||||
|
||||
let loaded_arguments = Vec::from_iter_in(
|
||||
(0..argument_layouts.len())
|
||||
.map(|i| Self::create_symbol(home, ident_ids, &format!("loaded_argument_{i}"))),
|
||||
arena,
|
||||
);
|
||||
|
||||
let mut arguments = loaded_arguments.clone();
|
||||
if capture_layout.is_some() {
|
||||
arguments.push(loaded_capture);
|
||||
}
|
||||
|
||||
let call = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
name: passed_function.name,
|
||||
@ -710,11 +740,7 @@ impl<'a> CallerProc<'a> {
|
||||
arg_layouts: passed_function.argument_layouts,
|
||||
specialization_id: passed_function.specialization_id,
|
||||
},
|
||||
arguments: if capture_layout.is_some() {
|
||||
arena.alloc([loaded_argument, loaded_capture])
|
||||
} else {
|
||||
arena.alloc([loaded_argument])
|
||||
},
|
||||
arguments: arguments.into_bump_slice(),
|
||||
});
|
||||
|
||||
let ptr_write = Expr::Call(Call {
|
||||
@ -722,31 +748,43 @@ impl<'a> CallerProc<'a> {
|
||||
op: LowLevel::PtrStore,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: arena.alloc([Symbol::ARG_3, call_result]),
|
||||
arguments: arena.alloc([return_symbol, call_result]),
|
||||
});
|
||||
|
||||
let mut body = Stmt::Let(
|
||||
loaded_argument,
|
||||
load_argument,
|
||||
passed_function.argument_layouts[0],
|
||||
call_result,
|
||||
call,
|
||||
passed_function.return_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
call_result,
|
||||
call,
|
||||
passed_function.return_layout,
|
||||
ignored,
|
||||
ptr_write,
|
||||
ptr_return_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
ignored,
|
||||
ptr_write,
|
||||
ptr_return_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
unit_symbol,
|
||||
Expr::Struct(&[]),
|
||||
Layout::UNIT,
|
||||
arena.alloc(Stmt::Ret(unit_symbol)),
|
||||
)),
|
||||
unit_symbol,
|
||||
Expr::Struct(&[]),
|
||||
Layout::UNIT,
|
||||
arena.alloc(Stmt::Ret(unit_symbol)),
|
||||
)),
|
||||
)),
|
||||
);
|
||||
|
||||
let it = loaded_arguments
|
||||
.iter()
|
||||
.zip(ARG_SYMBOLS.iter().skip(1))
|
||||
.zip(argument_layouts.iter())
|
||||
.rev();
|
||||
|
||||
for ((loaded_argument, load_argument), argument_layout) in it {
|
||||
let load_argument = Expr::ptr_load(arena.alloc(load_argument));
|
||||
|
||||
body = Stmt::Let(
|
||||
*loaded_argument,
|
||||
load_argument,
|
||||
*argument_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(capture_layout) = capture_layout {
|
||||
body = Stmt::Let(
|
||||
loaded_capture,
|
||||
@ -756,17 +794,18 @@ impl<'a> CallerProc<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
let args: &'a [(InLayout<'a>, Symbol)] = {
|
||||
arena.alloc([
|
||||
(ptr_capture_layout, ARG_1),
|
||||
(ptr_argument_layout, ARG_2),
|
||||
(ptr_return_layout, ARG_3),
|
||||
])
|
||||
};
|
||||
let mut arg_symbols = ARG_SYMBOLS.iter();
|
||||
let mut args = Vec::with_capacity_in(1 + ptr_argument_layouts.len() + 1, arena);
|
||||
|
||||
args.push((ptr_capture_layout, *arg_symbols.next().unwrap()));
|
||||
for l in &ptr_argument_layouts {
|
||||
args.push((*l, *arg_symbols.next().unwrap()));
|
||||
}
|
||||
args.push((ptr_return_layout, *arg_symbols.next().unwrap()));
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(proc_symbol),
|
||||
args,
|
||||
args: args.into_bump_slice(),
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: Layout::UNIT,
|
||||
@ -775,19 +814,150 @@ impl<'a> CallerProc<'a> {
|
||||
};
|
||||
|
||||
if false {
|
||||
let allocator = ven_pretty::BoxAllocator;
|
||||
let doc = proc
|
||||
.to_doc::<_, (), _>(
|
||||
&allocator,
|
||||
layout_interner,
|
||||
true,
|
||||
crate::ir::Parens::NotNeeded,
|
||||
)
|
||||
.1
|
||||
.pretty(80)
|
||||
.to_string();
|
||||
home.register_debug_idents(ident_ids);
|
||||
println!("{}", proc.to_pretty(layout_interner, 200, true));
|
||||
}
|
||||
|
||||
println!("{doc}");
|
||||
Self {
|
||||
proc_symbol,
|
||||
proc_layout,
|
||||
proc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_compare(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
passed_function: &PassedFunction<'a>,
|
||||
capture_layout: Option<InLayout<'a>>,
|
||||
) -> Self {
|
||||
const ARG_SYMBOLS: &[Symbol] = &[ARG_1, ARG_2, ARG_3];
|
||||
|
||||
let argument_layouts = match capture_layout {
|
||||
None => passed_function.argument_layouts,
|
||||
Some(_) => &passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
let capture_symbol = ARG_SYMBOLS[0];
|
||||
|
||||
let mut ctx = Context {
|
||||
new_linker_data: Vec::new_in(arena),
|
||||
recursive_union: None,
|
||||
op: HelperOp::Eq,
|
||||
};
|
||||
|
||||
let ptr_capture_layout = if let Some(capture_layout) = capture_layout {
|
||||
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(capture_layout))
|
||||
} else {
|
||||
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(Layout::UNIT))
|
||||
};
|
||||
|
||||
let it = argument_layouts
|
||||
.iter()
|
||||
.map(|l| layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(*l)));
|
||||
let ptr_argument_layouts = Vec::from_iter_in(it, arena);
|
||||
|
||||
let mut arguments = Vec::with_capacity_in(1 + ptr_argument_layouts.len(), arena);
|
||||
arguments.push(ptr_capture_layout);
|
||||
arguments.extend(ptr_argument_layouts.iter().copied());
|
||||
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arguments.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
niche: Niche::NONE,
|
||||
};
|
||||
|
||||
let proc_symbol = Self::create_caller_proc_symbol(
|
||||
home,
|
||||
ident_ids,
|
||||
"compare",
|
||||
passed_function.name.name(),
|
||||
);
|
||||
|
||||
ctx.new_linker_data.push((proc_symbol, proc_layout));
|
||||
|
||||
let load_capture = Expr::ptr_load(arena.alloc(capture_symbol));
|
||||
|
||||
let loaded_capture = Self::create_symbol(home, ident_ids, "loaded_capture");
|
||||
let call_result = Self::create_symbol(home, ident_ids, "call_result");
|
||||
|
||||
let loaded_arguments = Vec::from_iter_in(
|
||||
(0..argument_layouts.len())
|
||||
.map(|i| Self::create_symbol(home, ident_ids, &format!("loaded_argument_{i}"))),
|
||||
arena,
|
||||
);
|
||||
|
||||
let mut arguments = loaded_arguments.clone();
|
||||
if capture_layout.is_some() {
|
||||
arguments.push(loaded_capture);
|
||||
}
|
||||
|
||||
let call = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
name: passed_function.name,
|
||||
ret_layout: passed_function.return_layout,
|
||||
arg_layouts: passed_function.argument_layouts,
|
||||
specialization_id: passed_function.specialization_id,
|
||||
},
|
||||
arguments: arguments.into_bump_slice(),
|
||||
});
|
||||
|
||||
let mut body = Stmt::Let(
|
||||
call_result,
|
||||
call,
|
||||
passed_function.return_layout,
|
||||
arena.alloc(Stmt::Ret(call_result)),
|
||||
);
|
||||
|
||||
let it = loaded_arguments
|
||||
.iter()
|
||||
.zip(ARG_SYMBOLS.iter().skip(1))
|
||||
.zip(argument_layouts.iter())
|
||||
.rev();
|
||||
|
||||
for ((loaded_argument, load_argument), argument_layout) in it {
|
||||
let load_argument = Expr::ptr_load(arena.alloc(load_argument));
|
||||
|
||||
body = Stmt::Let(
|
||||
*loaded_argument,
|
||||
load_argument,
|
||||
*argument_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(capture_layout) = capture_layout {
|
||||
body = Stmt::Let(
|
||||
loaded_capture,
|
||||
load_capture,
|
||||
capture_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
let mut arg_symbols = ARG_SYMBOLS.iter();
|
||||
let mut args = Vec::with_capacity_in(1 + ptr_argument_layouts.len(), arena);
|
||||
|
||||
args.push((ptr_capture_layout, *arg_symbols.next().unwrap()));
|
||||
for l in &ptr_argument_layouts {
|
||||
args.push((*l, *arg_symbols.next().unwrap()));
|
||||
}
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(proc_symbol),
|
||||
args: args.into_bump_slice(),
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: Layout::BOOL,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
is_erased: false,
|
||||
};
|
||||
|
||||
if false {
|
||||
home.register_debug_idents(ident_ids);
|
||||
println!("{}", proc.to_pretty(layout_interner, 200, true));
|
||||
}
|
||||
|
||||
Self {
|
||||
|
@ -1388,7 +1388,7 @@ fn list_map_closure_string() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map4_group() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1402,7 +1402,7 @@ fn list_map4_group() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map4_different_length() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1421,7 +1421,7 @@ fn list_map4_different_length() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map3_group() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1435,7 +1435,7 @@ fn list_map3_group() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map3_different_length() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1453,7 +1453,7 @@ fn list_map3_different_length() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map2_pair() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -1468,7 +1468,7 @@ fn list_map2_pair() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_map2_different_lengths() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
@ -2909,7 +2909,7 @@ fn cleanup_because_exception() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_with() {
|
||||
assert_evals_to!(
|
||||
"List.sortWith [] Num.compare",
|
||||
@ -2929,7 +2929,7 @@ fn list_sort_with() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_asc() {
|
||||
assert_evals_to!(
|
||||
"List.sortAsc []",
|
||||
@ -2944,7 +2944,7 @@ fn list_sort_asc() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_desc() {
|
||||
assert_evals_to!(
|
||||
"List.sortDesc []",
|
||||
|
@ -7,8 +7,11 @@ use crate::helpers::llvm::assert_evals_to;
|
||||
#[cfg(feature = "gen-wasm")]
|
||||
use crate::helpers::wasm::assert_evals_to;
|
||||
|
||||
#[cfg(feature = "gen-dev")]
|
||||
use crate::helpers::dev::assert_evals_to;
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic = r#"User crash with message: "hello crash""#]
|
||||
fn crash_literal() {
|
||||
assert_evals_to!(
|
||||
@ -25,7 +28,7 @@ fn crash_literal() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic = r#"User crash with message: "hello crash""#]
|
||||
fn crash_variable() {
|
||||
assert_evals_to!(
|
||||
@ -44,7 +47,7 @@ fn crash_variable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic = r#"User crash with message: "turns out this was fallible""#]
|
||||
fn crash_in_call() {
|
||||
assert_evals_to!(
|
||||
@ -68,7 +71,7 @@ fn crash_in_call() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic = r#"User crash with message: "no new even primes""#]
|
||||
fn crash_in_passed_closure() {
|
||||
assert_evals_to!(
|
||||
|
Loading…
Reference in New Issue
Block a user