Baldrdash: implement support for sign-extension in returns;
This commit is contained in:
@@ -3,9 +3,9 @@
|
|||||||
use crate::ir;
|
use crate::ir;
|
||||||
use crate::ir::types;
|
use crate::ir::types;
|
||||||
use crate::ir::types::*;
|
use crate::ir::types::*;
|
||||||
use crate::ir::StackSlot;
|
use crate::ir::{ArgumentExtension, StackSlot};
|
||||||
use crate::isa;
|
use crate::isa;
|
||||||
use crate::isa::aarch64::inst::*;
|
use crate::isa::aarch64::{self, inst::*};
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::settings;
|
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<Reg>,
|
||||||
|
ext: ArgumentExtension,
|
||||||
|
) -> Vec<Inst> {
|
||||||
|
let mut ret = Vec::new();
|
||||||
match &self.sig.rets[idx] {
|
match &self.sig.rets[idx] {
|
||||||
&ABIArg::Reg(r, ty) => Inst::gen_move(Writable::from_reg(r.to_reg()), from_reg, ty),
|
&ABIArg::Reg(r, ty) => {
|
||||||
&ABIArg::Stack(off, ty) => store_stack(off + self.frame_size(), from_reg, 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 {
|
fn gen_ret(&self) -> Inst {
|
||||||
|
|||||||
@@ -2364,7 +2364,9 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(ctx: &mut C, insn: IRInst) {
|
|||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Helpers for instruction lowering.
|
// 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 {
|
match ty {
|
||||||
B1 => 1,
|
B1 => 1,
|
||||||
B8 | I8 => 8,
|
B8 | I8 => 8,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! ABI definitions.
|
//! ABI definitions.
|
||||||
|
|
||||||
use crate::ir::StackSlot;
|
use crate::ir::{ArgumentExtension, StackSlot};
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
@@ -34,9 +34,13 @@ pub trait ABIBody {
|
|||||||
/// register.
|
/// register.
|
||||||
fn gen_copy_arg_to_reg(&self, idx: usize, into_reg: Writable<Reg>) -> Self::I;
|
fn gen_copy_arg_to_reg(&self, idx: usize, into_reg: Writable<Reg>) -> Self::I;
|
||||||
|
|
||||||
/// Generate an instruction which copies a source register to a return
|
/// Generate an instruction which copies a source register to a return value slot.
|
||||||
/// value slot.
|
fn gen_copy_reg_to_retval(
|
||||||
fn gen_copy_reg_to_retval(&self, idx: usize, from_reg: Reg) -> Self::I;
|
&self,
|
||||||
|
idx: usize,
|
||||||
|
from_reg: Writable<Reg>,
|
||||||
|
ext: ArgumentExtension,
|
||||||
|
) -> Vec<Self::I>;
|
||||||
|
|
||||||
/// Generate a return instruction.
|
/// Generate a return instruction.
|
||||||
fn gen_ret(&self) -> Self::I;
|
fn gen_ret(&self) -> Self::I;
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use crate::entity::SecondaryMap;
|
|||||||
use crate::inst_predicates::has_side_effect;
|
use crate::inst_predicates::has_side_effect;
|
||||||
use crate::ir::instructions::BranchInfo;
|
use crate::ir::instructions::BranchInfo;
|
||||||
use crate::ir::{
|
use crate::ir::{
|
||||||
Block, ExternalName, Function, GlobalValueData, Inst, InstructionData, MemFlags, Opcode,
|
ArgumentExtension, Block, ExternalName, Function, GlobalValueData, Inst, InstructionData,
|
||||||
Signature, SourceLoc, Type, Value, ValueDef,
|
MemFlags, Opcode, Signature, SourceLoc, Type, Value, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::machinst::{ABIBody, BlockIndex, VCode, VCodeBuilder, VCodeInst};
|
use crate::machinst::{ABIBody, BlockIndex, VCode, VCodeBuilder, VCodeInst};
|
||||||
use crate::num_uses::NumUses;
|
use crate::num_uses::NumUses;
|
||||||
@@ -116,7 +116,7 @@ pub struct Lower<'func, I: VCodeInst> {
|
|||||||
value_regs: SecondaryMap<Value, Reg>,
|
value_regs: SecondaryMap<Value, Reg>,
|
||||||
|
|
||||||
/// Return-value vregs.
|
/// Return-value vregs.
|
||||||
retval_regs: Vec<Reg>,
|
retval_regs: Vec<(Reg, ArgumentExtension)>,
|
||||||
|
|
||||||
/// Next virtual register number to allocate.
|
/// Next virtual register number to allocate.
|
||||||
next_vreg: u32,
|
next_vreg: u32,
|
||||||
@@ -190,7 +190,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
next_vreg += 1;
|
next_vreg += 1;
|
||||||
let regclass = I::rc_for_type(ret.value_type);
|
let regclass = I::rc_for_type(ret.value_type);
|
||||||
let vreg = Reg::new_virtual(regclass, v);
|
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);
|
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) {
|
fn gen_retval_setup(&mut self, gen_ret_inst: GenerateReturn) {
|
||||||
for (i, reg) in self.retval_regs.iter().enumerate() {
|
for (i, (reg, ext)) in self.retval_regs.iter().enumerate() {
|
||||||
let insn = self.vcode.abi().gen_copy_reg_to_retval(i, *reg);
|
let reg = Writable::from_reg(*reg);
|
||||||
self.vcode.push(insn);
|
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 {
|
let inst = match gen_ret_inst {
|
||||||
GenerateReturn::Yes => self.vcode.abi().gen_ret(),
|
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.
|
/// Get the register for a return value.
|
||||||
fn retval(&self, idx: usize) -> Writable<Reg> {
|
fn retval(&self, idx: usize) -> Writable<Reg> {
|
||||||
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`.
|
/// Get the target for a call instruction, as an `ExternalName`.
|
||||||
|
|||||||
Reference in New Issue
Block a user