machinst x64: implement calls and int cmp/store/loads;

This makes it possible to run a simple recursive fibonacci function in
wasmtime.
This commit is contained in:
Benjamin Bouvier
2020-06-12 16:20:30 +02:00
parent 2d364f75bd
commit c9a3f05afd
11 changed files with 2364 additions and 998 deletions

View File

@@ -3,16 +3,20 @@
use std::fmt;
use std::string::{String, ToString};
use regalloc::{RealRegUniverse, Reg, RegClass, RegUsageCollector};
use regalloc::{RealRegUniverse, Reg, RegClass, RegUsageCollector, RegUsageMapper};
use crate::ir::condcodes::IntCC;
use crate::machinst::*;
use super::regs::show_ireg_sized;
use super::{
regs::{self, show_ireg_sized},
EmitState,
};
/// A Memory Address. These denote a 64-bit value only.
/// A possible addressing mode (amode) that can be used in instructions.
/// These denote a 64-bit value only.
#[derive(Clone)]
pub(crate) enum Addr {
pub enum Amode {
/// Immediate sign-extended and a Register.
ImmReg { simm32: u32, base: Reg },
@@ -25,7 +29,7 @@ pub(crate) enum Addr {
},
}
impl Addr {
impl Amode {
pub(crate) fn imm_reg(simm32: u32, base: Reg) -> Self {
debug_assert!(base.get_class() == RegClass::I64);
Self::ImmReg { simm32, base }
@@ -46,15 +50,10 @@ impl Addr {
/// Add the regs mentioned by `self` to `collector`.
pub(crate) fn get_regs_as_uses(&self, collector: &mut RegUsageCollector) {
match self {
Addr::ImmReg { simm32: _, base } => {
Amode::ImmReg { base, .. } => {
collector.add_use(*base);
}
Addr::ImmRegRegShift {
simm32: _,
base,
index,
shift: _,
} => {
Amode::ImmRegRegShift { base, index, .. } => {
collector.add_use(*base);
collector.add_use(*index);
}
@@ -62,13 +61,13 @@ impl Addr {
}
}
impl ShowWithRRU for Addr {
impl ShowWithRRU for Amode {
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
match self {
Addr::ImmReg { simm32, base } => {
Amode::ImmReg { simm32, base } => {
format!("{}({})", *simm32 as i32, base.show_rru(mb_rru))
}
Addr::ImmRegRegShift {
Amode::ImmRegRegShift {
simm32,
base,
index,
@@ -84,14 +83,84 @@ impl ShowWithRRU for Addr {
}
}
/// A Memory Address. These denote a 64-bit value only.
/// Used for usual addressing modes as well as addressing modes used during compilation, when the
/// moving SP offset is not known.
#[derive(Clone)]
pub enum SyntheticAmode {
/// A real amode.
Real(Amode),
/// A (virtual) offset to the "nominal SP" value, which will be recomputed as we push and pop
/// within the function.
NominalSPOffset { simm32: u32 },
}
impl SyntheticAmode {
pub(crate) fn nominal_sp_offset(simm32: u32) -> Self {
SyntheticAmode::NominalSPOffset { simm32 }
}
/// Add the regs mentioned by `self` to `collector`.
pub(crate) fn get_regs_as_uses(&self, collector: &mut RegUsageCollector) {
match self {
SyntheticAmode::Real(addr) => addr.get_regs_as_uses(collector),
SyntheticAmode::NominalSPOffset { .. } => {
// Nothing to do; the base is SP and isn't involved in regalloc.
}
}
}
pub(crate) fn map_uses<RUM: RegUsageMapper>(&mut self, map: &RUM) {
match self {
SyntheticAmode::Real(addr) => addr.map_uses(map),
SyntheticAmode::NominalSPOffset { .. } => {
// Nothing to do.
}
}
}
pub(crate) fn finalize(&self, state: &mut EmitState) -> Amode {
match self {
SyntheticAmode::Real(addr) => addr.clone(),
SyntheticAmode::NominalSPOffset { simm32 } => {
let off = *simm32 as i64 + state.virtual_sp_offset;
// TODO will require a sequence of add etc.
assert!(
off <= u32::max_value() as i64,
"amode finalize: add sequence NYI"
);
Amode::imm_reg(off as u32, regs::rsp())
}
}
}
}
impl Into<SyntheticAmode> for Amode {
fn into(self) -> SyntheticAmode {
SyntheticAmode::Real(self)
}
}
impl ShowWithRRU for SyntheticAmode {
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
match self {
SyntheticAmode::Real(addr) => addr.show_rru(mb_rru),
SyntheticAmode::NominalSPOffset { simm32 } => {
format!("rsp({} + virtual offset)", *simm32 as i32)
}
}
}
}
/// An operand which is either an integer Register, a value in Memory or an Immediate. This can
/// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only
/// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by
/// `simm32` is its sign-extension out to 64 bits.
#[derive(Clone)]
pub(crate) enum RegMemImm {
pub enum RegMemImm {
Reg { reg: Reg },
Mem { addr: Addr },
Mem { addr: SyntheticAmode },
Imm { simm32: u32 },
}
@@ -100,8 +169,8 @@ impl RegMemImm {
debug_assert!(reg.get_class() == RegClass::I64);
Self::Reg { reg }
}
pub(crate) fn mem(addr: Addr) -> Self {
Self::Mem { addr }
pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
Self::Mem { addr: addr.into() }
}
pub(crate) fn imm(simm32: u32) -> Self {
Self::Imm { simm32 }
@@ -134,9 +203,9 @@ impl ShowWithRRU for RegMemImm {
/// An operand which is either an integer Register or a value in Memory. This can denote an 8, 16,
/// 32 or 64 bit value.
#[derive(Clone)]
pub(crate) enum RegMem {
pub enum RegMem {
Reg { reg: Reg },
Mem { addr: Addr },
Mem { addr: SyntheticAmode },
}
impl RegMem {
@@ -144,8 +213,8 @@ impl RegMem {
debug_assert!(reg.get_class() == RegClass::I64 || reg.get_class() == RegClass::V128);
Self::Reg { reg }
}
pub(crate) fn mem(addr: Addr) -> Self {
Self::Mem { addr }
pub(crate) fn mem(addr: impl Into<SyntheticAmode>) -> Self {
Self::Mem { addr: addr.into() }
}
/// Add the regs mentioned by `self` to `collector`.
@@ -382,6 +451,13 @@ pub enum ExtMode {
}
impl ExtMode {
pub(crate) fn src_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::BQ => 1,
ExtMode::WL | ExtMode::WQ => 2,
ExtMode::LQ => 4,
}
}
pub(crate) fn dst_size(&self) -> u8 {
match self {
ExtMode::BL | ExtMode::WL => 4,