diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs index fdb9f29f49..733d35cdf3 100644 --- a/cranelift/codegen/src/isa/aarch64/abi.rs +++ b/cranelift/codegen/src/isa/aarch64/abi.rs @@ -3,9 +3,9 @@ use crate::ir; use crate::ir::types; use crate::ir::types::*; -use crate::ir::StackSlot; +use crate::ir::{ArgumentExtension, StackSlot}; use crate::isa; -use crate::isa::aarch64::inst::*; +use crate::isa::aarch64::{self, inst::*}; use crate::machinst::*; use crate::settings; @@ -469,11 +469,67 @@ impl ABIBody for AArch64ABIBody { } } - fn gen_copy_reg_to_retval(&self, idx: usize, from_reg: Reg) -> Inst { + fn gen_copy_reg_to_retval( + &self, + idx: usize, + from_reg: Writable, + ext: ArgumentExtension, + ) -> Vec { + let mut ret = Vec::new(); match &self.sig.rets[idx] { - &ABIArg::Reg(r, ty) => Inst::gen_move(Writable::from_reg(r.to_reg()), from_reg, ty), - &ABIArg::Stack(off, ty) => store_stack(off + self.frame_size(), from_reg, ty), + &ABIArg::Reg(r, ty) => { + let from_bits = aarch64::lower::ty_bits(ty) as u8; + let dest_reg = Writable::from_reg(r.to_reg()); + match (ext, from_bits) { + (ArgumentExtension::Uext, n) if n < 64 => { + ret.push(Inst::Extend { + rd: dest_reg, + rn: from_reg.to_reg(), + signed: false, + from_bits, + to_bits: 64, + }); + } + (ArgumentExtension::Sext, n) if n < 64 => { + ret.push(Inst::Extend { + rd: dest_reg, + rn: from_reg.to_reg(), + signed: true, + from_bits, + to_bits: 64, + }); + } + _ => ret.push(Inst::gen_move(dest_reg, from_reg.to_reg(), ty)), + }; + } + &ABIArg::Stack(off, ty) => { + let from_bits = aarch64::lower::ty_bits(ty) as u8; + // Trash the from_reg; it should be its last use. + match (ext, from_bits) { + (ArgumentExtension::Uext, n) if n < 64 => { + ret.push(Inst::Extend { + rd: from_reg, + rn: from_reg.to_reg(), + signed: false, + from_bits, + to_bits: 64, + }); + } + (ArgumentExtension::Sext, n) if n < 64 => { + ret.push(Inst::Extend { + rd: from_reg, + rn: from_reg.to_reg(), + signed: true, + from_bits, + to_bits: 64, + }); + } + _ => {} + }; + ret.push(store_stack(off + self.frame_size(), from_reg.to_reg(), ty)) + } } + ret } fn gen_ret(&self) -> Inst { diff --git a/cranelift/codegen/src/isa/aarch64/lower.rs b/cranelift/codegen/src/isa/aarch64/lower.rs index ac5adc8dd4..2771153052 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.rs +++ b/cranelift/codegen/src/isa/aarch64/lower.rs @@ -2364,7 +2364,9 @@ fn lower_insn_to_regs>(ctx: &mut C, insn: IRInst) { //============================================================================= // Helpers for instruction lowering. -fn ty_bits(ty: Type) -> usize { + +/// Returns the size (in bits) of a given type. +pub fn ty_bits(ty: Type) -> usize { match ty { B1 => 1, B8 | I8 => 8, diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs index 070af59d77..e22bc0bdc4 100644 --- a/cranelift/codegen/src/machinst/abi.rs +++ b/cranelift/codegen/src/machinst/abi.rs @@ -1,6 +1,6 @@ //! ABI definitions. -use crate::ir::StackSlot; +use crate::ir::{ArgumentExtension, StackSlot}; use crate::machinst::*; use crate::settings; @@ -34,9 +34,13 @@ pub trait ABIBody { /// register. fn gen_copy_arg_to_reg(&self, idx: usize, into_reg: Writable) -> Self::I; - /// Generate an instruction which copies a source register to a return - /// value slot. - fn gen_copy_reg_to_retval(&self, idx: usize, from_reg: Reg) -> Self::I; + /// Generate an instruction which copies a source register to a return value slot. + fn gen_copy_reg_to_retval( + &self, + idx: usize, + from_reg: Writable, + ext: ArgumentExtension, + ) -> Vec; /// Generate a return instruction. fn gen_ret(&self) -> Self::I; diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs index 2fa456627a..a2686d523c 100644 --- a/cranelift/codegen/src/machinst/lower.rs +++ b/cranelift/codegen/src/machinst/lower.rs @@ -6,8 +6,8 @@ use crate::entity::SecondaryMap; use crate::inst_predicates::has_side_effect; use crate::ir::instructions::BranchInfo; use crate::ir::{ - Block, ExternalName, Function, GlobalValueData, Inst, InstructionData, MemFlags, Opcode, - Signature, SourceLoc, Type, Value, ValueDef, + ArgumentExtension, Block, ExternalName, Function, GlobalValueData, Inst, InstructionData, + MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef, }; use crate::machinst::{ABIBody, BlockIndex, VCode, VCodeBuilder, VCodeInst}; use crate::num_uses::NumUses; @@ -116,7 +116,7 @@ pub struct Lower<'func, I: VCodeInst> { value_regs: SecondaryMap, /// Return-value vregs. - retval_regs: Vec, + retval_regs: Vec<(Reg, ArgumentExtension)>, /// Next virtual register number to allocate. next_vreg: u32, @@ -190,7 +190,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> { next_vreg += 1; let regclass = I::rc_for_type(ret.value_type); let vreg = Reg::new_virtual(regclass, v); - retval_regs.push(vreg); + retval_regs.push((vreg, ret.extension)); vcode.set_vreg_type(vreg.as_virtual_reg().unwrap(), ret.value_type); } @@ -220,9 +220,12 @@ impl<'func, I: VCodeInst> Lower<'func, I> { } fn gen_retval_setup(&mut self, gen_ret_inst: GenerateReturn) { - for (i, reg) in self.retval_regs.iter().enumerate() { - let insn = self.vcode.abi().gen_copy_reg_to_retval(i, *reg); - self.vcode.push(insn); + for (i, (reg, ext)) in self.retval_regs.iter().enumerate() { + let reg = Writable::from_reg(*reg); + let insns = self.vcode.abi().gen_copy_reg_to_retval(i, reg, *ext); + for insn in insns { + self.vcode.push(insn); + } } let inst = match gen_ret_inst { GenerateReturn::Yes => self.vcode.abi().gen_ret(), @@ -640,7 +643,7 @@ impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> { /// Get the register for a return value. fn retval(&self, idx: usize) -> Writable { - Writable::from_reg(self.retval_regs[idx]) + Writable::from_reg(self.retval_regs[idx].0) } /// Get the target for a call instruction, as an `ExternalName`.