mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
enable returning structs
That being said the support is very limited. It really only supports single field structs and the special case of 2 ints. I realized that general support for returning structs requires a calling conv extension for returning them. Instead of adding all of the calling conv versions, I just added a few basic cases that are shared accross calling conv. It turns out that the calling conv extension is quite detailed for how it works in Arm. X86 isn't too detailed overall.
This commit is contained in:
parent
ba58e1bbf4
commit
6a38ec03ed
3 changed files with 115 additions and 74 deletions
|
@ -523,19 +523,29 @@ impl<
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let Layout::Struct(field_layouts) = layout {
|
if let Layout::Struct(field_layouts) = layout {
|
||||||
let struct_size = layout.stack_size(PTR_SIZE);
|
let struct_size = layout.stack_size(PTR_SIZE);
|
||||||
let offset = self.increase_stack_size(struct_size)?;
|
if struct_size > 0 {
|
||||||
self.symbol_storage_map
|
let offset = self.increase_stack_size(struct_size)?;
|
||||||
.insert(*sym, SymbolStorage::Base(offset));
|
self.symbol_storage_map
|
||||||
|
.insert(*sym, SymbolStorage::Base(offset));
|
||||||
|
|
||||||
let mut current_offset = offset;
|
let mut current_offset = offset;
|
||||||
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
|
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
|
||||||
self.copy_symbol_to_stack_offset(current_offset, field, field_layout)?;
|
self.copy_symbol_to_stack_offset(current_offset, field, field_layout)?;
|
||||||
let field_size = field_layout.stack_size(PTR_SIZE);
|
let field_size = field_layout.stack_size(PTR_SIZE);
|
||||||
current_offset += field_size as i32;
|
current_offset += field_size as i32;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.symbol_storage_map.insert(*sym, SymbolStorage::Base(0));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(format!("struct has invalid layout: {:?}", layout))
|
// This is a single element struct. Just copy the single field to the stack.
|
||||||
|
let struct_size = layout.stack_size(PTR_SIZE);
|
||||||
|
let offset = self.increase_stack_size(struct_size)?;
|
||||||
|
self.symbol_storage_map
|
||||||
|
.insert(*sym, SymbolStorage::Base(offset));
|
||||||
|
self.copy_symbol_to_stack_offset(offset, &fields[0], layout)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,6 +625,41 @@ impl<
|
||||||
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
|
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Layout::Struct(
|
||||||
|
&[Layout::Builtin(Builtin::Int64), Layout::Builtin(Builtin::Int64)],
|
||||||
|
) => {
|
||||||
|
if let Some(SymbolStorage::Base(struct_offset)) =
|
||||||
|
self.symbol_storage_map.get(sym)
|
||||||
|
{
|
||||||
|
ASM::mov_reg64_base32(
|
||||||
|
&mut self.buf,
|
||||||
|
CC::GENERAL_RETURN_REGS[0],
|
||||||
|
*struct_offset,
|
||||||
|
);
|
||||||
|
ASM::mov_reg64_base32(
|
||||||
|
&mut self.buf,
|
||||||
|
CC::GENERAL_RETURN_REGS[1],
|
||||||
|
*struct_offset + 8,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("unknown struct: {:?}", sym))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Layout::Struct(_field_layouts) => {
|
||||||
|
let struct_size = layout.stack_size(PTR_SIZE);
|
||||||
|
if struct_size > 0 {
|
||||||
|
// Need at actually dispatch to call conv here since struct return is specific to that.
|
||||||
|
// CC::return_struct()
|
||||||
|
Err(format!(
|
||||||
|
"Returning struct with layout, {:?}, is not yet implemented",
|
||||||
|
layout
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
// Nothing to do for empty struct
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
x => Err(format!(
|
x => Err(format!(
|
||||||
"returning symbol with layout, {:?}, is not yet implemented",
|
"returning symbol with layout, {:?}, is not yet implemented",
|
||||||
x
|
x
|
||||||
|
|
|
@ -221,19 +221,19 @@ mod gen_record {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn when_on_record() {
|
fn when_on_record() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// when { x: 0x2 } is
|
when { x: 0x2 } is
|
||||||
// { x } -> x + 3
|
{ x } -> x + 3
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// 5,
|
5,
|
||||||
// i64
|
i64
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn when_record_with_guard_pattern() {
|
fn when_record_with_guard_pattern() {
|
||||||
|
@ -293,32 +293,46 @@ mod gen_record {
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// #[test]
|
#[test]
|
||||||
// fn empty_record() {
|
fn empty_record() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// v = {}
|
v = {}
|
||||||
|
|
||||||
// v
|
v
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// (),
|
(),
|
||||||
// ()
|
()
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// #[test]
|
|
||||||
// fn i64_record2_literal() {
|
#[test]
|
||||||
// assert_evals_to!(
|
fn i64_record1_literal() {
|
||||||
// indoc!(
|
assert_evals_to!(
|
||||||
// r#"
|
indoc!(
|
||||||
// { x: 3, y: 5 }
|
r#"
|
||||||
// "#
|
{ x: 3 }
|
||||||
// ),
|
"#
|
||||||
// (3, 5),
|
),
|
||||||
// (i64, i64)
|
3,
|
||||||
// );
|
i64
|
||||||
// }
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn i64_record2_literal() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{ x: 3, y: 5 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(3, 5),
|
||||||
|
(i64, i64)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// // #[test]
|
// // #[test]
|
||||||
// // fn i64_record3_literal() {
|
// // fn i64_record3_literal() {
|
||||||
|
@ -430,22 +444,6 @@ mod gen_record {
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn return_record() {
|
|
||||||
// assert_evals_to!(
|
|
||||||
// indoc!(
|
|
||||||
// r#"
|
|
||||||
// x = 4
|
|
||||||
// y = 3
|
|
||||||
|
|
||||||
// { x, y }
|
|
||||||
// "#
|
|
||||||
// ),
|
|
||||||
// (4, 3),
|
|
||||||
// (i64, i64)
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn optional_field_when_use_default() {
|
// fn optional_field_when_use_default() {
|
||||||
// assert_evals_to!(
|
// assert_evals_to!(
|
||||||
|
|
|
@ -67,19 +67,17 @@ pub fn helper<'a>(
|
||||||
..
|
..
|
||||||
} = loaded;
|
} = loaded;
|
||||||
|
|
||||||
/*
|
// println!("=========== Procedures ==========");
|
||||||
println!("=========== Procedures ==========");
|
// println!("{:?}", procedures);
|
||||||
println!("{:?}", procedures);
|
// println!("=================================\n");
|
||||||
println!("=================================\n");
|
|
||||||
|
|
||||||
println!("=========== Interns ==========");
|
// println!("=========== Interns ==========");
|
||||||
println!("{:?}", interns);
|
// println!("{:?}", interns);
|
||||||
println!("=================================\n");
|
// println!("=================================\n");
|
||||||
|
|
||||||
println!("=========== Exposed ==========");
|
// println!("=========== Exposed ==========");
|
||||||
println!("{:?}", exposed_to_host);
|
// println!("{:?}", exposed_to_host);
|
||||||
println!("=================================\n");
|
// println!("=================================\n");
|
||||||
*/
|
|
||||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||||
let main_fn_symbol = exposed_to_host.keys().copied().next().unwrap();
|
let main_fn_symbol = exposed_to_host.keys().copied().next().unwrap();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue