Skip to content

Commit

Permalink
Try #2574:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Sep 16, 2021
2 parents 6ee5540 + 2e5dae0 commit a67b0c4
Show file tree
Hide file tree
Showing 8 changed files with 374 additions and 205 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ ifneq ($(ENABLE_SINGLEPASS), 0)
ifeq ($(ENABLE_SINGLEPASS), 1)
compilers += singlepass
# … otherwise, we try to check whether Singlepass works on this host.
else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX)))
else ifneq (, $(filter 1, $(IS_DARWIN) $(IS_LINUX) $(IS_WINDOWS)))
ifeq ($(IS_AMD64), 1)
compilers += singlepass
endif
Expand Down
395 changes: 248 additions & 147 deletions lib/compiler-singlepass/src/codegen_x64.rs

Large diffs are not rendered by default.

36 changes: 25 additions & 11 deletions lib/compiler-singlepass/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ use loupe::MemoryUsage;
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::sync::Arc;
use wasmer_compiler::{
Architecture, Compilation, CompileError, CompileModuleInfo, CompiledFunction, Compiler,
CompilerConfig, FunctionBinaryReader, FunctionBody, FunctionBodyData, MiddlewareBinaryReader,
ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, OperatingSystem, SectionIndex,
Target, TrapInformation,
Architecture, CallingConvention, Compilation, CompileError, CompileModuleInfo,
CompiledFunction, Compiler, CompilerConfig, FunctionBinaryReader, FunctionBody,
FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware, ModuleMiddlewareChain,
ModuleTranslationState, OperatingSystem, SectionIndex, Target, TrapInformation,
};
use wasmer_types::entity::{EntityRef, PrimaryMap};
use wasmer_types::{
Expand Down Expand Up @@ -57,17 +57,24 @@ impl Compiler for SinglepassCompiler {
_module_translation: &ModuleTranslationState,
function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
) -> Result<Compilation, CompileError> {
if target.triple().operating_system == OperatingSystem::Windows {
/*if target.triple().operating_system == OperatingSystem::Windows {
return Err(CompileError::UnsupportedTarget(
OperatingSystem::Windows.to_string(),
));
}
}*/
if let Architecture::X86_32(arch) = target.triple().architecture {
return Err(CompileError::UnsupportedTarget(arch.to_string()));
}
if compile_info.features.multi_value {
return Err(CompileError::UnsupportedFeature("multivalue".to_string()));
}
let calling_convention = match target.triple().default_calling_convention() {
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
_ => panic!("Unsupported Calling convention for Singlepass compiler"),
};

let memory_styles = &compile_info.memory_styles;
let table_styles = &compile_info.table_styles;
let vmoffsets = VMOffsets::new(8, &compile_info.module);
Expand All @@ -77,7 +84,12 @@ impl Compiler for SinglepassCompiler {
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
.map(|i| {
gen_import_call_trampoline(&vmoffsets, i, &module.signatures[module.functions[i]])
gen_import_call_trampoline(
&vmoffsets,
i,
&module.signatures[module.functions[i]],
calling_convention,
)
})
.collect::<Vec<_>>()
.into_iter()
Expand Down Expand Up @@ -133,7 +145,7 @@ impl Compiler for SinglepassCompiler {
.values()
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
.map(gen_std_trampoline)
.map(|func_type| gen_std_trampoline(&func_type, calling_convention))
.collect::<Vec<_>>()
.into_iter()
.collect::<PrimaryMap<_, _>>();
Expand All @@ -142,7 +154,9 @@ impl Compiler for SinglepassCompiler {
.imported_function_types()
.collect::<Vec<_>>()
.into_par_iter_if_rayon()
.map(|func_type| gen_std_dynamic_import_trampoline(&vmoffsets, &func_type))
.map(|func_type| {
gen_std_dynamic_import_trampoline(&vmoffsets, &func_type, calling_convention)
})
.collect::<Vec<_>>()
.into_iter()
.collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
Expand Down Expand Up @@ -219,13 +233,13 @@ mod tests {
let compiler = SinglepassCompiler::new(Singlepass::default());

// Compile for win64
let win64 = Target::new(triple!("x86_64-pc-windows-msvc"), CpuFeature::for_host());
/*let win64 = Target::new(triple!("x86_64-pc-windows-msvc"), CpuFeature::for_host());
let (mut info, translation, inputs) = dummy_compilation_ingredients();
let result = compiler.compile_module(&win64, &mut info, &translation, inputs);
match result.unwrap_err() {
CompileError::UnsupportedTarget(name) => assert_eq!(name, "windows"),
error => panic!("Unexpected error: {:?}", error),
};
};*/

// Compile for 32bit Linux
let linux32 = Target::new(triple!("i686-unknown-linux-gnu"), CpuFeature::for_host());
Expand Down
12 changes: 11 additions & 1 deletion lib/compiler-singlepass/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use crate::compiler::SinglepassCompiler;
use loupe::MemoryUsage;
use std::sync::Arc;
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target};
use wasmer_compiler::{
CallingConvention, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target,
};
use wasmer_types::Features;

#[derive(Debug, Clone, MemoryUsage)]
Expand All @@ -13,6 +15,8 @@ pub struct Singlepass {
pub(crate) enable_stack_check: bool,
/// The middleware chain.
pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
#[loupe(skip)]
pub(crate) calling_convention: CallingConvention,
}

impl Singlepass {
Expand All @@ -23,6 +27,12 @@ impl Singlepass {
enable_nan_canonicalization: true,
enable_stack_check: false,
middlewares: vec![],
calling_convention: match Target::default().triple().default_calling_convention() {
Ok(CallingConvention::WindowsFastcall) => CallingConvention::WindowsFastcall,
Ok(CallingConvention::SystemV) => CallingConvention::SystemV,
//Ok(CallingConvention::AppleAarch64) => AppleAarch64,
_ => panic!("Unsupported Calling convention for Singlepass"),
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-singlepass/src/emitter_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ impl Emitter for Assembler {
}

fn emit_bkpt(&mut self) {
dynasm!(self ; int 0x3);
dynasm!(self ; int3);
}

fn emit_host_redirection(&mut self, target: GPR) {
Expand Down
33 changes: 22 additions & 11 deletions lib/compiler-singlepass/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use smallvec::SmallVec;
use std::cmp;
use std::collections::HashSet;
use wasmer_compiler::wasmparser::Type as WpType;
use wasmer_compiler::{CallingConvention, Target};

const NATIVE_PAGE_SIZE: usize = 4096;

Expand Down Expand Up @@ -330,6 +331,7 @@ impl Machine {
a: &mut E,
n: usize,
n_params: usize,
calling_convention: CallingConvention,
) -> Vec<Location> {
// Determine whether a local should be allocated on the stack.
fn is_local_on_stack(idx: usize) -> bool {
Expand Down Expand Up @@ -432,7 +434,7 @@ impl Machine {
// Locals are allocated on the stack from higher address to lower address,
// so we won't skip the stack guard page here.
for i in 0..n_params {
let loc = Self::get_param_location(i + 1);
let loc = Self::get_param_location(i + 1, calling_convention);
match loc {
Location::GPR(_) => {
a.emit_mov(Size::S64, loc, locations[i]);
Expand All @@ -454,7 +456,7 @@ impl Machine {
// Load vmctx into R15.
a.emit_mov(
Size::S64,
Self::get_param_location(0),
Self::get_param_location(0, calling_convention),
Location::GPR(GPR::R15),
);

Expand Down Expand Up @@ -521,15 +523,24 @@ impl Machine {
}
}

pub fn get_param_location(idx: usize) -> Location {
match idx {
0 => Location::GPR(GPR::RDI),
1 => Location::GPR(GPR::RSI),
2 => Location::GPR(GPR::RDX),
3 => Location::GPR(GPR::RCX),
4 => Location::GPR(GPR::R8),
5 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32),
pub fn get_param_location(idx: usize, calling_convention: CallingConvention) -> Location {
match calling_convention {
CallingConvention::WindowsFastcall => match idx {
0 => Location::GPR(GPR::RCX),
1 => Location::GPR(GPR::RDX),
2 => Location::GPR(GPR::R8),
3 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + 32 + (idx - 4) * 8) as i32),
},
_ => match idx {
0 => Location::GPR(GPR::RDI),
1 => Location::GPR(GPR::RSI),
2 => Location::GPR(GPR::RDX),
3 => Location::GPR(GPR::RCX),
4 => Location::GPR(GPR::R8),
5 => Location::GPR(GPR::R9),
_ => Location::Memory(GPR::RBP, (16 + (idx - 6) * 8) as i32),
},
}
}
}
Expand Down
98 changes: 66 additions & 32 deletions lib/compiler-singlepass/src/x64_decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::common_decl::{MachineState, MachineValue, RegisterIndex};
use std::collections::BTreeMap;
use wasmer_compiler::{CallingConvention, Target};
use wasmer_types::Type;

/// General-purpose registers.
Expand Down Expand Up @@ -170,42 +171,75 @@ pub struct ArgumentRegisterAllocator {

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) -> Option<X64Register> {
static GPR_SEQ: &'static [GPR] =
&[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
static XMM_SEQ: &'static [XMM] = &[
XMM::XMM0,
XMM::XMM1,
XMM::XMM2,
XMM::XMM3,
XMM::XMM4,
XMM::XMM5,
XMM::XMM6,
XMM::XMM7,
];
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(X64Register::GPR(gpr))
} else {
None
pub fn next(&mut self, ty: Type, calling_convention: CallingConvention) -> Option<X64Register> {
match calling_convention {
CallingConvention::WindowsFastcall => {
static GPR_SEQ: &'static [GPR] = &[GPR::RCX, GPR::RDX, GPR::R8, GPR::R9];
static XMM_SEQ: &'static [XMM] = &[XMM::XMM0, XMM::XMM1, XMM::XMM2, XMM::XMM3];
let idx = self.n_gprs + self.n_xmms;
match ty {
Type::I32 | Type::I64 => {
if idx < 4 {
let gpr = GPR_SEQ[idx];
self.n_gprs += 1;
Some(X64Register::GPR(gpr))
} else {
None
}
}
Type::F32 | Type::F64 => {
if idx < 4 {
let xmm = XMM_SEQ[idx];
self.n_xmms += 1;
Some(X64Register::XMM(xmm))
} else {
None
}
}
_ => todo!(
"ArgumentRegisterAllocator::next: Unsupported type: {:?}",
ty
),
}
}
Type::F32 | Type::F64 => {
if self.n_xmms < XMM_SEQ.len() {
let xmm = XMM_SEQ[self.n_xmms];
self.n_xmms += 1;
Some(X64Register::XMM(xmm))
} else {
None
_ => {
static GPR_SEQ: &'static [GPR] =
&[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
static XMM_SEQ: &'static [XMM] = &[
XMM::XMM0,
XMM::XMM1,
XMM::XMM2,
XMM::XMM3,
XMM::XMM4,
XMM::XMM5,
XMM::XMM6,
XMM::XMM7,
];
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(X64Register::GPR(gpr))
} else {
None
}
}
Type::F32 | Type::F64 => {
if self.n_xmms < XMM_SEQ.len() {
let xmm = XMM_SEQ[self.n_xmms];
self.n_xmms += 1;
Some(X64Register::XMM(xmm))
} else {
None
}
}
_ => todo!(
"ArgumentRegisterAllocator::next: Unsupported type: {:?}",
ty
),
}
}
_ => todo!(
"ArgumentRegisterAllocator::next: Unsupported type: {:?}",
ty
),
}
}
}
Expand Down
1 change: 0 additions & 1 deletion tests/ignores.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
singlepass spec::multi_value # Singlepass has not implemented multivalue (functions that returns "structs"/"tuples")
singlepass spec::simd # Singlepass doesn't support yet SIMD (no one asked for this feature)

singlepass+windows * # We might need to add support for Windows calling convention from host to wasm (Company showed interest to sponsor)
singlepass+dylib * # It needs to add support for PIC in Singlepass. Not implemented at the moment
windows+dylib * # This might be trivial to fix?
musl+dylib * # Dynamic loading not supported in Musl
Expand Down

0 comments on commit a67b0c4

Please sign in to comment.