Multi-register value support: framework for Values wider than machine regs.
This will allow for support for `I128` values everywhere, and `I64` values on 32-bit targets (e.g., ARM32 and x86-32). It does not alter the machine backends to build such support; it just adds the framework for the MachInst backends to *reason* about a `Value` residing in more than one register.
This commit is contained in:
@@ -82,7 +82,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
let reg = rreg(next_rreg);
|
||||
|
||||
ret.push(ABIArg::Reg(
|
||||
reg.to_real_reg(),
|
||||
ValueRegs::one(reg.to_real_reg()),
|
||||
param.value_type,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
@@ -102,7 +102,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
debug_assert!(args_or_rets == ArgsOrRets::Args);
|
||||
if next_rreg < max_reg_val {
|
||||
ret.push(ABIArg::Reg(
|
||||
rreg(next_rreg).to_real_reg(),
|
||||
ValueRegs::one(rreg(next_rreg).to_real_reg()),
|
||||
I32,
|
||||
ir::ArgumentExtension::None,
|
||||
ir::ArgumentPurpose::Normal,
|
||||
@@ -185,7 +185,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
Inst::EpiloguePlaceholder
|
||||
}
|
||||
|
||||
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallVec<[Inst; 4]> {
|
||||
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallInstVec<Inst> {
|
||||
let mut insts = SmallVec::new();
|
||||
|
||||
if let Some(imm12) = UImm12::maybe_from_i64(imm as i64) {
|
||||
@@ -209,7 +209,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallVec<[Inst; 2]> {
|
||||
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Inst> {
|
||||
let mut insts = SmallVec::new();
|
||||
insts.push(Inst::Cmp {
|
||||
rn: sp_reg(),
|
||||
@@ -243,7 +243,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
Inst::gen_store(from_reg, mem, ty)
|
||||
}
|
||||
|
||||
fn gen_sp_reg_adjust(amount: i32) -> SmallVec<[Inst; 2]> {
|
||||
fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Inst> {
|
||||
let mut ret = SmallVec::new();
|
||||
|
||||
if amount == 0 {
|
||||
@@ -283,7 +283,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
Inst::VirtualSPOffsetAdj { offset }
|
||||
}
|
||||
|
||||
fn gen_prologue_frame_setup() -> SmallVec<[Inst; 2]> {
|
||||
fn gen_prologue_frame_setup() -> SmallInstVec<Inst> {
|
||||
let mut ret = SmallVec::new();
|
||||
let reg_list = vec![fp_reg(), lr_reg()];
|
||||
ret.push(Inst::Push { reg_list });
|
||||
@@ -294,7 +294,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
ret
|
||||
}
|
||||
|
||||
fn gen_epilogue_frame_restore() -> SmallVec<[Inst; 2]> {
|
||||
fn gen_epilogue_frame_restore() -> SmallInstVec<Inst> {
|
||||
let mut ret = SmallVec::new();
|
||||
ret.push(Inst::Mov {
|
||||
rd: writable_sp_reg(),
|
||||
@@ -305,7 +305,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
||||
ret
|
||||
}
|
||||
|
||||
fn gen_probestack(_: u32) -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_probestack(_: u32) -> SmallInstVec<Self::I> {
|
||||
// TODO: implement if we ever require stack probes on ARM32 (unlikely
|
||||
// unless Lucet is ported)
|
||||
smallvec![]
|
||||
|
||||
@@ -807,12 +807,17 @@ impl MachInst for Inst {
|
||||
Inst::mov(to_reg, from_reg)
|
||||
}
|
||||
|
||||
fn gen_constant<F: FnMut(RegClass, Type) -> Writable<Reg>>(
|
||||
to_reg: Writable<Reg>,
|
||||
value: u64,
|
||||
fn gen_constant<F: FnMut(Type) -> Writable<Reg>>(
|
||||
to_regs: ValueRegs<Writable<Reg>>,
|
||||
value: u128,
|
||||
ty: Type,
|
||||
_alloc_tmp: F,
|
||||
) -> SmallVec<[Inst; 4]> {
|
||||
let to_reg = to_regs
|
||||
.only_reg()
|
||||
.expect("multi-reg values not supported yet");
|
||||
let value = value as u64;
|
||||
|
||||
match ty {
|
||||
B1 | I8 | B8 | I16 | B16 | I32 | B32 => {
|
||||
let v: i64 = value as i64;
|
||||
@@ -839,10 +844,10 @@ impl MachInst for Inst {
|
||||
None
|
||||
}
|
||||
|
||||
fn rc_for_type(ty: Type) -> CodegenResult<RegClass> {
|
||||
fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {
|
||||
match ty {
|
||||
I8 | I16 | I32 | B1 | B8 | B16 | B32 => Ok(RegClass::I32),
|
||||
IFLAGS => Ok(RegClass::I32),
|
||||
I8 | I16 | I32 | B1 | B8 | B16 | B32 => Ok((&[RegClass::I32], &[I32])),
|
||||
IFLAGS => Ok((&[RegClass::I32], &[I32])),
|
||||
_ => Err(CodegenError::Unsupported(format!(
|
||||
"Unexpected SSA-value type: {}",
|
||||
ty
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::isa::arm32::Arm32Backend;
|
||||
|
||||
use super::lower_inst;
|
||||
|
||||
use regalloc::{Reg, RegClass, Writable};
|
||||
use regalloc::{Reg, Writable};
|
||||
|
||||
//============================================================================
|
||||
// Lowering: convert instruction outputs to result types.
|
||||
@@ -55,7 +55,7 @@ pub(crate) enum NarrowValueMode {
|
||||
|
||||
/// Lower an instruction output to a reg.
|
||||
pub(crate) fn output_to_reg<C: LowerCtx<I = Inst>>(ctx: &mut C, out: InsnOutput) -> Writable<Reg> {
|
||||
ctx.get_output(out.insn, out.output)
|
||||
ctx.get_output(out.insn, out.output).only_reg().unwrap()
|
||||
}
|
||||
|
||||
/// Lower an instruction input to a reg.
|
||||
@@ -70,21 +70,25 @@ pub(crate) fn input_to_reg<C: LowerCtx<I = Inst>>(
|
||||
let from_bits = ty.bits() as u8;
|
||||
let inputs = ctx.get_input_as_source_or_const(input.insn, input.input);
|
||||
let in_reg = if let Some(c) = inputs.constant {
|
||||
let to_reg = ctx.alloc_tmp(Inst::rc_for_type(ty).unwrap(), ty);
|
||||
for inst in Inst::gen_constant(to_reg, c, ty, |reg_class, ty| ctx.alloc_tmp(reg_class, ty))
|
||||
.into_iter()
|
||||
let to_reg = ctx.alloc_tmp(ty).only_reg().unwrap();
|
||||
for inst in Inst::gen_constant(ValueRegs::one(to_reg), c as u128, ty, |ty| {
|
||||
ctx.alloc_tmp(ty).only_reg().unwrap()
|
||||
})
|
||||
.into_iter()
|
||||
{
|
||||
ctx.emit(inst);
|
||||
}
|
||||
to_reg.to_reg()
|
||||
} else {
|
||||
ctx.put_input_in_reg(input.insn, input.input)
|
||||
ctx.put_input_in_regs(input.insn, input.input)
|
||||
.only_reg()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
match (narrow_mode, from_bits) {
|
||||
(NarrowValueMode::None, _) => in_reg,
|
||||
(NarrowValueMode::ZeroExtend, 1) => {
|
||||
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
|
||||
let tmp = ctx.alloc_tmp(I32).only_reg().unwrap();
|
||||
ctx.emit(Inst::AluRRImm8 {
|
||||
alu_op: ALUOp::And,
|
||||
rd: tmp,
|
||||
@@ -94,7 +98,7 @@ pub(crate) fn input_to_reg<C: LowerCtx<I = Inst>>(
|
||||
tmp.to_reg()
|
||||
}
|
||||
(NarrowValueMode::ZeroExtend, n) if n < 32 => {
|
||||
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
|
||||
let tmp = ctx.alloc_tmp(I32).only_reg().unwrap();
|
||||
ctx.emit(Inst::Extend {
|
||||
rd: tmp,
|
||||
rm: in_reg,
|
||||
@@ -104,7 +108,7 @@ pub(crate) fn input_to_reg<C: LowerCtx<I = Inst>>(
|
||||
tmp.to_reg()
|
||||
}
|
||||
(NarrowValueMode::SignExtend, n) if n < 32 => {
|
||||
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
|
||||
let tmp = ctx.alloc_tmp(I32).only_reg().unwrap();
|
||||
ctx.emit(Inst::Extend {
|
||||
rd: tmp,
|
||||
rm: in_reg,
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::CodegenResult;
|
||||
use crate::isa::arm32::abi::*;
|
||||
use crate::isa::arm32::inst::*;
|
||||
|
||||
use regalloc::RegClass;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::lower::*;
|
||||
@@ -143,7 +142,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
let rd = output_to_reg(ctx, outputs[0]);
|
||||
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
|
||||
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
|
||||
let tmp = ctx.alloc_tmp(RegClass::I32, I32);
|
||||
let tmp = ctx.alloc_tmp(I32).only_reg().unwrap();
|
||||
|
||||
// ror rd, rn, 32 - (rm & 31)
|
||||
ctx.emit(Inst::AluRRImm8 {
|
||||
@@ -171,7 +170,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
match ty {
|
||||
I32 => {
|
||||
let rd_hi = output_to_reg(ctx, outputs[0]);
|
||||
let rd_lo = ctx.alloc_tmp(RegClass::I32, ty);
|
||||
let rd_lo = ctx.alloc_tmp(ty).only_reg().unwrap();
|
||||
let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None);
|
||||
let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None);
|
||||
|
||||
@@ -487,7 +486,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
Opcode::FallthroughReturn | Opcode::Return => {
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
let reg = input_to_reg(ctx, *input, NarrowValueMode::None);
|
||||
let retval_reg = ctx.retval(i);
|
||||
let retval_reg = ctx.retval(i).only_reg().unwrap();
|
||||
let ty = ctx.input_ty(insn, i);
|
||||
|
||||
ctx.emit(Inst::gen_move(retval_reg, reg, ty));
|
||||
@@ -522,12 +521,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
assert_eq!(inputs.len(), abi.num_args());
|
||||
for (i, input) in inputs.iter().enumerate().filter(|(i, _)| *i <= 3) {
|
||||
let arg_reg = input_to_reg(ctx, *input, NarrowValueMode::None);
|
||||
abi.emit_copy_reg_to_arg(ctx, i, arg_reg);
|
||||
abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(arg_reg));
|
||||
}
|
||||
abi.emit_call(ctx);
|
||||
for (i, output) in outputs.iter().enumerate() {
|
||||
let retval_reg = output_to_reg(ctx, *output);
|
||||
abi.emit_copy_retval_to_reg(ctx, i, retval_reg);
|
||||
abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(retval_reg));
|
||||
}
|
||||
}
|
||||
_ => panic!("lowering {} unimplemented!", op),
|
||||
|
||||
Reference in New Issue
Block a user