fix returning an aggregate value with ccc

This commit is contained in:
Folkert 2021-11-22 10:17:17 +01:00
parent 5a8c3d4f0f
commit 78c26c6096
2 changed files with 78 additions and 7 deletions

View file

@ -247,24 +247,91 @@ impl<'a> Storage<'a> {
} => {
let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer);
code_builder.get_local(local_id);
if format == StackMemoryFormat::Aggregate {
code_builder.get_local(local_id);
if offset != 0 {
code_builder.i32_const(offset as i32);
code_builder.i32_add();
}
code_builder.set_top_symbol(sym);
} else {
// It's one of the 128-bit numbers, all of which we load as two i64's
// (Mark the same Symbol twice. Shouldn't matter except for debugging.)
code_builder.get_local(local_id);
code_builder.i64_load(Align::Bytes8, offset);
code_builder.set_top_symbol(sym);
code_builder.get_local(local_id);
code_builder.i64_load(Align::Bytes8, offset + 8);
code_builder.set_top_symbol(sym);
}
code_builder.set_top_symbol(sym);
}
}
}
/// Return a value with the C calling convention. The difference with passing an argument is in
/// the StackMemory case, where we pass a pointer to write the result into.
fn return_symbol_ccc(&mut self, code_builder: &mut CodeBuilder, sym: Symbol) {
let storage = self.get(&sym).to_owned();
match storage {
StoredValue::VirtualMachineStack {
vm_state,
value_type,
size,
} => {
let next_local_id = self.get_next_local_id();
let maybe_next_vm_state = code_builder.load_symbol(sym, vm_state, next_local_id);
match maybe_next_vm_state {
// The act of loading the value changed the VM state, so update it
Some(next_vm_state) => {
self.symbol_storage_map.insert(
sym,
StoredValue::VirtualMachineStack {
vm_state: next_vm_state,
value_type,
size,
},
);
}
None => {
// Loading the value required creating a new local, because
// it was not in a convenient position in the VM stack.
self.local_types.push(value_type);
self.symbol_storage_map.insert(
sym,
StoredValue::Local {
local_id: next_local_id,
value_type,
size,
},
);
}
}
}
StoredValue::Local { local_id, .. } => {
code_builder.get_local(local_id);
code_builder.set_top_symbol(sym);
}
StoredValue::StackMemory { location, .. } => {
let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer);
// stack memory values are returned by pointer. e.g. a roc function
//
// add : I128, I128 -> I128
//
// is given the wasm type
//
// add : (i32, i64, i64, i64, i64) -> nil
//
// The returned value is written to the address passed as the first argument
code_builder.get_local(local_id);
if offset != 0 {
code_builder.i32_const(offset as i32);
code_builder.i32_add();
}
code_builder.set_top_symbol(sym);
}
}
}
@ -302,7 +369,7 @@ impl<'a> Storage<'a> {
if return_layout.is_stack_memory() {
// Load the address where the return value should be written
// Apparently for return values we still use a pointer to stack memory
self.load_symbol_ccc(code_builder, return_symbol);
self.return_symbol_ccc(code_builder, return_symbol);
};
for sym in symbols {