machinst aarch64: in baldrdash, allow returning only one value across register classes;

Baldrdash's API requires that there is at most one result in a register,
across all the possible register classes: in particular, it's not
possible to return an i64 value in a register while returning an v128
value in another register.

This patch adds a notion of "remaining register values", so this is
properly taking into account when choosing whether a return value may be
put into a register or not.
This commit is contained in:
Benjamin Bouvier
2020-08-31 11:29:41 +02:00
parent e535005c74
commit a7f7c23bf9

View File

@@ -124,10 +124,18 @@ impl ABIMachineImpl for AArch64MachineImpl {
let mut next_stack: u64 = 0; let mut next_stack: u64 = 0;
let mut ret = vec![]; let mut ret = vec![];
let max_reg_vals = match (args_or_rets, is_baldrdash) { // Note on return values: on the regular non-baldrdash ABI, we may return values in 8
(ArgsOrRets::Args, _) => 8, // x0-x7, v0-v7 // registers for V128 and I64 registers independently of the number of register values
(ArgsOrRets::Rets, false) => 8, // x0-x7, v0-v7 // returned in the other class. That is, we can return values in up to 8 integer and 8
(ArgsOrRets::Rets, true) => 1, // x0 or v0 // vector registers at once.
// In Baldrdash, we can only use one register for return value for all the register
// classes. That is, we can't return values in both one integer and one vector register;
// only one return value may be in a register.
let (max_per_class_reg_vals, mut remaining_reg_vals) = match (args_or_rets, is_baldrdash) {
(ArgsOrRets::Args, _) => (8, 16), // x0-x7 and v0-v7
(ArgsOrRets::Rets, false) => (8, 16), // x0-x7 and v0-v7
(ArgsOrRets::Rets, true) => (1, 1), // x0 or v0, but not both
}; };
for i in 0..params.len() { for i in 0..params.len() {
@@ -167,7 +175,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
if let Some(param) = try_fill_baldrdash_reg(call_conv, param) { if let Some(param) = try_fill_baldrdash_reg(call_conv, param) {
assert!(rc == RegClass::I64); assert!(rc == RegClass::I64);
ret.push(param); ret.push(param);
} else if *next_reg < max_reg_vals { } else if *next_reg < max_per_class_reg_vals && remaining_reg_vals > 0 {
let reg = match rc { let reg = match rc {
RegClass::I64 => xreg(*next_reg), RegClass::I64 => xreg(*next_reg),
RegClass::V128 => vreg(*next_reg), RegClass::V128 => vreg(*next_reg),
@@ -179,6 +187,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
param.extension, param.extension,
)); ));
*next_reg += 1; *next_reg += 1;
remaining_reg_vals -= 1;
} else { } else {
// Compute size. Every arg takes a minimum slot of 8 bytes. (16-byte // Compute size. Every arg takes a minimum slot of 8 bytes. (16-byte
// stack alignment happens separately after all args.) // stack alignment happens separately after all args.)
@@ -202,7 +211,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
let extra_arg = if add_ret_area_ptr { let extra_arg = if add_ret_area_ptr {
debug_assert!(args_or_rets == ArgsOrRets::Args); debug_assert!(args_or_rets == ArgsOrRets::Args);
if next_xreg < max_reg_vals { if next_xreg < max_per_class_reg_vals && remaining_reg_vals > 0 {
ret.push(ABIArg::Reg( ret.push(ABIArg::Reg(
xreg(next_xreg).to_real_reg(), xreg(next_xreg).to_real_reg(),
I64, I64,