use crate::isa::{reg::Reg, CallingConvention};
use smallvec::SmallVec;
use std::ops::{Add, BitAnd, Not, Sub};
use wasmtime_environ::{WasmFuncType, WasmType};
pub(crate) mod local;
pub(crate) use local::*;
pub(crate) trait ABI {
fn stack_align() -> u8;
fn call_stack_align() -> u8;
fn arg_base_offset() -> u8;
fn ret_addr_offset() -> u8;
fn sig(wasm_sig: &WasmFuncType, call_conv: &CallingConvention) -> ABISig;
fn result(returns: &[WasmType], call_conv: &CallingConvention) -> ABIResult;
fn word_bits() -> u32;
fn word_bytes() -> u32 {
Self::word_bits() / 8
}
fn scratch_reg() -> Reg;
fn fp_reg() -> Reg;
fn sp_reg() -> Reg;
fn vmctx_reg() -> Reg;
fn callee_saved_regs(call_conv: &CallingConvention) -> SmallVec<[Reg; 9]>;
}
#[derive(Debug)]
pub(crate) enum ABIArg {
Reg {
ty: WasmType,
reg: Reg,
},
Stack {
ty: WasmType,
offset: u32,
},
}
impl ABIArg {
pub fn reg(reg: Reg, ty: WasmType) -> Self {
Self::Reg { reg, ty }
}
pub fn stack_offset(offset: u32, ty: WasmType) -> Self {
Self::Stack { ty, offset }
}
pub fn is_reg(&self) -> bool {
match *self {
ABIArg::Reg { .. } => true,
_ => false,
}
}
pub fn get_reg(&self) -> Option<Reg> {
match *self {
ABIArg::Reg { reg, .. } => Some(reg),
_ => None,
}
}
pub fn ty(&self) -> WasmType {
match *self {
ABIArg::Reg { ty, .. } | ABIArg::Stack { ty, .. } => ty,
}
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum ABIResult {
Reg {
ty: Option<WasmType>,
reg: Reg,
},
}
impl ABIResult {
pub fn reg(ty: Option<WasmType>, reg: Reg) -> Self {
Self::Reg { ty, reg }
}
pub fn result_reg(&self) -> Reg {
match self {
Self::Reg { reg, .. } => *reg,
}
}
pub fn is_void(&self) -> bool {
match self {
Self::Reg { ty, .. } => ty.is_none(),
}
}
pub fn len(&self) -> usize {
if self.is_void() {
0
} else {
1
}
}
}
pub(crate) type ABIParams = SmallVec<[ABIArg; 6]>;
pub(crate) struct ABISig {
pub params: ABIParams,
pub result: ABIResult,
pub stack_bytes: u32,
}
impl ABISig {
pub fn new(params: ABIParams, result: ABIResult, stack_bytes: u32) -> Self {
Self {
params,
result,
stack_bytes,
}
}
}
pub(crate) fn ty_size(ty: &WasmType) -> u32 {
match *ty {
WasmType::I32 | WasmType::F32 => 4,
WasmType::I64 | WasmType::F64 => 8,
_ => panic!(),
}
}
pub(crate) fn align_to<N>(value: N, alignment: N) -> N
where
N: Not<Output = N>
+ BitAnd<N, Output = N>
+ Add<N, Output = N>
+ Sub<N, Output = N>
+ From<u8>
+ Copy,
{
let alignment_mask = alignment - 1.into();
(value + alignment_mask) & !alignment_mask
}
pub(crate) fn calculate_frame_adjustment(frame_size: u32, addend: u32, alignment: u32) -> u32 {
let total = frame_size + addend;
(alignment - (total % alignment)) % alignment
}