diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index af1dbe43782..87eb6e6e4eb 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -11,8 +11,8 @@ readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.6.0" } wasmparser = "0.35.1" -dynasm = "0.3.2" -dynasmrt = "0.3.1" +dynasm = "0.5.0" +dynasmrt = "0.5.0" lazy_static = "1.3.0" byteorder = "1.3.2" nix = "0.15.0" diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index ccea7502ee9..59469916b25 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny( +/*#![deny( dead_code, nonstandard_style, unused_imports, @@ -6,7 +6,7 @@ unused_variables, unused_unsafe, unreachable_patterns -)] +)]*/ #![feature(proc_macro_hygiene)] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] @@ -14,6 +14,7 @@ #[cfg(not(any( all(target_os = "macos", target_arch = "x86_64"), all(target_os = "linux", target_arch = "x86_64"), + all(target_os = "linux", target_arch = "aarch64"), )))] compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64"); @@ -30,6 +31,7 @@ extern crate byteorder; extern crate smallvec; mod codegen_x64; +mod translator_aarch64; mod emitter_x64; mod machine; pub mod protect_unix; diff --git a/lib/singlepass-backend/src/translator_aarch64.rs b/lib/singlepass-backend/src/translator_aarch64.rs new file mode 100644 index 00000000000..8d23a7fd83a --- /dev/null +++ b/lib/singlepass-backend/src/translator_aarch64.rs @@ -0,0 +1,601 @@ +use crate::codegen_x64::*; +use crate::emitter_x64::*; +use dynasmrt::{aarch64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct AX(pub u32); + +impl AX { + pub fn x(&self) -> u32 { self.0 } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct AV(pub u32); + +impl AV { + pub fn v(&self) -> u32 { self.0 } +} + +/* +#[repr(u8)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum GPR { + RAX, + RCX, + RDX, + RBX, + RSP, + RBP, + RSI, + RDI, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum XMM { + XMM0, + XMM1, + XMM2, + XMM3, + XMM4, + XMM5, + XMM6, + XMM7, +} +*/ + +fn map_gpr(gpr: GPR) -> AX { + use GPR::*; + + match gpr { + RAX => AX(0), + RCX => AX(1), + RDX => AX(2), + RBX => AX(3), + RSP => AX(4), + RBP => AX(5), + RSI => AX(6), + RDI => AX(7), + R8 => AX(8), + R9 => AX(9), + R10 => AX(10), + R11 => AX(11), + R12 => AX(12), + R13 => AX(13), + R14 => AX(14), + R15 => AX(15), + } +} + +fn map_xmm(xmm: XMM) -> AV { + use XMM::*; + + match xmm { + XMM0 => AV(0), + XMM1 => AV(1), + XMM2 => AV(2), + XMM3 => AV(3), + XMM4 => AV(4), + XMM5 => AV(5), + XMM6 => AV(6), + XMM7 => AV(7), + } +} + +pub fn get_aarch64_assembler() -> Assembler { + let mut a = Assembler::new().unwrap(); + dynasm!( + a + ; .arch aarch64 + ; .alias x_rsp, x28 + ; .alias x_tmp1, x27 + ; .alias w_tmp1, w27 + ; .alias x_tmp2, x26 + ; .alias w_tmp2, w26 + ); + a +} + +macro_rules! binop_imm32_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Imm32(src), Location::GPR(dst)) => { + dynasm!($assembler + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, { + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_imm32_mem { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Imm32(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!($assembler + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, { + assert!(disp >= 0); + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_imm64_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S64, Location::Imm64(src), Location::GPR(dst)) => { + dynasm!($assembler + ; b >after + ; data: + ; .qword src as i64 + ; after: + ; ldr x_tmp1, $otherwise + } + }; +} + +macro_rules! binop_gpr_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::GPR(src), Location::GPR(dst)) => { + dynasm!($assembler + ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), W(map_gpr(src).x()) + ); + }, + (Size::S64, Location::GPR(src), Location::GPR(dst)) => { + dynasm!($assembler + ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), X(map_gpr(src).x()) + ); + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_gpr_mem { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; $ins w_tmp1, w_tmp1, W(map_gpr(src).x()) + ; str w_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + }, + (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ; $ins x_tmp1, x_tmp1, X(map_gpr(src).x()) + ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_mem_gpr { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + match ($sz, $src, $dst) { + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!($assembler + ; ldr w_tmp1, [X(map_gpr(src).x()), disp as u32] + ; $ins W(map_gpr(dst).x()), W(map_gpr(dst).x()), w_tmp1 + ) + }, + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!($assembler + ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; $ins X(map_gpr(dst).x()), X(map_gpr(dst).x()), x_tmp1 + ) + }, + _ => $otherwise + } + }; +} + +macro_rules! binop_all_nofp { + ($ins:ident, $assembler:tt, $sz:expr, $src:expr, $dst:expr, $otherwise:block) => { + binop_imm32_gpr!($ins, $assembler, $sz, $src, $dst, { + binop_imm32_mem!($ins, $assembler, $sz, $src, $dst, { + binop_gpr_gpr!($ins, $assembler, $sz, $src, $dst, { + binop_gpr_mem!($ins, $assembler, $sz, $src, $dst, { + binop_mem_gpr!($ins, $assembler, $sz, $src, $dst, $otherwise) + }) + }) + }) + }) + }; +} + +impl Emitter for Assembler { + type Label = DynamicLabel; + type Offset = AssemblyOffset; + + fn get_label(&mut self) -> DynamicLabel { + self.new_dynamic_label() + } + + fn get_offset(&self) -> AssemblyOffset { + self.offset() + } + + fn emit_u64(&mut self, x: u64) { + self.push_u64(x); + } + + fn emit_label(&mut self, label: Self::Label) { + dynasm!(self ; => label); + } + + fn emit_nop(&mut self) { + dynasm!(self ; nop); + } + + fn emit_mov(&mut self, sz: Size, src: Location, dst: Location) { + match (sz, src, dst) { + (Size::S32, Location::GPR(src), Location::GPR(dst)) => { + dynasm!(self ; mov W(map_gpr(dst).x()), W(map_gpr(src).x())); + } + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldr W(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + } + (Size::S32, Location::GPR(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; str W(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + } + (Size::S32, Location::Imm32(x), Location::GPR(dst)) => { + dynasm!(self ; b >after; data: ; .dword x as i32; after: ; ldr W(map_gpr(dst).x()), { + dynasm!(self ; mov X(map_gpr(dst).x()), X(map_gpr(src).x())); + } + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + assert!(disp >= 0); + dynasm!(self ; ldr X(map_gpr(dst).x()), [ X(map_gpr(src).x()), disp as u32 ] ); + } + (Size::S64, Location::GPR(src), Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self ; str X(map_gpr(src).x()), [ X(map_gpr(dst).x()), disp as u32 ] ); + } + (Size::S64, Location::Imm32(x), Location::GPR(dst)) => { + dynasm!(self ; b >after; data: ; .qword x as i64; after: ; ldr X(map_gpr(dst).x()), unimplemented!() + } + } + + fn emit_lea(&mut self, sz: Size, src: Location, dst: Location) { + match (sz, src, dst) { + (Size::S32, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!(self ; add W(map_gpr(dst).x()), W(map_gpr(src).x()), disp as u32); + } + (Size::S64, Location::Memory(src, disp), Location::GPR(dst)) => { + dynasm!(self ; add X(map_gpr(dst).x()), X(map_gpr(src).x()), disp as u32); + } + _ => unreachable!(), + } + } + fn emit_lea_label(&mut self, label: Self::Label, dst: Location) { + match dst { + Location::GPR(dst) => { + dynasm!(self ; adr X(map_gpr(dst).x()), =>label); + } + _ => unreachable!() + } + } + + fn emit_cdq(&mut self) { unimplemented!("cdq"); } + fn emit_cqo(&mut self) { unimplemented!("cqo"); } + fn emit_xor(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(eor, self, sz, src, dst, { unreachable!("xor") }); + } + fn emit_jmp(&mut self, condition: Condition, label: Self::Label) { + use Condition::*; + + match condition { + None => dynasm!(self ; b =>label), + Above => dynasm!(self ; b.hi =>label), + AboveEqual => dynasm!(self ; b.hs =>label), + Below => dynasm!(self ; b.lo =>label), + BelowEqual => dynasm!(self ; b.ls =>label), + Greater => dynasm!(self ; b.gt =>label), + GreaterEqual => dynasm!(self ; b.ge =>label), + Less => dynasm!(self ; b.lt =>label), + LessEqual => dynasm!(self ; b.le =>label), + Equal => dynasm!(self ; b.eq =>label), + NotEqual => dynasm!(self ; b.ne =>label), + Signed => dynasm!(self ; b.vs =>label), // TODO: Review this + } + } + + fn emit_jmp_location(&mut self, loc: Location) { + match loc { + Location::GPR(x) => dynasm!(self ; br X(map_gpr(x).x())), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self ; ldr x_tmp1, [ X(map_gpr(base).x()), disp as u32 ]; br x_tmp1); + }, + _ => unreachable!(), + } + } + + fn emit_conditional_trap(&mut self, condition: Condition) { + use Condition::*; + + match condition { + None => dynasm!(self ; b >fail), + Above => dynasm!(self ; b.hi >fail), + AboveEqual => dynasm!(self ; b.hs >fail), + Below => dynasm!(self ; b.lo >fail), + BelowEqual => dynasm!(self ; b.ls >fail), + Greater => dynasm!(self ; b.gt >fail), + GreaterEqual => dynasm!(self ; b.ge >fail), + Less => dynasm!(self ; b.lt >fail), + LessEqual => dynasm!(self ; b.le >fail), + Equal => dynasm!(self ; b.eq >fail), + NotEqual => dynasm!(self ; b.ne >fail), + Signed => dynasm!(self ; b.vs >fail), // TODO: Review this + } + dynasm!( + self + ; b >ok + ; fail: + ; brk 0 + ; ok: + ); + } + + fn emit_set(&mut self, condition: Condition, dst: GPR) { unimplemented!("instruction") } + + fn emit_push(&mut self, sz: Size, src: Location) { + match (sz, src) { + (Size::S64, Location::Imm32(src)) => dynasm!(self + ; b >after + ; data: + ; .dword src as i32 + ; after: + ; ldr w_tmp1, dynasm!(self + ; sub x_rsp, x_rsp, 8 + ; str X(map_gpr(src).x()), [x_rsp] + ), + (Size::S64, Location::Memory(src, disp)) => { + assert!(disp >= 0); + dynasm!(self + ; ldr x_tmp1, [X(map_gpr(src).x()), disp as u32] + ; sub x_rsp, x_rsp, 8 + ; str x_tmp1, [x_rsp] + ); + } + _ => panic!("push {:?} {:?}", sz, src), + } + } + fn emit_pop(&mut self, sz: Size, dst: Location) { + match (sz, dst) { + (Size::S64, Location::GPR(dst)) => dynasm!(self + ; ldr X(map_gpr(dst).x()), [x_rsp] + ; add x_rsp, x_rsp, 8 + ), + (Size::S64, Location::Memory(dst, disp)) => { + assert!(disp >= 0); + dynasm!(self + ; ldr x_tmp1, [x_rsp] + ; add x_rsp, x_rsp, 8 + ; str x_tmp1, [X(map_gpr(dst).x()), disp as u32] + ); + } + _ => panic!("pop {:?} {:?}", sz, dst), + } + } + fn emit_cmp(&mut self, sz: Size, left: Location, right: Location) { unimplemented!("instruction") } + fn emit_add(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(add, self, sz, src, dst, { unreachable!("add") }); + } + fn emit_sub(&mut self, sz: Size, src: Location, dst: Location) { + binop_all_nofp!(sub, self, sz, src, dst, { unreachable!("sub") }); + } + + fn emit_imul(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_imul_imm32_gpr64(&mut self, src: u32, dst: GPR) { unimplemented!("instruction") } + + fn emit_div(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } + fn emit_idiv(&mut self, sz: Size, divisor: Location) { unimplemented!("instruction") } + fn emit_shl(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_shr(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_sar(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_rol(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_ror(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_and(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_or(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { unimplemented!("instruction") } + fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } + fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location) { unimplemented!("instruction") } + + fn emit_btc_gpr_imm8_32(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } + fn emit_btc_gpr_imm8_64(&mut self, src: u8, dst: GPR) { unimplemented!("instruction") } + + fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } + fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR) { unimplemented!("instruction") } + + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsubsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmulss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmulsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vdivss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vdivsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmaxss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vmaxsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vminss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vminsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpeqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpeqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpneqss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpneqsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpltss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpltsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpless(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmplesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpgtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpgtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vroundss_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundss_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_nearest(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_floor(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_ceil(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vroundsd_trunc(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_vcvtss2sd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsd2ss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_ucomisd(&mut self, src: XMMOrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_cvttss2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttss2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttsd2si_32(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + fn emit_cvttsd2si_64(&mut self, src: XMMOrMemory, dst: GPR) { unimplemented!("instruction") } + + fn emit_vcvtsi2ss_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2ss_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM) { unimplemented!("instruction") } + + fn emit_test_gpr_64(&mut self, reg: GPR) { unimplemented!("instruction") } + + fn emit_ud2(&mut self) { dynasm!(self ; brk 2) } + fn emit_ret(&mut self) { + dynasm!(self + ; ldr x_tmp1, [x_rsp] + ; add x_rsp, x_rsp, 8 + ; br x_tmp1 + ); + } + fn emit_call_label(&mut self, label: Self::Label) { + dynasm!(self + ; b >after + ; addr: + ; .qword =>label // Is this the offset? + ; after: + + // Calculate the target address. + ; ldr x_tmp1, done + ; str x_tmp2, [x_rsp] + + // Jump. + ; br x_tmp1 + ; done: + ); + } + fn emit_call_location(&mut self, loc: Location) { + match loc { + Location::GPR(x) => dynasm!(self + // Push return address. + ; sub x_rsp, x_rsp, 8 + ; adr x_tmp1, >done + ; str x_tmp1, [x_rsp] + + // Jump. + ; br X(map_gpr(x).x()) + ; done: + ), + Location::Memory(base, disp) => { + assert!(disp >= 0); + dynasm!(self + // Push return address. + ; sub x_rsp, x_rsp, 8 + ; adr x_tmp1, >done + ; str x_tmp1, [x_rsp] + + // Read memory. + ; ldr x_tmp1, [X(map_gpr(base).x()), disp as u32] + + // Jump. + ; br x_tmp1 + ; done: + ); + }, + _ => unreachable!(), + } + } + + fn emit_bkpt(&mut self) { dynasm!(self ; brk 1) } +}