2019-03-20 01:52:00 +08:00
|
|
|
#![allow(clippy::forget_copy)] // Used by dynasm.
|
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
use super::codegen::*;
|
2019-03-18 00:31:36 +08:00
|
|
|
use crate::protect_unix;
|
2019-02-24 00:52:32 +08:00
|
|
|
use byteorder::{ByteOrder, LittleEndian};
|
2019-02-15 02:21:52 +08:00
|
|
|
use dynasmrt::{
|
|
|
|
x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, ExecutableBuffer,
|
|
|
|
};
|
2019-03-09 02:57:23 +08:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::ptr::NonNull;
|
2019-03-12 20:59:10 -05:00
|
|
|
use std::{any::Any, collections::HashMap, sync::Arc};
|
2019-02-15 02:21:52 +08:00
|
|
|
use wasmer_runtime_core::{
|
2019-03-17 10:54:50 +08:00
|
|
|
backend::{FuncResolver, ProtectedCaller, Token, UserTrapper},
|
|
|
|
error::{RuntimeError, RuntimeResult},
|
2019-03-18 00:31:36 +08:00
|
|
|
memory::MemoryType,
|
2019-03-17 10:54:50 +08:00
|
|
|
module::{ModuleInfo, ModuleInner},
|
2019-02-15 02:21:52 +08:00
|
|
|
structures::{Map, TypedIndex},
|
|
|
|
types::{
|
2019-04-10 00:41:32 +08:00
|
|
|
FuncIndex, FuncSig, ImportedMemoryIndex, LocalFuncIndex, LocalGlobalIndex, GlobalIndex,
|
2019-04-07 17:19:23 +08:00
|
|
|
LocalMemoryIndex, LocalOrImport, MemoryIndex, SigIndex, Type, Value, TableIndex,
|
2019-02-15 02:21:52 +08:00
|
|
|
},
|
2019-03-14 10:30:24 +08:00
|
|
|
units::Pages,
|
2019-03-18 00:31:36 +08:00
|
|
|
vm::{self, ImportBacking, LocalGlobal, LocalMemory, LocalTable},
|
2019-04-04 09:38:22 +08:00
|
|
|
vmcalls,
|
2019-02-15 02:21:52 +08:00
|
|
|
};
|
2019-02-12 00:52:17 +08:00
|
|
|
use wasmparser::{Operator, Type as WpType};
|
2019-04-01 20:33:33 +08:00
|
|
|
use crate::machine::*;
|
|
|
|
use crate::emitter_x64::*;
|
2019-03-09 02:57:23 +08:00
|
|
|
|
2019-02-24 00:52:32 +08:00
|
|
|
lazy_static! {
|
2019-04-01 20:33:33 +08:00
|
|
|
static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u8, stack_base: *const u8, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = {
|
2019-03-09 00:07:13 +08:00
|
|
|
let mut assembler = Assembler::new().unwrap();
|
|
|
|
let offset = assembler.offset();
|
|
|
|
dynasm!(
|
|
|
|
assembler
|
|
|
|
; push r15
|
|
|
|
; push r14
|
|
|
|
; push r13
|
|
|
|
; push r12
|
2019-03-19 11:47:38 +08:00
|
|
|
; push r11
|
|
|
|
; push rbp
|
|
|
|
; mov rbp, rsp
|
2019-03-09 00:07:13 +08:00
|
|
|
|
|
|
|
; mov r15, rdi
|
|
|
|
; mov r14, rsi
|
|
|
|
; mov r13, rdx
|
|
|
|
; mov r12, rcx
|
|
|
|
|
2019-03-17 03:07:27 +08:00
|
|
|
; mov rdi, r13 // ctx
|
|
|
|
|
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rsi, [r14]
|
2019-03-17 03:07:27 +08:00
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rdx, [r14]
|
2019-03-17 03:07:27 +08:00
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rcx, [r14]
|
2019-03-17 03:07:27 +08:00
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov r8, [r14]
|
2019-03-17 03:07:27 +08:00
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
2019-03-19 11:47:38 +08:00
|
|
|
|
2019-03-17 03:07:27 +08:00
|
|
|
; mov r9, [r14]
|
2019-03-19 11:47:38 +08:00
|
|
|
; sub r14, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
2019-03-17 03:07:27 +08:00
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rax, r14
|
|
|
|
; sub rax, r15
|
|
|
|
; sub rsp, rax
|
|
|
|
; sub rsp, 8
|
|
|
|
; mov rax, QWORD 0xfffffffffffffff0u64 as i64
|
|
|
|
; and rsp, rax
|
|
|
|
; mov rax, rsp
|
|
|
|
; loop_begin:
|
|
|
|
; mov r11, [r14]
|
|
|
|
; mov [rax], r11
|
|
|
|
; sub r14, 8
|
|
|
|
; add rax, 8
|
|
|
|
; cmp r14, r15
|
|
|
|
; jb >stack_ready
|
|
|
|
; jmp <loop_begin
|
2019-03-09 00:07:13 +08:00
|
|
|
|
|
|
|
; stack_ready:
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rax, QWORD 0xfffffffffffffff0u64 as i64
|
|
|
|
; and rsp, rax
|
2019-03-09 00:07:13 +08:00
|
|
|
; call r12
|
|
|
|
|
2019-03-19 11:47:38 +08:00
|
|
|
; mov rsp, rbp
|
|
|
|
; pop rbp
|
|
|
|
; pop r11
|
2019-03-09 00:07:13 +08:00
|
|
|
; pop r12
|
|
|
|
; pop r13
|
|
|
|
; pop r14
|
|
|
|
; pop r15
|
|
|
|
; ret
|
|
|
|
);
|
|
|
|
let buf = assembler.finalize().unwrap();
|
|
|
|
let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) };
|
|
|
|
::std::mem::forget(buf);
|
|
|
|
ret
|
|
|
|
};
|
2019-02-24 00:52:32 +08:00
|
|
|
}
|
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
pub struct X64ModuleCodeGenerator {
|
|
|
|
functions: Vec<X64FunctionCode>,
|
2019-03-12 20:59:10 -05:00
|
|
|
signatures: Option<Arc<Map<SigIndex, FuncSig>>>,
|
2019-02-24 00:52:32 +08:00
|
|
|
function_signatures: Option<Arc<Map<FuncIndex, SigIndex>>>,
|
2019-03-09 02:57:23 +08:00
|
|
|
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
2019-02-26 20:56:10 +08:00
|
|
|
assembler: Option<Assembler>,
|
2019-03-08 01:31:37 +08:00
|
|
|
func_import_count: usize,
|
2019-02-12 00:52:17 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
|
|
enum LocalOrTemp {
|
|
|
|
Local,
|
|
|
|
Temp
|
|
|
|
}
|
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
pub struct X64FunctionCode {
|
2019-03-12 20:59:10 -05:00
|
|
|
signatures: Arc<Map<SigIndex, FuncSig>>,
|
2019-02-24 00:52:32 +08:00
|
|
|
function_signatures: Arc<Map<FuncIndex, SigIndex>>,
|
|
|
|
|
2019-02-15 02:21:52 +08:00
|
|
|
begin_offset: AssemblyOffset,
|
2019-02-12 00:52:17 +08:00
|
|
|
assembler: Option<Assembler>,
|
2019-03-09 02:57:23 +08:00
|
|
|
function_labels: Option<HashMap<usize, (DynamicLabel, Option<AssemblyOffset>)>>,
|
2019-02-24 12:00:35 +08:00
|
|
|
br_table_data: Option<Vec<Vec<usize>>>,
|
2019-02-14 00:53:06 +08:00
|
|
|
returns: Vec<WpType>,
|
2019-04-01 20:33:33 +08:00
|
|
|
locals: Vec<Location>,
|
2019-02-12 23:15:57 +08:00
|
|
|
num_params: usize,
|
2019-04-01 20:33:33 +08:00
|
|
|
num_locals: usize,
|
|
|
|
value_stack: Vec<(Location, LocalOrTemp)>,
|
|
|
|
control_stack: Vec<ControlFrame>,
|
|
|
|
machine: Machine,
|
2019-02-21 21:14:10 +08:00
|
|
|
unreachable_depth: usize,
|
2019-02-12 00:52:17 +08:00
|
|
|
}
|
|
|
|
|
2019-03-09 02:57:23 +08:00
|
|
|
enum FuncPtrInner {}
|
|
|
|
#[repr(transparent)]
|
2019-03-17 03:07:27 +08:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2019-03-09 02:57:23 +08:00
|
|
|
struct FuncPtr(*const FuncPtrInner);
|
|
|
|
unsafe impl Send for FuncPtr {}
|
|
|
|
unsafe impl Sync for FuncPtr {}
|
|
|
|
|
2019-02-15 02:21:52 +08:00
|
|
|
pub struct X64ExecutionContext {
|
|
|
|
code: ExecutableBuffer,
|
|
|
|
functions: Vec<X64FunctionCode>,
|
2019-03-12 20:59:10 -05:00
|
|
|
signatures: Arc<Map<SigIndex, FuncSig>>,
|
2019-03-09 02:57:23 +08:00
|
|
|
function_signatures: Arc<Map<FuncIndex, SigIndex>>,
|
|
|
|
function_pointers: Vec<FuncPtr>,
|
2019-03-17 10:54:50 +08:00
|
|
|
_br_table_data: Vec<Vec<usize>>,
|
2019-03-08 01:31:37 +08:00
|
|
|
func_import_count: usize,
|
2019-02-15 02:21:52 +08:00
|
|
|
}
|
|
|
|
|
2019-03-17 03:07:27 +08:00
|
|
|
pub struct X64RuntimeResolver {
|
2019-04-11 08:44:18 +08:00
|
|
|
local_function_pointers: Vec<FuncPtr>,
|
2019-04-01 20:33:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ControlFrame {
|
|
|
|
pub label: DynamicLabel,
|
|
|
|
pub loop_like: bool,
|
|
|
|
pub if_else: IfElseState,
|
|
|
|
pub returns: Vec<WpType>,
|
|
|
|
pub value_stack_depth: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub enum IfElseState {
|
|
|
|
None,
|
|
|
|
If(DynamicLabel),
|
|
|
|
Else,
|
2019-03-17 03:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl X64ExecutionContext {
|
2019-03-18 00:31:36 +08:00
|
|
|
fn get_runtime_resolver(
|
|
|
|
&self,
|
|
|
|
module_info: &ModuleInfo,
|
|
|
|
) -> Result<X64RuntimeResolver, CodegenError> {
|
2019-03-17 03:07:27 +08:00
|
|
|
Ok(X64RuntimeResolver {
|
2019-04-11 08:44:18 +08:00
|
|
|
local_function_pointers: self.function_pointers[self.func_import_count..].to_vec(),
|
2019-03-17 03:07:27 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FuncResolver for X64RuntimeResolver {
|
2019-03-09 02:57:23 +08:00
|
|
|
fn get(
|
|
|
|
&self,
|
|
|
|
_module: &ModuleInner,
|
|
|
|
_local_func_index: LocalFuncIndex,
|
|
|
|
) -> Option<NonNull<vm::Func>> {
|
2019-04-11 08:44:18 +08:00
|
|
|
NonNull::new(self.local_function_pointers[_local_func_index.index() as usize].0 as *mut vm::Func)
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 02:21:52 +08:00
|
|
|
impl ProtectedCaller for X64ExecutionContext {
|
|
|
|
fn call(
|
|
|
|
&self,
|
|
|
|
_module: &ModuleInner,
|
|
|
|
_func_index: FuncIndex,
|
|
|
|
_params: &[Value],
|
|
|
|
_import_backing: &ImportBacking,
|
|
|
|
_vmctx: *mut vm::Ctx,
|
|
|
|
_: Token,
|
|
|
|
) -> RuntimeResult<Vec<Value>> {
|
2019-03-08 01:31:37 +08:00
|
|
|
let index = _func_index.index() - self.func_import_count;
|
2019-02-15 02:21:52 +08:00
|
|
|
let ptr = self.code.ptr(self.functions[index].begin_offset);
|
|
|
|
let return_ty = self.functions[index].returns.last().cloned();
|
2019-04-01 20:33:33 +08:00
|
|
|
let buffer: Vec<u64> = _params.iter().rev().map(|x| {
|
|
|
|
match *x {
|
|
|
|
Value::I32(x) => x as u32 as u64,
|
|
|
|
Value::I64(x) => x as u64,
|
|
|
|
Value::F32(x) => f32::to_bits(x) as u64,
|
|
|
|
Value::F64(x) => f64::to_bits(x),
|
|
|
|
}
|
|
|
|
}).collect();
|
2019-03-09 00:07:13 +08:00
|
|
|
let ret = unsafe {
|
2019-04-08 17:47:41 +08:00
|
|
|
protect_unix::call_protected(|| {
|
|
|
|
CONSTRUCT_STACK_AND_CALL_WASM(
|
|
|
|
buffer.as_ptr() as *const u8,
|
|
|
|
buffer.as_ptr().offset(buffer.len() as isize) as *const u8,
|
|
|
|
_vmctx,
|
|
|
|
ptr as _,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}?;
|
2019-02-24 00:52:32 +08:00
|
|
|
Ok(if let Some(ty) = return_ty {
|
2019-03-13 18:23:50 +08:00
|
|
|
vec![match ty {
|
|
|
|
WpType::I32 => Value::I32(ret as i32),
|
2019-04-01 20:33:33 +08:00
|
|
|
WpType::I64 => Value::I64(ret as i64),
|
|
|
|
WpType::F32 => Value::F32(f32::from_bits(ret as u32)),
|
2019-03-13 18:23:50 +08:00
|
|
|
WpType::F64 => Value::F64(f64::from_bits(ret as u64)),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}]
|
2019-02-24 00:52:32 +08:00
|
|
|
} else {
|
|
|
|
vec![]
|
|
|
|
})
|
2019-02-15 02:21:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
|
|
|
pub struct Trapper;
|
|
|
|
|
|
|
|
impl UserTrapper for Trapper {
|
2019-03-17 10:54:50 +08:00
|
|
|
unsafe fn do_early_trap(&self, _data: Box<Any>) -> ! {
|
2019-03-12 20:59:10 -05:00
|
|
|
panic!("do_early_trap");
|
2019-02-15 02:21:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Box::new(Trapper)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
impl X64ModuleCodeGenerator {
|
|
|
|
pub fn new() -> X64ModuleCodeGenerator {
|
2019-02-26 20:56:10 +08:00
|
|
|
let mut assembler = Assembler::new().unwrap();
|
|
|
|
|
|
|
|
X64ModuleCodeGenerator {
|
|
|
|
functions: vec![],
|
|
|
|
signatures: None,
|
|
|
|
function_signatures: None,
|
2019-03-08 01:31:37 +08:00
|
|
|
function_labels: Some(HashMap::new()),
|
2019-02-26 20:56:10 +08:00
|
|
|
assembler: Some(assembler),
|
2019-03-08 01:31:37 +08:00
|
|
|
func_import_count: 0,
|
2019-02-26 20:56:10 +08:00
|
|
|
}
|
2019-02-12 00:52:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 00:31:36 +08:00
|
|
|
impl ModuleCodeGenerator<X64FunctionCode, X64ExecutionContext, X64RuntimeResolver>
|
|
|
|
for X64ModuleCodeGenerator
|
|
|
|
{
|
2019-03-19 21:30:26 +08:00
|
|
|
fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
|
2019-03-17 10:27:14 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> {
|
2019-02-24 12:00:35 +08:00
|
|
|
let (mut assembler, mut function_labels, br_table_data) = match self.functions.last_mut() {
|
2019-02-24 00:52:32 +08:00
|
|
|
Some(x) => (
|
|
|
|
x.assembler.take().unwrap(),
|
|
|
|
x.function_labels.take().unwrap(),
|
2019-02-24 12:00:35 +08:00
|
|
|
x.br_table_data.take().unwrap(),
|
2019-02-24 00:52:32 +08:00
|
|
|
),
|
2019-03-08 01:31:37 +08:00
|
|
|
None => (
|
|
|
|
self.assembler.take().unwrap(),
|
|
|
|
self.function_labels.take().unwrap(),
|
|
|
|
vec![],
|
|
|
|
),
|
2019-02-12 23:15:57 +08:00
|
|
|
};
|
2019-02-15 02:21:52 +08:00
|
|
|
let begin_offset = assembler.offset();
|
2019-03-09 02:57:23 +08:00
|
|
|
let begin_label_info = function_labels
|
|
|
|
.entry(self.functions.len() + self.func_import_count)
|
|
|
|
.or_insert_with(|| (assembler.new_dynamic_label(), None));
|
|
|
|
|
|
|
|
begin_label_info.1 = Some(begin_offset);
|
|
|
|
let begin_label = begin_label_info.0;
|
|
|
|
|
2019-02-12 23:15:57 +08:00
|
|
|
dynasm!(
|
|
|
|
assembler
|
|
|
|
; => begin_label
|
2019-02-21 22:04:43 +08:00
|
|
|
//; int 3
|
2019-02-12 23:15:57 +08:00
|
|
|
);
|
2019-02-12 00:52:17 +08:00
|
|
|
let code = X64FunctionCode {
|
2019-02-24 00:52:32 +08:00
|
|
|
signatures: self.signatures.as_ref().unwrap().clone(),
|
|
|
|
function_signatures: self.function_signatures.as_ref().unwrap().clone(),
|
|
|
|
|
2019-02-15 02:21:52 +08:00
|
|
|
begin_offset: begin_offset,
|
2019-02-12 23:15:57 +08:00
|
|
|
assembler: Some(assembler),
|
2019-02-24 00:52:32 +08:00
|
|
|
function_labels: Some(function_labels),
|
2019-02-24 12:00:35 +08:00
|
|
|
br_table_data: Some(br_table_data),
|
2019-02-14 00:53:06 +08:00
|
|
|
returns: vec![],
|
2019-02-12 00:52:17 +08:00
|
|
|
locals: vec![],
|
2019-02-12 23:15:57 +08:00
|
|
|
num_params: 0,
|
2019-04-01 20:33:33 +08:00
|
|
|
num_locals: 0,
|
|
|
|
value_stack: vec! [],
|
|
|
|
control_stack: vec! [],
|
|
|
|
machine: Machine::new(),
|
2019-02-21 21:14:10 +08:00
|
|
|
unreachable_depth: 0,
|
2019-02-12 00:52:17 +08:00
|
|
|
};
|
|
|
|
self.functions.push(code);
|
|
|
|
Ok(self.functions.last_mut().unwrap())
|
|
|
|
}
|
2019-02-14 00:53:06 +08:00
|
|
|
|
2019-03-18 00:31:36 +08:00
|
|
|
fn finalize(
|
|
|
|
mut self,
|
|
|
|
module_info: &ModuleInfo,
|
|
|
|
) -> Result<(X64ExecutionContext, X64RuntimeResolver), CodegenError> {
|
2019-03-17 10:54:50 +08:00
|
|
|
let (assembler, mut br_table_data) = match self.functions.last_mut() {
|
2019-02-24 12:00:35 +08:00
|
|
|
Some(x) => (x.assembler.take().unwrap(), x.br_table_data.take().unwrap()),
|
2019-02-15 02:21:52 +08:00
|
|
|
None => {
|
|
|
|
return Err(CodegenError {
|
|
|
|
message: "no function",
|
2019-03-18 00:48:50 +08:00
|
|
|
});
|
2019-02-15 02:21:52 +08:00
|
|
|
}
|
2019-02-14 00:53:06 +08:00
|
|
|
};
|
|
|
|
let output = assembler.finalize().unwrap();
|
2019-02-24 12:00:35 +08:00
|
|
|
|
|
|
|
for table in &mut br_table_data {
|
|
|
|
for entry in table {
|
|
|
|
*entry = output.ptr(AssemblyOffset(*entry)) as usize;
|
|
|
|
}
|
|
|
|
}
|
2019-03-09 02:57:23 +08:00
|
|
|
|
|
|
|
let function_labels = if let Some(x) = self.functions.last() {
|
|
|
|
x.function_labels.as_ref().unwrap()
|
|
|
|
} else {
|
|
|
|
self.function_labels.as_ref().unwrap()
|
|
|
|
};
|
|
|
|
let mut out_labels: Vec<FuncPtr> = vec![];
|
|
|
|
|
|
|
|
for i in 0..function_labels.len() {
|
|
|
|
let (_, offset) = match function_labels.get(&i) {
|
|
|
|
Some(x) => x,
|
|
|
|
None => {
|
|
|
|
return Err(CodegenError {
|
|
|
|
message: "label not found",
|
2019-03-18 00:48:50 +08:00
|
|
|
});
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let offset = match offset {
|
|
|
|
Some(x) => x,
|
|
|
|
None => {
|
|
|
|
return Err(CodegenError {
|
|
|
|
message: "offset is none",
|
2019-03-18 00:48:50 +08:00
|
|
|
});
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
out_labels.push(FuncPtr(output.ptr(*offset) as _));
|
|
|
|
}
|
|
|
|
|
2019-03-17 03:07:27 +08:00
|
|
|
let ctx = X64ExecutionContext {
|
2019-02-15 02:21:52 +08:00
|
|
|
code: output,
|
|
|
|
functions: self.functions,
|
2019-03-17 10:54:50 +08:00
|
|
|
_br_table_data: br_table_data,
|
2019-03-08 01:31:37 +08:00
|
|
|
func_import_count: self.func_import_count,
|
2019-03-09 02:57:23 +08:00
|
|
|
signatures: match self.signatures {
|
|
|
|
Some(x) => x,
|
|
|
|
None => {
|
|
|
|
return Err(CodegenError {
|
|
|
|
message: "no signatures",
|
2019-03-18 00:48:50 +08:00
|
|
|
});
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
function_pointers: out_labels,
|
|
|
|
function_signatures: match self.function_signatures {
|
|
|
|
Some(x) => x,
|
|
|
|
None => {
|
|
|
|
return Err(CodegenError {
|
|
|
|
message: "no function signatures",
|
2019-03-18 00:48:50 +08:00
|
|
|
});
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
|
|
|
},
|
2019-03-17 03:07:27 +08:00
|
|
|
};
|
|
|
|
let resolver = ctx.get_runtime_resolver(module_info)?;
|
|
|
|
|
|
|
|
Ok((ctx, resolver))
|
2019-02-14 00:53:06 +08:00
|
|
|
}
|
2019-02-24 00:52:32 +08:00
|
|
|
|
2019-03-18 00:31:36 +08:00
|
|
|
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), CodegenError> {
|
2019-02-24 00:52:32 +08:00
|
|
|
self.signatures = Some(Arc::new(signatures));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn feed_function_signatures(
|
|
|
|
&mut self,
|
|
|
|
assoc: Map<FuncIndex, SigIndex>,
|
|
|
|
) -> Result<(), CodegenError> {
|
|
|
|
self.function_signatures = Some(Arc::new(assoc));
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-08 01:31:37 +08:00
|
|
|
|
|
|
|
fn feed_import_function(&mut self) -> Result<(), CodegenError> {
|
2019-04-04 11:19:38 +08:00
|
|
|
let labels = self.function_labels.as_mut().unwrap();
|
2019-03-08 01:31:37 +08:00
|
|
|
let id = labels.len();
|
|
|
|
|
2019-04-04 11:19:38 +08:00
|
|
|
let a = self.assembler.as_mut().unwrap();
|
|
|
|
let offset = a.offset();
|
|
|
|
let label = a.get_label();
|
|
|
|
a.emit_label(label);
|
|
|
|
labels.insert(id, (label, Some(offset)));
|
2019-03-09 02:57:23 +08:00
|
|
|
|
2019-04-04 11:19:38 +08:00
|
|
|
a.emit_mov(
|
|
|
|
Size::S64,
|
|
|
|
Location::Memory(
|
|
|
|
GPR::RDI,
|
|
|
|
vm::Ctx::offset_imported_funcs() as i32,
|
|
|
|
),
|
|
|
|
Location::GPR(GPR::RAX),
|
2019-03-08 01:31:37 +08:00
|
|
|
);
|
2019-04-04 11:19:38 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(
|
|
|
|
GPR::RAX,
|
|
|
|
(vm::ImportedFunc::size() as usize * id + vm::ImportedFunc::offset_func() as usize) as i32
|
|
|
|
), Location::GPR(GPR::RAX));
|
|
|
|
a.emit_jmp_location(Location::GPR(GPR::RAX));
|
2019-03-08 01:31:37 +08:00
|
|
|
|
|
|
|
self.func_import_count += 1;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-02-12 00:52:17 +08:00
|
|
|
}
|
|
|
|
|
2019-02-13 20:04:10 +08:00
|
|
|
impl X64FunctionCode {
|
2019-04-01 23:49:46 +08:00
|
|
|
fn emit_relaxed_xdiv(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
op: fn(&mut Assembler, Size, Location),
|
|
|
|
sz: Size,
|
|
|
|
loc: Location,
|
|
|
|
) {
|
|
|
|
match loc {
|
|
|
|
Location::Imm64(_) | Location::Imm32(_) => {
|
|
|
|
a.emit_mov(sz, loc, Location::GPR(GPR::RCX)); // must not be used during div (rax, rdx)
|
|
|
|
op(a, sz, Location::GPR(GPR::RCX));
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
op(a, sz, loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 22:49:26 +08:00
|
|
|
fn emit_relaxed_zx_sx(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
op: fn(&mut Assembler, Size, Location, Size, Location),
|
|
|
|
sz_src: Size,
|
|
|
|
mut src: Location,
|
|
|
|
sz_dst: Size,
|
|
|
|
dst: Location,
|
|
|
|
) {
|
|
|
|
let tmp_src = m.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_dst = m.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
match src {
|
|
|
|
Location::Imm32(_) | Location::Imm64(_) => {
|
|
|
|
a.emit_mov(Size::S64, src, Location::GPR(tmp_src));
|
|
|
|
src = Location::GPR(tmp_src);
|
|
|
|
}
|
|
|
|
Location::Memory(_, _) | Location::GPR(_) => {}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
|
|
|
|
match dst {
|
|
|
|
Location::Imm32(_) | Location::Imm64(_) => unreachable!(),
|
|
|
|
Location::Memory(_, _) => {
|
|
|
|
op(a, sz_src, src, sz_dst, Location::GPR(tmp_dst));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_dst), dst);
|
|
|
|
}
|
|
|
|
Location::GPR(_) => {
|
|
|
|
op(a, sz_src, src, sz_dst, dst);
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
|
|
|
|
m.release_temp_gpr(tmp_dst);
|
|
|
|
m.release_temp_gpr(tmp_src);
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:56:32 +08:00
|
|
|
fn emit_relaxed_binop(
|
2019-04-01 20:33:33 +08:00
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
2019-04-01 20:56:32 +08:00
|
|
|
op: fn(&mut Assembler, Size, Location, Location),
|
2019-04-01 20:33:33 +08:00
|
|
|
sz: Size,
|
|
|
|
src: Location,
|
|
|
|
dst: Location,
|
|
|
|
) {
|
2019-04-01 20:56:32 +08:00
|
|
|
enum RelaxMode {
|
|
|
|
Direct,
|
|
|
|
SrcToGPR,
|
|
|
|
DstToGPR,
|
2019-04-01 23:49:46 +08:00
|
|
|
BothToGPR,
|
2019-04-01 20:56:32 +08:00
|
|
|
}
|
|
|
|
let mode = match (src, dst) {
|
|
|
|
(Location::Memory(_, _), Location::Memory(_, _)) => RelaxMode::SrcToGPR,
|
2019-04-01 23:49:46 +08:00
|
|
|
(Location::Imm64(_), Location::Imm64(_)) | (Location::Imm64(_), Location::Imm32(_)) => RelaxMode::BothToGPR,
|
2019-04-01 20:56:32 +08:00
|
|
|
(_, Location::Imm32(_)) | (_, Location::Imm64(_)) => RelaxMode::DstToGPR,
|
|
|
|
(Location::Imm64(_), Location::Memory(_, _)) => RelaxMode::SrcToGPR,
|
|
|
|
(Location::Imm64(_), Location::GPR(_)) if (op as *const u8 != Assembler::emit_mov as *const u8) => RelaxMode::SrcToGPR,
|
2019-04-09 01:24:30 +08:00
|
|
|
(_, Location::XMM(_)) => RelaxMode::SrcToGPR,
|
2019-04-08 17:47:41 +08:00
|
|
|
_ if (op as *const u8 == Assembler::emit_imul as *const u8) => RelaxMode::BothToGPR, // TODO: optimize this
|
2019-04-01 20:56:32 +08:00
|
|
|
_ => RelaxMode::Direct,
|
|
|
|
};
|
|
|
|
|
|
|
|
match mode {
|
|
|
|
RelaxMode::SrcToGPR => {
|
2019-04-01 20:33:33 +08:00
|
|
|
let temp = m.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(sz, src, Location::GPR(temp));
|
|
|
|
op(a, sz, Location::GPR(temp), dst);
|
|
|
|
m.release_temp_gpr(temp);
|
|
|
|
},
|
2019-04-01 20:56:32 +08:00
|
|
|
RelaxMode::DstToGPR => {
|
2019-04-01 20:33:33 +08:00
|
|
|
let temp = m.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(sz, dst, Location::GPR(temp));
|
|
|
|
op(a, sz, src, Location::GPR(temp));
|
|
|
|
m.release_temp_gpr(temp);
|
2019-04-01 20:56:32 +08:00
|
|
|
},
|
2019-04-01 23:49:46 +08:00
|
|
|
RelaxMode::BothToGPR => {
|
|
|
|
let temp_src = m.acquire_temp_gpr().unwrap();
|
|
|
|
let temp_dst = m.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(sz, src, Location::GPR(temp_src));
|
|
|
|
a.emit_mov(sz, dst, Location::GPR(temp_dst));
|
|
|
|
op(a, sz, Location::GPR(temp_src), Location::GPR(temp_dst));
|
2019-04-08 17:47:41 +08:00
|
|
|
match dst {
|
|
|
|
Location::Memory(_, _) | Location::GPR(_) => {
|
|
|
|
a.emit_mov(sz, Location::GPR(temp_dst), dst);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2019-04-01 23:49:46 +08:00
|
|
|
m.release_temp_gpr(temp_dst);
|
|
|
|
m.release_temp_gpr(temp_src);
|
|
|
|
},
|
2019-04-01 20:56:32 +08:00
|
|
|
RelaxMode::Direct => {
|
2019-04-01 20:33:33 +08:00
|
|
|
op(a, sz, src, dst);
|
2019-02-23 01:54:16 +08:00
|
|
|
}
|
|
|
|
}
|
2019-03-05 00:59:05 +08:00
|
|
|
}
|
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
fn emit_relaxed_avx(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
op: fn(&mut Assembler, XMM, XMMOrMemory, XMM),
|
|
|
|
src1: Location,
|
|
|
|
src2: Location,
|
|
|
|
dst: Location,
|
2019-04-09 17:08:31 +08:00
|
|
|
) {
|
|
|
|
Self::emit_relaxed_avx_base(a, m, |a, _, src1, src2, dst| op(a, src1, src2, dst), src1, src2, dst)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_relaxed_avx_base<F: FnOnce(&mut Assembler, &mut Machine, XMM, XMMOrMemory, XMM)>(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
op: F,
|
|
|
|
src1: Location,
|
|
|
|
src2: Location,
|
|
|
|
dst: Location,
|
2019-04-09 01:24:30 +08:00
|
|
|
) {
|
|
|
|
let tmp1 = m.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp2 = m.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp3 = m.acquire_temp_xmm().unwrap();
|
|
|
|
let tmpg = m.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
let src1 = match src1 {
|
|
|
|
Location::XMM(x) => x,
|
|
|
|
Location::GPR(_) | Location::Memory(_, _) => {
|
|
|
|
a.emit_mov(Size::S64, src1, Location::XMM(tmp1));
|
|
|
|
tmp1
|
|
|
|
}
|
|
|
|
Location::Imm32(_) => {
|
|
|
|
a.emit_mov(Size::S32, src1, Location::GPR(tmpg));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp1));
|
|
|
|
tmp1
|
|
|
|
}
|
|
|
|
Location::Imm64(_) => {
|
|
|
|
a.emit_mov(Size::S64, src1, Location::GPR(tmpg));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp1));
|
|
|
|
tmp1
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
|
|
|
|
let src2 = match src2 {
|
|
|
|
Location::XMM(x) => XMMOrMemory::XMM(x),
|
|
|
|
Location::Memory(base, disp) => XMMOrMemory::Memory(base, disp),
|
|
|
|
Location::GPR(_) => {
|
|
|
|
a.emit_mov(Size::S64, src2, Location::XMM(tmp2));
|
|
|
|
XMMOrMemory::XMM(tmp2)
|
|
|
|
}
|
|
|
|
Location::Imm32(_) => {
|
|
|
|
a.emit_mov(Size::S32, src2, Location::GPR(tmpg));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp2));
|
|
|
|
XMMOrMemory::XMM(tmp2)
|
|
|
|
}
|
|
|
|
Location::Imm64(_) => {
|
|
|
|
a.emit_mov(Size::S64, src2, Location::GPR(tmpg));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp2));
|
|
|
|
XMMOrMemory::XMM(tmp2)
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
|
|
|
|
|
|
|
match dst {
|
|
|
|
Location::XMM(x) => {
|
2019-04-09 17:08:31 +08:00
|
|
|
op(a, m, src1, src2, x);
|
2019-04-09 01:24:30 +08:00
|
|
|
},
|
2019-04-09 19:10:20 +08:00
|
|
|
Location::Memory(_, _) | Location::GPR(_) => {
|
2019-04-09 17:08:31 +08:00
|
|
|
op(a, m, src1, src2, tmp3);
|
2019-04-09 01:24:30 +08:00
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp3), dst);
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
|
|
|
|
m.release_temp_gpr(tmpg);
|
|
|
|
m.release_temp_xmm(tmp3);
|
|
|
|
m.release_temp_xmm(tmp2);
|
|
|
|
m.release_temp_xmm(tmp1);
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:56:32 +08:00
|
|
|
fn emit_binop_i32(
|
2019-04-01 20:33:33 +08:00
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
2019-04-01 20:56:32 +08:00
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
2019-04-01 20:33:33 +08:00
|
|
|
) {
|
|
|
|
// Using Red Zone here.
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
|
|
|
|
if loc_a != ret {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, loc_a, Location::GPR(tmp),
|
2019-02-19 20:25:09 +08:00
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, f,
|
|
|
|
Size::S32, loc_b, Location::GPR(tmp),
|
2019-02-19 20:25:09 +08:00
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, Location::GPR(tmp), ret,
|
2019-02-19 20:25:09 +08:00
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
m.release_temp_gpr(tmp);
|
2019-02-19 20:25:09 +08:00
|
|
|
} else {
|
2019-04-01 20:33:33 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, f,
|
|
|
|
Size::S32, loc_b, ret,
|
2019-02-19 20:25:09 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
2019-02-19 20:25:09 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 23:49:46 +08:00
|
|
|
fn emit_binop_i64(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
|
|
|
) {
|
|
|
|
// Using Red Zone here.
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
|
|
|
|
if loc_a != ret {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, loc_a, Location::GPR(tmp),
|
|
|
|
);
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, f,
|
|
|
|
Size::S64, loc_b, Location::GPR(tmp),
|
|
|
|
);
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, Location::GPR(tmp), ret,
|
|
|
|
);
|
|
|
|
m.release_temp_gpr(tmp);
|
|
|
|
} else {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, f,
|
|
|
|
Size::S64, loc_b, ret,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn emit_cmpop_i32_dynamic_b(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
c: Condition,
|
|
|
|
loc_b: Location,
|
|
|
|
) {
|
|
|
|
// Using Red Zone here.
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
match ret {
|
|
|
|
Location::GPR(x) => {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_cmp,
|
|
|
|
Size::S32, loc_b, loc_a,
|
|
|
|
);
|
|
|
|
a.emit_set(c, x);
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(x));
|
|
|
|
},
|
|
|
|
Location::Memory(_, _) => {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_cmp,
|
|
|
|
Size::S32, loc_b, loc_a,
|
|
|
|
);
|
|
|
|
a.emit_set(c, tmp);
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp), ret);
|
|
|
|
m.release_temp_gpr(tmp);
|
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
2019-03-05 00:59:05 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn emit_cmpop_i32(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
c: Condition,
|
|
|
|
) {
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
Self::emit_cmpop_i32_dynamic_b(a, m, value_stack, c, loc_b);
|
2019-03-05 00:59:05 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 23:49:46 +08:00
|
|
|
fn emit_cmpop_i64_dynamic_b(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
c: Condition,
|
|
|
|
loc_b: Location,
|
|
|
|
) {
|
|
|
|
// Using Red Zone here.
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
match ret {
|
|
|
|
Location::GPR(x) => {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_cmp,
|
|
|
|
Size::S64, loc_b, loc_a,
|
|
|
|
);
|
|
|
|
a.emit_set(c, x);
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(x));
|
|
|
|
},
|
|
|
|
Location::Memory(_, _) => {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_cmp,
|
|
|
|
Size::S64, loc_b, loc_a,
|
|
|
|
);
|
|
|
|
a.emit_set(c, tmp);
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0xff), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp), ret);
|
|
|
|
m.release_temp_gpr(tmp);
|
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_cmpop_i64(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
c: Condition,
|
|
|
|
) {
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
Self::emit_cmpop_i64_dynamic_b(a, m, value_stack, c, loc_b);
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:56:32 +08:00
|
|
|
fn emit_xcnt_i32(
|
2019-04-01 20:33:33 +08:00
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
2019-04-01 20:56:32 +08:00
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
2019-03-13 18:23:50 +08:00
|
|
|
) {
|
2019-04-01 20:33:33 +08:00
|
|
|
let loc = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
2019-04-01 23:49:46 +08:00
|
|
|
|
|
|
|
match loc {
|
|
|
|
Location::Imm32(_) => {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp));
|
|
|
|
if let Location::Memory(_, _) = ret {
|
|
|
|
let out_tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
f(a, Size::S32, Location::GPR(tmp), Location::GPR(out_tmp));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(out_tmp), ret);
|
|
|
|
m.release_temp_gpr(out_tmp);
|
|
|
|
} else {
|
|
|
|
f(a, Size::S32, Location::GPR(tmp), ret);
|
|
|
|
}
|
|
|
|
m.release_temp_gpr(tmp);
|
|
|
|
},
|
|
|
|
Location::Memory(_, _) | Location::GPR(_) => {
|
|
|
|
if let Location::Memory(_, _) = ret {
|
|
|
|
let out_tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
f(a, Size::S32, loc, Location::GPR(out_tmp));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(out_tmp), ret);
|
|
|
|
m.release_temp_gpr(out_tmp);
|
|
|
|
} else {
|
|
|
|
f(a, Size::S32, loc, ret);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_xcnt_i64(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
|
|
|
) {
|
|
|
|
let loc = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
|
|
|
|
match loc {
|
|
|
|
Location::Imm64(_) | Location::Imm32(_) => {
|
|
|
|
let tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp));
|
|
|
|
if let Location::Memory(_, _) = ret {
|
|
|
|
let out_tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
f(a, Size::S64, Location::GPR(tmp), Location::GPR(out_tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(out_tmp), ret);
|
|
|
|
m.release_temp_gpr(out_tmp);
|
|
|
|
} else {
|
|
|
|
f(a, Size::S64, Location::GPR(tmp), ret);
|
|
|
|
}
|
|
|
|
m.release_temp_gpr(tmp);
|
|
|
|
},
|
|
|
|
Location::Memory(_, _) | Location::GPR(_) => {
|
|
|
|
if let Location::Memory(_, _) = ret {
|
|
|
|
let out_tmp = m.acquire_temp_gpr().unwrap();
|
|
|
|
f(a, Size::S64, loc, Location::GPR(out_tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(out_tmp), ret);
|
|
|
|
m.release_temp_gpr(out_tmp);
|
|
|
|
} else {
|
|
|
|
f(a, Size::S64, loc, ret);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
2019-03-13 18:23:50 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
2019-03-13 18:23:50 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:56:32 +08:00
|
|
|
fn emit_shift_i32(
|
2019-04-01 20:33:33 +08:00
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
2019-04-01 20:56:32 +08:00
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
2019-02-19 20:25:09 +08:00
|
|
|
) {
|
2019-04-01 20:33:33 +08:00
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
2019-02-19 20:25:09 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, loc_b, Location::GPR(GPR::RCX));
|
2019-02-19 20:25:09 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
if loc_a != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, loc_a, ret
|
2019-02-19 20:25:09 +08:00
|
|
|
);
|
2019-03-06 01:16:24 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
f(a, Size::S32, Location::GPR(GPR::RCX), ret);
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
2019-02-19 20:25:09 +08:00
|
|
|
|
2019-04-01 23:49:46 +08:00
|
|
|
fn emit_shift_i64(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, Size, Location, Location),
|
|
|
|
) {
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
|
2019-04-11 00:55:55 +08:00
|
|
|
a.emit_mov(Size::S64, loc_b, Location::GPR(GPR::RCX));
|
2019-04-01 23:49:46 +08:00
|
|
|
|
|
|
|
if loc_a != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, loc_a, ret
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
f(a, Size::S64, Location::GPR(GPR::RCX), ret);
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
2019-04-03 22:49:26 +08:00
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
fn emit_fp_binop_avx(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, XMM, XMMOrMemory, XMM),
|
|
|
|
) {
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret);
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
fn emit_fp_cmpop_avx(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, XMM, XMMOrMemory, XMM),
|
|
|
|
) {
|
|
|
|
let loc_b = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_relaxed_avx(a, m, f, loc_a, loc_b, ret);
|
2019-04-10 00:41:32 +08:00
|
|
|
a.emit_and(Size::S32, Location::Imm32(1), ret); // FIXME: Why?
|
2019-04-09 19:10:20 +08:00
|
|
|
}
|
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
fn emit_fp_unop_avx(
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
value_stack: &mut Vec<(Location, LocalOrTemp)>,
|
|
|
|
f: fn(&mut Assembler, XMM, XMMOrMemory, XMM),
|
|
|
|
) {
|
|
|
|
let loc = get_location_released(a, m, value_stack.pop().unwrap());
|
|
|
|
let ret = m.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_relaxed_avx(a, m, f, loc, loc, ret);
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
// This function must not use RAX before `cb` is called.
|
2019-04-04 09:38:22 +08:00
|
|
|
fn emit_call_sysv<I: Iterator<Item = Location>, F: FnOnce(&mut Assembler)>(a: &mut Assembler, m: &mut Machine, cb: F, params: I) {
|
2019-04-04 10:50:48 +08:00
|
|
|
let params: Vec<_> = params.collect();
|
|
|
|
|
|
|
|
// Save used GPRs.
|
2019-04-03 22:49:26 +08:00
|
|
|
let used_gprs = m.get_used_gprs();
|
|
|
|
for r in used_gprs.iter() {
|
|
|
|
a.emit_push(Size::S64, Location::GPR(*r));
|
|
|
|
}
|
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
// Save used XMM registers.
|
|
|
|
let used_xmms = m.get_used_xmms();
|
|
|
|
if used_xmms.len() > 0 {
|
|
|
|
a.emit_sub(Size::S64, Location::Imm32((used_xmms.len() * 8) as u32), Location::GPR(GPR::RSP));
|
2019-04-09 19:10:20 +08:00
|
|
|
|
|
|
|
// FIXME: Possible dynasm bug. This is a workaround.
|
|
|
|
// Using RSP as the source/destination operand of a `mov` instruction produces invalid code.
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RCX));
|
2019-04-09 01:24:30 +08:00
|
|
|
for (i, r) in used_xmms.iter().enumerate() {
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, Location::XMM(*r), Location::Memory(GPR::RCX, (i * 8) as i32));
|
2019-04-09 01:24:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 22:49:26 +08:00
|
|
|
let mut stack_offset: usize = 0;
|
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Calculate stack offset.
|
|
|
|
for (i, param) in params.iter().enumerate() {
|
|
|
|
let loc = Machine::get_param_location(1 + i);
|
|
|
|
match loc {
|
|
|
|
Location::Memory(_, _) => {
|
|
|
|
stack_offset += 8;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Align stack to 16 bytes.
|
|
|
|
if (m.get_stack_offset() + used_gprs.len() * 8 + stack_offset) % 16 != 0 {
|
|
|
|
a.emit_sub(Size::S64, Location::Imm32(8), Location::GPR(GPR::RSP));
|
|
|
|
stack_offset += 8;
|
|
|
|
}
|
|
|
|
|
2019-04-03 22:49:26 +08:00
|
|
|
let mut call_movs: Vec<(Location, GPR)> = vec![];
|
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Prepare register & stack parameters.
|
|
|
|
for (i, param) in params.iter().enumerate() {
|
2019-04-03 22:49:26 +08:00
|
|
|
let loc = Machine::get_param_location(1 + i);
|
|
|
|
match loc {
|
|
|
|
Location::GPR(x) => {
|
2019-04-04 10:50:48 +08:00
|
|
|
call_movs.push((*param, x));
|
2019-04-03 22:49:26 +08:00
|
|
|
}
|
|
|
|
Location::Memory(_, _) => {
|
2019-04-11 00:55:55 +08:00
|
|
|
match *param {
|
|
|
|
// Dynasm bug: RSP in memory operand does not work
|
|
|
|
Location::Imm64(_) | Location::XMM(_) => {
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), Location::XMM(XMM::XMM0));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RCX), Location::XMM(XMM::XMM1));
|
|
|
|
a.emit_sub(Size::S64, Location::Imm32(8), Location::GPR(GPR::RSP));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RCX));
|
|
|
|
a.emit_mov(Size::S64, *param, Location::GPR(GPR::RAX));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), Location::Memory(GPR::RCX, 0));
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(XMM::XMM0), Location::GPR(GPR::RAX));
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(XMM::XMM1), Location::GPR(GPR::RCX));
|
|
|
|
},
|
|
|
|
_ => a.emit_push(Size::S64, *param)
|
|
|
|
}
|
2019-04-03 22:49:26 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Sort register moves so that register are not overwritten before read.
|
2019-04-03 22:49:26 +08:00
|
|
|
sort_call_movs(&mut call_movs);
|
2019-04-04 10:50:48 +08:00
|
|
|
|
|
|
|
// Emit register moves.
|
2019-04-03 22:49:26 +08:00
|
|
|
for (loc, gpr) in call_movs {
|
|
|
|
if loc != Location::GPR(gpr) {
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(gpr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Put vmctx as the first parameter.
|
2019-04-03 22:49:26 +08:00
|
|
|
a.emit_mov(Size::S64, Location::GPR(Machine::get_vmctx_reg()), Machine::get_param_location(0)); // vmctx
|
2019-04-04 10:50:48 +08:00
|
|
|
|
2019-04-04 09:38:22 +08:00
|
|
|
cb(a);
|
2019-04-03 22:49:26 +08:00
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Restore stack.
|
2019-04-03 22:49:26 +08:00
|
|
|
if stack_offset > 0 {
|
|
|
|
a.emit_add(Size::S64, Location::Imm32(stack_offset as u32), Location::GPR(GPR::RSP));
|
|
|
|
}
|
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
// Restore XMMs.
|
|
|
|
if used_xmms.len() > 0 {
|
2019-04-09 19:10:20 +08:00
|
|
|
// FIXME: Possible dynasm bug. This is a workaround.
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RDX));
|
2019-04-09 01:24:30 +08:00
|
|
|
for (i, r) in used_xmms.iter().enumerate() {
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(GPR::RDX, (i * 8) as i32), Location::XMM(*r));
|
2019-04-09 01:24:30 +08:00
|
|
|
}
|
|
|
|
a.emit_add(Size::S64, Location::Imm32((used_xmms.len() * 8) as u32), Location::GPR(GPR::RSP));
|
|
|
|
}
|
|
|
|
|
2019-04-04 10:50:48 +08:00
|
|
|
// Restore GPRs.
|
2019-04-03 22:49:26 +08:00
|
|
|
for r in used_gprs.iter().rev() {
|
|
|
|
a.emit_pop(Size::S64, Location::GPR(*r));
|
|
|
|
}
|
|
|
|
}
|
2019-04-04 09:38:22 +08:00
|
|
|
|
|
|
|
fn emit_call_sysv_label<I: Iterator<Item = Location>>(a: &mut Assembler, m: &mut Machine, label: DynamicLabel, params: I) {
|
|
|
|
Self::emit_call_sysv(a, m, |a| a.emit_call_label(label), params)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_memory_op<F: FnOnce(&mut Assembler, &mut Machine, GPR)>(
|
|
|
|
module_info: &ModuleInfo,
|
|
|
|
a: &mut Assembler,
|
|
|
|
m: &mut Machine,
|
|
|
|
addr: Location,
|
|
|
|
offset: usize,
|
|
|
|
value_size: usize,
|
|
|
|
cb: F
|
|
|
|
) {
|
|
|
|
let tmp_addr = m.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_base = m.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_bound = m.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(
|
|
|
|
Size::S64,
|
|
|
|
Location::Memory(
|
|
|
|
Machine::get_vmctx_reg(),
|
|
|
|
match MemoryIndex::new(0).local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(_) => vm::Ctx::offset_memories(),
|
|
|
|
LocalOrImport::Import(_) => vm::Ctx::offset_imported_memories(),
|
|
|
|
} as i32
|
|
|
|
),
|
|
|
|
Location::GPR(tmp_base),
|
|
|
|
);
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(tmp_base, 0), Location::GPR(tmp_base));
|
|
|
|
a.emit_mov(Size::S32, Location::Memory(tmp_base, LocalMemory::offset_bound() as i32), Location::GPR(tmp_bound));
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(tmp_base, LocalMemory::offset_base() as i32), Location::GPR(tmp_base));
|
|
|
|
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_bound));
|
|
|
|
|
|
|
|
let mem_desc = match MemoryIndex::new(0).local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(local_mem_index) => &module_info.memories[local_mem_index],
|
|
|
|
LocalOrImport::Import(import_mem_index) => {
|
|
|
|
&module_info.imported_memories[import_mem_index].1
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let need_check = match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => true,
|
|
|
|
MemoryType::Static | MemoryType::SharedStatic => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if need_check {
|
|
|
|
a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
|
|
|
a.emit_add(Size::S64, Location::Imm32((offset + value_size) as u32), Location::GPR(tmp_addr));
|
|
|
|
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr));
|
|
|
|
a.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr));
|
|
|
|
a.emit_conditional_trap(Condition::Above);
|
|
|
|
}
|
|
|
|
|
|
|
|
m.release_temp_gpr(tmp_bound);
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, addr, Location::GPR(tmp_addr));
|
|
|
|
a.emit_add(Size::S64, Location::Imm32(offset as u32), Location::GPR(tmp_addr));
|
|
|
|
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr));
|
|
|
|
m.release_temp_gpr(tmp_base);
|
|
|
|
|
|
|
|
cb(a, m, tmp_addr);
|
|
|
|
|
|
|
|
m.release_temp_gpr(tmp_addr);
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
}
|
2019-02-20 22:56:32 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
impl FunctionCodeGenerator for X64FunctionCode {
|
|
|
|
fn feed_return(&mut self, ty: WpType) -> Result<(), CodegenError> {
|
|
|
|
self.returns.push(ty);
|
|
|
|
Ok(())
|
2019-02-23 01:54:16 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn feed_param(&mut self, ty: WpType) -> Result<(), CodegenError> {
|
|
|
|
self.num_params += 1;
|
|
|
|
self.num_locals += 1;
|
|
|
|
Ok(())
|
2019-03-05 00:59:05 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
|
|
|
|
self.num_locals += n;
|
|
|
|
Ok(())
|
2019-02-21 22:04:43 +08:00
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn begin_body(&mut self) -> Result<(), CodegenError> {
|
|
|
|
let a = self.assembler.as_mut().unwrap();
|
|
|
|
a.emit_push(Size::S64, Location::GPR(GPR::RBP));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RSP), Location::GPR(GPR::RBP));
|
2019-03-02 01:41:31 +08:00
|
|
|
|
2019-04-02 20:50:56 +08:00
|
|
|
self.locals = self.machine.init_locals(a, self.num_locals, self.num_params);
|
2019-02-24 00:52:32 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
self.control_stack.push(ControlFrame {
|
|
|
|
label: a.get_label(),
|
|
|
|
loop_like: false,
|
|
|
|
if_else: IfElseState::None,
|
|
|
|
returns: self.returns.clone(),
|
|
|
|
value_stack_depth: 0,
|
|
|
|
});
|
2019-02-24 00:52:32 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn finalize(&mut self) -> Result<(), CodegenError> {
|
|
|
|
let a = self.assembler.as_mut().unwrap();
|
|
|
|
a.emit_ud2();
|
|
|
|
Ok(())
|
2019-03-02 01:41:31 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
|
|
|
|
fn feed_opcode(&mut self, op: Operator, module_info: &ModuleInfo) -> Result<(), CodegenError> {
|
2019-04-10 01:38:16 +08:00
|
|
|
//println!("{:?} {}", op, self.value_stack.len());
|
2019-04-01 20:33:33 +08:00
|
|
|
let was_unreachable;
|
2019-02-21 21:14:10 +08:00
|
|
|
|
|
|
|
if self.unreachable_depth > 0 {
|
|
|
|
was_unreachable = true;
|
|
|
|
match op {
|
|
|
|
Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => {
|
|
|
|
self.unreachable_depth += 1;
|
|
|
|
}
|
2019-03-14 17:11:35 +08:00
|
|
|
Operator::End => {
|
2019-02-21 21:14:10 +08:00
|
|
|
self.unreachable_depth -= 1;
|
|
|
|
}
|
2019-03-14 17:11:35 +08:00
|
|
|
Operator::Else => {
|
|
|
|
// We are in a reachable true branch
|
|
|
|
if self.unreachable_depth == 1 {
|
2019-03-18 00:31:36 +08:00
|
|
|
if let Some(IfElseState::If(_)) = self
|
|
|
|
.control_stack
|
|
|
|
.last()
|
|
|
|
.map(|x| x.if_else)
|
|
|
|
{
|
2019-03-14 17:11:35 +08:00
|
|
|
self.unreachable_depth -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-21 21:14:10 +08:00
|
|
|
_ => {}
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
if self.unreachable_depth > 0 {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
was_unreachable = false;
|
|
|
|
}
|
2019-03-09 02:57:23 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
let a = self.assembler.as_mut().unwrap();
|
|
|
|
match op {
|
|
|
|
Operator::GetGlobal { global_index } => {
|
|
|
|
let mut global_index = global_index as usize;
|
2019-03-09 02:57:23 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
2019-03-09 02:57:23 +08:00
|
|
|
|
2019-04-10 00:41:32 +08:00
|
|
|
let loc = match GlobalIndex::new(global_index).local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(local_index) => {
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_globals() as i32), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(tmp, (local_index.index() as i32) * 8), Location::GPR(tmp));
|
|
|
|
self.machine.acquire_locations(
|
|
|
|
a,
|
|
|
|
&[type_to_wp_type(
|
|
|
|
module_info.globals[local_index]
|
|
|
|
.desc
|
|
|
|
.ty,
|
|
|
|
)],
|
|
|
|
false
|
|
|
|
)[0]
|
|
|
|
},
|
|
|
|
LocalOrImport::Import(import_index) => {
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_imported_globals() as i32), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(tmp, (import_index.index() as i32) * 8), Location::GPR(tmp));
|
|
|
|
self.machine.acquire_locations(
|
|
|
|
a,
|
|
|
|
&[type_to_wp_type(
|
|
|
|
module_info.imported_globals[import_index].1
|
|
|
|
.ty,
|
|
|
|
)],
|
|
|
|
false
|
|
|
|
)[0]
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.value_stack.push((loc, LocalOrTemp::Temp));
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, Location::Memory(tmp, LocalGlobal::offset_data() as i32), loc
|
2019-03-09 02:57:23 +08:00
|
|
|
);
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
self.machine.release_temp_gpr(tmp);
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::SetGlobal { global_index } => {
|
|
|
|
let mut global_index = global_index as usize;
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
2019-02-21 22:04:43 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
2019-02-21 22:04:43 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
if global_index < module_info.imported_globals.len() {
|
2019-04-04 09:38:22 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_imported_globals() as i32), Location::GPR(tmp));
|
2019-02-21 21:14:10 +08:00
|
|
|
} else {
|
2019-04-01 20:33:33 +08:00
|
|
|
global_index -= module_info.imported_globals.len();
|
|
|
|
assert!(global_index < module_info.globals.len());
|
2019-04-04 09:38:22 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_globals() as i32), Location::GPR(tmp));
|
2019-02-14 00:53:06 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(tmp, (global_index as i32) * 8), Location::GPR(tmp));
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, Location::Memory(tmp, LocalGlobal::offset_data() as i32)
|
|
|
|
);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
2019-02-14 00:53:06 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::GetLocal { local_index } => {
|
|
|
|
let local_index = local_index as usize;
|
|
|
|
self.value_stack.push((self.locals[local_index], LocalOrTemp::Local));
|
|
|
|
}
|
|
|
|
Operator::SetLocal { local_index } => {
|
|
|
|
let local_index = local_index as usize;
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, self.locals[local_index],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Operator::TeeLocal { local_index } => {
|
|
|
|
let local_index = local_index as usize;
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
|
|
|
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, self.locals[local_index],
|
2019-02-23 01:54:16 +08:00
|
|
|
);
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::I32Const { value } => self.value_stack.push((Location::Imm32(value as u32), LocalOrTemp::Temp)),
|
|
|
|
Operator::I32Add => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_add),
|
|
|
|
Operator::I32Sub => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_sub),
|
|
|
|
Operator::I32Mul => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_imul),
|
|
|
|
Operator::I32DivU => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
a.emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX));
|
|
|
|
a.emit_xor(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RDX));
|
2019-04-01 23:49:46 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_div, Size::S32, loc_b);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, Location::GPR(GPR::RAX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I32DivS => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
a.emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX));
|
2019-04-09 01:24:30 +08:00
|
|
|
a.emit_cdq();
|
2019-04-01 23:49:46 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_idiv, Size::S32, loc_b);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, Location::GPR(GPR::RAX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I32RemU => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
a.emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX));
|
|
|
|
a.emit_xor(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RDX));
|
2019-04-09 19:10:20 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_div, Size::S32, loc_b);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, Location::GPR(GPR::RDX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I32RemS => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
2019-04-11 01:53:13 +08:00
|
|
|
|
|
|
|
let normal_path = a.get_label();
|
|
|
|
let end = a.get_label();
|
|
|
|
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(0x80000000), loc_a,
|
|
|
|
);
|
|
|
|
a.emit_jmp(Condition::NotEqual, normal_path);
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(0xffffffff), loc_b,
|
|
|
|
);
|
|
|
|
a.emit_jmp(Condition::NotEqual, normal_path);
|
|
|
|
a.emit_mov(Size::S32, Location::Imm32(0), ret);
|
|
|
|
a.emit_jmp(Condition::None, end);
|
|
|
|
|
|
|
|
a.emit_label(normal_path);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, loc_a, Location::GPR(GPR::RAX));
|
2019-04-10 00:41:32 +08:00
|
|
|
a.emit_cdq();
|
2019-04-09 19:10:20 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_idiv, Size::S32, loc_b);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S32, Location::GPR(GPR::RDX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-11 01:53:13 +08:00
|
|
|
|
|
|
|
a.emit_label(end);
|
2019-04-01 20:33:33 +08:00
|
|
|
}
|
|
|
|
Operator::I32And => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_and),
|
|
|
|
Operator::I32Or => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_or),
|
|
|
|
Operator::I32Xor => Self::emit_binop_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_xor),
|
|
|
|
Operator::I32Eq => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Equal),
|
|
|
|
Operator::I32Ne => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::NotEqual),
|
|
|
|
Operator::I32Eqz => Self::emit_cmpop_i32_dynamic_b(a, &mut self.machine, &mut self.value_stack, Condition::Equal, Location::Imm32(0)),
|
|
|
|
Operator::I32Clz => Self::emit_xcnt_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_lzcnt),
|
|
|
|
Operator::I32Ctz => Self::emit_xcnt_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_tzcnt),
|
|
|
|
Operator::I32Popcnt => Self::emit_xcnt_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_popcnt),
|
|
|
|
Operator::I32Shl => Self::emit_shift_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_shl),
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I32ShrU => Self::emit_shift_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_shr),
|
|
|
|
Operator::I32ShrS => Self::emit_shift_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_sar),
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::I32Rotl => Self::emit_shift_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_rol),
|
|
|
|
Operator::I32Rotr => Self::emit_shift_i32(a, &mut self.machine, &mut self.value_stack, Assembler::emit_ror),
|
|
|
|
Operator::I32LtU => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Below),
|
|
|
|
Operator::I32LeU => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::BelowEqual),
|
|
|
|
Operator::I32GtU => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Above),
|
|
|
|
Operator::I32GeU => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::AboveEqual),
|
|
|
|
Operator::I32LtS => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Less),
|
|
|
|
Operator::I32LeS => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::LessEqual),
|
|
|
|
Operator::I32GtS => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::Greater),
|
|
|
|
Operator::I32GeS => Self::emit_cmpop_i32(a, &mut self.machine, &mut self.value_stack, Condition::GreaterEqual),
|
2019-04-01 23:49:46 +08:00
|
|
|
Operator::I64Const { value } => {
|
|
|
|
let value = value as u64;
|
2019-04-10 01:38:16 +08:00
|
|
|
self.value_stack.push((Location::Imm64(value), LocalOrTemp::Temp));
|
2019-04-01 23:49:46 +08:00
|
|
|
},
|
|
|
|
Operator::I64Add => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_add),
|
|
|
|
Operator::I64Sub => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_sub),
|
|
|
|
Operator::I64Mul => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_imul),
|
|
|
|
Operator::I64DivU => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
a.emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX));
|
|
|
|
a.emit_xor(Size::S64, Location::GPR(GPR::RDX), Location::GPR(GPR::RDX));
|
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_div, Size::S64, loc_b);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I64DivS => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
a.emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX));
|
2019-04-09 01:24:30 +08:00
|
|
|
a.emit_cqo();
|
2019-04-01 23:49:46 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_idiv, Size::S64, loc_b);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I64RemU => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
a.emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX));
|
|
|
|
a.emit_xor(Size::S64, Location::GPR(GPR::RDX), Location::GPR(GPR::RDX));
|
2019-04-09 19:10:20 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_div, Size::S64, loc_b);
|
2019-04-01 23:49:46 +08:00
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RDX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
}
|
|
|
|
Operator::I64RemS => {
|
|
|
|
// We assume that RAX and RDX are temporary registers here.
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
2019-04-11 01:53:13 +08:00
|
|
|
|
|
|
|
let normal_path = a.get_label();
|
|
|
|
let end = a.get_label();
|
|
|
|
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S64, Location::Imm64(0x8000000000000000u64), loc_a,
|
|
|
|
);
|
|
|
|
a.emit_jmp(Condition::NotEqual, normal_path);
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S64, Location::Imm64(0xffffffffffffffffu64), loc_b,
|
|
|
|
);
|
|
|
|
a.emit_jmp(Condition::NotEqual, normal_path);
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0), ret);
|
|
|
|
a.emit_jmp(Condition::None, end);
|
|
|
|
|
|
|
|
a.emit_label(normal_path);
|
|
|
|
|
2019-04-01 23:49:46 +08:00
|
|
|
a.emit_mov(Size::S64, loc_a, Location::GPR(GPR::RAX));
|
2019-04-10 00:41:32 +08:00
|
|
|
a.emit_cqo();
|
2019-04-09 19:10:20 +08:00
|
|
|
Self::emit_relaxed_xdiv(a, &mut self.machine, Assembler::emit_idiv, Size::S64, loc_b);
|
2019-04-01 23:49:46 +08:00
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RDX), ret);
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-11 01:53:13 +08:00
|
|
|
a.emit_label(end);
|
2019-04-01 23:49:46 +08:00
|
|
|
}
|
|
|
|
Operator::I64And => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_and),
|
|
|
|
Operator::I64Or => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_or),
|
|
|
|
Operator::I64Xor => Self::emit_binop_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_xor),
|
|
|
|
Operator::I64Eq => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Equal),
|
|
|
|
Operator::I64Ne => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::NotEqual),
|
|
|
|
Operator::I64Eqz => Self::emit_cmpop_i64_dynamic_b(a, &mut self.machine, &mut self.value_stack, Condition::Equal, Location::Imm64(0)),
|
|
|
|
Operator::I64Clz => Self::emit_xcnt_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_lzcnt),
|
|
|
|
Operator::I64Ctz => Self::emit_xcnt_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_tzcnt),
|
|
|
|
Operator::I64Popcnt => Self::emit_xcnt_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_popcnt),
|
|
|
|
Operator::I64Shl => Self::emit_shift_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_shl),
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I64ShrU => Self::emit_shift_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_shr),
|
|
|
|
Operator::I64ShrS => Self::emit_shift_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_sar),
|
2019-04-01 23:49:46 +08:00
|
|
|
Operator::I64Rotl => Self::emit_shift_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_rol),
|
|
|
|
Operator::I64Rotr => Self::emit_shift_i64(a, &mut self.machine, &mut self.value_stack, Assembler::emit_ror),
|
|
|
|
Operator::I64LtU => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Below),
|
|
|
|
Operator::I64LeU => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::BelowEqual),
|
|
|
|
Operator::I64GtU => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Above),
|
|
|
|
Operator::I64GeU => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::AboveEqual),
|
|
|
|
Operator::I64LtS => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Less),
|
|
|
|
Operator::I64LeS => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::LessEqual),
|
|
|
|
Operator::I64GtS => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::Greater),
|
|
|
|
Operator::I64GeS => Self::emit_cmpop_i64(a, &mut self.machine, &mut self.value_stack, Condition::GreaterEqual),
|
|
|
|
Operator::I64ExtendUI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S32, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
2019-04-03 22:49:26 +08:00
|
|
|
Operator::I64ExtendSI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, &mut self.machine, Assembler::emit_movsx,
|
|
|
|
Size::S32, loc, Size::S64, ret,
|
|
|
|
);
|
|
|
|
}
|
2019-04-01 23:49:46 +08:00
|
|
|
Operator::I32WrapI64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S32, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
2019-04-09 17:08:31 +08:00
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
Operator::F32Const { value } => self.value_stack.push((Location::Imm32(value.bits()), LocalOrTemp::Temp)),
|
|
|
|
Operator::F32Add => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vaddss),
|
|
|
|
Operator::F32Sub => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsubss),
|
|
|
|
Operator::F32Mul => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmulss),
|
|
|
|
Operator::F32Div => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vdivss),
|
|
|
|
Operator::F32Max => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmaxss),
|
|
|
|
Operator::F32Min => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vminss),
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F32Eq => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpeqss),
|
|
|
|
Operator::F32Ne => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpneqss),
|
|
|
|
Operator::F32Lt => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpltss),
|
|
|
|
Operator::F32Le => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpless),
|
|
|
|
Operator::F32Gt => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgtss),
|
|
|
|
Operator::F32Ge => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgess),
|
2019-04-09 01:24:30 +08:00
|
|
|
Operator::F32Nearest => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_nearest),
|
|
|
|
Operator::F32Floor => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_floor),
|
|
|
|
Operator::F32Ceil => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_ceil),
|
|
|
|
Operator::F32Trunc => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundss_trunc),
|
|
|
|
Operator::F32Sqrt => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsqrtss),
|
|
|
|
|
2019-04-09 17:08:31 +08:00
|
|
|
Operator::F32Copysign => {
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
|
|
|
|
let tmp1 = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp2 = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S32, loc_a, Location::GPR(tmp1));
|
|
|
|
a.emit_mov(Size::S32, loc_b, Location::GPR(tmp2));
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0x7fffffffu32), Location::GPR(tmp1));
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0x80000000u32), Location::GPR(tmp2));
|
|
|
|
a.emit_or(Size::S32, Location::GPR(tmp2), Location::GPR(tmp1));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp1), ret);
|
|
|
|
self.machine.release_temp_gpr(tmp2);
|
|
|
|
self.machine.release_temp_gpr(tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F32Abs => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp));
|
|
|
|
a.emit_and(Size::S32, Location::Imm32(0x7fffffffu32), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp), ret);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F32Neg => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp));
|
|
|
|
a.emit_btc_gpr_imm8_32(31, tmp);
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp), ret);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
}
|
|
|
|
|
2019-04-09 01:24:30 +08:00
|
|
|
Operator::F64Const { value } => self.value_stack.push((Location::Imm64(value.bits()), LocalOrTemp::Temp)),
|
|
|
|
Operator::F64Add => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vaddsd),
|
|
|
|
Operator::F64Sub => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsubsd),
|
|
|
|
Operator::F64Mul => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmulsd),
|
|
|
|
Operator::F64Div => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vdivsd),
|
|
|
|
Operator::F64Max => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vmaxsd),
|
|
|
|
Operator::F64Min => Self::emit_fp_binop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vminsd),
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F64Eq => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpeqsd),
|
|
|
|
Operator::F64Ne => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpneqsd),
|
|
|
|
Operator::F64Lt => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpltsd),
|
|
|
|
Operator::F64Le => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmplesd),
|
|
|
|
Operator::F64Gt => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgtsd),
|
|
|
|
Operator::F64Ge => Self::emit_fp_cmpop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcmpgesd),
|
2019-04-09 01:24:30 +08:00
|
|
|
Operator::F64Nearest => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_nearest),
|
|
|
|
Operator::F64Floor => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_floor),
|
|
|
|
Operator::F64Ceil => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_ceil),
|
|
|
|
Operator::F64Trunc => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vroundsd_trunc),
|
|
|
|
Operator::F64Sqrt => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vsqrtsd),
|
|
|
|
|
2019-04-09 17:08:31 +08:00
|
|
|
Operator::F64Copysign => {
|
|
|
|
let loc_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let loc_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
|
|
|
|
let tmp1 = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp2 = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let c = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc_a, Location::GPR(tmp1));
|
|
|
|
a.emit_mov(Size::S64, loc_b, Location::GPR(tmp2));
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0x7fffffffffffffffu64), Location::GPR(c));
|
|
|
|
a.emit_and(Size::S64, Location::GPR(c), Location::GPR(tmp1));
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0x8000000000000000u64), Location::GPR(c));
|
|
|
|
a.emit_and(Size::S64, Location::GPR(c), Location::GPR(tmp2));
|
|
|
|
|
|
|
|
a.emit_or(Size::S64, Location::GPR(tmp2), Location::GPR(tmp1));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp1), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(c);
|
|
|
|
self.machine.release_temp_gpr(tmp2);
|
|
|
|
self.machine.release_temp_gpr(tmp1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F64Abs => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
|
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let c = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0x7fffffffffffffffu64), Location::GPR(c));
|
|
|
|
a.emit_and(Size::S64, Location::GPR(c), Location::GPR(tmp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(c);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F64Neg => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
2019-04-09 19:10:20 +08:00
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
2019-04-09 17:08:31 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp));
|
|
|
|
a.emit_btc_gpr_imm8_64(63, tmp);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp), ret);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F64PromoteF32 => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcvtss2sd),
|
|
|
|
Operator::F32DemoteF64 => Self::emit_fp_unop_avx(a, &mut self.machine, &mut self.value_stack, Assembler::emit_vcvtsd2ss),
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::I32ReinterpretF32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
if loc != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S32, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Operator::F32ReinterpretI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
if loc != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S32, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::I64ReinterpretF64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
if loc != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Operator::F64ReinterpretI64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
if loc != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, ret,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::I32TruncUF32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::I32TruncSF32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttss2si_32(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I64TruncSF32 => {
|
2019-04-09 19:10:20 +08:00
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I64TruncUF32 => {
|
|
|
|
/*
|
|
|
|
; movq xmm5, r15
|
|
|
|
; mov r15d, 1593835520u32 as i32 //float 9.22337203E+18
|
|
|
|
; movd xmm1, r15d
|
|
|
|
; movd xmm2, Rd(reg as u8)
|
|
|
|
; movd xmm3, Rd(reg as u8)
|
|
|
|
; subss xmm2, xmm1
|
|
|
|
; cvttss2si Rq(reg as u8), xmm2
|
|
|
|
; mov r15, QWORD 0x8000000000000000u64 as i64
|
|
|
|
; xor r15, Rq(reg as u8)
|
|
|
|
; cvttss2si Rq(reg as u8), xmm3
|
|
|
|
; ucomiss xmm3, xmm1
|
|
|
|
; cmovae Rq(reg as u8), r15
|
|
|
|
; movq r15, xmm5
|
|
|
|
*/
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2
|
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15
|
|
|
|
let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1
|
|
|
|
let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, Location::Imm32(1593835520u32), Location::GPR(tmp)); //float 9.22337203E+18
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp), Location::XMM(tmp_x1));
|
|
|
|
a.emit_mov(Size::S32, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_mov(Size::S32, Location::XMM(tmp_in), Location::XMM(tmp_x2));
|
|
|
|
a.emit_vsubss(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in);
|
|
|
|
a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0x8000000000000000u64), Location::GPR(tmp));
|
|
|
|
a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp));
|
|
|
|
a.emit_cvttss2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out);
|
|
|
|
a.emit_ucomiss(XMMOrMemory::XMM(tmp_x1), tmp_x2);
|
|
|
|
a.emit_cmovae_gpr_64(tmp, tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_x2);
|
|
|
|
self.machine.release_temp_xmm(tmp_x1);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::I32TruncUF64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::I32TruncSF64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttsd2si_32(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I64TruncSF64 => {
|
2019-04-09 19:10:20 +08:00
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-11 01:53:13 +08:00
|
|
|
Operator::I64TruncUF64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_xmm().unwrap(); // xmm2
|
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap(); // r15
|
|
|
|
let tmp_x1 = self.machine.acquire_temp_xmm().unwrap(); // xmm1
|
|
|
|
let tmp_x2 = self.machine.acquire_temp_xmm().unwrap(); // xmm3
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(4890909195324358656u64), Location::GPR(tmp)); //double 9.2233720368547758E+18
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp), Location::XMM(tmp_x1));
|
|
|
|
a.emit_mov(Size::S64, loc, Location::XMM(tmp_in));
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp_in), Location::XMM(tmp_x2));
|
|
|
|
a.emit_vsubsd(tmp_in, XMMOrMemory::XMM(tmp_x1), tmp_in);
|
|
|
|
a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0x8000000000000000u64), Location::GPR(tmp));
|
|
|
|
a.emit_xor(Size::S64, Location::GPR(tmp_out), Location::GPR(tmp));
|
|
|
|
a.emit_cvttsd2si_64(XMMOrMemory::XMM(tmp_x2), tmp_out);
|
|
|
|
a.emit_ucomisd(XMMOrMemory::XMM(tmp_x1), tmp_x2);
|
|
|
|
a.emit_cmovae_gpr_64(tmp, tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_xmm(tmp_x2);
|
|
|
|
self.machine.release_temp_xmm(tmp_x1);
|
|
|
|
self.machine.release_temp_gpr(tmp);
|
|
|
|
self.machine.release_temp_xmm(tmp_in);
|
|
|
|
self.machine.release_temp_gpr(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F32ConvertSI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2ss_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
Operator::F32ConvertUI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
2019-04-10 01:38:16 +08:00
|
|
|
Operator::F32ConvertSI64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S32, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
Operator::F32ConvertUI64 => {
|
2019-04-09 19:10:20 +08:00
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
2019-04-10 01:38:16 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
let do_convert = a.get_label();
|
|
|
|
let end_convert = a.get_label();
|
2019-04-09 19:10:20 +08:00
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp_in));
|
2019-04-10 01:38:16 +08:00
|
|
|
a.emit_test_gpr_64(tmp_in);
|
|
|
|
a.emit_jmp(Condition::Signed, do_convert);
|
|
|
|
a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_jmp(Condition::None, end_convert);
|
|
|
|
a.emit_label(do_convert);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp));
|
|
|
|
a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp));
|
|
|
|
a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in));
|
|
|
|
a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in));
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_vcvtsi2ss_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
2019-04-10 01:38:16 +08:00
|
|
|
a.emit_vaddss(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out);
|
|
|
|
a.emit_label(end_convert);
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S32, Location::XMM(tmp_out), ret);
|
|
|
|
|
2019-04-10 01:38:16 +08:00
|
|
|
self.machine.release_temp_gpr(tmp);
|
2019-04-09 19:10:20 +08:00
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operator::F64ConvertSI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2sd_32(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
Operator::F64ConvertUI32 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S32, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
2019-04-10 01:38:16 +08:00
|
|
|
Operator::F64ConvertSI64 => {
|
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp_out), ret);
|
|
|
|
|
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
Operator::F64ConvertUI64 => {
|
2019-04-09 19:10:20 +08:00
|
|
|
let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
let tmp_out = self.machine.acquire_temp_xmm().unwrap();
|
|
|
|
let tmp_in = self.machine.acquire_temp_gpr().unwrap();
|
2019-04-10 01:38:16 +08:00
|
|
|
let tmp = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
|
|
|
|
let do_convert = a.get_label();
|
|
|
|
let end_convert = a.get_label();
|
2019-04-09 19:10:20 +08:00
|
|
|
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(tmp_in));
|
2019-04-10 01:38:16 +08:00
|
|
|
a.emit_test_gpr_64(tmp_in);
|
|
|
|
a.emit_jmp(Condition::Signed, do_convert);
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
2019-04-10 01:38:16 +08:00
|
|
|
a.emit_jmp(Condition::None, end_convert);
|
|
|
|
a.emit_label(do_convert);
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(tmp_in), Location::GPR(tmp));
|
|
|
|
a.emit_and(Size::S64, Location::Imm32(1), Location::GPR(tmp));
|
|
|
|
a.emit_shr(Size::S64, Location::Imm8(1), Location::GPR(tmp_in));
|
|
|
|
a.emit_or(Size::S64, Location::GPR(tmp), Location::GPR(tmp_in));
|
|
|
|
a.emit_vcvtsi2sd_64(tmp_out, GPROrMemory::GPR(tmp_in), tmp_out);
|
|
|
|
a.emit_vaddsd(tmp_out, XMMOrMemory::XMM(tmp_out), tmp_out);
|
|
|
|
a.emit_label(end_convert);
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, Location::XMM(tmp_out), ret);
|
|
|
|
|
2019-04-10 01:38:16 +08:00
|
|
|
self.machine.release_temp_gpr(tmp);
|
2019-04-09 19:10:20 +08:00
|
|
|
self.machine.release_temp_gpr(tmp_in);
|
|
|
|
self.machine.release_temp_xmm(tmp_out);
|
|
|
|
}
|
|
|
|
|
2019-04-02 01:16:37 +08:00
|
|
|
Operator::Call { function_index } => {
|
|
|
|
let function_index = function_index as usize;
|
|
|
|
let label = self
|
|
|
|
.function_labels
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
|
|
|
.entry(function_index)
|
|
|
|
.or_insert_with(|| (a.get_label(), None))
|
|
|
|
.0;
|
|
|
|
let sig_index = *self.function_signatures.get(FuncIndex::new(function_index)).unwrap();
|
|
|
|
let sig = self.signatures.get(sig_index).unwrap();
|
|
|
|
let param_types: Vec<WpType> =
|
|
|
|
sig.params().iter().cloned().map(type_to_wp_type).collect();
|
|
|
|
let return_types: Vec<WpType> =
|
|
|
|
sig.returns().iter().cloned().map(type_to_wp_type).collect();
|
|
|
|
|
2019-04-02 11:11:45 +08:00
|
|
|
let params: Vec<_> = self.value_stack.drain(self.value_stack.len() - param_types.len()..).collect();
|
|
|
|
let released: Vec<Location> = params.iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations_only_regs(&released);
|
2019-04-02 01:16:37 +08:00
|
|
|
|
2019-04-04 09:38:22 +08:00
|
|
|
Self::emit_call_sysv_label(a, &mut self.machine, label, params.iter().map(|&(x, _)| x));
|
2019-04-02 01:16:37 +08:00
|
|
|
|
2019-04-02 11:11:45 +08:00
|
|
|
self.machine.release_locations_only_stack(a, &released);
|
2019-04-02 01:16:37 +08:00
|
|
|
|
2019-04-07 17:19:23 +08:00
|
|
|
if return_types.len() > 0 {
|
|
|
|
let ret = self.machine.acquire_locations(a, &[return_types[0]], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Operator::CallIndirect { index, table_index } => {
|
|
|
|
assert_eq!(table_index, 0);
|
|
|
|
let sig = self.signatures.get(SigIndex::new(index as usize)).unwrap();
|
|
|
|
let param_types: Vec<WpType> =
|
|
|
|
sig.params().iter().cloned().map(type_to_wp_type).collect();
|
|
|
|
let return_types: Vec<WpType> =
|
|
|
|
sig.returns().iter().cloned().map(type_to_wp_type).collect();
|
|
|
|
|
|
|
|
let func_index = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
let params: Vec<_> = self.value_stack.drain(self.value_stack.len() - param_types.len()..).collect();
|
|
|
|
let released: Vec<Location> = params.iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations_only_regs(&released);
|
|
|
|
|
|
|
|
let table_base = self.machine.acquire_temp_gpr().unwrap();
|
|
|
|
let table_count = self.machine.acquire_temp_gpr().unwrap();
|
2019-04-09 19:10:20 +08:00
|
|
|
let sigidx = self.machine.acquire_temp_gpr().unwrap();
|
2019-04-07 17:19:23 +08:00
|
|
|
|
|
|
|
a.emit_mov(
|
|
|
|
Size::S64,
|
|
|
|
Location::Memory(
|
|
|
|
Machine::get_vmctx_reg(),
|
|
|
|
match TableIndex::new(0).local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(_) => vm::Ctx::offset_tables(),
|
|
|
|
LocalOrImport::Import(_) => vm::Ctx::offset_imported_tables(),
|
|
|
|
} as i32
|
|
|
|
),
|
|
|
|
Location::GPR(table_base),
|
|
|
|
);
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(table_base, 0), Location::GPR(table_base));
|
|
|
|
a.emit_mov(Size::S32, Location::Memory(table_base, LocalTable::offset_count() as i32), Location::GPR(table_count));
|
|
|
|
a.emit_mov(Size::S64, Location::Memory(table_base, LocalTable::offset_base() as i32), Location::GPR(table_base));
|
|
|
|
a.emit_cmp(Size::S32, func_index, Location::GPR(table_count));
|
|
|
|
a.emit_conditional_trap(Condition::BelowEqual);
|
|
|
|
a.emit_mov(Size::S64, func_index, Location::GPR(table_count));
|
|
|
|
a.emit_imul_imm32_gpr64(vm::Anyfunc::size() as u32, table_count);
|
|
|
|
a.emit_add(Size::S64, Location::GPR(table_base), Location::GPR(table_count));
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, Location::Memory(Machine::get_vmctx_reg(), vm::Ctx::offset_signatures() as i32), Location::GPR(sigidx));
|
|
|
|
a.emit_mov(Size::S32, Location::Memory(sigidx, (index * 4) as i32), Location::GPR(sigidx));
|
|
|
|
a.emit_cmp(Size::S32, Location::GPR(sigidx), Location::Memory(table_count, (vm::Anyfunc::offset_sig_id() as usize) as i32));
|
2019-04-07 17:19:23 +08:00
|
|
|
a.emit_conditional_trap(Condition::NotEqual);
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
self.machine.release_temp_gpr(sigidx);
|
2019-04-07 17:19:23 +08:00
|
|
|
self.machine.release_temp_gpr(table_count);
|
|
|
|
self.machine.release_temp_gpr(table_base);
|
|
|
|
|
2019-04-09 19:10:20 +08:00
|
|
|
if table_count != GPR::RAX {
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(table_count), Location::GPR(GPR::RAX));
|
|
|
|
}
|
|
|
|
|
2019-04-07 17:19:23 +08:00
|
|
|
Self::emit_call_sysv(a, &mut self.machine, |a| {
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_call_location(Location::Memory(GPR::RAX, (vm::Anyfunc::offset_func() as usize) as i32));
|
2019-04-07 17:19:23 +08:00
|
|
|
}, params.iter().map(|&(x, _)| x));
|
|
|
|
|
|
|
|
self.machine.release_locations_only_stack(a, &released);
|
|
|
|
|
|
|
|
if return_types.len() > 0 {
|
|
|
|
let ret = self.machine.acquire_locations(a, &[return_types[0]], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
}
|
2019-04-02 01:16:37 +08:00
|
|
|
}
|
2019-02-27 23:38:45 +08:00
|
|
|
Operator::If { ty } => {
|
2019-04-01 20:33:33 +08:00
|
|
|
let label_end = a.get_label();
|
|
|
|
let label_else = a.get_label();
|
2019-02-27 23:38:45 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
2019-02-27 23:38:45 +08:00
|
|
|
|
|
|
|
self.control_stack
|
|
|
|
.push(ControlFrame {
|
|
|
|
label: label_end,
|
|
|
|
loop_like: false,
|
|
|
|
if_else: IfElseState::If(label_else),
|
|
|
|
returns: match ty {
|
|
|
|
WpType::EmptyBlockType => vec![],
|
|
|
|
_ => vec![ty],
|
|
|
|
},
|
2019-04-01 20:33:33 +08:00
|
|
|
value_stack_depth: self.value_stack.len(),
|
2019-02-27 23:38:45 +08:00
|
|
|
});
|
2019-04-01 20:33:33 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(0), cond,
|
2019-02-27 23:38:45 +08:00
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::Equal, label_else);
|
2019-02-27 23:38:45 +08:00
|
|
|
}
|
|
|
|
Operator::Else => {
|
2019-04-01 20:33:33 +08:00
|
|
|
let mut frame = self.control_stack.last_mut().unwrap();
|
2019-04-02 01:16:37 +08:00
|
|
|
|
|
|
|
if frame.returns.len() > 0 {
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, Location::GPR(GPR::RAX),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-04-01 23:49:46 +08:00
|
|
|
let released: Vec<Location> = self.value_stack.drain(frame.value_stack_depth..)
|
2019-04-01 20:33:33 +08:00
|
|
|
.filter(|&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations(a, &released);
|
|
|
|
|
|
|
|
match frame.if_else {
|
|
|
|
IfElseState::If(label) => {
|
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
|
|
|
a.emit_label(label);
|
|
|
|
frame.if_else = IfElseState::Else;
|
|
|
|
}
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
2019-02-27 23:38:45 +08:00
|
|
|
}
|
2019-02-28 23:12:42 +08:00
|
|
|
Operator::Select => {
|
2019-04-01 20:33:33 +08:00
|
|
|
let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let v_b = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let v_a = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
let end_label = a.get_label();
|
|
|
|
let zero_label = a.get_label();
|
|
|
|
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(0), cond,
|
2019-02-28 23:12:42 +08:00
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::Equal, zero_label);
|
|
|
|
if v_a != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, v_a, ret,
|
|
|
|
);
|
2019-02-28 23:12:42 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::None, end_label);
|
|
|
|
a.emit_label(zero_label);
|
|
|
|
if v_b != ret {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, v_b, ret,
|
|
|
|
);
|
2019-02-28 23:12:42 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_label(end_label);
|
2019-02-28 23:12:42 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::Block { ty } => {
|
|
|
|
self.control_stack
|
|
|
|
.push(ControlFrame {
|
|
|
|
label: a.get_label(),
|
|
|
|
loop_like: false,
|
|
|
|
if_else: IfElseState::None,
|
|
|
|
returns: match ty {
|
|
|
|
WpType::EmptyBlockType => vec![],
|
|
|
|
_ => vec![ty],
|
|
|
|
},
|
|
|
|
value_stack_depth: self.value_stack.len(),
|
|
|
|
});
|
2019-02-20 23:21:33 +08:00
|
|
|
}
|
2019-04-02 00:11:01 +08:00
|
|
|
Operator::Loop { ty } => {
|
|
|
|
let label = a.get_label();
|
|
|
|
self.control_stack
|
|
|
|
.push(ControlFrame {
|
|
|
|
label: label,
|
|
|
|
loop_like: true,
|
|
|
|
if_else: IfElseState::None,
|
|
|
|
returns: match ty {
|
|
|
|
WpType::EmptyBlockType => vec![],
|
|
|
|
_ => vec![ty],
|
|
|
|
},
|
|
|
|
value_stack_depth: self.value_stack.len(),
|
|
|
|
});
|
|
|
|
a.emit_label(label);
|
|
|
|
}
|
2019-04-04 09:38:22 +08:00
|
|
|
Operator::Nop => {}
|
|
|
|
Operator::MemorySize { reserved } => {
|
|
|
|
let memory_index = MemoryIndex::new(reserved as usize);
|
|
|
|
let target: usize = match memory_index.local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(local_mem_index) => {
|
|
|
|
let mem_desc = &module_info.memories[local_mem_index];
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => vmcalls::local_dynamic_memory_size as usize,
|
|
|
|
MemoryType::Static => vmcalls::local_static_memory_size as usize,
|
|
|
|
MemoryType::SharedStatic => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalOrImport::Import(import_mem_index) => {
|
|
|
|
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => vmcalls::imported_dynamic_memory_size as usize,
|
|
|
|
MemoryType::Static => vmcalls::imported_static_memory_size as usize,
|
|
|
|
MemoryType::SharedStatic => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Self::emit_call_sysv(a, &mut self.machine, |a| {
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(target as u64), Location::GPR(GPR::RAX));
|
|
|
|
a.emit_call_location(Location::GPR(GPR::RAX));
|
|
|
|
}, ::std::iter::once(Location::Imm32(memory_index.index() as u32)));
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
}
|
|
|
|
Operator::MemoryGrow { reserved } => {
|
|
|
|
let memory_index = MemoryIndex::new(reserved as usize);
|
|
|
|
let target: usize = match memory_index.local_or_import(module_info) {
|
|
|
|
LocalOrImport::Local(local_mem_index) => {
|
|
|
|
let mem_desc = &module_info.memories[local_mem_index];
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => vmcalls::local_dynamic_memory_grow as usize,
|
|
|
|
MemoryType::Static => vmcalls::local_static_memory_grow as usize,
|
|
|
|
MemoryType::SharedStatic => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalOrImport::Import(import_mem_index) => {
|
|
|
|
let mem_desc = &module_info.imported_memories[import_mem_index].1;
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => vmcalls::imported_dynamic_memory_grow as usize,
|
|
|
|
MemoryType::Static => vmcalls::imported_static_memory_grow as usize,
|
|
|
|
MemoryType::SharedStatic => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let (param_pages, param_pages_lot) = self.value_stack.pop().unwrap();
|
|
|
|
|
|
|
|
if param_pages_lot == LocalOrTemp::Temp {
|
|
|
|
self.machine.release_locations_only_regs(&[param_pages]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Self::emit_call_sysv(a, &mut self.machine, |a| {
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(target as u64), Location::GPR(GPR::RAX));
|
|
|
|
a.emit_call_location(Location::GPR(GPR::RAX));
|
|
|
|
}, ::std::iter::once(Location::Imm32(memory_index.index() as u32)).chain(::std::iter::once(param_pages)));
|
|
|
|
|
|
|
|
if param_pages_lot == LocalOrTemp::Temp {
|
|
|
|
self.machine.release_locations_only_stack(a, &[param_pages]);
|
|
|
|
}
|
|
|
|
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
|
|
|
|
}
|
|
|
|
Operator::I32Load { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, Location::Memory(addr, 0), ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F32Load { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, Location::Memory(addr, 0), ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-04 09:38:22 +08:00
|
|
|
Operator::I32Load8U { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movzx,
|
|
|
|
Size::S8, Location::Memory(addr, 0), Size::S32, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I32Load8S { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movsx,
|
|
|
|
Size::S8, Location::Memory(addr, 0), Size::S32, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I32Load16U { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movzx,
|
|
|
|
Size::S16, Location::Memory(addr, 0), Size::S32, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I32Load16S { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I32], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movsx,
|
|
|
|
Size::S16, Location::Memory(addr, 0), Size::S32, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I32Store { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F32Store { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-04 10:50:48 +08:00
|
|
|
Operator::I32Store8 { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S8, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I32Store16 { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S16, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
Operator::I64Load { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 8, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, Location::Memory(addr, 0), ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F64Load { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::F64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 8, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, Location::Memory(addr, 0), ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
Operator::I64Load8U { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movzx,
|
|
|
|
Size::S8, Location::Memory(addr, 0), Size::S64, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Load8S { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movsx,
|
|
|
|
Size::S8, Location::Memory(addr, 0), Size::S64, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Load16U { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movzx,
|
|
|
|
Size::S16, Location::Memory(addr, 0), Size::S64, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Load16S { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movsx,
|
|
|
|
Size::S16, Location::Memory(addr, 0), Size::S64, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Load32U { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
match ret {
|
|
|
|
Location::GPR(_) => {},
|
|
|
|
_ => {
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(0), ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, Location::Memory(addr, 0), ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Load32S { memarg } => {
|
|
|
|
let target = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let ret = self.machine.acquire_locations(a, &[WpType::I64], false)[0];
|
|
|
|
self.value_stack.push((ret, LocalOrTemp::Temp));
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_zx_sx(
|
|
|
|
a, m, Assembler::emit_movsx,
|
|
|
|
Size::S32, Location::Memory(addr, 0), Size::S64, ret,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Store { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 8, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-09 19:10:20 +08:00
|
|
|
Operator::F64Store { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 8, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S64, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
Operator::I64Store8 { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 1, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S8, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Store16 { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 2, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S16, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Operator::I64Store32 { memarg } => {
|
|
|
|
let target_value = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let target_addr = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
|
|
|
|
Self::emit_memory_op(module_info, a, &mut self.machine, target_addr, memarg.offset as usize, 4, |a, m, addr| {
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, m, Assembler::emit_mov,
|
|
|
|
Size::S32, target_value, Location::Memory(addr, 0),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::Unreachable => {
|
|
|
|
a.emit_ud2();
|
|
|
|
self.unreachable_depth = 1;
|
2019-02-21 22:04:43 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::Return => {
|
|
|
|
let frame = &self.control_stack[0];
|
|
|
|
let has_return = if frame.returns.len() > 0 {
|
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
2019-04-02 01:16:37 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, Location::GPR(GPR::RAX),
|
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2019-02-24 12:00:35 +08:00
|
|
|
};
|
2019-04-08 17:47:41 +08:00
|
|
|
let released: Vec<Location> = self.value_stack[frame.value_stack_depth..].iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
2019-04-01 20:33:33 +08:00
|
|
|
.collect();
|
2019-04-08 17:47:41 +08:00
|
|
|
self.machine.release_locations_keep_state(a, &released);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
2019-02-24 12:00:35 +08:00
|
|
|
self.unreachable_depth = 1;
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::Br { relative_depth } => {
|
|
|
|
let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)];
|
2019-04-09 19:10:20 +08:00
|
|
|
if !frame.loop_like && frame.returns.len() > 0 {
|
2019-04-01 20:33:33 +08:00
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX));
|
|
|
|
}
|
2019-04-02 00:17:52 +08:00
|
|
|
let released: Vec<Location> = self.value_stack[frame.value_stack_depth..].iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
2019-04-01 20:33:33 +08:00
|
|
|
.collect();
|
2019-04-02 00:17:52 +08:00
|
|
|
self.machine.release_locations_keep_state(a, &released);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
|
|
|
self.unreachable_depth = 1;
|
2019-03-17 10:27:14 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::BrIf { relative_depth }=> {
|
|
|
|
let after = a.get_label();
|
|
|
|
let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
2019-04-08 17:47:41 +08:00
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(0), cond,
|
|
|
|
);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_jmp(Condition::Equal, after);
|
|
|
|
|
|
|
|
let frame = &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)];
|
2019-04-09 19:10:20 +08:00
|
|
|
if !frame.loop_like && frame.returns.len() > 0 {
|
2019-04-01 20:33:33 +08:00
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
2019-04-09 19:10:20 +08:00
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX));
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
let released: Vec<Location> = self.value_stack[frame.value_stack_depth..].iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations_keep_state(a, &released);
|
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
2019-03-17 19:54:20 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_label(after);
|
2019-03-17 10:27:14 +08:00
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
Operator::BrTable { table } => {
|
|
|
|
let (targets, default_target) = table.read_table().unwrap();
|
|
|
|
let cond = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
|
|
|
let mut table = vec![0usize; targets.len()];
|
|
|
|
let default_br = a.get_label();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_cmp,
|
|
|
|
Size::S32, Location::Imm32(targets.len() as u32), cond,
|
|
|
|
);
|
|
|
|
a.emit_jmp(Condition::AboveEqual, default_br);
|
|
|
|
|
|
|
|
a.emit_mov(Size::S64, Location::Imm64(table.as_ptr() as usize as u64), Location::GPR(GPR::RCX));
|
|
|
|
a.emit_mov(Size::S32, cond, Location::GPR(GPR::RDX));
|
|
|
|
a.emit_shl(Size::S32, Location::Imm8(3), Location::GPR(GPR::RDX));
|
|
|
|
a.emit_add(Size::S64, Location::GPR(GPR::RCX), Location::GPR(GPR::RDX));
|
|
|
|
a.emit_jmp_location(Location::Memory(GPR::RDX, 0));
|
|
|
|
|
|
|
|
for (i, target) in targets.iter().enumerate() {
|
|
|
|
let AssemblyOffset(offset) = a.offset();
|
|
|
|
table[i] = offset;
|
|
|
|
let frame = &self.control_stack[self.control_stack.len() - 1 - (*target as usize)];
|
2019-04-09 19:10:20 +08:00
|
|
|
if !frame.loop_like && frame.returns.len() > 0 {
|
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX));
|
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
let released: Vec<Location> = self.value_stack[frame.value_stack_depth..].iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations_keep_state(a, &released);
|
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
|
|
|
}
|
|
|
|
a.emit_label(default_br);
|
|
|
|
|
|
|
|
{
|
|
|
|
let frame = &self.control_stack[self.control_stack.len() - 1 - (default_target as usize)];
|
2019-04-09 19:10:20 +08:00
|
|
|
if !frame.loop_like && frame.returns.len() > 0 {
|
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
|
|
|
a.emit_mov(Size::S64, loc, Location::GPR(GPR::RAX));
|
|
|
|
}
|
2019-04-08 17:47:41 +08:00
|
|
|
let released: Vec<Location> = self.value_stack[frame.value_stack_depth..].iter()
|
|
|
|
.filter(|&&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|&(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations_keep_state(a, &released);
|
|
|
|
a.emit_jmp(Condition::None, frame.label);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.br_table_data.as_mut().unwrap().push(table);
|
|
|
|
self.unreachable_depth = 1;
|
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::Drop => {
|
|
|
|
get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap());
|
2019-03-15 01:10:31 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
Operator::End => {
|
|
|
|
let frame = self.control_stack.pop().unwrap();
|
2019-04-02 00:11:01 +08:00
|
|
|
|
|
|
|
if !was_unreachable && frame.returns.len() > 0 {
|
|
|
|
let (loc, _) = *self.value_stack.last().unwrap();
|
|
|
|
Self::emit_relaxed_binop(
|
|
|
|
a, &mut self.machine, Assembler::emit_mov,
|
|
|
|
Size::S64, loc, Location::GPR(GPR::RAX),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
if self.control_stack.len() == 0 {
|
|
|
|
a.emit_label(frame.label);
|
2019-04-02 20:50:56 +08:00
|
|
|
self.machine.finalize_locals(a, &self.locals);
|
2019-04-01 20:33:33 +08:00
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RBP), Location::GPR(GPR::RSP));
|
|
|
|
a.emit_pop(Size::S64, Location::GPR(GPR::RBP));
|
|
|
|
a.emit_ret();
|
|
|
|
} else {
|
2019-04-01 23:49:46 +08:00
|
|
|
let released: Vec<Location> = self.value_stack.drain(frame.value_stack_depth..)
|
2019-04-01 20:33:33 +08:00
|
|
|
.filter(|&(_, lot)| lot == LocalOrTemp::Temp)
|
|
|
|
.map(|(x, _)| x)
|
|
|
|
.collect();
|
|
|
|
self.machine.release_locations(a, &released);
|
|
|
|
|
|
|
|
if !frame.loop_like {
|
|
|
|
a.emit_label(frame.label);
|
2019-03-14 10:30:24 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
|
|
|
|
if let IfElseState::If(label) = frame.if_else {
|
|
|
|
a.emit_label(label);
|
2019-03-14 10:30:24 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
|
|
|
|
if frame.returns.len() > 0 {
|
|
|
|
assert_eq!(frame.returns.len(), 1);
|
|
|
|
let loc = self.machine.acquire_locations(a, &frame.returns, false)[0];
|
|
|
|
a.emit_mov(Size::S64, Location::GPR(GPR::RAX), loc);
|
|
|
|
self.value_stack.push((loc, LocalOrTemp::Temp));
|
2019-03-14 10:30:24 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
}
|
2019-03-14 10:30:24 +08:00
|
|
|
}
|
2019-03-13 18:23:50 +08:00
|
|
|
_ => {
|
2019-04-01 20:33:33 +08:00
|
|
|
panic!("not yet implemented: {:?}", op);
|
2019-03-18 00:31:36 +08:00
|
|
|
}
|
2019-02-12 23:15:57 +08:00
|
|
|
}
|
2019-02-20 22:56:32 +08:00
|
|
|
|
2019-02-12 00:52:17 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-24 00:52:32 +08:00
|
|
|
fn type_to_wp_type(ty: Type) -> WpType {
|
|
|
|
match ty {
|
|
|
|
Type::I32 => WpType::I32,
|
|
|
|
Type::I64 => WpType::I64,
|
|
|
|
Type::F32 => WpType::F32,
|
|
|
|
Type::F64 => WpType::F64,
|
|
|
|
}
|
|
|
|
}
|
2019-02-26 20:56:10 +08:00
|
|
|
|
2019-04-01 20:33:33 +08:00
|
|
|
fn get_location_released(a: &mut Assembler, m: &mut Machine, (loc, lot): (Location, LocalOrTemp)) -> Location {
|
|
|
|
if lot == LocalOrTemp::Temp {
|
|
|
|
m.release_locations(a, &[loc]);
|
2019-03-09 02:57:23 +08:00
|
|
|
}
|
2019-04-01 20:33:33 +08:00
|
|
|
loc
|
2019-03-14 10:30:24 +08:00
|
|
|
}
|
2019-04-02 11:11:45 +08:00
|
|
|
|
|
|
|
fn sort_call_movs(movs: &mut [(Location, GPR)]) {
|
|
|
|
for i in 0..movs.len() {
|
|
|
|
for j in (i + 1)..movs.len() {
|
|
|
|
if let Location::GPR(src_gpr) = movs[j].0 {
|
|
|
|
if src_gpr == movs[i].1 {
|
|
|
|
movs.swap(i, j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|