Skip to content

Commit

Permalink
Merge #2750
Browse files Browse the repository at this point in the history
2750: Singlepass aarch64 r=syrusakbary a=ptitSeb

# Description

Add Aarch64 support on Singlapass, for both Linux and MacOS.


Co-authored-by: ptitSeb <sebastien.chev@gmail.com>
  • Loading branch information
bors[bot] and ptitSeb committed Jan 27, 2022
2 parents 67be3ea + bff3c09 commit cfcc891
Show file tree
Hide file tree
Showing 14 changed files with 8,580 additions and 223 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@
Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/CHANGELOG.md).

## **[Unreleased]**
- [#2750](https://github.com/wasmerio/wasmer/pull/2750) Added Aarch64 support to Singlepass (both Linux and macOS).

## 2.1.1 - 2021/12/20

Expand Down
8 changes: 8 additions & 0 deletions Makefile
Expand Up @@ -179,6 +179,11 @@ ifneq ($(ENABLE_SINGLEPASS), 0)
ifeq ($(IS_AMD64), 1)
compilers += singlepass
endif
ifeq ($(IS_AARCH64), 1)
ifneq ($(IS_WINDOWS), 1)
compilers += singlepass
endif
endif
endif
endif

Expand Down Expand Up @@ -249,6 +254,9 @@ ifeq ($(ENABLE_SINGLEPASS), 1)
ifeq ($(IS_AMD64), 1)
compilers_engines += singlepass-universal
endif
ifeq ($(IS_AARCH64), 1)
compilers_engines += singlepass-universal
endif
endif
endif

Expand Down
4 changes: 2 additions & 2 deletions lib/compiler-singlepass/Cargo.toml
Expand Up @@ -18,8 +18,8 @@ wasmer-types = { path = "../types", version = "=2.1.1", default-features = false
rayon = { version = "1.5", optional = true }
hashbrown = { version = "0.11", optional = true }
more-asserts = "0.2"
dynasm = "1.2"
dynasmrt = "1.2"
dynasm = "1.2.1"
dynasmrt = "1.2.1"
lazy_static = "1.4"
byteorder = "1.3"
smallvec = "1.6"
Expand Down
302 changes: 302 additions & 0 deletions lib/compiler-singlepass/src/arm64_decl.rs
@@ -0,0 +1,302 @@
//! ARM64 structures.

use crate::common_decl::{MachineState, MachineValue, RegisterIndex};
use crate::location::CombinedRegister;
use crate::location::Reg as AbstractReg;
use std::collections::BTreeMap;
use wasmer_compiler::CallingConvention;
use wasmer_types::Type;

/// General-purpose registers.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum GPR {
X0 = 0,
X1 = 1,
X2 = 2,
X3 = 3,
X4 = 4,
X5 = 5,
X6 = 6,
X7 = 7,
X8 = 8,
X9 = 9,
X10 = 10,
X11 = 11,
X12 = 12,
X13 = 13,
X14 = 14,
X15 = 15,
X16 = 16,
X17 = 17,
X18 = 18,
X19 = 19,
X20 = 20,
X21 = 21,
X22 = 22,
X23 = 23,
X24 = 24,
X25 = 25,
X26 = 26,
X27 = 27,
X28 = 28,
X29 = 29,
X30 = 30,
XzrSp = 31,
}

/// NEON registers.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[allow(dead_code)]
pub enum NEON {
V0 = 0,
V1 = 1,
V2 = 2,
V3 = 3,
V4 = 4,
V5 = 5,
V6 = 6,
V7 = 7,
V8 = 8,
V9 = 9,
V10 = 10,
V11 = 11,
V12 = 12,
V13 = 13,
V14 = 14,
V15 = 15,
V16 = 16,
V17 = 17,
V18 = 18,
V19 = 19,
V20 = 20,
V21 = 21,
V22 = 22,
V23 = 23,
V24 = 24,
V25 = 25,
V26 = 26,
V27 = 27,
V28 = 28,
V29 = 29,
V30 = 30,
V31 = 31,
}

impl AbstractReg for GPR {
fn is_callee_save(self) -> bool {
self as usize > 18
}
fn is_reserved(self) -> bool {
match self.into_index() {
0..=16 | 19..=27 => false,
_ => true,
}
}
fn into_index(self) -> usize {
self as usize
}
fn from_index(n: usize) -> Result<GPR, ()> {
const REGS: [GPR; 32] = [
GPR::X0,
GPR::X1,
GPR::X2,
GPR::X3,
GPR::X4,
GPR::X5,
GPR::X6,
GPR::X7,
GPR::X8,
GPR::X9,
GPR::X10,
GPR::X11,
GPR::X12,
GPR::X13,
GPR::X14,
GPR::X15,
GPR::X16,
GPR::X17,
GPR::X18,
GPR::X19,
GPR::X20,
GPR::X21,
GPR::X22,
GPR::X23,
GPR::X24,
GPR::X25,
GPR::X26,
GPR::X27,
GPR::X28,
GPR::X29,
GPR::X30,
GPR::XzrSp,
];
REGS.get(n).cloned().ok_or(())
}
}

impl AbstractReg for NEON {
fn is_callee_save(self) -> bool {
self as usize > 16
}
fn is_reserved(self) -> bool {
false
}
fn into_index(self) -> usize {
self as usize
}
fn from_index(n: usize) -> Result<NEON, ()> {
const REGS: [NEON; 32] = [
NEON::V0,
NEON::V1,
NEON::V2,
NEON::V3,
NEON::V4,
NEON::V5,
NEON::V6,
NEON::V7,
NEON::V8,
NEON::V9,
NEON::V10,
NEON::V11,
NEON::V12,
NEON::V13,
NEON::V14,
NEON::V15,
NEON::V16,
NEON::V17,
NEON::V18,
NEON::V19,
NEON::V20,
NEON::V21,
NEON::V22,
NEON::V23,
NEON::V24,
NEON::V25,
NEON::V26,
NEON::V27,
NEON::V28,
NEON::V29,
NEON::V30,
NEON::V31,
];
match n {
0..=31 => Ok(REGS[n]),
_ => Err(()),
}
}
}

/// A machine register under the x86-64 architecture.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ARM64Register {
/// General-purpose registers.
GPR(GPR),
/// NEON (floating point/SIMD) registers.
NEON(NEON),
}

impl CombinedRegister for ARM64Register {
/// Returns the index of the register.
fn to_index(&self) -> RegisterIndex {
match *self {
ARM64Register::GPR(x) => RegisterIndex(x as usize),
ARM64Register::NEON(x) => RegisterIndex(x as usize + 64),
}
}
/// Convert from a GPR register
fn from_gpr(x: u16) -> Self {
ARM64Register::GPR(GPR::from_index(x as usize).unwrap())
}
/// Convert from an SIMD register
fn from_simd(x: u16) -> Self {
ARM64Register::NEON(NEON::from_index(x as usize).unwrap())
}

/// Converts a DWARF regnum to ARM64Register.
fn _from_dwarf_regnum(x: u16) -> Option<ARM64Register> {
Some(match x {
0..=31 => ARM64Register::GPR(GPR::from_index(x as usize).unwrap()),
64..=95 => ARM64Register::NEON(NEON::from_index(x as usize - 64).unwrap()),
_ => return None,
})
}
}

/// An allocator that allocates registers for function arguments according to the System V ABI.
#[derive(Default)]
pub struct ArgumentRegisterAllocator {
n_gprs: usize,
n_neons: usize,
}

impl ArgumentRegisterAllocator {
/// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type.
pub fn next(
&mut self,
ty: Type,
calling_convention: CallingConvention,
) -> Option<ARM64Register> {
match calling_convention {
CallingConvention::SystemV | CallingConvention::AppleAarch64 => {
static GPR_SEQ: &'static [GPR] = &[
GPR::X0,
GPR::X1,
GPR::X2,
GPR::X3,
GPR::X4,
GPR::X5,
GPR::X6,
GPR::X7,
];
static NEON_SEQ: &'static [NEON] = &[
NEON::V0,
NEON::V1,
NEON::V2,
NEON::V3,
NEON::V4,
NEON::V5,
NEON::V6,
NEON::V7,
];
match ty {
Type::I32 | Type::I64 => {
if self.n_gprs < GPR_SEQ.len() {
let gpr = GPR_SEQ[self.n_gprs];
self.n_gprs += 1;
Some(ARM64Register::GPR(gpr))
} else {
None
}
}
Type::F32 | Type::F64 => {
if self.n_neons < NEON_SEQ.len() {
let neon = NEON_SEQ[self.n_neons];
self.n_neons += 1;
Some(ARM64Register::NEON(neon))
} else {
None
}
}
_ => todo!(
"ArgumentRegisterAllocator::next: Unsupported type: {:?}",
ty
),
}
}
_ => unimplemented!(),
}
}
}

/// Create a new `MachineState` with default values.
pub fn new_machine_state() -> MachineState {
MachineState {
stack_values: vec![],
register_values: vec![MachineValue::Undefined; 32 + 32],
prev_frame: BTreeMap::new(),
wasm_stack: vec![],
wasm_inst_offset: std::usize::MAX,
}
}

0 comments on commit cfcc891

Please sign in to comment.