AArch64 ABI: properly store full 64-bit width of extended args/retvals.

When storing an argument to a stack location for consumption by a
callee, or storing a return value to an on-stack return slot for
consumption by the caller, the ABI implementation was properly extending
the value but was then performing a store with only the original width.
This fixes the issue by always performing a 64-bit store of the extended
value.

Issue reported by @uweigand (thanks!).
This commit is contained in:
Chris Fallin
2020-08-17 14:57:31 -07:00
parent 7fdbd081e6
commit 5fa0be3515
2 changed files with 64 additions and 3 deletions

View File

@@ -674,11 +674,12 @@ impl<M: ABIMachineImpl> ABIBody for ABIBodyImpl<M> {
_ => ret.push(M::gen_move(dest_reg, from_reg.to_reg(), ty)),
};
}
&ABIArg::Stack(off, ty, ext) => {
&ABIArg::Stack(off, mut ty, ext) => {
let from_bits = ty_bits(ty) as u8;
// Trash the from_reg; it should be its last use.
match (ext, from_bits) {
(ArgumentExtension::Uext, n) | (ArgumentExtension::Sext, n) if n < 64 => {
assert_eq!(RegClass::I64, from_reg.to_reg().get_class());
let signed = ext == ArgumentExtension::Sext;
ret.push(M::gen_extend(
from_reg,
@@ -687,6 +688,8 @@ impl<M: ABIMachineImpl> ABIBody for ABIBodyImpl<M> {
from_bits,
/* to_bits = */ 64,
));
// Store the extended version.
ty = I64;
}
_ => {}
};
@@ -1083,7 +1086,7 @@ impl<M: ABIMachineImpl> ABICall for ABICallImpl<M> {
&ABIArg::Reg(reg, ty, _) => {
ctx.emit(M::gen_move(Writable::from_reg(reg.to_reg()), from_reg, ty));
}
&ABIArg::Stack(off, ty, ext) => {
&ABIArg::Stack(off, mut ty, ext) => {
if ext != ir::ArgumentExtension::None && ty_bits(ty) < 64 {
assert_eq!(RegClass::I64, from_reg.get_class());
let signed = match ext {
@@ -1101,6 +1104,8 @@ impl<M: ABIMachineImpl> ABICall for ABICallImpl<M> {
ty_bits(ty) as u8,
64,
));
// Store the extended version.
ty = I64;
}
ctx.emit(M::gen_store_stack(
StackAMode::SPOffset(off, ty),