Feat riscv llvm and cranelift (#3244)

* Basic changes for RISC-V support

* RISC-V in compiler LLVM

* RISC-V support in dylib engine

* RISC-V support in universal engine

* Various small fixes

* [RISCV] LLVM-riscv working, with some ignored tests to be worked on later

* Update rustc to 4.65 (1.64 has some issue with riscv64 target)

* Fixed some (new) Linting issues

* Updated Cargo.toml and remove split-debuginfo for Windows build

* Removed profile.dev from Cargo.toml as it cannot be per platform (breaks Windows). split-debug info is now the default value

* Enable Cranelift compiler for RISCV

* Update crates and fixed all the new clippy errors

* Taken review remarks into account

* Removed change from deny.toml, it's not needed anymore

* Added some more comment about llvm abi hack

* Added doc about current state of RISCV support

* Fixed (newer) linter

---------

Co-authored-by: Toru Nayuki <tnayuki@icloud.com>
This commit is contained in:
ptitSeb 2023-03-22 15:26:28 +01:00 committed by GitHub
parent a72e655be6
commit 7500ce76fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 358 additions and 105 deletions

View File

@ -24,7 +24,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
- name: Configure cargo data directory
# After this point, all cargo registry and crate data is stored in
# $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files

View File

@ -94,7 +94,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
target: ${{ matrix.target }}
- name: Install Rust nightly (to build capi-headless)
uses: dtolnay/rust-toolchain@stable

View File

@ -21,7 +21,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
target: ${{ matrix.target }}
- name: Install wasm32-wasi target
shell: bash

View File

@ -16,7 +16,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
- name: Install LLVM
shell: bash
run: |

View File

@ -43,7 +43,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
components: rustfmt, clippy
- name: Install libtinfo
shell: bash
@ -95,7 +95,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
- name: Install NodeJS
uses: actions/setup-node@v2
with:
@ -263,7 +263,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
target: ${{ matrix.metadata.target }}
- name: Install Rust nightly (to build capi-headless)
uses: dtolnay/rust-toolchain@stable
@ -487,7 +487,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
target: ${{ matrix.metadata.target }}
- name: Install LLVM (macOS Apple Silicon)
if: matrix.metadata.os == 'macos-11.0' && !matrix.metadata.llvm_url
@ -587,7 +587,7 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.64
toolchain: 1.65
target: ${{ matrix.metadata.target }}
- name: Cache
uses: whywaita/actions-cache-s3@v2

44
Cargo.lock generated
View File

@ -143,7 +143,7 @@ checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -926,7 +926,7 @@ dependencies = [
"proc-macro2",
"quote",
"scratch",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -943,7 +943,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -1487,7 +1487,7 @@ checksum = "e77ac7b51b8e6313251737fcef4b1c01a2ea102bde68415b62c0ee9268fec357"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -1763,6 +1763,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e6cd45a270dff33553602fd84beb02c89460ee32db638715f10d9060389fd6a"
dependencies = [
"native-tls",
"rustls 0.19.1",
"unicase",
"webpki 0.21.4",
@ -1833,16 +1834,16 @@ dependencies = [
[[package]]
name = "iana-time-zone"
version = "0.1.53"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"winapi",
"windows",
]
[[package]]
@ -2994,9 +2995,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
version = "1.0.52"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
@ -3219,9 +3220,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.7.1"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
dependencies = [
"aho-corasick",
"memchr",
@ -3239,9 +3240,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.28"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "region"
@ -3718,7 +3719,7 @@ checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -4037,9 +4038,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.3"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60"
checksum = "89c2d1c76a26822187a1fbb5964e3fff108bc208f02e820ab9dac1234f6b388a"
dependencies = [
"proc-macro2",
"quote",
@ -4201,7 +4202,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.3",
"syn 2.0.5",
]
[[package]]
@ -6253,6 +6254,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.33.0"

View File

@ -129,9 +129,6 @@ test-universal = ["test-generator/test-universal"]
# that raise signals because that interferes with tarpaulin.
coverage = []
[profile.dev]
split-debuginfo = "unpacked"
#[profile.release]
#debug = true

View File

@ -14,7 +14,7 @@ SHELL=/usr/bin/env bash
# |------------|----------|--------------|-------|
# | Cranelift | Linux | amd64 | glibc |
# | LLVM | Darwin | aarch64 | musl |
# | Singlepass | Windows | | |
# | Singlepass | Windows | riscv | |
# |------------|----------|--------------|-------|
#
# Here is what works and what doesn't:
@ -22,13 +22,16 @@ SHELL=/usr/bin/env bash
# * Cranelift works everywhere,
#
# * LLVM works on Linux+Darwin/`amd64`,
# but it doesn't work on */`aarch64` or Windows/*.
# and linux+`aarch64`, linux+`riscv`
# but it doesn't work on Darwin/`aarch64` or Windows/`aarch64`.
#
# * Singlepass works on Linux+Darwin/`amd64`, but
# it doesn't work on */`aarch64` or Windows/*.
# * Singlepass works on Linux+Darwin+Windows/`amd64`,
# and Linux+Darwin/`aarch64`
# it doesn't work on */`riscv`.
#
# * Windows isn't tested on `aarch64`, that's why we consider it's not
# working, but it might possibly be.
# * The Only target for `riscv` familly of processor is the RV64, with the `GC` extensions
#####
@ -45,6 +48,7 @@ IS_FREEBSD := 0
IS_WINDOWS := 0
IS_AMD64 := 0
IS_AARCH64 := 0
IS_RISCV64 := 0
# Test Windows apart because it doesn't support `uname -s`.
ifeq ($(OS), Windows_NT)
@ -75,6 +79,8 @@ else
IS_AMD64 := 1
else ifneq (, $(filter $(uname), aarch64 arm64))
IS_AARCH64 := 1
else ifneq (, $(filter $(uname), riscv64))
IS_RISCV64 := 1
else
# We use spaces instead of tabs to indent `$(error)`
# otherwise it's considered as a command outside a
@ -116,8 +122,16 @@ compilers :=
# If the user didn't disable the Cranelift compiler…
ifneq ($(ENABLE_CRANELIFT), 0)
# … then it can always be enabled.
compilers += cranelift
# … then maybe the user forced to enable the Cranelift compiler.
ifeq ($(ENABLE_CRANELIFT), 1)
compilers += cranelift
# … otherwise, we try to check whether Cranelift works on this host.
else
compilers += cranelift
endif
endif
ifneq (, $(findstring cranelift,$(compilers)))
ENABLE_CRANELIFT := 1
endif
@ -235,6 +249,8 @@ ifeq ($(ENABLE_LLVM), 1)
compilers_engines += llvm-universal
else ifeq ($(IS_AARCH64), 1)
compilers_engines += llvm-universal
else ifeq ($(IS_RISCV64), 1)
compilers_engines += llvm-universal
endif
endif
endif

12
docs/RISCV.md Executable file
View File

@ -0,0 +1,12 @@
# Current state of the RISCV support
Only Cranelift and LLVM compiler are supported.
Singlepass can be done, but no ressources are allocated on this task for now.
Both LLVM and Cranelift support are quite new, and so it is expected to have a few things not working well.
LLVM code needs a hack to force the ABI to "lp64d", and some tested with funciton & float/double values are still not working correctly and have be disable for now.
On Cranelift, SIMD is not supported as the CPU doesn't have official SIMD/Vector extension for now, and no Workaround is in place.
Test have be conducted on actual hardware, with a Vision Fixe 2 board running Debian. Some previous tests have also be done on a Vison Five 1 running Fedora (with LLVM only).

View File

@ -118,7 +118,7 @@ pub(super) enum RefCow<'a, T> {
impl<'a, T> AsRef<T> for RefCow<'a, T> {
fn as_ref(&self) -> &T {
match self {
Self::Borrowed(val) => *val,
Self::Borrowed(val) => val,
Self::Owned(val, _) => val,
}
}
@ -130,7 +130,7 @@ impl<'a, T> AsMut<T> for RefCow<'a, T> {
// not leak the bytes into the memory
// https://stackoverflow.com/questions/61114026/does-stdptrwrite-transfer-the-uninitialized-ness-of-the-bytes-it-writes
match self {
Self::Borrowed(val) => *val,
Self::Borrowed(val) => val,
Self::Owned(val, modified) => {
*modified = true;
val

View File

@ -140,6 +140,7 @@ impl Imports {
/// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
///
/// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
#[allow(clippy::result_large_err)]
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
let mut ret = vec![];
for import in module.imports() {

View File

@ -58,6 +58,7 @@ impl Instance {
/// Those are, as defined by the spec:
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
#[allow(clippy::result_large_err)]
pub fn new(
store: &mut impl AsStoreMut,
module: &Module,
@ -81,6 +82,7 @@ impl Instance {
/// Those are, as defined by the spec:
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
#[allow(clippy::result_large_err)]
pub fn new_by_index(
store: &mut impl AsStoreMut,
module: &Module,

View File

@ -37,6 +37,7 @@ impl From<wasmer_compiler::InstantiationError> for InstantiationError {
}
impl Instance {
#[allow(clippy::result_large_err)]
pub(crate) fn new(
store: &mut impl AsStoreMut,
module: &Module,
@ -55,6 +56,7 @@ impl Instance {
Ok((instance, exports))
}
#[allow(clippy::result_large_err)]
pub(crate) fn new_by_index(
store: &mut impl AsStoreMut,
module: &Module,

View File

@ -94,6 +94,7 @@ impl Module {
Self { artifact }
}
#[allow(clippy::result_large_err)]
pub(crate) fn instantiate(
&self,
store: &mut impl AsStoreMut,

View File

@ -32,7 +32,7 @@ impl Display for Hash {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut buffer = [0_u8; 64];
hex::encode_to_slice(&self.0, &mut buffer)
hex::encode_to_slice(self.0, &mut buffer)
.expect("Can never fail with a hard-coded buffer length");
let s = std::str::from_utf8(&buffer).map_err(|_| fmt::Error)?;

View File

@ -54,8 +54,6 @@ distance = "0.4"
bytesize = "1.0"
cfg-if = "1.0"
tempfile = "3.4.0"
http_req = { version="^0.8", default-features = false, features = ["rust-tls"] }
reqwest = { version = "^0.11", default-features = false, features = ["rustls-tls", "json", "multipart"] }
serde = { version = "1.0.147", features = ["derive"] }
dirs = { version = "4.0" }
serde_json = { version = "1.0" }
@ -95,6 +93,14 @@ tracing-subscriber = { version = "0.3", features = [ "env-filter", "fmt" ] }
clap-verbosity-flag = "1"
wapm-targz-to-pirita = "0.1.7"
[target.'cfg(not(target_arch = "riscv64"))'.dependencies]
http_req = { version="^0.8", default-features = false, features = ["rust-tls"] }
reqwest = { version = "^0.11", default-features = false, features = ["rustls-tls", "json", "multipart"] }
[target.'cfg(target_arch = "riscv64")'.dependencies]
http_req = { version="^0.8", default-features = false, features = ["native-tls"] }
reqwest = { version = "^0.11", default-features = false, features = ["native-tls", "json", "multipart"] }
[build-dependencies]
chrono = { version = "^0.4", default-features = false, features = ["std", "clock"] }

View File

@ -4,7 +4,7 @@ use std::process::Command;
pub fn main() {
// Set WASMER_GIT_HASH
let git_hash = Command::new("git")
.args(&["rev-parse", "HEAD"])
.args(["rev-parse", "HEAD"])
.output()
.ok()
.and_then(|output| String::from_utf8(output.stdout).ok())

View File

@ -826,7 +826,7 @@ fn write_volume_obj(
object_name,
)?;
let mut writer = BufWriter::new(File::create(&output_path)?);
let mut writer = BufWriter::new(File::create(output_path)?);
volumes_object
.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
@ -1136,7 +1136,7 @@ fn link_exe_from_dir(
.as_ref()
.ok_or_else(|| anyhow::anyhow!("could not find zig in $PATH {}", directory.display()))?;
let mut cmd = Command::new(&zig_binary_path);
let mut cmd = Command::new(zig_binary_path);
cmd.arg("build-exe");
cmd.arg("--verbose-cc");
cmd.arg("--verbose-link");
@ -1796,7 +1796,7 @@ pub(super) mod utils {
let path_var = std::env::var("PATH").unwrap_or_default();
#[cfg(unix)]
let system_path_var = std::process::Command::new("getconf")
.args(&["PATH"])
.args(["PATH"])
.output()
.map(|output| output.stdout)
.unwrap_or_default();
@ -2187,7 +2187,7 @@ mod http_fetch {
pub(crate) fn list_dir(target: &Path) -> Vec<PathBuf> {
use walkdir::WalkDir;
WalkDir::new(&target)
WalkDir::new(target)
.into_iter()
.filter_map(|e| e.ok())
.map(|entry| entry.path().to_path_buf())

View File

@ -161,7 +161,7 @@ impl Init {
.collect::<Vec<_>>()
.join(NEWLINE);
std::fs::write(&path, &toml_string)
std::fs::write(path, &toml_string)
.with_context(|| format!("Unable to write to \"{}\"", path.display()))?;
Ok(())
@ -494,7 +494,7 @@ fn construct_manifest(
}
fn parse_cargo_toml(manifest_path: &PathBuf) -> Result<MiniCargoTomlPackage, anyhow::Error> {
let mut metadata = MetadataCommand::new();
metadata.manifest_path(&manifest_path);
metadata.manifest_path(manifest_path);
metadata.no_deps();
metadata.features(CargoOpt::AllFeatures);

View File

@ -247,7 +247,7 @@ fn append_path_to_tar_gz(
.metadata()
.map_err(|e| (normalized_path.clone(), e))?;
builder
.append_path_with_name(&normalized_path, &target_path)
.append_path_with_name(&normalized_path, target_path)
.map_err(|e| (normalized_path.clone(), e))?;
Ok(normalized_path)
}
@ -386,7 +386,7 @@ fn apply_migration(conn: &mut Connection, migration_number: i32) -> Result<(), M
tx.execute_batch(migration_to_apply)
.map_err(|e| MigrationError::TransactionFailed(migration_number, format!("{}", e)))?;
tx.pragma_update(None, "user_version", &(migration_number + 1))
tx.pragma_update(None, "user_version", migration_number + 1)
.map_err(|e| MigrationError::TransactionFailed(migration_number, format!("{}", e)))?;
tx.commit()
.map_err(|_| MigrationError::CommitFailed(migration_number))

View File

@ -125,7 +125,7 @@ impl RunWithPathBuf {
let default = indexmap::IndexMap::default();
let fs = manifest.fs.as_ref().unwrap_or(&default);
for (alias, real_dir) in fs.iter() {
let real_dir = self_clone.path.join(&real_dir);
let real_dir = self_clone.path.join(real_dir);
if !real_dir.exists() {
#[cfg(feature = "debug")]
if self_clone.debug {

View File

@ -464,7 +464,7 @@ impl TargetOnDisk {
Ok(ExecutableTarget::Webc(container))
}
TargetOnDisk::WebAssemblyBinary(path) => {
let wasm = std::fs::read(&path)
let wasm = std::fs::read(path)
.with_context(|| format!("Unable to read \"{}\"", path.display()))?;
let module = compile_wasm_cached(path, &wasm, cache, store)?;
Ok(ExecutableTarget::WebAssembly(module))
@ -566,7 +566,7 @@ fn generate_coredump(err: &Error, source: &Path, coredump_path: &Path) -> Result
.map_err(Error::msg)
.context("Coredump serializing failed")?;
std::fs::write(&coredump_path, &coredump).with_context(|| {
std::fs::write(coredump_path, &coredump).with_context(|| {
format!(
"Unable to save the coredump to \"{}\"",
coredump_path.display()

View File

@ -15,7 +15,7 @@ edition = "2018"
wasmer-compiler = { path = "../compiler", version = "=3.2.0-alpha.1", features = ["translator", "compiler"], default-features = false }
wasmer-types = { path = "../types", version = "=3.2.0-alpha.1", default-features = false, features = ["std"] }
cranelift-entity = { version = "0.91.1", default-features = false }
cranelift-codegen = { version = "0.91.1", default-features = false, features = ["x86", "arm64"] }
cranelift-codegen = { version = "0.91.1", default-features = false, features = ["x86", "arm64", "riscv64"] }
cranelift-frontend = { version = "0.91.1", default-features = false }
tracing = "0.1"
hashbrown = { version = "0.11", optional = true }

View File

@ -117,11 +117,12 @@ impl Cranelift {
builder.enable("has_lzcnt").expect("should be valid flag");
}
builder.finish(self.flags())
builder.finish(self.flags(target))
}
/// Generates the flags for the compiler
pub fn flags(&self) -> settings::Flags {
pub fn flags(&self, target: &Target) -> settings::Flags {
let is_riscv = matches!(target.triple().architecture, Architecture::Riscv64(_));
let mut flags = settings::builder();
// Enable probestack
@ -169,9 +170,15 @@ impl Cranelift {
)
.expect("should be valid flag");
flags
.set("enable_simd", "true")
.expect("should be valid flag");
if is_riscv {
flags
.set("enable_simd", "false")
.expect("should be valid flag");
} else {
flags
.set("enable_simd", "true")
.expect("should be valid flag");
}
let enable_nan_canonicalization = if self.enable_nan_canonicalization {
"true"

View File

@ -84,6 +84,7 @@ pub fn irreloc_to_relocationkind(reloc: Reloc) -> RelocationKind {
Reloc::X86CallPLTRel4 => RelocationKind::X86CallPLTRel4,
Reloc::X86GOTPCRel4 => RelocationKind::X86GOTPCRel4,
Reloc::Arm64Call => RelocationKind::Arm64Call,
Reloc::RiscvCall => RelocationKind::RiscvCall,
_ => panic!("The relocation {} is not yet supported.", reloc),
}
}

View File

@ -29,7 +29,7 @@ rayon = "1.5"
package = "inkwell"
version = "0.1.1"
default-features = false
features = ["llvm14-0", "target-x86", "target-aarch64"]
features = ["llvm14-0", "target-x86", "target-aarch64", "target-riscv"]
[build-dependencies]
cc = "1.0"

View File

@ -21,19 +21,14 @@ impl Abi for Aarch64SystemV {
// Given a function definition, retrieve the parameter that is the vmctx pointer.
fn get_vmctx_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
func_value
.get_nth_param(
if func_value
.get_nth_param(u32::from(
func_value
.get_enum_attribute(
AttributeLoc::Param(0),
Attribute::get_named_enum_kind_id("sret"),
)
.is_some()
{
1
} else {
0
},
)
.is_some(),
))
.unwrap()
.into_pointer_value()
}

View File

@ -23,19 +23,14 @@ impl Abi for X86_64SystemV {
// Given a function definition, retrieve the parameter that is the vmctx pointer.
fn get_vmctx_ptr_param<'ctx>(&self, func_value: &FunctionValue<'ctx>) -> PointerValue<'ctx> {
func_value
.get_nth_param(
if func_value
.get_nth_param(u32::from(
func_value
.get_enum_attribute(
AttributeLoc::Param(0),
Attribute::get_named_enum_kind_id("sret"),
)
.is_some()
{
1
} else {
0
},
)
.is_some(),
))
.unwrap()
.into_pointer_value()
}

View File

@ -97,6 +97,13 @@ impl LLVM {
}
fn target_triple(&self, target: &Target) -> TargetTriple {
let architecture = if target.triple().architecture
== Architecture::Riscv64(target_lexicon::Riscv64Architecture::Riscv64gc)
{
target_lexicon::Architecture::Riscv64(target_lexicon::Riscv64Architecture::Riscv64)
} else {
target.triple().architecture
};
// Hack: we're using is_pic to determine whether this is a native
// build or not.
let operating_system = if target.triple().operating_system
@ -123,7 +130,7 @@ impl LLVM {
target_lexicon::BinaryFormat::Elf
};
let triple = Triple {
architecture: target.triple().architecture,
architecture,
vendor: target.triple().vendor.clone(),
operating_system,
environment: target.triple().environment,
@ -156,6 +163,14 @@ impl LLVM {
info: true,
machine_code: true,
}),
Architecture::Riscv64(_) => InkwellTarget::initialize_riscv(&InitializationConfig {
asm_parser: true,
asm_printer: true,
base: true,
disassembler: true,
info: true,
machine_code: true,
}),
// Architecture::Arm(_) => InkwellTarget::initialize_arm(&InitializationConfig {
// asm_parser: true,
// asm_printer: true,
@ -177,16 +192,57 @@ impl LLVM {
let target_triple = self.target_triple(target);
let llvm_target = InkwellTarget::from_triple(&target_triple).unwrap();
llvm_target
let llvm_target_machine = llvm_target
.create_target_machine(
&target_triple,
"generic",
&llvm_cpu_features,
match triple.architecture {
Architecture::Riscv64(_) => "generic-rv64",
_ => "generic",
},
match triple.architecture {
Architecture::Riscv64(_) => "+m,+a,+c,+d,+f",
_ => &llvm_cpu_features,
},
self.opt_level,
self.reloc_mode(),
self.code_model(),
match triple.architecture {
Architecture::Riscv64(_) => CodeModel::Medium,
_ => self.code_model(),
},
)
.unwrap()
.unwrap();
if let Architecture::Riscv64(_) = triple.architecture {
// TODO: totally non-portable way to change ABI
unsafe {
// This structure mimic the internal structure from inkwell
// that is defined as
// #[derive(Debug)]
// pub struct TargetMachine {
// pub(crate) target_machine: LLVMTargetMachineRef,
// }
pub struct MyTargetMachine {
pub target_machine: *const u8,
}
// It is use to live patch the create LLVMTargetMachine
// to hard change the ABI and force "-mabi=lp64d" ABI
// instead of the default that don't use float registers
// because there is no current way to do this change
let my_target_machine: MyTargetMachine = std::mem::transmute(llvm_target_machine);
*((my_target_machine.target_machine as *mut u8).offset(0x410) as *mut u64) = 5;
std::ptr::copy_nonoverlapping(
"lp64d\0".as_ptr(),
(my_target_machine.target_machine as *mut u8).offset(0x418),
6,
);
std::mem::transmute(my_target_machine)
}
} else {
llvm_target_machine
}
}
}

View File

@ -216,6 +216,21 @@ where
object::RelocationKind::Elf(object::elf::R_AARCH64_MOVW_UABS_G3),
0,
) => RelocationKind::Arm64Movw3,
(
object::Architecture::Riscv64,
object::RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT),
0,
) => RelocationKind::RiscvCall,
(
object::Architecture::Riscv64,
object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_HI20),
0,
) => RelocationKind::RiscvPCRelHi20,
(
object::Architecture::Riscv64,
object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I),
0,
) => RelocationKind::RiscvPCRelLo12I,
_ => {
return Err(CompileError::Codegen(format!(
"unknown relocation {:?}",
@ -223,7 +238,7 @@ where
)));
}
};
let addend = reloc.addend();
let mut addend = reloc.addend();
let target = match reloc.target() {
object::read::RelocationTarget::Symbol(index) => {
let symbol = elf.symbol_by_index(index).map_err(map_object_err)?;
@ -254,6 +269,19 @@ where
symbol_name_to_relocation_target(symbol_name)?
{
reloc_target
} else if let object::SymbolSection::Section(section_index) = symbol.section() {
// TODO: Encode symbol address into addend, I think this is a bit hacky.
addend = addend.wrapping_add(symbol.address() as i64);
if section_index == root_section_index {
root_section_reloc_target
} else {
if visited.insert(section_index) {
worklist.push(section_index);
}
elf_section_to_target(section_index)
}
} else {
return Err(CompileError::Codegen(format!(
"relocation targets unknown symbol {:?}",

View File

@ -25,6 +25,17 @@ const X86_64_TRAMPOLINE: [u8; 16] = [
0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
// can it be shorter than this?
// 4 padding bytes are used to preserve alignment.
// AUIPC t1,0 17 03 00 00
// LD t1, 16(t1) 03 33 03 01
// JR t1 67 00 03 00 [00 00 00 00]
// JMPADDR 00 00 00 00 00 00 00 00
const RISCV64_TRAMPOLINE: [u8; 24] = [
0x17, 0x03, 0x00, 0x00, 0x03, 0x33, 0x03, 0x01, 0x67, 0x00, 0x03, 0x00, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
fn make_trampoline(
target: &Target,
libcall: LibCall,
@ -50,6 +61,15 @@ fn make_trampoline(
addend: 0,
});
}
Architecture::Riscv64(_) => {
code.extend(RISCV64_TRAMPOLINE);
relocations.push(Relocation {
kind: RelocationKind::Abs8,
reloc_target: RelocationTarget::LibCall(libcall),
offset: code.len() as u32 - 8,
addend: 0,
});
}
arch => panic!("Unsupported architecture: {}", arch),
};
}
@ -59,6 +79,7 @@ pub fn libcall_trampoline_len(target: &Target) -> usize {
match target.triple().architecture {
Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(),
Architecture::X86_64 => X86_64_TRAMPOLINE.len(),
Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(),
arch => panic!("Unsupported architecture: {}", arch),
}
}

View File

@ -420,6 +420,7 @@ impl Artifact {
}
/// Do preinstantiation logic that is executed before instantiating
#[allow(clippy::result_large_err)]
pub fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(())
}
@ -429,6 +430,7 @@ impl Artifact {
/// # Safety
///
/// See [`VMInstance::new`].
#[allow(clippy::result_large_err)]
pub unsafe fn instantiate(
&self,
tunables: &dyn Tunables,
@ -509,6 +511,7 @@ impl Artifact {
/// # Safety
///
/// See [`VMInstance::finish_instantiation`].
#[allow(clippy::result_large_err)]
pub unsafe fn finish_instantiation(
&self,
trap_handler: Option<*const TrapHandlerFn<'static>>,

View File

@ -2,6 +2,7 @@
use crate::get_libcall_trampoline;
use crate::FunctionExtent;
use std::collections::HashMap;
use std::ptr::{read_unaligned, write_unaligned};
use wasmer_types::entity::PrimaryMap;
use wasmer_types::{LocalFunctionIndex, ModuleInfo};
@ -16,6 +17,7 @@ fn apply_relocation(
allocated_sections: &PrimaryMap<SectionIndex, SectionBodyPtr>,
libcall_trampolines: SectionIndex,
libcall_trampoline_len: usize,
riscv_pcrel_hi20s: &mut HashMap<usize, u32>,
) {
let target_func_address: usize = match r.reloc_target {
RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize,
@ -93,6 +95,32 @@ fn apply_relocation(
| read_unaligned(reloc_address as *mut u32);
write_unaligned(reloc_address as *mut u32, reloc_delta);
},
RelocationKind::RiscvPCRelHi20 => unsafe {
let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
// save for later reference with RiscvPCRelLo12I
riscv_pcrel_hi20s.insert(reloc_address, reloc_delta as u32);
let reloc_delta = ((reloc_delta.wrapping_add(0x800) & 0xfffff000) as u32)
| read_unaligned(reloc_address as *mut u32);
write_unaligned(reloc_address as *mut u32, reloc_delta);
},
RelocationKind::RiscvPCRelLo12I => unsafe {
let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64);
let reloc_delta = ((riscv_pcrel_hi20s.get(&(reloc_abs as usize)).expect(
"R_RISCV_PCREL_LO12_I relocation target must be a symbol with R_RISCV_PCREL_HI20",
) & 0xfff)
<< 20)
| read_unaligned(reloc_address as *mut u32);
write_unaligned(reloc_address as *mut u32, reloc_delta);
},
RelocationKind::RiscvCall => unsafe {
let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
let reloc_delta = ((reloc_delta & 0xfff) << 52)
| (reloc_delta.wrapping_add(0x800) & 0xfffff000)
| read_unaligned(reloc_address as *mut u64);
write_unaligned(reloc_address as *mut u64, reloc_delta);
},
kind => panic!(
"Relocation kind unsupported in the current architecture {}",
kind
@ -111,6 +139,8 @@ pub fn link_module(
libcall_trampolines: SectionIndex,
trampoline_len: usize,
) {
let mut riscv_pcrel_hi20s: HashMap<usize, u32> = HashMap::new();
for (i, section_relocs) in section_relocations.iter() {
let body = *allocated_sections[i] as usize;
for r in section_relocs {
@ -121,6 +151,7 @@ pub fn link_module(
allocated_sections,
libcall_trampolines,
trampoline_len,
&mut riscv_pcrel_hi20s,
);
}
}
@ -134,6 +165,7 @@ pub fn link_module(
allocated_sections,
libcall_trampolines,
trampoline_len,
&mut riscv_pcrel_hi20s,
);
}
}

View File

@ -60,6 +60,7 @@ fn get_runtime_size(context: &StoreObjects, extern_: &VMExtern) -> Option<u32> {
/// a `Resolver`.
///
/// If all imports are satisfied returns an `Imports` instance required for a module instantiation.
#[allow(clippy::result_large_err)]
pub fn resolve_imports(
module: &ModuleInfo,
imports: &[VMExtern],

View File

@ -60,6 +60,7 @@ pub trait Tunables {
///
/// # Safety
/// - `memory_definition_locations` must point to a valid locations in VM memory.
#[allow(clippy::result_large_err)]
unsafe fn create_memories(
&self,
context: &mut StoreObjects,
@ -93,6 +94,7 @@ pub trait Tunables {
/// # Safety
///
/// To be done
#[allow(clippy::result_large_err)]
unsafe fn create_tables(
&self,
context: &mut StoreObjects,
@ -123,6 +125,7 @@ pub trait Tunables {
/// Allocate memory for just the globals of the current module,
/// with initializers applied.
#[allow(clippy::result_large_err)]
fn create_globals(
&self,
context: &mut StoreObjects,

View File

@ -3,8 +3,8 @@ use object::write::{
Object, Relocation, StandardSection, StandardSegment, Symbol as ObjSymbol, SymbolSection,
};
use object::{
elf, macho, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind,
SymbolScope,
elf, macho, FileFlags, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags,
SymbolKind, SymbolScope,
};
use wasmer_types::entity::PrimaryMap;
use wasmer_types::LocalFunctionIndex;
@ -46,6 +46,7 @@ pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
let obj_architecture = match triple.architecture {
Architecture::X86_64 => object::Architecture::X86_64,
Architecture::Aarch64(_) => object::Architecture::Aarch64,
Architecture::Riscv64(_) => object::Architecture::Riscv64,
architecture => {
return Err(ObjectError::UnsupportedArchitecture(format!(
"{}",
@ -61,11 +62,15 @@ pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
Endianness::Big => object::Endianness::Big,
};
Ok(Object::new(
obj_binary_format,
obj_architecture,
obj_endianness,
))
let mut object = Object::new(obj_binary_format, obj_architecture, obj_endianness);
if let Architecture::Riscv64(_) = triple.architecture {
object.flags = FileFlags::Elf {
e_flags: elf::EF_RISCV_FLOAT_ABI_DOUBLE,
};
}
Ok(object)
}
/// Write data into an existing object.

View File

@ -13,7 +13,6 @@ dirs = "4.0.0"
graphql_client = "0.11.0"
serde = { version = "1.0.145", features = ["derive"] }
anyhow = "1.0.65"
reqwest = { version = "0.11.12", default-features = false, features = ["rustls-tls", "blocking", "multipart", "json", "stream"] }
futures-util = "0.3.25"
whoami = "1.2.3"
serde_json = "1.0.85"
@ -37,3 +36,9 @@ console = "0.15.2"
indicatif = "0.17.2"
lazy_static = "1.4.0"
tempfile = "3.4.0"
[target.'cfg(not(target_arch = "riscv64"))'.dependencies]
reqwest = { version = "0.11.12", default-features = false, features = ["rustls-tls", "blocking", "multipart", "json", "stream"] }
[target.'cfg(target_arch = "riscv64")'.dependencies]
reqwest = { version = "0.11.12", default-features = false, features = ["native-tls", "blocking", "multipart", "json", "stream"] }

View File

@ -475,7 +475,7 @@ pub fn try_unpack_targz<P: AsRef<Path>>(
)
})
} else {
ar.unpack(&target_path).map_err(|e| {
ar.unpack(target_path).map_err(|e| {
anyhow::anyhow!(
"failed to unpack (with parent) {}: {e}",
target_targz_path.display()

View File

@ -50,8 +50,12 @@ pub enum RelocationKind {
Arm64Movw2,
/// Arm64 movk/z part 3
Arm64Movw3,
// /// RISC-V call target
// RiscvCall,
/// RISC-V PC-relative high 20bit
RiscvPCRelHi20,
/// RISC-V PC-relative low 12bit, I-type
RiscvPCRelLo12I,
/// RISC-V call target
RiscvCall,
/// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol.
ElfX86_64TlsGd,
// /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry.
@ -70,12 +74,14 @@ impl fmt::Display for RelocationKind {
Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
Self::Arm32Call | Self::Arm64Call => write!(f, "Call"),
Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"),
Self::Arm64Movw0 => write!(f, "Arm64MovwG0"),
Self::Arm64Movw1 => write!(f, "Arm64MovwG1"),
Self::Arm64Movw2 => write!(f, "Arm64MovwG2"),
Self::Arm64Movw3 => write!(f, "Arm64MovwG3"),
Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"),
Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"),
// Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
}
}
@ -119,7 +125,8 @@ impl Relocation {
| RelocationKind::Arm64Movw0
| RelocationKind::Arm64Movw1
| RelocationKind::Arm64Movw2
| RelocationKind::Arm64Movw3 => {
| RelocationKind::Arm64Movw3
| RelocationKind::RiscvPCRelLo12I => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_abs = target_func_address
@ -153,7 +160,9 @@ impl Relocation {
.wrapping_add(reloc_addend as u32);
(reloc_address, reloc_delta_u32 as u64)
}
RelocationKind::Arm64Call => {
RelocationKind::Arm64Call
| RelocationKind::RiscvCall
| RelocationKind::RiscvPCRelHi20 => {
let reloc_address = start + self.offset as usize;
let reloc_addend = self.addend as isize;
let reloc_delta_u32 = target_func_address

View File

@ -85,7 +85,8 @@ where
) -> Result<Box<dyn VirtualFile + Send + Sync>, FsError> {
match get_volume_name_opt(path) {
Some(volume) => {
let file = (*self.webc)
let file = self
.webc
.volumes
.get(&volume)
.ok_or(FsError::EntryNotFound)?

View File

@ -63,12 +63,18 @@ wcgi-host = { version = "0.1.0", optional = true }
tower-http = { version = "0.4.0", features = ["trace", "util", "catch-panic", "cors"], optional = true }
tower = { version = "0.4.13", features = ["make", "util"], optional = true }
[dependencies.reqwest]
[target.'cfg(not(target_arch = "riscv64"))'.dependencies.reqwest]
version = "0.11"
default-features = false
features = ["rustls-tls", "json"]
optional = true
[target.'cfg(target_arch = "riscv64")'.dependencies.reqwest]
version = "0.11"
default-features = false
features = ["native-tls", "json"]
optional = true
[target.'cfg(unix)'.dependencies]
libc = { version = "^0.2", default-features = false }
termios = { version = "0.3" }

View File

@ -258,6 +258,7 @@ impl WasiRuntimeError {
}
}
#[allow(clippy::result_large_err)]
pub(crate) fn run_wasi_func(
func: &wasmer::Function,
store: &mut impl AsStoreMut,
@ -279,6 +280,7 @@ pub(crate) fn run_wasi_func(
/// The function will not receive arguments or return values.
///
/// An exit code that is not 0 will be returned as a `WasiError::Exit`.
#[allow(clippy::result_large_err)]
pub(crate) fn run_wasi_func_start(
func: &wasmer::Function,
store: &mut impl AsStoreMut,

View File

@ -764,6 +764,7 @@ impl WasiEnvBuilder {
Ok(init)
}
#[allow(clippy::result_large_err)]
pub fn build(self) -> Result<WasiEnv, WasiRuntimeError> {
let init = self.build_init()?;
WasiEnv::from_init(init)
@ -774,6 +775,7 @@ impl WasiEnvBuilder {
/// NOTE: you still must call [`WasiFunctionEnv::initialize`] to make an
/// instance usable.
#[doc(hidden)]
#[allow(clippy::result_large_err)]
pub fn finalize(
self,
store: &mut impl AsStoreMut,
@ -789,6 +791,7 @@ impl WasiEnvBuilder {
///
/// Returns the error from `WasiFs::new` if there's an error
// FIXME: use a proper custom error type
#[allow(clippy::result_large_err)]
pub fn instantiate(
self,
module: Module,
@ -798,11 +801,13 @@ impl WasiEnvBuilder {
WasiEnv::instantiate(init, module, store)
}
#[allow(clippy::result_large_err)]
pub fn run(self, module: Module) -> Result<(), WasiRuntimeError> {
let mut store = wasmer::Store::default();
self.run_with_store(module, &mut store)
}
#[allow(clippy::result_large_err)]
pub fn run_with_store(
self,
module: Module,

View File

@ -375,6 +375,7 @@ impl WasiEnv {
self.thread.tid()
}
#[allow(clippy::result_large_err)]
pub(crate) fn from_init(init: WasiEnvInit) -> Result<Self, WasiRuntimeError> {
let process = if let Some(p) = init.process {
p
@ -415,6 +416,7 @@ impl WasiEnv {
}
// FIXME: use custom error type
#[allow(clippy::result_large_err)]
pub(crate) fn instantiate(
mut init: WasiEnvInit,
module: Module,

View File

@ -18,5 +18,5 @@ pub fn environ_get<M: MemorySize>(
let env = ctx.data();
let (memory, mut state) = env.get_memory_and_wasi_state(&ctx, 0);
write_buffer_array(&memory, &*state.envs, environ, environ_buf)
write_buffer_array(&memory, &state.envs, environ, environ_buf)
}

View File

@ -121,7 +121,7 @@ pub fn path_rename<M: MemorySize>(
// implements the logic of "I'm not actually a file, I'll try to be as needed".
let result = if let Some(h) = handle {
drop(guard);
state.fs_rename(&source_path, &host_adjusted_target_path)
state.fs_rename(source_path, &host_adjusted_target_path)
} else {
let path_clone = path.clone();
drop(guard);

View File

@ -1 +1 @@
1.64
1.65

View File

@ -8,6 +8,7 @@ singlepass spec::simd # Singlepass doesn't support yet SIMD (no one asked for th
singlepass+aarch64+macos traps::test_trap_trace
cranelift+aarch64+macos traps::test_trap_trace
llvm+aarch64 traps::test_trap_trace
llvm+riscv64 traps::test_trap_trace
singlepass+aarch64+macos traps::test_trap_stack_overflow # Need to investigate
singlepass+aarch64+macos traps::trap_display_pretty
llvm traps::trap_display_pretty
@ -28,6 +29,34 @@ cranelift+aarch64+macos traps::start_trap_pretty
# https://github.com/wasmerio/wasmer/issues/2808
cranelift+aarch64 spec::skip_stack_guard_page
llvm+aarch64 spec::skip_stack_guard_page
cranelift+riscv64 spec::skip_stack_guard_page
llvm+riscv64 spec::skip_stack_guard_page
# riscv support is still early, function call ABI needs some work
llvm+riscv64 static_function::llvm::universal
llvm+riscv64 static_function_with_env::llvm::universal
llvm+riscv64 static_function_with_results::llvm::universal
llvm+riscv64 spec::f32::llvm::universal
llvm+riscv64 spec::f64::llvm::universal
llvm+riscv64 spec::float_misc::llvm::universal
llvm+riscv64 spec::memory_copy::llvm::universal
llvm+riscv64 spec::memory_init::llvm::universal
llvm+riscv64 spec::memory_trap::llvm::universal
llvm+riscv64 spec::multi_value::binary::llvm::universal
llvm+riscv64 spec::multi_value::block::llvm::universal
llvm+riscv64 spec::simd::simd_align::llvm::universal
llvm+riscv64 spec::simd::simd_f32x4_rounding::llvm::universal
llvm+riscv64 spec::simd::simd_f64x2_rounding::llvm::universal
llvm+riscv64 wasmer::nan_canonicalization::llvm::universal
llvm+riscv64 wasmer::stack_overflow_sret::llvm::universal
# riscv support on Cranelift is also very young
cranelift+riscv64 spec::align::cranelift::universal
cranelift+riscv64 spec::memory_copy::cranelift::universal
cranelift+riscv64 spec::memory_trap::cranelift::universal
cranelift+riscv64 spec::r#if::cranelift::universal
# no SIMD on riscv, Cranelift will not handle them
cranelift+riscv64 spec::simd
# Windows doesn't overcommit and fails to allocate 4GB of memory
windows wasmer::max_size_of_memory

View File

@ -111,7 +111,7 @@ impl Ignores {
target_env = Some(alias.to_string());
}
// Chipset architectures
"aarch64" | "x86" | "x64" => {
"aarch64" | "x86" | "x64" | "riscv64" => {
arch = Some(alias.to_string());
}
// Engines

View File

@ -437,7 +437,7 @@ impl Wast {
// Checks if the `assert_unlinkable` message matches the expected one
fn matches_message_assert_unlinkable(expected: &str, actual: &str) -> bool {
actual.contains(&expected)
actual.contains(expected)
}
// Checks if the `assert_invalid` message matches the expected one