Merge pull request #598 from wasmerio/features/llvm-windows

LLVM backend enabled for Windows
This commit is contained in:
Syrus Akbary 2019-07-30 17:38:50 -07:00 committed by GitHub
commit 99ecfaa503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 234 additions and 119 deletions

View File

@ -18,24 +18,22 @@ environment:
cache:
- 'C:\Users\appveyor\.cargo'
- target
- wapm-cli-target
install:
# # Install LLVM
# - mkdir C:\projects\deps
# - cd C:\projects\deps
# - appveyor DownloadFile https://prereleases.llvm.org/win-snapshots/LLVM-8.0.0-r351033-win64.exe -FileName llvm.exe
# - 7z x llvm.exe -oC:\projects\deps\llvm
# # - set "PATH=%PATH%;C:\projects\deps\llvm\bin"
# - set "LLD_LINK=C:\projects\deps\llvm\bin\lld-link.exe"
# - set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm"
# - cd "%APPVEYOR_BUILD_FOLDER%"
# Install LLVM
- mkdir C:\projects\deps
- cd C:\projects\deps
- appveyor DownloadFile https://github.com/wasmerio/windows-llvm-build/releases/download/v8.0.0/llvm-8.0.0-install.zip -FileName llvm-8.0.0-install.zip
- 7z x llvm-8.0.0-install.zip
- C:\projects\deps\llvm-8.0.0-install\bin\llvm-config.exe --version
- set "LLVM_SYS_80_PREFIX=C:\projects\deps\llvm-8.0.0-install"
- cd "%APPVEYOR_BUILD_FOLDER%"
# Install Rust
# uncomment these lines if the cache is cleared, or if we must re-install rust for some reason
# - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
# - rustup-init.exe -yv --default-host %target%
- set PATH=%PATH%;C:\\Libraries\\llvm-5.0.0\\bin;%USERPROFILE%\.cargo\bin
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustup default stable-%target%
- rustup update
- rustc -vV
@ -52,16 +50,7 @@ build_script:
- cargo build --release --verbose
- git submodule init
- git submodule update
# Cache wapm cli target in dir above to prevent breaking git submodule on windows
- if not exist wapm-cli-target mkdir wapm-cli-target
- move wapm-cli-target wapm-cli
- cd wapm-cli
- rename wapm-cli-target target
- cd ..
- cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
- cd wapm-cli
- cd ..
- xcopy wapm-cli\target wapm-cli-target\ /i /y
- if %APPVEYOR_REPO_BRANCH%==master cargo build --release --manifest-path wapm-cli/Cargo.toml --features "telemetry update-notifications"
- cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml
test_script:

View File

@ -5,6 +5,7 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.
## **[Unreleased]**
- [#598](https://github.com/wasmerio/wasmer/pull/598) LLVM Backend is now supported in Windows
- [#599](https://github.com/wasmerio/wasmer/pull/599) Fix llvm backend failures in fat spec tests and simd_binaryen spec test.
- [#579](https://github.com/wasmerio/wasmer/pull/579) Fix bug in caching with LLVM and Singlepass backends.
Add `default-backend-singlepass`, `default-backend-llvm`, and `default-backend-cranelift` features to `wasmer-runtime`

6
Cargo.lock generated
View File

@ -565,19 +565,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "inkwell"
version = "0.1.0"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#f1775622b6d88fd30006b377042726854c9e0193"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638"
dependencies = [
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)",
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
"llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inkwell_internal_macros"
version = "0.1.0"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#f1775622b6d88fd30006b377042726854c9e0193"
source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#4c5359e507b8a3439c9e2c7fff5c336224069638"
dependencies = [
"cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1522,6 +1523,7 @@ dependencies = [
"wabt 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.5.7",
"wasmparser 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

BIN
examples/particle-repel-simd.wasm Executable file

Binary file not shown.

BIN
examples/particle-repel.wasm Executable file

Binary file not shown.

View File

@ -1,13 +1,12 @@
[package]
name = "wasmer-llvm-backend"
version = "0.5.7"
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
edition = "2018"
readme = "README.md"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.5.7" }
inkwell = { git = "https://github.com/wasmerio/inkwell", branch = "llvm8-0", features = ["llvm8-0"] }
wasmparser = "0.34.0"
hashbrown = "0.1.8"
smallvec = "0.6.8"
@ -16,6 +15,15 @@ libc = "0.2.49"
nix = "0.14.0"
capstone = { version = "0.5.0", optional = true }
[dependencies.inkwell]
git = "https://github.com/wasmerio/inkwell"
branch = "llvm8-0"
default-features = false
features = ["llvm8-0", "target-x86"]
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["memoryapi"] }
[build-dependencies]
cc = "1.0"
lazy_static = "1.2.0"

View File

@ -75,16 +75,24 @@ public:
}
virtual void registerEHFrames(uint8_t* addr, uint64_t LoadAddr, size_t size) override {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
eh_frame_ptr = addr;
eh_frame_size = size;
eh_frames_registered = true;
callbacks.visit_fde(addr, size, __register_frame);
#endif
}
virtual void deregisterEHFrames() override {
// We don't know yet how to do this on Windows, so we hide this on compilation
// so we can compile and pass spectests on unix systems
#ifndef _WIN32
if (eh_frames_registered) {
callbacks.visit_fde(eh_frame_ptr, eh_frame_size, __deregister_frame);
}
#endif
}
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {

View File

@ -1,14 +1,12 @@
use crate::intrinsics::Intrinsics;
use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect};
use inkwell::{
memory_buffer::MemoryBuffer,
module::Module,
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
OptimizationLevel,
};
use libc::{
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
PROT_WRITE,
};
use libc::c_char;
use std::{
any::Any,
ffi::{c_void, CString},
@ -31,42 +29,6 @@ use wasmer_runtime_core::{
vm, vmcalls,
};
#[repr(C)]
struct LLVMModule {
_private: [u8; 0],
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
enum MemProtect {
NONE,
READ,
READ_WRITE,
READ_EXECUTE,
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
enum LLVMResult {
OK,
ALLOCATE_FAILURE,
PROTECT_FAILURE,
DEALLOC_FAILURE,
OBJECT_LOAD_FAILURE,
}
#[repr(C)]
struct Callbacks {
alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
}
extern "C" {
fn module_load(
mem_ptr: *const u8,
@ -99,69 +61,21 @@ extern "C" {
}
fn get_callbacks() -> Callbacks {
fn round_up_to_page_size(size: usize) -> usize {
(size + (4096 - 1)) & !(4096 - 1)
}
extern "C" fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = unsafe {
mmap(
ptr::null_mut(),
size,
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
MAP_PRIVATE | MAP_ANON,
-1,
0,
)
};
if ptr as isize == -1 {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
unsafe { crate::platform::alloc_memory(size, protect, ptr_out, size_out) }
}
extern "C" fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let res = unsafe {
mprotect(
ptr as _,
round_up_to_page_size(size),
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
)
};
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::PROTECT_FAILURE
}
unsafe { crate::platform::protect_memory(ptr, size, protect) }
}
extern "C" fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let res = unsafe { munmap(ptr as _, round_up_to_page_size(size)) };
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
unsafe { crate::platform::dealloc_memory(ptr, size) }
}
extern "C" fn lookup_vm_symbol(name_ptr: *const c_char, length: usize) -> *const vm::Func {

View File

@ -7,6 +7,7 @@ mod intrinsics;
mod platform;
mod read_info;
mod state;
mod structs;
mod trampolines;
pub use code::LLVMFunctionCodeGenerator as FunctionCodeGenerator;

View File

@ -0,0 +1,3 @@
pub fn round_up_to_page_size(size: usize) -> usize {
(size + (4096 - 1)) & !(4096 - 1)
}

View File

@ -1,7 +1,14 @@
mod common;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use self::unix::*;
#[cfg(target_family = "windows")]
compile_error!("windows not yet supported for the llvm-based compiler backend");
mod win;
#[cfg(target_family = "windows")]
pub use self::win::*;
#[cfg(not(any(unix, target_family = "windows")))]
compile_error!("Your system is not yet supported for the llvm-based compiler backend");

View File

@ -1,5 +1,11 @@
use libc::{c_void, siginfo_t};
use super::common::round_up_to_page_size;
use crate::structs::{LLVMResult, MemProtect};
use libc::{
c_void, mmap, mprotect, munmap, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE,
PROT_READ, PROT_WRITE,
};
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGSEGV};
use std::ptr;
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
/// argument, so we need to parse the fde table here.
@ -68,3 +74,60 @@ extern "C" fn signal_trap_handler(
throw_trap(2);
}
}
pub unsafe fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = mmap(
ptr::null_mut(),
size,
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
MAP_PRIVATE | MAP_ANON,
-1,
0,
);
if ptr as isize == -1 {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
}
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let res = mprotect(
ptr as _,
round_up_to_page_size(size),
match protect {
MemProtect::NONE => PROT_NONE,
MemProtect::READ => PROT_READ,
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
},
);
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::PROTECT_FAILURE
}
}
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let res = munmap(ptr as _, round_up_to_page_size(size));
if res == 0 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
}

View File

@ -0,0 +1,80 @@
use super::common::round_up_to_page_size;
use crate::structs::{LLVMResult, MemProtect};
use std::ptr;
use winapi::um::memoryapi::{VirtualAlloc, VirtualFree};
use winapi::um::winnt::{
MEM_COMMIT, MEM_DECOMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_NOACCESS, PAGE_READONLY,
PAGE_READWRITE,
};
pub unsafe fn visit_fde(_addr: *mut u8, _size: usize, _visitor: extern "C" fn(*mut u8)) {
// Do nothing on Windows
}
pub unsafe fn install_signal_handler() {
// Do nothing on Windows
}
pub unsafe fn alloc_memory(
size: usize,
protect: MemProtect,
ptr_out: &mut *mut u8,
size_out: &mut usize,
) -> LLVMResult {
let size = round_up_to_page_size(size);
let flags = if protect == MemProtect::NONE {
MEM_RESERVE
} else {
MEM_RESERVE | MEM_COMMIT
};
let ptr = VirtualAlloc(
ptr::null_mut(),
size,
flags,
memprotect_to_protect_const(protect),
);
if ptr.is_null() {
return LLVMResult::ALLOCATE_FAILURE;
}
*ptr_out = ptr as _;
*size_out = size;
LLVMResult::OK
}
pub unsafe fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
let size = round_up_to_page_size(size);
let ptr = VirtualAlloc(
ptr as _,
size,
MEM_COMMIT,
memprotect_to_protect_const(protect),
);
if ptr.is_null() {
LLVMResult::PROTECT_FAILURE
} else {
LLVMResult::OK
}
}
pub unsafe fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
let success = VirtualFree(ptr as _, size, MEM_DECOMMIT);
// If the function succeeds, the return value is nonzero.
if success == 1 {
LLVMResult::OK
} else {
LLVMResult::DEALLOC_FAILURE
}
}
fn memprotect_to_protect_const(protect: MemProtect) -> u32 {
match protect {
MemProtect::NONE => PAGE_NOACCESS,
MemProtect::READ => PAGE_READONLY,
MemProtect::READ_WRITE => PAGE_READWRITE,
MemProtect::READ_EXECUTE => PAGE_EXECUTE_READ,
}
}

View File

@ -0,0 +1,39 @@
use libc::c_char;
use wasmer_runtime_core::vm;
#[repr(C)]
pub struct LLVMModule {
_private: [u8; 0],
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub enum MemProtect {
NONE,
READ,
READ_WRITE,
READ_EXECUTE,
}
#[allow(non_camel_case_types, dead_code)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub enum LLVMResult {
OK,
ALLOCATE_FAILURE,
PROTECT_FAILURE,
DEALLOC_FAILURE,
OBJECT_LOAD_FAILURE,
}
#[repr(C)]
pub struct Callbacks {
pub alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
pub protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
pub dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
pub lookup_vm_symbol: extern "C" fn(*const c_char, usize) -> *const vm::Func,
pub visit_fde: extern "C" fn(*mut u8, usize, extern "C" fn(*mut u8)),
}

View File

@ -27,7 +27,7 @@ tempfile = "3.0.7"
criterion = "0.2"
wabt = "0.9.0"
[target.'cfg(not(windows))'.dependencies.wasmer-llvm-backend]
[dependencies.wasmer-llvm-backend]
path = "../llvm-backend"
optional = true