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:
@@ -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, .. } => {
|
||||
|
||||
Reference in New Issue
Block a user