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:
@@ -32,7 +32,7 @@ fn try_fill_baldrdash_reg(call_conv: CallConv, param: &ir::AbiParam) -> Option<A
|
||||
&ir::ArgumentPurpose::VMContext => {
|
||||
// This is SpiderMonkey's `WasmTlsReg`.
|
||||
Some(ABIArg::Reg(
|
||||
regs::r14().to_real_reg(),
|
||||
ValueRegs::one(regs::r14().to_real_reg()),
|
||||
types::I64,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
@@ -41,7 +41,7 @@ fn try_fill_baldrdash_reg(call_conv: CallConv, param: &ir::AbiParam) -> Option<A
|
||||
&ir::ArgumentPurpose::SignatureId => {
|
||||
// This is SpiderMonkey's `WasmTableCallSigReg`.
|
||||
Some(ABIArg::Reg(
|
||||
regs::r10().to_real_reg(),
|
||||
ValueRegs::one(regs::r10().to_real_reg()),
|
||||
types::I64,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
@@ -168,7 +168,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
ret.push(param);
|
||||
} else if let Some(reg) = candidate {
|
||||
ret.push(ABIArg::Reg(
|
||||
reg.to_real_reg(),
|
||||
ValueRegs::one(reg.to_real_reg()),
|
||||
param.value_type,
|
||||
param.extension,
|
||||
param.purpose,
|
||||
@@ -200,7 +200,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
debug_assert!(args_or_rets == ArgsOrRets::Args);
|
||||
if let Some(reg) = get_intreg_for_arg_systemv(&call_conv, next_gpr) {
|
||||
ret.push(ABIArg::Reg(
|
||||
reg.to_real_reg(),
|
||||
ValueRegs::one(reg.to_real_reg()),
|
||||
types::I64,
|
||||
ir::ArgumentExtension::None,
|
||||
ir::ArgumentPurpose::Normal,
|
||||
@@ -288,7 +288,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
Inst::epilogue_placeholder()
|
||||
}
|
||||
|
||||
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallVec<[Self::I; 4]> {
|
||||
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallInstVec<Self::I> {
|
||||
let mut ret = SmallVec::new();
|
||||
if from_reg != into_reg.to_reg() {
|
||||
ret.push(Inst::gen_move(into_reg, from_reg, I64));
|
||||
@@ -302,7 +302,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
ret
|
||||
}
|
||||
|
||||
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec<Self::I> {
|
||||
smallvec![
|
||||
Inst::cmp_rmi_r(/* bytes = */ 8, RegMemImm::reg(regs::rsp()), limit_reg),
|
||||
Inst::TrapIf {
|
||||
@@ -343,7 +343,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
Inst::store(ty, from_reg, mem)
|
||||
}
|
||||
|
||||
fn gen_sp_reg_adjust(amount: i32) -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Self::I> {
|
||||
let (alu_op, amount) = if amount >= 0 {
|
||||
(AluRmiROpcode::Add, amount)
|
||||
} else {
|
||||
@@ -366,7 +366,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_prologue_frame_setup() -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_prologue_frame_setup() -> SmallInstVec<Self::I> {
|
||||
let r_rsp = regs::rsp();
|
||||
let r_rbp = regs::rbp();
|
||||
let w_rbp = Writable::from_reg(r_rbp);
|
||||
@@ -378,7 +378,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_epilogue_frame_restore() -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_epilogue_frame_restore() -> SmallInstVec<Self::I> {
|
||||
let mut insts = SmallVec::new();
|
||||
insts.push(Inst::mov_r_r(
|
||||
true,
|
||||
@@ -389,7 +389,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
||||
insts
|
||||
}
|
||||
|
||||
fn gen_probestack(frame_size: u32) -> SmallVec<[Self::I; 2]> {
|
||||
fn gen_probestack(frame_size: u32) -> SmallInstVec<Self::I> {
|
||||
let mut insts = SmallVec::new();
|
||||
insts.push(Inst::imm(
|
||||
OperandSize::Size32,
|
||||
|
||||
@@ -2506,22 +2506,28 @@ 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 {
|
||||
types::I8
|
||||
| types::I16
|
||||
| types::I32
|
||||
| types::I64
|
||||
| types::B1
|
||||
| types::B8
|
||||
| types::B16
|
||||
| types::B32
|
||||
| types::B64
|
||||
| types::R32
|
||||
| types::R64 => Ok(RegClass::I64),
|
||||
types::F32 | types::F64 => Ok(RegClass::V128),
|
||||
_ if ty.bits() == 128 => Ok(RegClass::V128),
|
||||
types::IFLAGS | types::FFLAGS => Ok(RegClass::I64),
|
||||
types::I8 => Ok((&[RegClass::I64], &[types::I8])),
|
||||
types::I16 => Ok((&[RegClass::I64], &[types::I16])),
|
||||
types::I32 => Ok((&[RegClass::I64], &[types::I32])),
|
||||
types::I64 => Ok((&[RegClass::I64], &[types::I64])),
|
||||
types::B1 => Ok((&[RegClass::I64], &[types::B1])),
|
||||
types::B8 => Ok((&[RegClass::I64], &[types::B8])),
|
||||
types::B16 => Ok((&[RegClass::I64], &[types::B16])),
|
||||
types::B32 => Ok((&[RegClass::I64], &[types::B32])),
|
||||
types::B64 => Ok((&[RegClass::I64], &[types::B64])),
|
||||
types::R32 => panic!("32-bit reftype pointer should never be seen on x86-64"),
|
||||
types::R64 => Ok((&[RegClass::I64], &[types::R64])),
|
||||
types::F32 => Ok((&[RegClass::V128], &[types::F32])),
|
||||
types::F64 => Ok((&[RegClass::V128], &[types::F64])),
|
||||
types::I128 => Ok((&[RegClass::I64, RegClass::I64], &[types::I64, types::I64])),
|
||||
types::B128 => Ok((&[RegClass::I64, RegClass::I64], &[types::B64, types::B64])),
|
||||
_ if ty.is_vector() => {
|
||||
assert!(ty.bits() <= 128);
|
||||
Ok((&[RegClass::V128], &[types::I8X16]))
|
||||
}
|
||||
types::IFLAGS | types::FFLAGS => Ok((&[RegClass::I64], &[types::I64])),
|
||||
_ => Err(CodegenError::Unsupported(format!(
|
||||
"Unexpected SSA-value type: {}",
|
||||
ty
|
||||
@@ -2533,13 +2539,18 @@ impl MachInst for Inst {
|
||||
Inst::jmp_known(label)
|
||||
}
|
||||
|
||||
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,
|
||||
mut alloc_tmp: F,
|
||||
) -> SmallVec<[Self; 4]> {
|
||||
// We don't support 128-bit constants.
|
||||
assert!(value <= u64::MAX as u128);
|
||||
let mut ret = SmallVec::new();
|
||||
let to_reg = to_regs
|
||||
.only_reg()
|
||||
.expect("multi-reg values not supported on x64");
|
||||
if ty == types::F32 {
|
||||
if value == 0 {
|
||||
ret.push(Inst::xmm_rm_r(
|
||||
@@ -2548,8 +2559,8 @@ impl MachInst for Inst {
|
||||
to_reg,
|
||||
));
|
||||
} else {
|
||||
let tmp = alloc_tmp(RegClass::I64, types::I32);
|
||||
ret.push(Inst::imm(OperandSize::Size32, value, tmp));
|
||||
let tmp = alloc_tmp(types::I32);
|
||||
ret.push(Inst::imm(OperandSize::Size32, value as u64, tmp));
|
||||
|
||||
ret.push(Inst::gpr_to_xmm(
|
||||
SseOpcode::Movd,
|
||||
@@ -2566,8 +2577,8 @@ impl MachInst for Inst {
|
||||
to_reg,
|
||||
));
|
||||
} else {
|
||||
let tmp = alloc_tmp(RegClass::I64, types::I64);
|
||||
ret.push(Inst::imm(OperandSize::Size64, value, tmp));
|
||||
let tmp = alloc_tmp(types::I64);
|
||||
ret.push(Inst::imm(OperandSize::Size64, value as u64, tmp));
|
||||
|
||||
ret.push(Inst::gpr_to_xmm(
|
||||
SseOpcode::Movq,
|
||||
@@ -2599,6 +2610,7 @@ impl MachInst for Inst {
|
||||
to_reg,
|
||||
));
|
||||
} else {
|
||||
let value = value as u64;
|
||||
ret.push(Inst::imm(
|
||||
OperandSize::from_bytes(ty.bytes()),
|
||||
value.into(),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user