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:
Brendan Hansknecht 2021-05-15 23:01:23 -07:00
parent ba58e1bbf4
commit 6a38ec03ed
3 changed files with 115 additions and 74 deletions

View file

@ -523,6 +523,7 @@ 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);
if struct_size > 0 {
let offset = self.increase_stack_size(struct_size)?; let offset = self.increase_stack_size(struct_size)?;
self.symbol_storage_map self.symbol_storage_map
.insert(*sym, SymbolStorage::Base(offset)); .insert(*sym, SymbolStorage::Base(offset));
@ -533,9 +534,18 @@ impl<
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

View file

@ -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!(

View file

@ -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();