Fix StructReturn handling: properly mark the clobber, and offset actual rets. (#5023)

* Fix StructReturn handling: properly mark the clobber, and offset actual rets.

The legalization of `StructReturn` was causing issues in the new
call-handling code: the `StructReturn` ret was included in the `SigData` as
if it were an actual CLIF-level return value, but it is not.

Prior to using regalloc constraints for return values, we
unconditionally included rax (or the architecture's usual return
register) as a def, so it would be properly handled as "clobbered" by
the regalloc. With the new scheme, we include defs on the call only for
CLIF-level outputs. Callees with `StructReturn` args were thus not known
to clobber the return-value register, and values might be corrupted.

This PR updates the code to include a `StructReturn` ret as a clobber
rather than a returned value in the relevant spots. I observed it
causing saves/restores of rax in some CLIF that @bjorn3 provided me, but
I was having difficulty minimizing this into a test-case that I would be
comfortable including as a precise-output case (including the whole
thing verbatim would lock down a bunch of other irrelevant details and
cause test-update noise later). If we can find a more minimized example
I'm happy to include it as a filetest.

Fixes #5018.
This commit is contained in:
Chris Fallin
2022-10-06 17:14:38 -07:00
committed by GitHub
parent b454110ac7
commit e95ffe4413
4 changed files with 38 additions and 9 deletions

View File

@@ -1206,13 +1206,22 @@ macro_rules! isle_prelude_method_helpers {
self.lower_ctx.emit(inst);
}
}
// Handle retvals prior to emitting call, so the
// constraints are on the call instruction; but buffer the
// instructions till after the call.
let mut outputs = InstOutput::new();
let mut retval_insts: crate::machinst::abi::SmallInstVec<_> = smallvec::smallvec![];
for i in 0..num_rets {
let ret = self.lower_ctx.sigs()[abi].get_ret(i);
// We take the *last* `num_rets` returns of the sig:
// this skips a StructReturn, if any, that is present.
let sigdata = &self.lower_ctx.sigs()[abi];
debug_assert!(num_rets <= sigdata.num_rets());
for i in (sigdata.num_rets() - num_rets)..sigdata.num_rets() {
// Borrow `sigdata` again so we don't hold a `self`
// borrow across the `&mut self` arg to
// `abi_arg_slot_regs()` below.
let sigdata = &self.lower_ctx.sigs()[abi];
let ret = sigdata.get_ret(i);
let retval_regs = self.abi_arg_slot_regs(&ret).unwrap();
retval_insts.extend(
caller