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

@@ -561,7 +561,7 @@ pub struct Sig(u32);
cranelift_entity::entity_impl!(Sig);
/// ABI information shared between body (callee) and caller.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct SigData {
/// Argument locations (regs or stack slots). Stack offsets are relative to
/// SP on entry to function.
@@ -669,10 +669,17 @@ impl SigData {
// regs, which we will remove from the clobber set below.
let mut clobbers = M::get_regs_clobbered_by_call(self.call_conv);
// Compute defs: all retval regs, and all caller-save (clobbered) regs.
// Compute defs: all retval regs, and all caller-save
// (clobbered) regs, except for StructRet args.
let mut defs = smallvec![];
for ret in &self.rets {
if let &ABIArg::Slots { ref slots, .. } = ret {
if let &ABIArg::Slots {
ref slots, purpose, ..
} = ret
{
if purpose == ir::ArgumentPurpose::StructReturn {
continue;
}
for slot in slots {
match slot {
&ABIArgSlot::Reg { reg, .. } => {
@@ -694,9 +701,17 @@ impl SigData {
// regs, which we will remove from the clobber set below.
let mut clobbers = M::get_regs_clobbered_by_call(self.call_conv);
// Remove retval regs from clobbers.
// Remove retval regs from clobbers. Skip StructRets: these
// are not, semantically, returns at the CLIF level, so we
// treat such a value as a clobber instead.
for ret in &self.rets {
if let &ABIArg::Slots { ref slots, .. } = ret {
if let &ABIArg::Slots {
ref slots, purpose, ..
} = ret
{
if purpose == ir::ArgumentPurpose::StructReturn {
continue;
}
for slot in slots {
match slot {
&ABIArgSlot::Reg { reg, .. } => {