зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1517752: Update to Cranelift 0.26; r=sunfish
This commit is contained in:
Родитель
67343a1ac8
Коммит
1542471486
|
@ -161,8 +161,8 @@ name = "baldrdash"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen 0.43.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-wasm 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-wasm 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -352,6 +352,11 @@ dependencies = [
|
|||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.23"
|
||||
|
@ -480,20 +485,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-bforest 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen-meta 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-bforest 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen-meta 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -502,35 +507,36 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cranelift-codegen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-frontend 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cranelift-frontend 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3199,6 +3205,7 @@ dependencies = [
|
|||
"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8"
|
||||
"checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
|
||||
"checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cc 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "c37f0efaa4b9b001fa6f02d4b644dee4af97d3414df07c51e3e4f015f3a3e131"
|
||||
"checksum cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc0086be9ca82f7fc89fc873435531cb898b86e850005850de1f820e2db6e9b"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
|
@ -3214,12 +3221,12 @@ dependencies = [
|
|||
"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
|
||||
"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
|
||||
"checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
|
||||
"checksum cranelift-bforest 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b2d527b241af388ff017d72f2b0b323929a70cf97342c6ec1534e3b0f4dfaa0"
|
||||
"checksum cranelift-codegen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e92fa0fa287cf00a6739c46aba114957e0a8eeeb4f0d1aa65d6ed0699c34ca6b"
|
||||
"checksum cranelift-codegen-meta 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "963262697a05d9aa63ca40f4670a7243e4525f4a098e10d654c3f5143fcef686"
|
||||
"checksum cranelift-entity 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc9a0329208e5e0d7d4d6e64cd50985d4c4cbfdbeeb594ae2157a094b98e8dcc"
|
||||
"checksum cranelift-frontend 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98d9eb4a2343435d520499236c805725c88d6d55eefb9a6ad0819b7970c76bdd"
|
||||
"checksum cranelift-wasm 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5022a3a3d1044fdc8c97909b5e8d701884982dcfb43885034d004cfdd9b7d577"
|
||||
"checksum cranelift-bforest 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40f8ff24e9a6c89b8a846b14df9a34d2cac17cea7bdb5c81ed6b4744ee0e38bf"
|
||||
"checksum cranelift-codegen 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "42f5b809bd885c368e01aeec8fe04f21dcb07569834b907d75b4a7bed8d067eb"
|
||||
"checksum cranelift-codegen-meta 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "014c23ed3ebdc8377d41540af638245207dd169f421df042dfccc867465734ed"
|
||||
"checksum cranelift-entity 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4df40e26c0cf7b4d86919cb995bb412ee3001cc18e4f3c83a903f30b7007d8b"
|
||||
"checksum cranelift-frontend 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "789907218eeebebcea8122c2053d71affac91c96ce72cea35ebfdbbf547e82af"
|
||||
"checksum cranelift-wasm 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49723365dab9a48b354bdc24cb6d9d5719bc1d3b858ffd2ea179d0d7d885804a"
|
||||
"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
|
||||
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
|
||||
"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
|
||||
|
|
|
@ -8,10 +8,10 @@ crate-type = ["rlib"]
|
|||
name = "baldrdash"
|
||||
|
||||
[dependencies]
|
||||
cranelift-codegen = "0.25.0"
|
||||
cranelift-wasm = "0.25.0"
|
||||
cranelift-codegen = "0.26.0"
|
||||
cranelift-wasm = "0.26.0"
|
||||
target-lexicon = "0.2.0"
|
||||
log = { version = "0.4.4", default-features = false, features = ["release_max_level_info"] }
|
||||
log = { version = "0.4.5", default-features = false, features = ["release_max_level_info"] }
|
||||
env_logger = "0.5.6"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -48,7 +48,8 @@ fn main() {
|
|||
"-std=gnu++14",
|
||||
"-fno-sized-deallocation",
|
||||
"-DRUST_BINDGEN",
|
||||
]).clang_arg("-I../..");
|
||||
])
|
||||
.clang_arg("-I../..");
|
||||
|
||||
match env::var_os("MOZ_TOPOBJDIR") {
|
||||
Some(path) => {
|
||||
|
|
|
@ -21,11 +21,11 @@ extern crate target_lexicon;
|
|||
extern crate log;
|
||||
extern crate env_logger;
|
||||
|
||||
mod baldrapi; // Low-level C API, ignore this.
|
||||
mod baldrapi; // Low-level C API, ignore this.
|
||||
mod baldrdash; // High-level Rust API, use this.
|
||||
mod compile; // Cranelift function compiler.
|
||||
mod cpu; // CPU detection and `TargetISA` configuration.
|
||||
mod utils; // Helpers for other source files.
|
||||
mod compile; // Cranelift function compiler.
|
||||
mod cpu; // CPU detection and `TargetISA` configuration.
|
||||
mod utils; // Helpers for other source files.
|
||||
mod wasm2clif; // WebAssembly to Cranelift translation callbacks.
|
||||
|
||||
use baldrdash::{CompiledFunc, FuncCompileInput, ModuleEnvironment, StaticEnvironment};
|
||||
|
|
|
@ -62,6 +62,11 @@ fn imm64(offset: usize) -> ir::immediates::Imm64 {
|
|||
(offset as i64).into()
|
||||
}
|
||||
|
||||
/// Convert a usize offset into a `Uimm64`.
|
||||
fn uimm64(offset: usize) -> ir::immediates::Uimm64 {
|
||||
(offset as u64).into()
|
||||
}
|
||||
|
||||
/// Initialize a `Signature` from a wasm signature.
|
||||
fn init_sig_from_wsig(sig: &mut ir::Signature, wsig: bd::FuncTypeWithId) {
|
||||
sig.clear(CallConv::Baldrdash);
|
||||
|
@ -301,7 +306,8 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
|||
base: vmctx,
|
||||
offset: imm64(self.static_env.cxTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
}).into();
|
||||
})
|
||||
.into();
|
||||
}
|
||||
if self.realm_addr.is_none() {
|
||||
let vmctx = self.get_vmctx_gv(&mut pos.func);
|
||||
|
@ -311,7 +317,8 @@ impl<'a, 'b, 'c> TransEnv<'a, 'b, 'c> {
|
|||
base: vmctx,
|
||||
offset: imm64(self.static_env.realmTlsOffset),
|
||||
global_type: native_pointer_type(),
|
||||
}).into();
|
||||
})
|
||||
.into();
|
||||
}
|
||||
|
||||
let ptr = native_pointer_type();
|
||||
|
@ -389,35 +396,31 @@ impl<'a, 'b, 'c> FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
|||
let mut pos = FuncCursor::new(func);
|
||||
pos.next_ebb().expect("empty function");
|
||||
pos.next_inst();
|
||||
GlobalVariable::Const(global.emit_constant(&mut pos))
|
||||
return GlobalVariable::Const(global.emit_constant(&mut pos));
|
||||
}
|
||||
|
||||
// This is a global variable. Here we don't care if it is mutable or not.
|
||||
let vmctx_gv = self.get_vmctx_gv(func);
|
||||
let offset = global.tls_offset();
|
||||
|
||||
// Some globals are represented as a pointer to the actual data, in which case we
|
||||
// must do an extra dereference to get to them.
|
||||
let (base_gv, offset) = if global.is_indirect() {
|
||||
let gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx_gv,
|
||||
offset: offset32(offset),
|
||||
global_type: native_pointer_type(),
|
||||
readonly: false,
|
||||
});
|
||||
(gv, 0.into())
|
||||
} else {
|
||||
// This is a global variable. Here we don't care if it is mutable or not.
|
||||
let offset = global.tls_offset();
|
||||
let mut gv = self.get_vmctx_gv(func);
|
||||
(vmctx_gv, offset32(offset))
|
||||
};
|
||||
|
||||
// Some globals are represented as a pointer to the actual data, in which case we
|
||||
// must do an extra dereference to get to them.
|
||||
if global.is_indirect() {
|
||||
gv = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: gv,
|
||||
offset: offset32(offset),
|
||||
global_type: native_pointer_type(),
|
||||
readonly: false,
|
||||
});
|
||||
} else {
|
||||
gv = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: gv,
|
||||
offset: imm64(offset),
|
||||
global_type: native_pointer_type(),
|
||||
});
|
||||
}
|
||||
|
||||
// Create a Cranelift global variable. We don't need to remember the reference, the
|
||||
// function translator does that for us.
|
||||
GlobalVariable::Memory {
|
||||
gv,
|
||||
ty: global.value_type().into(),
|
||||
}
|
||||
GlobalVariable::Memory {
|
||||
gv: base_gv,
|
||||
ty: global.value_type().into(),
|
||||
offset,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,13 +436,13 @@ impl<'a, 'b, 'c> FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
|||
global_type: native_pointer_type(),
|
||||
readonly: true,
|
||||
});
|
||||
let min_size = ir::immediates::Imm64::new(self.env.min_memory_length());
|
||||
let guard_size = imm64(self.static_env.memoryGuardSize);
|
||||
let min_size = ir::immediates::Uimm64::new(self.env.min_memory_length() as u64);
|
||||
let guard_size = uimm64(self.static_env.memoryGuardSize);
|
||||
|
||||
let bound = self.static_env.staticMemoryBound;
|
||||
let style = if bound > 0 {
|
||||
// We have a static heap.
|
||||
let bound = (bound as i64).into();
|
||||
let bound = (bound as u64).into();
|
||||
ir::HeapStyle::Static { bound }
|
||||
} else {
|
||||
// Get the `TlsData::boundsCheckLimit` field.
|
||||
|
@ -455,7 +458,7 @@ impl<'a, 'b, 'c> FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
|||
func.create_heap(ir::HeapData {
|
||||
base,
|
||||
min_size,
|
||||
guard_size,
|
||||
offset_guard_size: guard_size,
|
||||
style,
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
|
@ -498,9 +501,9 @@ impl<'a, 'b, 'c> FuncEnvironment for TransEnv<'a, 'b, 'c> {
|
|||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv,
|
||||
min_size: ir::immediates::Imm64::new(0),
|
||||
min_size: ir::immediates::Uimm64::new(0),
|
||||
bound_gv,
|
||||
element_size: ir::immediates::Imm64::new(i64::from(self.pointer_bytes()) * 2),
|
||||
element_size: ir::immediates::Uimm64::new(u64::from(self.pointer_bytes()) * 2),
|
||||
index_type: ir::types::I32,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"b24b688b552ea12f4ef03b2c76e17ecfb8c05104d4f494c47b698fd7d94d3e3a","Cargo.toml":"3908d7c2421a4071d3fdd4a7c7a44c1c8779cf9d229cec307fd1a2b96398aa60","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"005b3f9b4687364514bbaea2a25e96d54ce6a59277d157386e8259cbcae8e095","README.md":"006ae145ee89fa14a9d755b206ec2011a3687408e9d5fe3943f2448767b01d62","ci/install.sh":"f3965bda34345579d0799ca2e581efd7ae51f3191aa9203b018f4ade8b986b15","ci/script.sh":"0f8329c7345731c12f35a392e8deeb2e265b75f107c5aca6eed584096896737f","src/lib.rs":"52418274bc4ec5c59dba1885de7324157e677739a2c9624b5d462d5d4c77b5e3","src/test.rs":"58ea38d755d5eae72b1df29fc602483fef888a111bb2e9c3a219e2b2a1ed222f"},"package":"926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"}
|
|
@ -0,0 +1,42 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.2.2] - 2017-05-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- UB in the checked cast from `f32` to `u128`.
|
||||
|
||||
## [v0.2.1] - 2017-05-06
|
||||
|
||||
### Added
|
||||
|
||||
- Support for 128-bit integers, behind the `x128` Cargo feature (nightly
|
||||
needed).
|
||||
|
||||
## [v0.2.0] - 2017-02-08
|
||||
|
||||
### Added
|
||||
|
||||
- Now `cast::Error` implements the `std::error::Error` trait among other traits
|
||||
like `Display`, `Clone`, etc.
|
||||
|
||||
### Changed
|
||||
|
||||
- [breaking-change] This crate now depends on the `std` crate by default but you
|
||||
can make it `no_std` by opting out of the `std` Cargo feature.
|
||||
|
||||
## v0.1.0 - 2016-02-07
|
||||
|
||||
Initial release
|
||||
|
||||
[Unreleased]: https://github.com/japaric/cast.rs/compare/v0.2.2...HEAD
|
||||
[v0.2.2]: https://github.com/japaric/cast.rs/compare/v0.2.1...v0.2.2
|
||||
[v0.2.1]: https://github.com/japaric/cast.rs/compare/v0.2.0...v0.2.1
|
||||
[v0.2.0]: https://github.com/japaric/cast.rs/compare/v0.1.0...v0.2.0
|
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
description = "Ergonomic, checked cast functions for primitive types"
|
||||
documentation = "https://docs.rs/cast"
|
||||
keywords = ["checked", "cast", "primitive", "integer", "float"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "cast"
|
||||
repository = "https://github.com/japaric/cast.rs"
|
||||
version = "0.2.2"
|
||||
|
||||
[features]
|
||||
# Assume we should use `std` unless asked to do otherwise.
|
||||
default = ["std"]
|
||||
# Enable this to get a std::error::Error impl for convenient use with other
|
||||
# libraries.
|
||||
std = []
|
||||
# Enable this for i128/u128 support
|
||||
x128 = []
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.4.1"
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2014-2017 Jorge Aparicio
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,44 @@
|
|||
[![crates.io](https://img.shields.io/crates/d/cast.svg)](https://crates.io/crates/cast)
|
||||
[![crates.io](https://img.shields.io/crates/v/cast.svg)](https://crates.io/crates/cast)
|
||||
|
||||
# `cast`
|
||||
|
||||
> Ergonomic, checked cast functions for primitive types
|
||||
|
||||
``` rust
|
||||
extern crate cast;
|
||||
|
||||
// `u8` and `u16` are checked cast functions, use them to cast from any numeric
|
||||
// primitive to `u8`/`u16` respectively
|
||||
use cast::{u8, u16, Error};
|
||||
|
||||
// Infallible operations, like integer promotion, are equivalent to a normal
|
||||
// cast with `as`
|
||||
assert_eq!(u16(0u8), 0u16);
|
||||
|
||||
// Everything else will return a `Result` depending on the success of the
|
||||
// operation
|
||||
assert_eq!(u8(0u16), Ok(0u8));
|
||||
assert_eq!(u8(256u16), Err(Error::Overflow));
|
||||
assert_eq!(u8(-1i8), Err(Error::Underflow));
|
||||
assert_eq!(u8(1. / 0.), Err(Error::Infinite));
|
||||
assert_eq!(u8(0. / 0.), Err(Error::NaN));
|
||||
```
|
||||
|
||||
## [API docs](https://docs.rs/cast)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
|
@ -0,0 +1,21 @@
|
|||
set -ex
|
||||
|
||||
main() {
|
||||
curl https://sh.rustup.rs -sSf | \
|
||||
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
|
||||
|
||||
local latest=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
|
||||
| cut -d/ -f3 \
|
||||
| grep -E '^v[0-9.]+$' \
|
||||
| sort --version-sort \
|
||||
| tail -n1)
|
||||
|
||||
curl -LSfs https://japaric.github.io/trust/install.sh | \
|
||||
sh -s -- \
|
||||
--force \
|
||||
--git japaric/cross \
|
||||
--tag $latest \
|
||||
--target x86_64-unknown-linux-gnu
|
||||
}
|
||||
|
||||
main
|
|
@ -0,0 +1,14 @@
|
|||
set -ex
|
||||
|
||||
main() {
|
||||
cross test --target $TARGET
|
||||
cross test --target $TARGET --release
|
||||
|
||||
[ "$TRAVIS_RUST_VERSION" -eq "nightly" ] && cross test --feature x128 --target $TARGET
|
||||
[ "$TRAVIS_RUST_VERSION" -eq "nightly" ] && cross test --feature x128 --target $TARGET --release
|
||||
|
||||
cross test --no-default-features --target $TARGET
|
||||
cross test --no-default-features --target $TARGET --release
|
||||
}
|
||||
|
||||
main
|
|
@ -0,0 +1,523 @@
|
|||
//! Ergonomic, checked cast functions for primitive types
|
||||
//!
|
||||
//! This crate provides one checked cast function for each numeric primitive.
|
||||
//! Use these functions to perform a cast from any other numeric primitive:
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate cast;
|
||||
//!
|
||||
//! use cast::{u8, u16, Error};
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! // Infallible operations, like integer promotion, are equivalent to a normal
|
||||
//! // cast with `as`
|
||||
//! assert_eq!(u16(0u8), 0u16);
|
||||
//!
|
||||
//! // Everything else will return a `Result` depending on the success of the
|
||||
//! // operation
|
||||
//! assert_eq!(u8(0u16), Ok(0u8));
|
||||
//! assert_eq!(u8(256u16), Err(Error::Overflow));
|
||||
//! assert_eq!(u8(-1i8), Err(Error::Underflow));
|
||||
//! assert_eq!(u8(1. / 0.), Err(Error::Infinite));
|
||||
//! assert_eq!(u8(0. / 0.), Err(Error::NaN));
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! There are no namespace problems between these functions, the "primitive
|
||||
//! modules" in `core`/`std` and the built-in primitive types, so all them can
|
||||
//! be in the same scope:
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate cast;
|
||||
//!
|
||||
//! use std::u8;
|
||||
//! use cast::{u8, u16};
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! // `u8` as a type
|
||||
//! let x: u8 = 0;
|
||||
//! // `u8` as a module
|
||||
//! let y = u16(u8::MAX);
|
||||
//! // `u8` as a function
|
||||
//! let z = u8(y).unwrap();
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! The checked cast functionality is also usable with type aliases via the
|
||||
//! `cast` static method:
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate cast;
|
||||
//!
|
||||
//! use std::os::raw::c_ulonglong;
|
||||
//! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311
|
||||
//! use cast::From as _0;
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! assert_eq!(c_ulonglong::cast(0u8), 0u64);
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! This crate also provides a `From` trait that can be used, for example,
|
||||
//! to create a generic function that accepts any type that can be infallibly
|
||||
//! casted to `u32`.
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate cast;
|
||||
//!
|
||||
//! fn to_u32<T>(x: T) -> u32
|
||||
//! // reads as: "where u32 can be casted from T with output u32"
|
||||
//! where u32: cast::From<T, Output=u32>,
|
||||
//! {
|
||||
//! cast::u32(x)
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! assert_eq!(to_u32(0u8), 0u32);
|
||||
//! assert_eq!(to_u32(1u16), 1u32);
|
||||
//! assert_eq!(to_u32(2u32), 2u32);
|
||||
//!
|
||||
//! // to_u32(-1i32); // Compile error
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Building without `std`
|
||||
//!
|
||||
//! This crate can be used without Rust's `std` crate by declaring it as
|
||||
//! follows in your `Cargo.toml`:
|
||||
//!
|
||||
//! ``` toml
|
||||
//! cast = { version = "*", default-features = false }
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![allow(const_err)]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#![cfg_attr(feature = "x128", feature(i128_type, i128))]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate quickcheck;
|
||||
|
||||
use core::fmt;
|
||||
#[cfg(feature="std")]
|
||||
use std::error;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// Cast errors
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Error {
|
||||
/// Infinite value casted to a type that can only represent finite values
|
||||
Infinite,
|
||||
/// NaN value casted to a type that can't represent a NaN value
|
||||
NaN,
|
||||
/// Source value is greater than the maximum value that the destination type
|
||||
/// can hold
|
||||
Overflow,
|
||||
/// Source value is smaller than the minimum value that the destination type
|
||||
/// can hold
|
||||
Underflow,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// A private helper function that implements `description`, because
|
||||
/// `description` is only available when we have `std` enabled.
|
||||
fn description_helper(&self) -> &str {
|
||||
match *self {
|
||||
Error::Infinite => "Cannot store infinite value in finite type",
|
||||
Error::NaN => "Cannot store NaN in type which does not support it",
|
||||
Error::Overflow => "Overflow during numeric conversion",
|
||||
Error::Underflow => "Underflow during numeric conversion",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description_helper())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
self.description_helper()
|
||||
}
|
||||
}
|
||||
|
||||
/// The "cast from" operation
|
||||
pub trait From<Src> {
|
||||
/// The result of the cast operation: either `Self` or `Result<Self, Error>`
|
||||
type Output;
|
||||
|
||||
/// Checked cast from `Src` to `Self`
|
||||
fn cast(Src) -> Self::Output;
|
||||
}
|
||||
|
||||
macro_rules! fns {
|
||||
($($ty:ident),+) => {
|
||||
$(
|
||||
/// Checked cast function
|
||||
#[inline]
|
||||
pub fn $ty<T>(x: T) -> <$ty as From<T>>::Output
|
||||
where $ty: From<T>
|
||||
{
|
||||
<$ty as From<T>>::cast(x)
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
|
||||
#[cfg(feature = "x128")]
|
||||
fns!(i128, u128);
|
||||
|
||||
/// `$dst` can hold any value of `$src`
|
||||
macro_rules! promotion {
|
||||
($($src:ty => $($dst: ty),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = $dst;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: $src) -> $dst {
|
||||
src as $dst
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// `$dst` can hold any positive value of `$src`
|
||||
macro_rules! half_promotion {
|
||||
($($src:ty => $($dst:ty),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = Result<$dst, Error>;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: $src) -> Self::Output {
|
||||
if src < 0 {
|
||||
Err(Error::Underflow)
|
||||
} else {
|
||||
Ok(src as $dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// From an unsigned `$src` to a smaller `$dst`
|
||||
macro_rules! from_unsigned {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = Result<$dst, Error>;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: $src) -> Self::Output {
|
||||
use core::$dst;
|
||||
|
||||
if src > $dst::MAX as $src {
|
||||
Err(Error::Overflow)
|
||||
} else {
|
||||
Ok(src as $dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// From a signed `$src` to a smaller `$dst`
|
||||
macro_rules! from_signed {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = Result<$dst, Error>;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: $src) -> Self::Output {
|
||||
use core::$dst;
|
||||
|
||||
Err(if src < $dst::MIN as $src {
|
||||
Error::Underflow
|
||||
} else if src > $dst::MAX as $src {
|
||||
Error::Overflow
|
||||
} else {
|
||||
return Ok(src as $dst);
|
||||
})
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// From a float `$src` to an integer `$dst`
|
||||
macro_rules! from_float {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = Result<$dst, Error>;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: $src) -> Self::Output {
|
||||
use core::{$dst, $src};
|
||||
|
||||
Err(if src != src {
|
||||
Error::NaN
|
||||
} else if src == $src::INFINITY ||
|
||||
src == $src::NEG_INFINITY {
|
||||
Error::Infinite
|
||||
} else if src < $dst::MIN as $src {
|
||||
Error::Underflow
|
||||
} else if src > $dst::MAX as $src {
|
||||
Error::Overflow
|
||||
} else {
|
||||
return Ok(src as $dst);
|
||||
})
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// From a float `$src` to an integer `$dst`, where $dst is large enough to contain
|
||||
/// all values of `$src`. We can't ever overflow here
|
||||
macro_rules! from_float_dst {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
$(
|
||||
$(
|
||||
impl From<$src> for $dst {
|
||||
type Output = Result<$dst, Error>;
|
||||
|
||||
#[inline]
|
||||
#[allow(unused_comparisons)]
|
||||
fn cast(src: $src) -> Self::Output {
|
||||
use core::{$dst, $src};
|
||||
|
||||
Err(if src != src {
|
||||
Error::NaN
|
||||
} else if src == $src::INFINITY ||
|
||||
src == $src::NEG_INFINITY {
|
||||
Error::Infinite
|
||||
} else if ($dst::MIN == 0) && src < 0.0 {
|
||||
Error::Underflow
|
||||
} else {
|
||||
return Ok(src as $dst);
|
||||
})
|
||||
}
|
||||
}
|
||||
)+
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
// PLAY TETRIS! ;-)
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
mod _32 {
|
||||
use {Error, From};
|
||||
|
||||
// Signed
|
||||
promotion! {
|
||||
i8 => f32, f64, i8, i16, i32, isize, i64;
|
||||
i16 => f32, f64, i16, i32, isize, i64;
|
||||
i32 => f32, f64, i32, isize, i64;
|
||||
isize => f32, f64, i32, isize, i64;
|
||||
i64 => f32, f64, i64;
|
||||
}
|
||||
|
||||
half_promotion! {
|
||||
i8 => u8, u16, u32, usize, u64;
|
||||
i16 => u16, u32, usize, u64;
|
||||
i32 => u32, usize, u64;
|
||||
isize => u32, usize, u64;
|
||||
i64 => u64;
|
||||
}
|
||||
|
||||
from_signed! {
|
||||
|
||||
i16 => i8, u8;
|
||||
i32 => i8, i16, u8, u16;
|
||||
isize => i8, i16, u8, u16;
|
||||
i64 => i8, i16, i32, isize, u8, u16, u32, usize;
|
||||
}
|
||||
|
||||
// Unsigned
|
||||
promotion! {
|
||||
u8 => f32, f64, i16, i32, isize, i64, u8, u16, u32, usize, u64;
|
||||
u16 => f32, f64, i32, isize, i64, u16, u32, usize, u64;
|
||||
u32 => f32, f64, i64, u32, usize, u64;
|
||||
usize => f32, f64, i64, u32, usize, u64;
|
||||
u64 => f32, f64, u64;
|
||||
}
|
||||
|
||||
from_unsigned! {
|
||||
u8 => i8;
|
||||
u16 => i8, i16, u8;
|
||||
u32 => i8, i16, i32, isize, u8, u16;
|
||||
usize => i8, i16, i32, isize, u8, u16;
|
||||
u64 => i8, i16, i32, isize, i64, u8, u16, u32, usize;
|
||||
}
|
||||
|
||||
// Float
|
||||
promotion! {
|
||||
f32 => f32, f64;
|
||||
f64 => f64;
|
||||
}
|
||||
|
||||
from_float! {
|
||||
f32 => i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
|
||||
f64 => i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod _64 {
|
||||
use {Error, From};
|
||||
|
||||
// Signed
|
||||
promotion! {
|
||||
i8 => f32, f64, i8, i16, i32, i64, isize;
|
||||
i16 => f32, f64, i16, i32, i64, isize;
|
||||
i32 => f32, f64, i32, i64, isize;
|
||||
i64 => f32, f64, i64, isize;
|
||||
isize => f32, f64, i64, isize;
|
||||
}
|
||||
|
||||
half_promotion! {
|
||||
i8 => u8, u16, u32, u64, usize;
|
||||
i16 => u16, u32, u64, usize;
|
||||
i32 => u32, u64, usize;
|
||||
i64 => u64, usize;
|
||||
isize => u64, usize;
|
||||
}
|
||||
|
||||
from_signed! {
|
||||
|
||||
i16 => i8, u8;
|
||||
i32 => i8, i16, u8, u16;
|
||||
i64 => i8, i16, i32, u8, u16, u32;
|
||||
isize => i8, i16, i32, u8, u16, u32;
|
||||
}
|
||||
|
||||
// Unsigned
|
||||
promotion! {
|
||||
u8 => f32, f64, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
u16 => f32, f64, i32, i64, isize, u16, u32, u64, usize;
|
||||
u32 => f32, f64, i64, isize, u32, u64, usize;
|
||||
u64 => f32, f64, u64, usize;
|
||||
usize => f32, f64, u64, usize;
|
||||
}
|
||||
|
||||
from_unsigned! {
|
||||
u8 => i8;
|
||||
u16 => i8, i16, u8;
|
||||
u32 => i8, i16, i32, u8, u16;
|
||||
u64 => i8, i16, i32, i64, isize, u8, u16, u32;
|
||||
usize => i8, i16, i32, i64, isize, u8, u16, u32;
|
||||
}
|
||||
|
||||
// Float
|
||||
promotion! {
|
||||
f32 => f32, f64;
|
||||
f64 => f64;
|
||||
}
|
||||
|
||||
from_float! {
|
||||
f32 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
f64 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "x128")]
|
||||
mod _x128 {
|
||||
use {Error, From};
|
||||
|
||||
// Signed
|
||||
promotion! {
|
||||
i8 => i128;
|
||||
i16 => i128;
|
||||
i32 => i128;
|
||||
i64 => i128;
|
||||
isize => i128;
|
||||
i128 => f32, f64, i128;
|
||||
}
|
||||
|
||||
half_promotion! {
|
||||
i8 => u128;
|
||||
i16 => u128;
|
||||
i32 => u128;
|
||||
i64 => u128;
|
||||
isize => u128;
|
||||
i128 => u128;
|
||||
}
|
||||
|
||||
from_signed! {
|
||||
i128 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
}
|
||||
|
||||
// Unsigned
|
||||
promotion! {
|
||||
u8 => i128, u128;
|
||||
u16 => i128, u128;
|
||||
u32 => i128, u128;
|
||||
u64 => i128, u128;
|
||||
usize => i128, u128;
|
||||
u128 => f64, u128;
|
||||
}
|
||||
|
||||
from_unsigned! {
|
||||
u128 => f32, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize;
|
||||
}
|
||||
|
||||
// Float
|
||||
from_float! {
|
||||
f32 => i128;
|
||||
f64 => i128, u128;
|
||||
}
|
||||
from_float_dst! {
|
||||
f32 => u128;
|
||||
}
|
||||
}
|
||||
|
||||
// The missing piece
|
||||
impl From<f64> for f32 {
|
||||
type Output = Result<f32, Error>;
|
||||
|
||||
#[inline]
|
||||
fn cast(src: f64) -> Self::Output {
|
||||
use core::{f32, f64};
|
||||
|
||||
if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY {
|
||||
Ok(src as f32)
|
||||
} else if src < f32::MIN as f64 {
|
||||
Err(Error::Underflow)
|
||||
} else if src > f32::MAX as f64 {
|
||||
Err(Error::Overflow)
|
||||
} else {
|
||||
Ok(src as f32)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
// If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to
|
||||
// `$src`
|
||||
macro_rules! promote_and_back {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
mod demoting_to {
|
||||
$(
|
||||
mod $src {
|
||||
mod from {
|
||||
use From;
|
||||
|
||||
$(
|
||||
quickcheck! {
|
||||
fn $dst(src: $src) -> bool {
|
||||
$src::cast($dst::cast(src)).is_ok()
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
promote_and_back! {
|
||||
i8 => f32, f64, i16, i32, isize, i64 ;
|
||||
i16 => f32, f64, i32, isize, i64 ;
|
||||
i32 => f32, f64, i64 ;
|
||||
isize => f32, f64, i64 ;
|
||||
i64 => f32, f64 ;
|
||||
u8 => f32, f64, i16, i32, isize, i64, u16, u32, usize, u64;
|
||||
u16 => f32, f64, i32, isize, i64, u32, usize, u64;
|
||||
u32 => f32, f64, i64, u64;
|
||||
usize => f32, f64, i64, u64;
|
||||
u64 => f32, f64 ;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
promote_and_back! {
|
||||
i8 => f32, f64, i16, i32, i64, isize ;
|
||||
i16 => f32, f64, i32, i64, isize ;
|
||||
i32 => f32, f64, i64, isize ;
|
||||
i64 => f32, f64 ;
|
||||
isize => f32, f64 ;
|
||||
u8 => f32, f64, i16, i32, i64, isize, u16, u32, u64, usize;
|
||||
u16 => f32, f64, i32, i64, isize, u32, u64, usize;
|
||||
u32 => f32, f64, i64, isize, u64, usize;
|
||||
u64 => f32, f64 ;
|
||||
usize => f32, f64 ;
|
||||
}
|
||||
|
||||
// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
|
||||
// https://github.com/BurntSushi/quickcheck/issues/162
|
||||
/*#[cfg(feature = "x128")]
|
||||
promote_and_back! {
|
||||
i8 => i128 ;
|
||||
i16 => i128 ;
|
||||
i32 => i128 ;
|
||||
isize => i128 ;
|
||||
i64 => i128 ;
|
||||
i128 => f32, f64 ;
|
||||
u8 => i128, u128;
|
||||
u16 => i128, u128;
|
||||
u32 => i128, u128;
|
||||
usize => i128, u128;
|
||||
u64 => i128, u128;
|
||||
u128 => f32, f64 ;
|
||||
}*/
|
||||
|
||||
// If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
|
||||
// `$src`
|
||||
macro_rules! symmetric_cast_between {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
mod symmetric_cast_between {
|
||||
$(
|
||||
mod $src {
|
||||
mod and {
|
||||
use quickcheck::TestResult;
|
||||
|
||||
use From;
|
||||
|
||||
$(
|
||||
quickcheck! {
|
||||
fn $dst(src: $src) -> TestResult {
|
||||
if let Ok(dst) = $dst::cast(src) {
|
||||
TestResult::from_bool(
|
||||
$src::cast(dst).is_ok())
|
||||
} else {
|
||||
TestResult::discard()
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
symmetric_cast_between! {
|
||||
u8 => i8 ;
|
||||
u16 => i8, i16 ;
|
||||
u32 => i8, i16, i32 ;
|
||||
usize => i8, i16, i32 ;
|
||||
u64 => i8, i16, i32, i64, isize;
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
symmetric_cast_between! {
|
||||
u8 => i8 ;
|
||||
u16 => i8, i16 ;
|
||||
u32 => i8, i16, i32 ;
|
||||
u64 => i8, i16, i32, i64, isize;
|
||||
usize => i8, i16, i32, i64, isize;
|
||||
}
|
||||
|
||||
// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
|
||||
// https://github.com/BurntSushi/quickcheck/issues/162
|
||||
/*#[cfg(feature = "x128")]
|
||||
symmetric_cast_between! {
|
||||
u128 => i8, i16, i32, isize, i64, i128;
|
||||
}*/
|
||||
|
||||
macro_rules! from_float {
|
||||
($($src:ident => $($dst:ident),+);+;) => {
|
||||
$(
|
||||
mod $src {
|
||||
mod inf {
|
||||
mod to {
|
||||
use {Error, From};
|
||||
|
||||
$(
|
||||
#[test]
|
||||
fn $dst() {
|
||||
let _0: $src = 0.;
|
||||
let _1: $src = 1.;
|
||||
let inf = _1 / _0;
|
||||
let neg_inf = -_1 / _0;
|
||||
|
||||
assert_eq!($dst::cast(inf),
|
||||
Err(Error::Infinite));
|
||||
assert_eq!($dst::cast(neg_inf),
|
||||
Err(Error::Infinite));
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
mod nan {
|
||||
mod to {
|
||||
use {Error, From};
|
||||
|
||||
$(
|
||||
#[test]
|
||||
fn $dst() {
|
||||
let _0: $src = 0.;
|
||||
let nan = _0 / _0;
|
||||
|
||||
assert_eq!($dst::cast(nan),
|
||||
Err(Error::NaN));
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
from_float! {
|
||||
f32 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
f64 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
|
||||
}
|
||||
|
||||
// TODO uncomment this once quickcheck supports Arbitrary for i128/u128
|
||||
// https://github.com/BurntSushi/quickcheck/issues/162
|
||||
/*#[cfg(feature = "x128")]
|
||||
from_float! {
|
||||
f32 => i128, u128;
|
||||
f64 => i128, u128;
|
||||
}*/
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "x128")]
|
||||
fn test_fl_conversion() {
|
||||
use u128;
|
||||
assert_eq!(u128(42.0f32), Ok(42));
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"8c219cb955621bfeb89eb1175dc9d810dc98323ccb54360e623425308c970e72","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"01f8c9b8a077975c8f0803f793b8c20b583aaef2dc1f4400b9d90ba132ff4133","src/map.rs":"77eb9fd2ffdaafaf4daea609602a0c775c5012efae21c03547f63653271da163","src/node.rs":"309609acc70f1ce6be2f3c964430d23c0680bd7a647afab837a2aedc06235531","src/path.rs":"25326bacbb99189e873cb70e770f21c13fdef0fb2cd20f484830386fc4c75c6a","src/pool.rs":"196216124922dc42708a3aa944e98b6a57ef9bb770dab7e01f154b6382cab021","src/set.rs":"d4ff99fe51de9eefb4c774e919259d952ab5dde4dd3b99bd9974e4eedbb28938"},"package":"7b2d527b241af388ff017d72f2b0b323929a70cf97342c6ec1534e3b0f4dfaa0"}
|
||||
{"files":{"Cargo.toml":"591c2da0dad7eafa9aff626400b38e0b08927df674292ca6774f60e2bc02ac32","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"af367c67340fa7f6fb9a35b0aa637dcf303957f7ae7427a5f4f6356801c8bb04","src/lib.rs":"eb691a3bc63c3ed8a64d564cf656fdc56c62ade8b7882efd7b987353acc627bd","src/map.rs":"77eb9fd2ffdaafaf4daea609602a0c775c5012efae21c03547f63653271da163","src/node.rs":"309609acc70f1ce6be2f3c964430d23c0680bd7a647afab837a2aedc06235531","src/path.rs":"25326bacbb99189e873cb70e770f21c13fdef0fb2cd20f484830386fc4c75c6a","src/pool.rs":"196216124922dc42708a3aa944e98b6a57ef9bb770dab7e01f154b6382cab021","src/set.rs":"d4ff99fe51de9eefb4c774e919259d952ab5dde4dd3b99bd9974e4eedbb28938"},"package":"40f8ff24e9a6c89b8a846b14df9a34d2cac17cea7bdb5c81ed6b4744ee0e38bf"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "A forest of B+-trees"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
@ -22,7 +22,7 @@ categories = ["no-std"]
|
|||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
|
|
|
@ -16,10 +16,7 @@
|
|||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "std", warn(unstable_features))]
|
||||
#![cfg_attr(
|
||||
feature = "clippy",
|
||||
plugin(clippy(conf_file = "../../clippy.toml"))
|
||||
)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(new_without_default, new_without_default_derive)
|
||||
|
@ -27,14 +24,14 @@
|
|||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
float_arithmetic,
|
||||
mut_mut,
|
||||
nonminimal_bool,
|
||||
option_map_unwrap_or,
|
||||
option_map_unwrap_or_else,
|
||||
print_stdout,
|
||||
unicode_not_nfc,
|
||||
use_self
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
// Turns on no_std and alloc features if std is not available.
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"0e4050095c283d025e30ccba0e3d9753b63340604b6373e4ea06d221eb3a97e1","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/base/mod.rs":"9320dfed2250bdb0347e01862b2ff7bf7db78920dae1719834b374de11131e87","src/base/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/cdsl/isa.rs":"b34150e2658dd7ab30e9846dece89f56a0acbfff0341927cec06bf0de1d9b419","src/cdsl/mod.rs":"311726d7e4ad9278eab301fd4f6e31e697b7d4260733c6a00fe39cd61db977d3","src/cdsl/regs.rs":"41cca844b390bba3ceefa147e7b0dec170aba2b5759a41ecb5b9cd7f2cc59f60","src/cdsl/types.rs":"f9756e483329f00a1d8a15e30bc05e8d4c8fa71ff1f649b808528ddeb5fbdfea","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_registers.rs":"3d38ff5b0c6183209d4ba84bd1f14b1d84bea697c0589471aa5ce4abc209f20b","src/gen_types.rs":"5eb4e9bd0fda7f7644bb2428045f0bf16f2b698ff32cadcbbf7f2c7669f18de3","src/isa/arm32/mod.rs":"ceb8290344a245f11eb541d60c2678ddfe7beaf60cde491c22fd48090fa210ba","src/isa/arm64/mod.rs":"db7f828940372a21c62cf6f5aefca7cc05c974ba731b8db602da0a336e29ea1e","src/isa/mod.rs":"36c001f8ecdea4aaf8cadcad4f91fe79a82806e4f43182e216c2fa99cecf55dc","src/isa/riscv/mod.rs":"aecb127f8c06970a00dde8ad772fdebe5497b6e7f342fa2a0e859355ae027055","src/isa/x86/mod.rs":"2b3a181a226d66a8faf855d517fb4a13554a31020f6b8875ba75a2fe650f378a","src/lib.rs":"dd97d73d41ffee2d2cc62705f9f6f7ed6b9af982aff8d1fafb72590e097c513c","src/srcgen.rs":"abe118fb41a643ffc63577cc4b62de9a2286e1eeb34b95bff79648d0ea582886"},"package":"963262697a05d9aa63ca40f4670a7243e4525f4a098e10d654c3f5143fcef686"}
|
||||
{"files":{"Cargo.toml":"cdd4cff2d17ca34e3305e9fcf1e8277b0e9987e7369ce70da597e3957e56e408","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"b123f056d0d458396679c5f7f2a16d2762af0258fcda4ac14b6655a95e5a0022","src/base/mod.rs":"559075f0b76a744dd36224e06ff1c2e28ee70aaca9442fc724b116e37028ac52","src/base/settings.rs":"9cbe9bdd5141b9175074370a9b1d28f371249d586e999a31f76631739bf09c13","src/base/types.rs":"a3e449db1f515d268f3ad21301740ba415444d399f8433dbc48979f78557f66a","src/cdsl/isa.rs":"5c9a8173466e69d105245396abd342251eb00e704ab13f179ba1567b339f47e1","src/cdsl/mod.rs":"66ac1b5d095e431bcab88c4b9c5b1492a5d1ca87bcb9c9c3e544ede05b2ba925","src/cdsl/regs.rs":"41cca844b390bba3ceefa147e7b0dec170aba2b5759a41ecb5b9cd7f2cc59f60","src/cdsl/settings.rs":"724a4bd7cfd0608cfc8751ee7c38dbed90b91cfafd34585ed7df953807932794","src/cdsl/types.rs":"78f476f5f700697b94f2d2f00049af8684d3b27afc5684b2c87ea517aeb77e85","src/constant_hash.rs":"6522f86ebfd44efe9b47256d822d0e49d641ccdbb4fcc61d57bb94e6d52702c1","src/error.rs":"5110a4e3c1e97396ba02d9f5abbb8af4b586f0cc4d33a5c2473f1718cc4bef05","src/gen_registers.rs":"9bd381da256c19724964c6445db4fbac80d91174266dccfc5d3b72497a5332c9","src/gen_settings.rs":"a827a90cc1db7345e8081635169b77be497494e558c6e985eaa654386d5e8e48","src/gen_types.rs":"5eb4e9bd0fda7f7644bb2428045f0bf16f2b698ff32cadcbbf7f2c7669f18de3","src/isa/arm32/mod.rs":"b4049ff95164bbf244b6727e16974383e4d58c5be750f7ded3ef8cfe113e5373","src/isa/arm64/mod.rs":"759adfd4dd5c885644de26386797211efc82c5b47f2e147a58d57d24608b9cfb","src/isa/mod.rs":"d3a87bc45173f3743f25d3a004a9b40966c12feb7d95d794b5918bb9ccb988ac","src/isa/riscv/mod.rs":"6e3d96c48e9c289a13912d7f777bde805be327e4a56677d3f3bccf440ae4a09b","src/isa/x86/mod.rs":"e38c60a9d1aba3e5a48052c6185bab3f2b039e9cce639826becfe9f853c41499","src/lib.rs":"c4bfd9d2973e4a382f7a1ce8389cc1604aeba8478432a542ff3f1c24412c5b41","src/srcgen.rs":"e358b6232f0820e6e4525cdbe216206996ae5eb16a1df7a5fe41e3ce2e25b633","src/unique_table.rs":"f6041df1fa85f2a1ee914b84791e80165a0858a6253c212eaa99ff67cb56af26"},"package":"014c23ed3ebdc8377d41540af638245207dd169f421df042dfccc867465734ed"}
|
|
@ -12,14 +12,14 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Metaprogram for cranelift-codegen code generator library"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
[badges.maintenance]
|
||||
status = "experimental"
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//! Definitions for the base Cranelift language.
|
||||
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn generate() -> SettingGroup {
|
||||
let mut settings = SettingGroupBuilder::new("shared");
|
||||
|
||||
settings.add_enum(
|
||||
"opt_level",
|
||||
r#"
|
||||
Optimization level:
|
||||
|
||||
- default: Very profitable optimizations enabled, none slow.
|
||||
- best: Enable all optimizations
|
||||
- fastest: Optimize for compile time by disabling most optimizations.
|
||||
"#,
|
||||
vec!["default", "best", "fastest"],
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"enable_verifier",
|
||||
r#"
|
||||
Run the Cranelift IR verifier at strategic times during compilation.
|
||||
|
||||
This makes compilation slower but catches many bugs. The verifier is
|
||||
disabled by default, except when reading Cranelift IR from a text file.
|
||||
"#,
|
||||
true,
|
||||
);
|
||||
|
||||
// Note that Cranelift doesn't currently need an is_pie flag, because PIE is
|
||||
// just PIC where symbols can't be pre-empted, which can be expressed with the
|
||||
// `colocated` flag on external functions and global values.
|
||||
settings.add_bool(
|
||||
"is_pic",
|
||||
"Enable Position-Independent Code generation",
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"colocated_libcalls",
|
||||
r#"
|
||||
Use colocated libcalls.
|
||||
|
||||
Generate code that assumes that libcalls can be declared "colocated",
|
||||
meaning they will be defined along with the current function, such that
|
||||
they can use more efficient addressing.
|
||||
"#,
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"avoid_div_traps",
|
||||
r#"
|
||||
Generate explicit checks around native division instructions to avoid
|
||||
their trapping.
|
||||
|
||||
This is primarily used by SpiderMonkey which doesn't install a signal
|
||||
handler for SIGFPE, but expects a SIGILL trap for division by zero.
|
||||
|
||||
On ISAs like ARM where the native division instructions don't trap,
|
||||
this setting has no effect - explicit checks are always inserted.
|
||||
"#,
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"enable_float",
|
||||
r#"
|
||||
Enable the use of floating-point instructions
|
||||
|
||||
Disabling use of floating-point instructions is not yet implemented.
|
||||
"#,
|
||||
true,
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"enable_nan_canonicalization",
|
||||
r#"
|
||||
Enable NaN canonicalization
|
||||
|
||||
This replaces NaNs with a single canonical value, for users requiring
|
||||
entirely deterministic WebAssembly computation. This is not required
|
||||
by the WebAssembly spec, so it is not enabled by default.
|
||||
"#,
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_bool("enable_simd", "Enable the use of SIMD instructions.", true);
|
||||
|
||||
settings.add_bool(
|
||||
"enable_atomics",
|
||||
"Enable the use of atomic instructions",
|
||||
true,
|
||||
);
|
||||
|
||||
// Settings specific to the `baldrdash` calling convention.
|
||||
|
||||
settings.add_num(
|
||||
"baldrdash_prologue_words",
|
||||
r#"
|
||||
Number of pointer-sized words pushed by the baldrdash prologue.
|
||||
|
||||
Functions with the `baldrdash` calling convention don't generate their
|
||||
own prologue and epilogue. They depend on externally generated code
|
||||
that pushes a fixed number of words in the prologue and restores them
|
||||
in the epilogue.
|
||||
|
||||
This setting configures the number of pointer-sized words pushed on the
|
||||
stack when the Cranelift-generated code is entered. This includes the
|
||||
pushed return address on x86.
|
||||
"#,
|
||||
0,
|
||||
);
|
||||
|
||||
// BaldrMonkey requires that not-yet-relocated function addresses be encoded
|
||||
// as all-ones bitpatterns.
|
||||
settings.add_bool(
|
||||
"allones_funcaddrs",
|
||||
"Emit not-yet-relocated function addresses as all-ones bit patterns.",
|
||||
false,
|
||||
);
|
||||
|
||||
// Stack probing options.
|
||||
|
||||
settings.add_bool(
|
||||
"probestack_enabled",
|
||||
r#"
|
||||
Enable the use of stack probes, for calling conventions which support this
|
||||
functionality.
|
||||
"#,
|
||||
true,
|
||||
);
|
||||
|
||||
settings.add_bool(
|
||||
"probestack_func_adjusts_sp",
|
||||
r#"
|
||||
Set this to true of the stack probe function modifies the stack pointer
|
||||
itself.
|
||||
"#,
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_num(
|
||||
"probestack_size_log2",
|
||||
r#"
|
||||
The log2 of the size of the stack guard region.
|
||||
|
||||
Stack frames larger than this size will have stack overflow checked
|
||||
by calling the probestack function.
|
||||
|
||||
The default is 12, which translates to a size of 4096.
|
||||
"#,
|
||||
12,
|
||||
);
|
||||
|
||||
// Jump table options.
|
||||
|
||||
settings.add_bool(
|
||||
"jump_tables_enabled",
|
||||
"Enable the use of jump tables in generated machine code.",
|
||||
true,
|
||||
);
|
||||
|
||||
settings.finish()
|
||||
}
|
|
@ -3,19 +3,22 @@ use cranelift_entity::PrimaryMap;
|
|||
use super::regs::{
|
||||
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex, RegClassProto,
|
||||
};
|
||||
use super::settings::SettingGroup;
|
||||
|
||||
pub struct TargetIsa {
|
||||
pub name: &'static str,
|
||||
pub reg_banks: PrimaryMap<RegBankIndex, RegBank>,
|
||||
pub reg_classes: PrimaryMap<RegClassIndex, RegClass>,
|
||||
pub settings: SettingGroup,
|
||||
}
|
||||
|
||||
impl TargetIsa {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||
Self {
|
||||
name,
|
||||
reg_banks: PrimaryMap::new(),
|
||||
reg_classes: PrimaryMap::new(),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +28,9 @@ pub struct TargetIsaBuilder {
|
|||
}
|
||||
|
||||
impl TargetIsaBuilder {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||
Self {
|
||||
isa: TargetIsa::new(name),
|
||||
isa: TargetIsa::new(name, settings),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,16 +153,15 @@ impl TargetIsaBuilder {
|
|||
|
||||
// If the intersection is the second one, then it must be a subclass.
|
||||
if intersect == rc2_mask {
|
||||
assert!(
|
||||
self.isa
|
||||
.reg_classes
|
||||
.get(*i1)
|
||||
.unwrap()
|
||||
.subclasses
|
||||
.iter()
|
||||
.find(|x| **x == *i2)
|
||||
.is_some()
|
||||
);
|
||||
assert!(self
|
||||
.isa
|
||||
.reg_classes
|
||||
.get(*i1)
|
||||
.unwrap()
|
||||
.subclasses
|
||||
.iter()
|
||||
.find(|x| **x == *i2)
|
||||
.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +183,8 @@ impl TargetIsaBuilder {
|
|||
.values()
|
||||
.filter(|x| {
|
||||
x.toprc == x.index && self.isa.reg_banks.get(x.bank).unwrap().pressure_tracking
|
||||
}).count();
|
||||
})
|
||||
.count();
|
||||
assert!(num_toplevel <= 4, "Too many top-level register classes");
|
||||
|
||||
self.isa
|
||||
|
|
|
@ -5,10 +5,38 @@
|
|||
|
||||
pub mod isa;
|
||||
pub mod regs;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
||||
/// A macro that converts boolean settings into predicates to look more natural.
|
||||
#[macro_export]
|
||||
macro_rules! predicate {
|
||||
($a:ident && $($b:tt)*) => {
|
||||
PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*)))
|
||||
};
|
||||
($a:ident) => {
|
||||
$a.into()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! preset {
|
||||
() => {
|
||||
vec![]
|
||||
};
|
||||
($($x:ident)&&*) => {
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
$(
|
||||
v.push($x.into());
|
||||
)*
|
||||
v
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert the string `s` to CamelCase.
|
||||
fn _camel_case(s: &str) -> String {
|
||||
pub fn camel_case(s: &str) -> String {
|
||||
let mut output_chars = String::with_capacity(s.len());
|
||||
|
||||
let mut capitalize = true;
|
||||
|
@ -30,7 +58,7 @@ fn _camel_case(s: &str) -> String {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::_camel_case as camel_case;
|
||||
use super::camel_case;
|
||||
|
||||
#[test]
|
||||
fn camel_case_works() {
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct BoolSettingIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct BoolSetting {
|
||||
pub default: bool,
|
||||
pub bit_offset: u8,
|
||||
pub predicate_number: u8,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum SpecificSetting {
|
||||
Bool(BoolSetting),
|
||||
Enum(Vec<&'static str>),
|
||||
Num(u8),
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct Setting {
|
||||
pub name: &'static str,
|
||||
pub comment: &'static str,
|
||||
pub specific: SpecificSetting,
|
||||
pub byte_offset: u8,
|
||||
}
|
||||
|
||||
impl Setting {
|
||||
pub fn default_byte(&self) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting {
|
||||
default,
|
||||
bit_offset,
|
||||
..
|
||||
}) => {
|
||||
if default {
|
||||
1 << bit_offset
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
SpecificSetting::Enum(_) => 0,
|
||||
SpecificSetting::Num(default) => default,
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_for_value(&self, v: bool) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
|
||||
if v {
|
||||
1 << bit_offset
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_mask(&self) -> u8 {
|
||||
match self.specific {
|
||||
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset,
|
||||
_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct PresetIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum PresetType {
|
||||
BoolSetting(BoolSettingIndex),
|
||||
OtherPreset(PresetIndex),
|
||||
}
|
||||
|
||||
impl Into<PresetType> for BoolSettingIndex {
|
||||
fn into(self) -> PresetType {
|
||||
PresetType::BoolSetting(self)
|
||||
}
|
||||
}
|
||||
impl Into<PresetType> for PresetIndex {
|
||||
fn into(self) -> PresetType {
|
||||
PresetType::OtherPreset(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct Preset {
|
||||
pub name: &'static str,
|
||||
values: Vec<BoolSettingIndex>,
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> {
|
||||
let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0))
|
||||
.take(group.settings_size as usize)
|
||||
.collect();
|
||||
for bool_index in &self.values {
|
||||
let setting = &group.settings[bool_index.0];
|
||||
let mask = setting.byte_mask();
|
||||
let val = setting.byte_for_value(true);
|
||||
assert!((val & !mask) == 0);
|
||||
let (l_mask, l_val) = layout.get_mut(setting.byte_offset as usize).unwrap();
|
||||
*l_mask |= mask;
|
||||
*l_val = (*l_val & !mask) | val;
|
||||
}
|
||||
layout
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingGroup {
|
||||
pub name: &'static str,
|
||||
pub settings: Vec<Setting>,
|
||||
pub bool_start_byte_offset: u8,
|
||||
pub settings_size: u8,
|
||||
pub presets: Vec<Preset>,
|
||||
pub predicates: Vec<Predicate>,
|
||||
}
|
||||
|
||||
impl SettingGroup {
|
||||
fn num_bool_settings(&self) -> u8 {
|
||||
self.settings
|
||||
.iter()
|
||||
.filter(|s| {
|
||||
if let SpecificSetting::Bool(_) = s.specific {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.count() as u8
|
||||
}
|
||||
|
||||
pub fn byte_size(&self) -> u8 {
|
||||
let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8);
|
||||
self.bool_start_byte_offset + (num_predicates + 7) / 8
|
||||
}
|
||||
|
||||
pub fn get_bool(&self, name: &'static str) -> (BoolSettingIndex, &Self) {
|
||||
for (i, s) in self.settings.iter().enumerate() {
|
||||
if let SpecificSetting::Bool(_) = s.specific {
|
||||
if s.name == name {
|
||||
return (BoolSettingIndex(i), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("Should have found bool setting by name.");
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the basic information needed to track the specific parts of a setting when building
|
||||
/// them.
|
||||
pub enum ProtoSpecificSetting {
|
||||
Bool(bool, u8),
|
||||
Enum(Vec<&'static str>),
|
||||
Num(u8),
|
||||
}
|
||||
|
||||
/// This is the information provided during building for a setting.
|
||||
struct ProtoSetting {
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
specific: ProtoSpecificSetting,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum PredicateNode {
|
||||
OwnedBool(BoolSettingIndex),
|
||||
SharedBool(&'static str, &'static str),
|
||||
And(Box<PredicateNode>, Box<PredicateNode>),
|
||||
}
|
||||
|
||||
impl Into<PredicateNode> for BoolSettingIndex {
|
||||
fn into(self) -> PredicateNode {
|
||||
PredicateNode::OwnedBool(self)
|
||||
}
|
||||
}
|
||||
impl<'a> Into<PredicateNode> for (BoolSettingIndex, &'a SettingGroup) {
|
||||
fn into(self) -> PredicateNode {
|
||||
let (index, group) = (self.0, self.1);
|
||||
let setting = &group.settings[index.0];
|
||||
PredicateNode::SharedBool(group.name, setting.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl PredicateNode {
|
||||
fn render(&self, group: &SettingGroup) -> String {
|
||||
match self {
|
||||
PredicateNode::OwnedBool(bool_setting_index) => format!(
|
||||
"{}.{}()",
|
||||
group.name, group.settings[bool_setting_index.0].name
|
||||
),
|
||||
PredicateNode::SharedBool(group_name, bool_name) => {
|
||||
format!("{}.{}()", group_name, bool_name)
|
||||
}
|
||||
PredicateNode::And(lhs, rhs) => {
|
||||
format!("{} && {}", lhs.render(group), rhs.render(group))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Predicate {
|
||||
pub name: &'static str,
|
||||
node: PredicateNode,
|
||||
pub number: u8,
|
||||
}
|
||||
|
||||
impl Predicate {
|
||||
pub fn render(&self, group: &SettingGroup) -> String {
|
||||
self.node.render(group)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingGroupBuilder {
|
||||
name: &'static str,
|
||||
settings: Vec<ProtoSetting>,
|
||||
presets: Vec<Preset>,
|
||||
predicates: Vec<Predicate>,
|
||||
predicate_number: u8,
|
||||
}
|
||||
|
||||
impl SettingGroupBuilder {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
settings: Vec::new(),
|
||||
presets: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
predicate_number: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_setting(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
specific: ProtoSpecificSetting,
|
||||
) {
|
||||
self.settings.push(ProtoSetting {
|
||||
name,
|
||||
comment,
|
||||
specific,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_bool(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
default: bool,
|
||||
) -> BoolSettingIndex {
|
||||
assert!(
|
||||
self.predicates.len() == 0,
|
||||
"predicates must be added after the boolean settings"
|
||||
);
|
||||
let predicate_number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.add_setting(
|
||||
name,
|
||||
comment,
|
||||
ProtoSpecificSetting::Bool(default, predicate_number),
|
||||
);
|
||||
BoolSettingIndex(self.settings.len() - 1)
|
||||
}
|
||||
|
||||
pub fn add_enum(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
comment: &'static str,
|
||||
values: Vec<&'static str>,
|
||||
) {
|
||||
self.add_setting(name, comment, ProtoSpecificSetting::Enum(values));
|
||||
}
|
||||
|
||||
pub fn add_num(&mut self, name: &'static str, comment: &'static str, default: u8) {
|
||||
self.add_setting(name, comment, ProtoSpecificSetting::Num(default));
|
||||
}
|
||||
|
||||
pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {
|
||||
let number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.predicates.push(Predicate { name, node, number });
|
||||
}
|
||||
|
||||
pub fn add_preset(&mut self, name: &'static str, args: Vec<PresetType>) -> PresetIndex {
|
||||
let mut values = Vec::new();
|
||||
for arg in args {
|
||||
match arg {
|
||||
PresetType::OtherPreset(index) => {
|
||||
values.extend(self.presets[index.0].values.iter());
|
||||
}
|
||||
PresetType::BoolSetting(index) => values.push(index),
|
||||
}
|
||||
}
|
||||
self.presets.push(Preset { name, values });
|
||||
PresetIndex(self.presets.len() - 1)
|
||||
}
|
||||
|
||||
/// Compute the layout of the byte vector used to represent this settings
|
||||
/// group.
|
||||
///
|
||||
/// The byte vector contains the following entries in order:
|
||||
///
|
||||
/// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.
|
||||
/// 2. `BoolSetting` settings.
|
||||
/// 3. Precomputed named predicates.
|
||||
/// 4. Other numbered predicates, including anonymous predicates and parent
|
||||
/// predicates that need to be accessible by number.
|
||||
///
|
||||
/// Set `self.settings_size` to the length of the byte vector prefix that
|
||||
/// contains the settings. All bytes after that are computed, not
|
||||
/// configured.
|
||||
///
|
||||
/// Set `self.boolean_offset` to the beginning of the numbered predicates,
|
||||
/// 2. in the list above.
|
||||
///
|
||||
/// Assign `byte_offset` and `bit_offset` fields in all settings.
|
||||
///
|
||||
/// After calling this method, no more settings can be added, but
|
||||
/// additional predicates can be made accessible with `number_predicate()`.
|
||||
pub fn finish(self) -> SettingGroup {
|
||||
let mut group = SettingGroup {
|
||||
name: self.name,
|
||||
settings: Vec::new(),
|
||||
bool_start_byte_offset: 0,
|
||||
settings_size: 0,
|
||||
presets: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
};
|
||||
|
||||
let mut byte_offset = 0;
|
||||
|
||||
// Assign the non-boolean settings first.
|
||||
for s in &self.settings {
|
||||
let specific = match s.specific {
|
||||
ProtoSpecificSetting::Bool(..) => continue,
|
||||
ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),
|
||||
ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),
|
||||
};
|
||||
|
||||
group.settings.push(Setting {
|
||||
name: s.name,
|
||||
comment: s.comment,
|
||||
byte_offset,
|
||||
specific,
|
||||
});
|
||||
|
||||
byte_offset += 1;
|
||||
}
|
||||
|
||||
group.bool_start_byte_offset = byte_offset;
|
||||
|
||||
// Then the boolean settings.
|
||||
for s in &self.settings {
|
||||
let (default, predicate_number) = match s.specific {
|
||||
ProtoSpecificSetting::Bool(default, predicate_number) => {
|
||||
(default, predicate_number)
|
||||
}
|
||||
ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
|
||||
};
|
||||
group.settings.push(Setting {
|
||||
name: s.name,
|
||||
comment: s.comment,
|
||||
byte_offset: byte_offset + predicate_number / 8,
|
||||
specific: SpecificSetting::Bool(BoolSetting {
|
||||
default,
|
||||
bit_offset: predicate_number % 8,
|
||||
predicate_number,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
assert!(
|
||||
group.predicates.len() == 0,
|
||||
"settings_size is the byte size before adding predicates"
|
||||
);
|
||||
group.settings_size = group.byte_size();
|
||||
|
||||
group.predicates.extend(self.predicates);
|
||||
group.presets.extend(self.presets);
|
||||
|
||||
group
|
||||
}
|
||||
}
|
|
@ -190,19 +190,20 @@ impl LaneType {
|
|||
|
||||
/// Find the unique number associated with this lane type.
|
||||
pub fn number(self) -> u8 {
|
||||
LANE_BASE + match self {
|
||||
LaneType::BoolType(base_types::Bool::B1) => 0,
|
||||
LaneType::BoolType(base_types::Bool::B8) => 1,
|
||||
LaneType::BoolType(base_types::Bool::B16) => 2,
|
||||
LaneType::BoolType(base_types::Bool::B32) => 3,
|
||||
LaneType::BoolType(base_types::Bool::B64) => 4,
|
||||
LaneType::IntType(base_types::Int::I8) => 5,
|
||||
LaneType::IntType(base_types::Int::I16) => 6,
|
||||
LaneType::IntType(base_types::Int::I32) => 7,
|
||||
LaneType::IntType(base_types::Int::I64) => 8,
|
||||
LaneType::FloatType(base_types::Float::F32) => 9,
|
||||
LaneType::FloatType(base_types::Float::F64) => 10,
|
||||
}
|
||||
LANE_BASE
|
||||
+ match self {
|
||||
LaneType::BoolType(base_types::Bool::B1) => 0,
|
||||
LaneType::BoolType(base_types::Bool::B8) => 1,
|
||||
LaneType::BoolType(base_types::Bool::B16) => 2,
|
||||
LaneType::BoolType(base_types::Bool::B32) => 3,
|
||||
LaneType::BoolType(base_types::Bool::B64) => 4,
|
||||
LaneType::IntType(base_types::Int::I8) => 5,
|
||||
LaneType::IntType(base_types::Int::I16) => 6,
|
||||
LaneType::IntType(base_types::Int::I32) => 7,
|
||||
LaneType::IntType(base_types::Int::I64) => 8,
|
||||
LaneType::FloatType(base_types::Float::F32) => 9,
|
||||
LaneType::FloatType(base_types::Float::F64) => 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
pub fn simple_hash(s: &str) -> usize {
|
||||
let mut h: u32 = 5381;
|
||||
for c in s.chars() {
|
||||
h = (h ^ c as u32).wrapping_add(h.rotate_right(6));
|
||||
}
|
||||
h as usize
|
||||
}
|
||||
|
||||
/// Compute an open addressed, quadratically probed hash table containing
|
||||
/// `items`. The returned table is a list containing the elements of the
|
||||
/// iterable `items` and `None` in unused slots.
|
||||
pub fn generate_table<T, H: Fn(&T) -> usize>(items: &Vec<T>, hash_function: H) -> Vec<Option<&T>> {
|
||||
let size = (1.20 * items.len() as f64) as usize;
|
||||
// TODO do we really need the multiply by two here?
|
||||
let size = if size.is_power_of_two() {
|
||||
size * 2
|
||||
} else {
|
||||
size.next_power_of_two()
|
||||
};
|
||||
|
||||
let mut table: Vec<Option<&T>> = Vec::new();
|
||||
table.resize(size, None);
|
||||
|
||||
for i in items {
|
||||
let mut h = hash_function(i) % size;
|
||||
let mut s = 0;
|
||||
while table[h].is_some() {
|
||||
s += 1;
|
||||
h = (h + s) % size;
|
||||
}
|
||||
table[h] = Some(i);
|
||||
}
|
||||
|
||||
table
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_table() {
|
||||
let v = vec!["Hello".to_string(), "world".to_string()];
|
||||
let table = generate_table(&v, |s| simple_hash(&s));
|
||||
assert_eq!(
|
||||
table,
|
||||
vec![
|
||||
None,
|
||||
Some(&"Hello".to_string()),
|
||||
Some(&"world".to_string()),
|
||||
None
|
||||
]
|
||||
);
|
||||
}
|
|
@ -78,7 +78,7 @@ fn gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter) {
|
|||
}
|
||||
}
|
||||
|
||||
fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) -> Result<(), error::Error> {
|
||||
fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
|
||||
// Emit RegInfo.
|
||||
fmt.line("pub static INFO: RegInfo = RegInfo {");
|
||||
|
||||
|
@ -128,13 +128,11 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) -> Result<(), error::Error> {
|
|||
fmt.line("}")
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate(isa: TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
pub fn generate(isa: &TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
let mut fmt = Formatter::new();
|
||||
gen_isa(&isa, &mut fmt)?;
|
||||
gen_isa(&isa, &mut fmt);
|
||||
fmt.update_file(&format!("{}-{}.rs", base_filename, isa.name), out_dir)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,447 @@
|
|||
use base;
|
||||
use cdsl::camel_case;
|
||||
use cdsl::isa::TargetIsa;
|
||||
use cdsl::settings::{BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting};
|
||||
use constant_hash::{generate_table, simple_hash};
|
||||
use error;
|
||||
use srcgen::{Formatter, Match};
|
||||
use std::collections::HashMap;
|
||||
use unique_table::UniqueTable;
|
||||
|
||||
enum ParentGroup {
|
||||
None,
|
||||
Shared,
|
||||
}
|
||||
|
||||
/// Emits the constructor of the Flags structure.
|
||||
fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
|
||||
let args = match parent {
|
||||
ParentGroup::None => "builder: Builder",
|
||||
ParentGroup::Shared => "shared: &settings::Flags, builder: Builder",
|
||||
};
|
||||
fmt.line("impl Flags {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.doc_comment(&format!("Create flags {} settings group.", group.name));
|
||||
fmt.line("#[allow(unused_variables)]");
|
||||
fmt.line(&format!("pub fn new({}) -> Self {{", args));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!(
|
||||
"let bvec = builder.state_for(\"{}\");",
|
||||
group.name
|
||||
));
|
||||
fmt.line(&format!(
|
||||
"let mut {} = Self {{ bytes: [0; {}] }};",
|
||||
group.name,
|
||||
group.byte_size()
|
||||
));
|
||||
fmt.line(&format!(
|
||||
"debug_assert_eq!(bvec.len(), {});",
|
||||
group.settings_size
|
||||
));
|
||||
fmt.line(&format!(
|
||||
"{}.bytes[0..{}].copy_from_slice(&bvec);",
|
||||
group.name, group.settings_size
|
||||
));
|
||||
|
||||
// Now compute the predicates.
|
||||
for p in &group.predicates {
|
||||
fmt.comment(&format!("Precompute #{}.", p.number));
|
||||
fmt.line(&format!("if {} {{", p.render(group)));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!(
|
||||
"{}.bytes[{}] |= 1 << {};",
|
||||
group.name,
|
||||
group.bool_start_byte_offset + p.number / 8,
|
||||
p.number % 8
|
||||
));
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
fmt.line(group.name);
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
/// Emit Display and FromStr implementations for enum settings.
|
||||
fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {
|
||||
fmt.line(&format!("impl fmt::Display for {} {{", name));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("f.write_str(match *self {");
|
||||
fmt.indent(|fmt| {
|
||||
for v in values.iter() {
|
||||
fmt.line(&format!("{}::{} => \"{}\",", name, camel_case(v), v));
|
||||
}
|
||||
});
|
||||
fmt.line("})");
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
fmt.line(&format!("impl str::FromStr for {} {{", name));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("type Err = ();");
|
||||
fmt.line("fn from_str(s: &str) -> Result<Self, Self::Err> {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("match s {");
|
||||
fmt.indent(|fmt| {
|
||||
for v in values.iter() {
|
||||
fmt.line(&format!("\"{}\" => Ok({}::{}),", v, name, camel_case(v)));
|
||||
}
|
||||
fmt.line("_ => Err(()),");
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
/// Emit real enum for the Enum settings.
|
||||
fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
for setting in group.settings.iter() {
|
||||
let values = match setting.specific {
|
||||
SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,
|
||||
SpecificSetting::Enum(ref values) => values,
|
||||
};
|
||||
let name = camel_case(setting.name);
|
||||
|
||||
fmt.doc_comment(&format!("Values for `{}.{}`.", group.name, setting.name));
|
||||
fmt.line("#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");
|
||||
fmt.line(&format!("pub enum {} {{", name));
|
||||
fmt.indent(|fmt| {
|
||||
for v in values.iter() {
|
||||
fmt.doc_comment(&format!("`{}`.", v));
|
||||
fmt.line(&format!("{},", camel_case(v)));
|
||||
}
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
gen_to_and_from_str(&name, values, fmt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a getter function for `setting`.
|
||||
fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
|
||||
fmt.doc_comment(setting.comment);
|
||||
match setting.specific {
|
||||
SpecificSetting::Bool(BoolSetting {
|
||||
predicate_number, ..
|
||||
}) => {
|
||||
fmt.line(&format!("pub fn {}(&self) -> bool {{", setting.name));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("self.numbered_predicate({})", predicate_number));
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
SpecificSetting::Enum(ref values) => {
|
||||
let ty = camel_case(setting.name);
|
||||
fmt.line(&format!("pub fn {}(&self) -> {} {{", setting.name, ty));
|
||||
fmt.indent(|fmt| {
|
||||
let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
|
||||
for (i, v) in values.iter().enumerate() {
|
||||
m.arm(
|
||||
format!("{}", i),
|
||||
vec![],
|
||||
format!("{}::{}", ty, camel_case(v)),
|
||||
);
|
||||
}
|
||||
m.arm("_", vec![], "panic!(\"Invalid enum value\")");
|
||||
fmt.add_match(m);
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
SpecificSetting::Num(_) => {
|
||||
fmt.line(&format!("pub fn {}(&self) -> u8 {{", setting.name));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("self.bytes[{}]", setting.byte_offset));
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) {
|
||||
fmt.doc_comment(&format!(
|
||||
"Computed predicate `{}`.",
|
||||
predicate.render(group)
|
||||
));
|
||||
fmt.line(&format!("pub fn {}(&self) -> bool {{", predicate.name));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("self.numbered_predicate({})", predicate.number));
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
/// Emits getters for each setting value.
|
||||
fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
fmt.doc_comment("User-defined settings.");
|
||||
fmt.line("#[allow(dead_code)]");
|
||||
fmt.line("impl Flags {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.doc_comment("Get a view of the boolean predicates.");
|
||||
fmt.line("pub fn predicate_view(&self) -> ::settings::PredicateView {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!(
|
||||
"::settings::PredicateView::new(&self.bytes[{}..])",
|
||||
group.bool_start_byte_offset
|
||||
));
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
if group.settings.len() > 0 {
|
||||
fmt.doc_comment("Dynamic numbered predicate getter.");
|
||||
fmt.line("fn numbered_predicate(&self, p: usize) -> bool {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!(
|
||||
"self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",
|
||||
group.bool_start_byte_offset
|
||||
));
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
for setting in &group.settings {
|
||||
gen_getter(&setting, fmt);
|
||||
}
|
||||
for predicate in &group.predicates {
|
||||
gen_pred_getter(&predicate, &group, fmt);
|
||||
}
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
enum SettingOrPreset<'a> {
|
||||
Setting(&'a Setting),
|
||||
Preset(&'a Preset),
|
||||
}
|
||||
|
||||
impl<'a> SettingOrPreset<'a> {
|
||||
fn name(&self) -> &str {
|
||||
match self {
|
||||
SettingOrPreset::Setting(s) => s.name,
|
||||
SettingOrPreset::Preset(p) => p.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.
|
||||
fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
let mut enum_table: UniqueTable<&'static str> = UniqueTable::new();
|
||||
|
||||
let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
|
||||
|
||||
// Generate descriptors.
|
||||
fmt.line(&format!(
|
||||
"static DESCRIPTORS: [detail::Descriptor; {}] = [",
|
||||
group.settings.len() + group.presets.len()
|
||||
));
|
||||
fmt.indent(|fmt| {
|
||||
for (idx, setting) in group.settings.iter().enumerate() {
|
||||
fmt.line("detail::Descriptor {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("name: \"{}\",", setting.name));
|
||||
fmt.line(&format!("offset: {},", setting.byte_offset));
|
||||
match &setting.specific {
|
||||
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
|
||||
fmt.line(&format!(
|
||||
"detail: detail::Detail::Bool {{ bit: {} }},",
|
||||
bit_offset
|
||||
));
|
||||
}
|
||||
SpecificSetting::Enum(values) => {
|
||||
let offset = enum_table.add(values);
|
||||
fmt.line(&format!(
|
||||
"detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",
|
||||
values.len() - 1,
|
||||
offset
|
||||
));
|
||||
}
|
||||
SpecificSetting::Num(_) => {
|
||||
fmt.line("detail: detail::Detail::Num,");
|
||||
}
|
||||
}
|
||||
|
||||
descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);
|
||||
});
|
||||
fmt.line("},");
|
||||
}
|
||||
|
||||
for (idx, preset) in group.presets.iter().enumerate() {
|
||||
fmt.line("detail::Descriptor {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("name: \"{}\",", preset.name));
|
||||
fmt.line(&format!("offset: {},", (idx as u8) * group.settings_size));
|
||||
fmt.line("detail: detail::Detail::Preset,");
|
||||
});
|
||||
fmt.line("},");
|
||||
|
||||
descriptor_index_map.insert(SettingOrPreset::Preset(preset), idx);
|
||||
}
|
||||
});
|
||||
fmt.line("];");
|
||||
|
||||
// Generate enumerators.
|
||||
fmt.line(&format!(
|
||||
"static ENUMERATORS: [&str; {}] = [",
|
||||
enum_table.len()
|
||||
));
|
||||
fmt.indent(|fmt| {
|
||||
for enum_val in enum_table.iter() {
|
||||
fmt.line(&format!("\"{}\",", enum_val));
|
||||
}
|
||||
});
|
||||
fmt.line("];");
|
||||
|
||||
// Generate hash table.
|
||||
let mut hash_entries: Vec<SettingOrPreset> = Vec::new();
|
||||
hash_entries.extend(
|
||||
group
|
||||
.settings
|
||||
.iter()
|
||||
.map(|x| SettingOrPreset::Setting(x))
|
||||
.collect::<Vec<SettingOrPreset>>(),
|
||||
);
|
||||
hash_entries.extend(
|
||||
group
|
||||
.presets
|
||||
.iter()
|
||||
.map(|x| SettingOrPreset::Preset(x))
|
||||
.collect::<Vec<SettingOrPreset>>(),
|
||||
);
|
||||
let hash_table = generate_table(&hash_entries, |entry| simple_hash(entry.name()));
|
||||
fmt.line(&format!(
|
||||
"static HASH_TABLE: [u16; {}] = [",
|
||||
hash_table.len()
|
||||
));
|
||||
fmt.indent(|fmt| {
|
||||
for h in &hash_table {
|
||||
match h {
|
||||
Some(setting_or_preset) => fmt.line(&format!(
|
||||
"{},",
|
||||
&descriptor_index_map
|
||||
.get(setting_or_preset)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
)),
|
||||
None => fmt.line("0xffff,"),
|
||||
}
|
||||
}
|
||||
});
|
||||
fmt.line("];");
|
||||
|
||||
// Generate presets.
|
||||
fmt.line(&format!(
|
||||
"static PRESETS: [(u8, u8); {}] = [",
|
||||
group.presets.len()
|
||||
));
|
||||
fmt.indent(|fmt| {
|
||||
for preset in &group.presets {
|
||||
fmt.comment(preset.name);
|
||||
for (mask, value) in preset.layout(&group) {
|
||||
fmt.line(&format!("(0b{:08b}, 0b{:08b}),", mask, value));
|
||||
}
|
||||
}
|
||||
});
|
||||
fmt.line("];");
|
||||
}
|
||||
|
||||
fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
let mut default_bytes: Vec<u8> = Vec::new();
|
||||
default_bytes.resize(group.settings_size as usize, 0);
|
||||
for setting in &group.settings {
|
||||
*default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();
|
||||
}
|
||||
|
||||
let default_bytes: Vec<String> = default_bytes
|
||||
.iter()
|
||||
.map(|x| format!("{:#04x}", x))
|
||||
.collect();
|
||||
let default_bytes_str = default_bytes.join(", ");
|
||||
|
||||
fmt.line("static TEMPLATE: detail::Template = detail::Template {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("name: \"{}\",", group.name));
|
||||
fmt.line("descriptors: &DESCRIPTORS,");
|
||||
fmt.line("enumerators: &ENUMERATORS,");
|
||||
fmt.line("hash_table: &HASH_TABLE,");
|
||||
fmt.line(&format!("defaults: &[{}],", default_bytes_str));
|
||||
fmt.line("presets: &PRESETS,");
|
||||
});
|
||||
fmt.line("};");
|
||||
|
||||
fmt.doc_comment(&format!(
|
||||
"Create a `settings::Builder` for the {} settings group.",
|
||||
group.name
|
||||
));
|
||||
fmt.line("pub fn builder() -> Builder {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("Builder::new(&TEMPLATE)");
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {
|
||||
fmt.line("impl fmt::Display for Flags {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("writeln!(f, \"[{}]\")?;", group.name));
|
||||
fmt.line("for d in &DESCRIPTORS {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("if !d.detail.is_preset() {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("write!(f, \"{} = \", d.name)?;");
|
||||
fmt.line(
|
||||
"TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",
|
||||
);
|
||||
fmt.line("writeln!(f)?;");
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
fmt.line("Ok(())");
|
||||
});
|
||||
fmt.line("}")
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
|
||||
fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
|
||||
// Generate struct.
|
||||
fmt.line("#[derive(Clone)]");
|
||||
fmt.doc_comment(&format!("Flags group `{}`.", group.name));
|
||||
fmt.line("pub struct Flags {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(&format!("bytes: [u8; {}],", group.byte_size()));
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
gen_constructor(group, parent, fmt);
|
||||
gen_enum_types(group, fmt);
|
||||
gen_getters(group, fmt);
|
||||
gen_descriptors(group, fmt);
|
||||
gen_template(group, fmt);
|
||||
gen_display(group, fmt);
|
||||
}
|
||||
|
||||
pub fn generate_common(filename: &str, out_dir: &str) -> Result<SettingGroup, error::Error> {
|
||||
let settings = base::settings::generate();
|
||||
let mut fmt = Formatter::new();
|
||||
gen_group(&settings, ParentGroup::None, &mut fmt);
|
||||
fmt.update_file(filename, out_dir)?;
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
pub fn generate(isa: &TargetIsa, prefix: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||
let mut fmt = Formatter::new();
|
||||
gen_group(&isa.settings, ParentGroup::Shared, &mut fmt);
|
||||
fmt.update_file(&format!("{}-{}.rs", prefix, isa.name), out_dir)?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm32");
|
||||
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let setting = SettingGroupBuilder::new("arm32");
|
||||
setting.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm32", define_settings(shared_settings));
|
||||
|
||||
let builder = RegBankBuilder::new("FloatRegs", "s")
|
||||
.units(64)
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm64");
|
||||
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let setting = SettingGroupBuilder::new("arm64");
|
||||
setting.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm64", define_settings(shared_settings));
|
||||
|
||||
// The `x31` regunit serves as the stack pointer / zero register depending on context. We
|
||||
// reserve it and don't model the difference.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use cdsl::isa::TargetIsa;
|
||||
use cdsl::settings::SettingGroup;
|
||||
use std::fmt;
|
||||
|
||||
mod arm32;
|
||||
|
@ -61,11 +62,11 @@ impl fmt::Display for Isa {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn define_all() -> Vec<TargetIsa> {
|
||||
pub fn define_all(shared_settings: &SettingGroup) -> Vec<TargetIsa> {
|
||||
vec![
|
||||
riscv::define(),
|
||||
arm32::define(),
|
||||
arm64::define(),
|
||||
x86::define(),
|
||||
riscv::define(shared_settings),
|
||||
arm32::define(shared_settings),
|
||||
arm64::define(shared_settings),
|
||||
x86::define(shared_settings),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,8 +1,61 @@
|
|||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("riscv");
|
||||
fn define_settings(shared: &SettingGroup) -> SettingGroup {
|
||||
let mut setting = SettingGroupBuilder::new("riscv");
|
||||
|
||||
let supports_m = setting.add_bool(
|
||||
"supports_m",
|
||||
"CPU supports the 'M' extension (mul/div)",
|
||||
false,
|
||||
);
|
||||
let supports_a = setting.add_bool(
|
||||
"supports_a",
|
||||
"CPU supports the 'A' extension (atomics)",
|
||||
false,
|
||||
);
|
||||
let supports_f = setting.add_bool(
|
||||
"supports_f",
|
||||
"CPU supports the 'F' extension (float)",
|
||||
false,
|
||||
);
|
||||
let supports_d = setting.add_bool(
|
||||
"supports_d",
|
||||
"CPU supports the 'D' extension (double)",
|
||||
false,
|
||||
);
|
||||
|
||||
let enable_m = setting.add_bool(
|
||||
"enable_m",
|
||||
"Enable the use of 'M' instructions if available",
|
||||
true,
|
||||
);
|
||||
|
||||
setting.add_bool(
|
||||
"enable_e",
|
||||
"Enable the 'RV32E' instruction set with only 16 registers",
|
||||
true,
|
||||
);
|
||||
|
||||
let shared_enable_atomics = shared.get_bool("enable_atomics");
|
||||
let shared_enable_float = shared.get_bool("enable_float");
|
||||
let shared_enable_simd = shared.get_bool("enable_simd");
|
||||
|
||||
setting.add_predicate("use_m", predicate!(supports_m && enable_m));
|
||||
setting.add_predicate("use_a", predicate!(supports_a && shared_enable_atomics));
|
||||
setting.add_predicate("use_f", predicate!(supports_f && shared_enable_float));
|
||||
setting.add_predicate("use_d", predicate!(supports_d && shared_enable_float));
|
||||
setting.add_predicate(
|
||||
"full_float",
|
||||
predicate!(shared_enable_simd && supports_f && supports_d),
|
||||
);
|
||||
|
||||
setting.finish()
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("riscv", define_settings(shared_settings));
|
||||
|
||||
let builder = RegBankBuilder::new("IntRegs", "x")
|
||||
.units(32)
|
||||
|
|
|
@ -1,9 +1,74 @@
|
|||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("x86");
|
||||
pub fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||
let mut settings = SettingGroupBuilder::new("x86");
|
||||
|
||||
// CPUID.01H:ECX
|
||||
let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
|
||||
let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
|
||||
let has_sse41 = settings.add_bool("has_sse41", "SSE4.1: CPUID.01H:ECX.SSE4_1[bit 19]", false);
|
||||
let has_sse42 = settings.add_bool("has_sse42", "SSE4.2: CPUID.01H:ECX.SSE4_2[bit 20]", false);
|
||||
let has_popcnt = settings.add_bool("has_popcnt", "POPCNT: CPUID.01H:ECX.POPCNT[bit 23]", false);
|
||||
settings.add_bool("has_avx", "AVX: CPUID.01H:ECX.AVX[bit 28]", false);
|
||||
|
||||
// CPUID.(EAX=07H, ECX=0H):EBX
|
||||
let has_bmi1 = settings.add_bool(
|
||||
"has_bmi1",
|
||||
"BMI1: CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]",
|
||||
false,
|
||||
);
|
||||
let has_bmi2 = settings.add_bool(
|
||||
"has_bmi2",
|
||||
"BMI2: CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]",
|
||||
false,
|
||||
);
|
||||
|
||||
// CPUID.EAX=80000001H:ECX
|
||||
let has_lzcnt = settings.add_bool(
|
||||
"has_lzcnt",
|
||||
"LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]",
|
||||
false,
|
||||
);
|
||||
|
||||
settings.add_predicate("use_sse41", predicate!(has_sse41));
|
||||
settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42));
|
||||
settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42));
|
||||
settings.add_predicate("use_bmi1", predicate!(has_bmi1));
|
||||
settings.add_predicate("use_lznct", predicate!(has_lzcnt));
|
||||
|
||||
settings.add_preset("baseline", preset!());
|
||||
let nehalem = settings.add_preset(
|
||||
"nehalem",
|
||||
preset!(has_sse3 && has_ssse3 && has_sse41 && has_sse42 && has_popcnt),
|
||||
);
|
||||
let haswell = settings.add_preset(
|
||||
"haswell",
|
||||
preset!(nehalem && has_bmi1 && has_bmi2 && has_lzcnt),
|
||||
);
|
||||
let broadwell = settings.add_preset("broadwell", preset!(haswell));
|
||||
let skylake = settings.add_preset("skylake", preset!(broadwell));
|
||||
let cannonlake = settings.add_preset("cannonlake", preset!(skylake));
|
||||
settings.add_preset("icelake", preset!(cannonlake));
|
||||
settings.add_preset(
|
||||
"znver1",
|
||||
preset!(
|
||||
has_sse3
|
||||
&& has_ssse3
|
||||
&& has_sse41
|
||||
&& has_sse42
|
||||
&& has_popcnt
|
||||
&& has_bmi1
|
||||
&& has_bmi2
|
||||
&& has_lzcnt
|
||||
),
|
||||
);
|
||||
|
||||
settings.finish()
|
||||
}
|
||||
|
||||
fn define_registers(isa: &mut TargetIsaBuilder) {
|
||||
let builder = RegBankBuilder::new("IntRegs", "r")
|
||||
.units(16)
|
||||
.names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"])
|
||||
|
@ -38,6 +103,14 @@ pub fn define() -> TargetIsa {
|
|||
|
||||
let builder = RegClassBuilder::subclass_of("FPR8", fpr, 0, 8);
|
||||
isa.add_reg_class(builder);
|
||||
}
|
||||
|
||||
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||
let settings = define_settings(shared_settings);
|
||||
|
||||
let mut isa = TargetIsaBuilder::new("x86", settings);
|
||||
|
||||
define_registers(&mut isa);
|
||||
|
||||
isa.finish()
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#[macro_use]
|
||||
extern crate cranelift_entity;
|
||||
|
||||
#[macro_use]
|
||||
mod cdsl;
|
||||
|
||||
pub mod error;
|
||||
pub mod gen_registers;
|
||||
pub mod gen_settings;
|
||||
pub mod gen_types;
|
||||
pub mod isa;
|
||||
|
||||
mod base;
|
||||
mod cdsl;
|
||||
mod constant_hash;
|
||||
mod srcgen;
|
||||
mod unique_table;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
//! The `srcgen` module contains generic helper routines and classes for
|
||||
//! generating source code.
|
||||
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::cmp;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path;
|
||||
|
@ -98,7 +99,7 @@ impl Formatter {
|
|||
}
|
||||
|
||||
/// Add a comment line.
|
||||
pub fn _comment(&mut self, s: &str) {
|
||||
pub fn comment(&mut self, s: &str) {
|
||||
let commented_line = format!("// {}", s);
|
||||
self.line(&commented_line);
|
||||
}
|
||||
|
@ -107,13 +108,41 @@ impl Formatter {
|
|||
pub fn doc_comment(&mut self, contents: &str) {
|
||||
parse_multiline(contents)
|
||||
.iter()
|
||||
.map(|l| format!("/// {}", l))
|
||||
.map(|l| {
|
||||
if l.len() == 0 {
|
||||
"///".into()
|
||||
} else {
|
||||
format!("/// {}", l)
|
||||
}
|
||||
})
|
||||
.for_each(|s| self.line(s.as_str()));
|
||||
}
|
||||
|
||||
/// Add a match expression.
|
||||
fn _add_match(&mut self, _m: &_Match) {
|
||||
unimplemented!();
|
||||
pub fn add_match(&mut self, m: Match) {
|
||||
self.line(&format!("match {} {{", m.expr));
|
||||
self.indent(|fmt| {
|
||||
for ((fields, body), names) in m.arms.iter() {
|
||||
// name { fields } | name { fields } => { body }
|
||||
let conditions: Vec<String> = names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
if fields.len() > 0 {
|
||||
format!("{} {{ {} }}", name, fields.join(", "))
|
||||
} else {
|
||||
name.clone()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let lhs = conditions.join(" | ");
|
||||
fmt.line(&format!("{} => {{", lhs));
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line(body);
|
||||
});
|
||||
fmt.line("}");
|
||||
}
|
||||
});
|
||||
self.line("}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,10 +164,11 @@ fn parse_multiline(s: &str) -> Vec<String> {
|
|||
let expanded_tab = format!("{:-1$}", " ", SHIFTWIDTH);
|
||||
let lines: Vec<String> = s.lines().map(|l| l.replace("\t", &expanded_tab)).collect();
|
||||
|
||||
// Determine minimum indentation, ignoring the first line.
|
||||
// Determine minimum indentation, ignoring the first line and empty lines.
|
||||
let indent = lines
|
||||
.iter()
|
||||
.skip(1)
|
||||
.filter(|l| !l.trim().is_empty())
|
||||
.map(|l| l.len() - l.trim_left().len())
|
||||
.min();
|
||||
|
||||
|
@ -153,8 +183,9 @@ fn parse_multiline(s: &str) -> Vec<String> {
|
|||
|
||||
// Remove trailing whitespace from other lines.
|
||||
let mut other_lines = if let Some(indent) = indent {
|
||||
// Note that empty lines may have fewer than `indent` chars.
|
||||
lines_iter
|
||||
.map(|l| &l[indent..])
|
||||
.map(|l| &l[cmp::min(indent, l.len())..])
|
||||
.map(|l| l.trim_right())
|
||||
.map(|l| l.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -186,44 +217,78 @@ fn parse_multiline(s: &str) -> Vec<String> {
|
|||
/// expression, automatically deduplicating overlapping identical arms.
|
||||
///
|
||||
/// Note that this class is ignorant of Rust types, and considers two fields
|
||||
/// with the same name to be equivalent. A BTreeMap is used to represent the
|
||||
/// arms in order to make the order deterministic.
|
||||
struct _Match<'a> {
|
||||
_expr: &'a str,
|
||||
arms: BTreeMap<(Vec<&'a str>, &'a str), HashSet<&'a str>>,
|
||||
/// with the same name to be equivalent. BTreeMap/BTreeSet are used to
|
||||
/// represent the arms in order to make the order deterministic.
|
||||
pub struct Match {
|
||||
expr: String,
|
||||
arms: BTreeMap<(Vec<String>, String), BTreeSet<String>>,
|
||||
}
|
||||
|
||||
impl<'a> _Match<'a> {
|
||||
impl Match {
|
||||
/// Create a new match statement on `expr`.
|
||||
fn _new(expr: &'a str) -> Self {
|
||||
pub fn new<T: Into<String>>(expr: T) -> Self {
|
||||
Self {
|
||||
_expr: expr,
|
||||
expr: expr.into(),
|
||||
arms: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an arm to the Match statement.
|
||||
fn _arm(&mut self, name: &'a str, fields: Vec<&'a str>, body: &'a str) {
|
||||
pub fn arm<T: Into<String>>(&mut self, name: T, fields: Vec<T>, body: T) {
|
||||
// let key = (fields, body);
|
||||
let match_arm = self.arms.entry((fields, body)).or_insert_with(HashSet::new);
|
||||
match_arm.insert(name);
|
||||
let body = body.into();
|
||||
let fields = fields.into_iter().map(|x| x.into()).collect();
|
||||
let match_arm = self
|
||||
.arms
|
||||
.entry((fields, body))
|
||||
.or_insert_with(BTreeSet::new);
|
||||
match_arm.insert(name.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod srcgen_tests {
|
||||
use super::_Match;
|
||||
use super::parse_multiline;
|
||||
use super::Formatter;
|
||||
use super::Match;
|
||||
|
||||
fn from_raw_string(s: impl Into<String>) -> Vec<String> {
|
||||
s.into()
|
||||
.trim()
|
||||
.split("\n")
|
||||
.into_iter()
|
||||
.map(|x| format!("{}\n", x))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adding_arms_works() {
|
||||
let mut m = _Match::_new("x");
|
||||
m._arm("Orange", vec!["a", "b"], "some body");
|
||||
m._arm("Yellow", vec!["a", "b"], "some body");
|
||||
m._arm("Green", vec!["a", "b"], "different body");
|
||||
m._arm("Blue", vec!["x", "y"], "some body");
|
||||
let mut m = Match::new("x");
|
||||
m.arm("Orange", vec!["a", "b"], "some body");
|
||||
m.arm("Yellow", vec!["a", "b"], "some body");
|
||||
m.arm("Green", vec!["a", "b"], "different body");
|
||||
m.arm("Blue", vec!["x", "y"], "some body");
|
||||
assert_eq!(m.arms.len(), 3);
|
||||
|
||||
let mut fmt = Formatter::new();
|
||||
fmt.add_match(m);
|
||||
|
||||
let expected_lines = from_raw_string(
|
||||
r#"
|
||||
match x {
|
||||
Green { a, b } => {
|
||||
different body
|
||||
}
|
||||
Orange { a, b } | Yellow { a, b } => {
|
||||
some body
|
||||
}
|
||||
Blue { x, y } => {
|
||||
some body
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(fmt.lines, expected_lines);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -239,7 +304,7 @@ mod srcgen_tests {
|
|||
let mut fmt = Formatter::new();
|
||||
fmt.line("Hello line 1");
|
||||
fmt.indent_push();
|
||||
fmt._comment("Nested comment");
|
||||
fmt.comment("Nested comment");
|
||||
fmt.indent_pop();
|
||||
fmt.line("Back home again");
|
||||
let expected_lines = vec![
|
||||
|
@ -294,4 +359,24 @@ mod srcgen_tests {
|
|||
let expected_lines = vec!["/// documentation\n", "/// is\n", "/// good\n"];
|
||||
assert_eq!(fmt.lines, expected_lines);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fmt_can_add_doc_comments_with_empty_lines() {
|
||||
let mut fmt = Formatter::new();
|
||||
fmt.doc_comment(
|
||||
r#"documentation
|
||||
can be really good.
|
||||
|
||||
If you stick to writing it.
|
||||
"#,
|
||||
);
|
||||
let expected_lines = from_raw_string(
|
||||
r#"
|
||||
/// documentation
|
||||
/// can be really good.
|
||||
///
|
||||
/// If you stick to writing it."#,
|
||||
);
|
||||
assert_eq!(fmt.lines, expected_lines);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
use std::slice;
|
||||
|
||||
/// A table of sequences which tries to avoid common subsequences.
|
||||
pub struct UniqueTable<T: PartialEq + Clone> {
|
||||
table: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Clone> UniqueTable<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { table: Vec::new() }
|
||||
}
|
||||
pub fn add(&mut self, values: &Vec<T>) -> usize {
|
||||
if let Some(offset) = find_subsequence(values, &self.table) {
|
||||
offset
|
||||
} else {
|
||||
let offset = self.table.len();
|
||||
self.table.extend((*values).clone());
|
||||
offset
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.table.len()
|
||||
}
|
||||
pub fn iter(&self) -> slice::Iter<T> {
|
||||
self.table.iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to find the subsequence `sub` in the `whole` sequence. Returns None if
|
||||
/// it's not been found, or Some(index) if it has been. Naive implementation
|
||||
/// until proven we need something better.
|
||||
fn find_subsequence<T: PartialEq>(sub: &Vec<T>, whole: &Vec<T>) -> Option<usize> {
|
||||
assert!(sub.len() > 0);
|
||||
// We want i + sub.len() <= whole.len(), i.e. i < whole.len() + 1 - sub.len().
|
||||
if whole.len() < sub.len() {
|
||||
return None;
|
||||
}
|
||||
let max = whole.len() + 1 - sub.len();
|
||||
for i in 0..max {
|
||||
let mut found: Option<usize> = Some(i);
|
||||
for j in 0..sub.len() {
|
||||
if sub[j] != whole[i + j] {
|
||||
found = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if found.is_some() {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_subsequence() {
|
||||
assert_eq!(find_subsequence(&vec![1], &vec![4]), None);
|
||||
assert_eq!(find_subsequence(&vec![1], &vec![1]), Some(0));
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![1]), None);
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 2]), Some(0));
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 3]), None);
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 2]), Some(1));
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1]), None);
|
||||
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1, 2]), Some(3));
|
||||
assert_eq!(
|
||||
find_subsequence(&vec![1, 1, 3], &vec![1, 1, 1, 3, 3]),
|
||||
Some(1)
|
||||
);
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
build = "build.rs"
|
||||
description = "Low-level code generator library"
|
||||
|
@ -23,11 +23,11 @@ categories = ["no-std"]
|
|||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-bforest]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.failure]
|
||||
|
@ -51,7 +51,7 @@ default-features = false
|
|||
version = "0.2.0"
|
||||
default-features = false
|
||||
[build-dependencies.cranelift-codegen-meta]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
|
||||
[features]
|
||||
core = ["hashmap_core"]
|
||||
|
|
|
@ -23,8 +23,11 @@ extern crate cranelift_codegen_meta as meta;
|
|||
use meta::isa::Isa;
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::time::Instant;
|
||||
|
||||
fn main() {
|
||||
let start_time = Instant::now();
|
||||
|
||||
let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
|
||||
let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
|
||||
let cranelift_targets = env::var("CRANELIFT_TARGETS").ok();
|
||||
|
@ -79,21 +82,35 @@ fn main() {
|
|||
// Now that the Python build process is complete, generate files that are
|
||||
// emitted by the `meta` crate.
|
||||
// ------------------------------------------------------------------------
|
||||
let isas = meta::isa::define_all();
|
||||
|
||||
if let Err(err) = meta::gen_types::generate("types.rs", &out_dir) {
|
||||
if let Err(err) = generate_meta(&out_dir) {
|
||||
eprintln!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
for isa in isas {
|
||||
if let Err(err) = meta::gen_registers::generate(isa, "registers", &out_dir) {
|
||||
eprintln!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
if let Ok(_) = env::var("CRANELIFT_VERBOSE") {
|
||||
println!(
|
||||
"cargo:warning=Build step took {:?}.",
|
||||
Instant::now() - start_time
|
||||
);
|
||||
println!("cargo:warning=Generated files are in {}", out_dir);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_meta(out_dir: &str) -> Result<(), meta::error::Error> {
|
||||
let shared_settings = meta::gen_settings::generate_common("new_settings.rs", &out_dir)?;
|
||||
let isas = meta::isa::define_all(&shared_settings);
|
||||
|
||||
meta::gen_types::generate("types.rs", &out_dir)?;
|
||||
|
||||
for isa in &isas {
|
||||
meta::gen_registers::generate(&isa, "registers", &out_dir)?;
|
||||
meta::gen_settings::generate(&isa, "new_settings", &out_dir)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn identify_python() -> &'static str {
|
||||
for python in &["python", "python3", "python2.7"] {
|
||||
if process::Command::new(python)
|
||||
|
|
|
@ -181,6 +181,10 @@ indirect_jump_table_br = Instruction(
|
|||
ins=(addr, JT),
|
||||
is_branch=True, is_indirect_branch=True, is_terminator=True)
|
||||
|
||||
debugtrap = Instruction('debugtrap', r"""
|
||||
Encodes an assembly debug trap.
|
||||
""", can_load=True, can_store=True, other_side_effects=True)
|
||||
|
||||
code = Operand('code', trapcode)
|
||||
trap = Instruction(
|
||||
'trap', r"""
|
||||
|
|
|
@ -340,7 +340,7 @@ class SettingGroup(object):
|
|||
precomputed predicates.
|
||||
|
||||
This is the size of the byte-sized settings plus all the numbered
|
||||
predcate bits rounded up to a whole number of bytes.
|
||||
predicate bits rounded up to a whole number of bytes.
|
||||
"""
|
||||
return self.boolean_offset + (len(self.predicate_number) + 7) // 8
|
||||
|
||||
|
|
|
@ -17,7 +17,11 @@ function runif {
|
|||
runif flake8 .
|
||||
|
||||
# Type checking.
|
||||
runif mypy --py2 build.py
|
||||
# TODO: Re-enable mypy on Travis osx. Pip currently installs mypy into a
|
||||
# directory which is not in the PATH.
|
||||
if [ "${TRAVIS_OS_NAME:-other}" != "osx" ]; then
|
||||
runif mypy --py2 build.py
|
||||
fi
|
||||
|
||||
# Python unit tests.
|
||||
runif python2.7 -m unittest discover
|
||||
|
|
|
@ -255,8 +255,8 @@ def gen_display(sgrp, fmt):
|
|||
fmt.line('Ok(())')
|
||||
|
||||
|
||||
def gen_constructor(sgrp, parent, fmt):
|
||||
# type: (SettingGroup, PredContext, srcgen.Formatter) -> None
|
||||
def gen_constructor(sgrp, fmt):
|
||||
# type: (SettingGroup, srcgen.Formatter) -> None
|
||||
"""
|
||||
Generate a Flags constructor.
|
||||
"""
|
||||
|
@ -310,7 +310,7 @@ def gen_group(sgrp, fmt):
|
|||
with fmt.indented('pub struct Flags {', '}'):
|
||||
fmt.line('bytes: [u8; {}],'.format(sgrp.byte_size()))
|
||||
|
||||
gen_constructor(sgrp, None, fmt)
|
||||
gen_constructor(sgrp, fmt)
|
||||
gen_enum_types(sgrp, fmt)
|
||||
gen_getters(sgrp, fmt)
|
||||
gen_descriptors(sgrp, fmt)
|
||||
|
|
|
@ -521,12 +521,17 @@ X86_32.enc(base.jump_table_base.i32, *r.jt_base(0x8d))
|
|||
|
||||
enc_x86_64(base.indirect_jump_table_br.i64, r.indirect_jmp, 0xff, rrr=4)
|
||||
X86_32.enc(base.indirect_jump_table_br.i32, *r.indirect_jmp(0xff, rrr=4))
|
||||
|
||||
#
|
||||
# Trap as ud2
|
||||
#
|
||||
X86_32.enc(base.trap, *r.trap(0x0f, 0x0b))
|
||||
X86_64.enc(base.trap, *r.trap(0x0f, 0x0b))
|
||||
|
||||
# Debug trap as int3
|
||||
X86_32.enc(base.debugtrap, r.debugtrap, 0)
|
||||
X86_64.enc(base.debugtrap, r.debugtrap, 0)
|
||||
|
||||
# Using a standard EncRecipe, not the TailRecipe.
|
||||
X86_32.enc(base.trapif, r.trapif, 0)
|
||||
X86_64.enc(base.trapif, r.trapif, 0)
|
||||
|
|
|
@ -295,6 +295,11 @@ def valid_scale(iform):
|
|||
# copies and no-op conversions.
|
||||
null = EncRecipe('null', Unary, base_size=0, ins=GPR, outs=0, emit='')
|
||||
|
||||
debugtrap = EncRecipe('debugtrap', NullAry, base_size=1, ins=(), outs=(),
|
||||
emit='''
|
||||
sink.put1(0xcc);
|
||||
''')
|
||||
|
||||
# XX opcode, no ModR/M.
|
||||
trap = TailRecipe(
|
||||
'trap', Trap, base_size=0, ins=(), outs=(),
|
||||
|
|
|
@ -186,7 +186,8 @@ fn relax_branch(
|
|||
debug!(" trying [{}]: OK", encinfo.display(enc));
|
||||
true
|
||||
}
|
||||
}) {
|
||||
})
|
||||
{
|
||||
cur.func.encodings[inst] = enc;
|
||||
return encinfo.byte_size(enc, inst, &divert, &cur.func);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ pub fn probe<K: Copy + Eq, T: Table<K> + ?Sized>(
|
|||
}
|
||||
|
||||
/// A primitive hash function for matching opcodes.
|
||||
/// Must match `lib/codegen/meta-python/constant_hash.py`.
|
||||
/// Must match `lib/codegen/meta-python/constant_hash.py` and `lib/codegen/meta/constant_hash.rs`.
|
||||
pub fn simple_hash(s: &str) -> usize {
|
||||
let mut h: u32 = 5381;
|
||||
for c in s.chars() {
|
||||
|
|
|
@ -802,9 +802,9 @@ impl DataFlowGraph {
|
|||
.remove(num as usize, &mut self.value_lists);
|
||||
for index in num..(self.num_ebb_params(ebb) as u16) {
|
||||
match self.values[self.ebbs[ebb]
|
||||
.params
|
||||
.get(index as usize, &self.value_lists)
|
||||
.unwrap()]
|
||||
.params
|
||||
.get(index as usize, &self.value_lists)
|
||||
.unwrap()]
|
||||
{
|
||||
ValueData::Param { ref mut num, .. } => {
|
||||
*num -= 1;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Heaps.
|
||||
|
||||
use ir::immediates::Imm64;
|
||||
use ir::immediates::Uimm64;
|
||||
use ir::{GlobalValue, Type};
|
||||
use std::fmt;
|
||||
|
||||
|
@ -12,10 +12,10 @@ pub struct HeapData {
|
|||
|
||||
/// Guaranteed minimum heap size in bytes. Heap accesses before `min_size` don't need bounds
|
||||
/// checking.
|
||||
pub min_size: Imm64,
|
||||
pub min_size: Uimm64,
|
||||
|
||||
/// Size in bytes of the guard pages following the heap.
|
||||
pub guard_size: Imm64,
|
||||
/// Size in bytes of the offset-guard pages following the heap.
|
||||
pub offset_guard_size: Uimm64,
|
||||
|
||||
/// Heap style, with additional style-specific info.
|
||||
pub style: HeapStyle,
|
||||
|
@ -34,10 +34,10 @@ pub enum HeapStyle {
|
|||
},
|
||||
|
||||
/// A static heap has a fixed base address and a number of not-yet-allocated pages before the
|
||||
/// guard pages.
|
||||
/// offset-guard pages.
|
||||
Static {
|
||||
/// Heap bound in bytes. The guard pages are allocated after the bound.
|
||||
bound: Imm64,
|
||||
/// Heap bound in bytes. The offset-guard pages are allocated after the bound.
|
||||
bound: Uimm64,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,8 @@ impl fmt::Display for HeapData {
|
|||
}
|
||||
write!(
|
||||
f,
|
||||
", guard {}, index_type {}",
|
||||
self.guard_size, self.index_type
|
||||
", offset_guard {}, index_type {}",
|
||||
self.offset_guard_size, self.index_type
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::mem;
|
|||
use std::str::FromStr;
|
||||
use std::{i32, u32};
|
||||
|
||||
/// 64-bit immediate integer operand.
|
||||
/// 64-bit immediate signed integer operand.
|
||||
///
|
||||
/// An `Imm64` operand can also be used to represent immediate values of smaller integer types by
|
||||
/// sign-extending to `i64`.
|
||||
|
@ -40,13 +40,87 @@ impl From<i64> for Imm64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Imm64 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let x = self.0;
|
||||
if -10_000 < x && x < 10_000 {
|
||||
// Use decimal for small numbers.
|
||||
write!(f, "{}", x)
|
||||
} else {
|
||||
write_hex(x as u64, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a 64-bit signed number.
|
||||
fn parse_i64(s: &str) -> Result<i64, &'static str> {
|
||||
let negative = s.starts_with('-');
|
||||
let s2 = if negative || s.starts_with('+') {
|
||||
&s[1..]
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
let mut value = parse_u64(s2)?;
|
||||
|
||||
// We support the range-and-a-half from -2^63 .. 2^64-1.
|
||||
if negative {
|
||||
value = value.wrapping_neg();
|
||||
// Don't allow large negative values to wrap around and become positive.
|
||||
if value as i64 > 0 {
|
||||
return Err("Negative number too small");
|
||||
}
|
||||
}
|
||||
Ok(value as i64)
|
||||
}
|
||||
|
||||
impl FromStr for Imm64 {
|
||||
type Err = &'static str;
|
||||
|
||||
// Parse a decimal or hexadecimal `Imm64`, formatted as above.
|
||||
fn from_str(s: &str) -> Result<Self, &'static str> {
|
||||
parse_i64(s).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
/// 64-bit immediate unsigned integer operand.
|
||||
///
|
||||
/// A `Uimm64` operand can also be used to represent immediate values of smaller integer types by
|
||||
/// zero-extending to `i64`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct Uimm64(u64);
|
||||
|
||||
impl Uimm64 {
|
||||
/// Create a new `Uimm64` representing the unsigned number `x`.
|
||||
pub fn new(x: u64) -> Self {
|
||||
Uimm64(x)
|
||||
}
|
||||
|
||||
/// Return self negated.
|
||||
pub fn wrapping_neg(self) -> Self {
|
||||
Uimm64(self.0.wrapping_neg())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u64> for Uimm64 {
|
||||
fn into(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Uimm64 {
|
||||
fn from(x: u64) -> Self {
|
||||
Uimm64(x)
|
||||
}
|
||||
}
|
||||
|
||||
/// Hexadecimal with a multiple of 4 digits and group separators:
|
||||
///
|
||||
/// 0xfff0
|
||||
/// 0x0001_ffff
|
||||
/// 0xffff_ffff_fff8_4400
|
||||
///
|
||||
fn write_hex(x: i64, f: &mut Formatter) -> fmt::Result {
|
||||
fn write_hex(x: u64, f: &mut Formatter) -> fmt::Result {
|
||||
let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;
|
||||
write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;
|
||||
while pos > 0 {
|
||||
|
@ -56,10 +130,10 @@ fn write_hex(x: i64, f: &mut Formatter) -> fmt::Result {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl Display for Imm64 {
|
||||
impl Display for Uimm64 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let x = self.0;
|
||||
if -10_000 < x && x < 10_000 {
|
||||
if x < 10_000 {
|
||||
// Use decimal for small numbers.
|
||||
write!(f, "{}", x)
|
||||
} else {
|
||||
|
@ -68,20 +142,16 @@ impl Display for Imm64 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a 64-bit number.
|
||||
fn parse_i64(s: &str) -> Result<i64, &'static str> {
|
||||
/// Parse a 64-bit unsigned number.
|
||||
fn parse_u64(s: &str) -> Result<u64, &'static str> {
|
||||
let mut value: u64 = 0;
|
||||
let mut digits = 0;
|
||||
let negative = s.starts_with('-');
|
||||
let s2 = if negative || s.starts_with('+') {
|
||||
&s[1..]
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
if s2.starts_with("0x") {
|
||||
if s.starts_with("-0x") {
|
||||
return Err("Invalid character in hexadecimal number");
|
||||
} else if s.starts_with("0x") {
|
||||
// Hexadecimal.
|
||||
for ch in s2[2..].chars() {
|
||||
for ch in s[2..].chars() {
|
||||
match ch.to_digit(16) {
|
||||
Some(digit) => {
|
||||
digits += 1;
|
||||
|
@ -101,7 +171,7 @@ fn parse_i64(s: &str) -> Result<i64, &'static str> {
|
|||
}
|
||||
} else {
|
||||
// Decimal number, possibly negative.
|
||||
for ch in s2.chars() {
|
||||
for ch in s.chars() {
|
||||
match ch.to_digit(16) {
|
||||
Some(digit) => {
|
||||
digits += 1;
|
||||
|
@ -128,23 +198,15 @@ fn parse_i64(s: &str) -> Result<i64, &'static str> {
|
|||
return Err("No digits in number");
|
||||
}
|
||||
|
||||
// We support the range-and-a-half from -2^63 .. 2^64-1.
|
||||
if negative {
|
||||
value = value.wrapping_neg();
|
||||
// Don't allow large negative values to wrap around and become positive.
|
||||
if value as i64 > 0 {
|
||||
return Err("Negative number too small");
|
||||
}
|
||||
}
|
||||
Ok(value as i64)
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
impl FromStr for Imm64 {
|
||||
impl FromStr for Uimm64 {
|
||||
type Err = &'static str;
|
||||
|
||||
// Parse a decimal or hexadecimal `Imm64`, formatted as above.
|
||||
// Parse a decimal or hexadecimal `Uimm64`, formatted as above.
|
||||
fn from_str(s: &str) -> Result<Self, &'static str> {
|
||||
parse_i64(s).map(Self::new)
|
||||
parse_u64(s).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +244,7 @@ impl Display for Uimm32 {
|
|||
if self.0 < 10_000 {
|
||||
write!(f, "{}", self.0)
|
||||
} else {
|
||||
write_hex(i64::from(self.0), f)
|
||||
write_hex(u64::from(self.0), f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +330,7 @@ impl Display for Offset32 {
|
|||
if val < 10_000 {
|
||||
write!(f, "{}", val)
|
||||
} else {
|
||||
write_hex(val, f)
|
||||
write_hex(val as u64, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -683,6 +745,20 @@ mod tests {
|
|||
assert_eq!(Imm64(0x10000).to_string(), "0x0001_0000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_uimm64() {
|
||||
assert_eq!(Uimm64(0).to_string(), "0");
|
||||
assert_eq!(Uimm64(9999).to_string(), "9999");
|
||||
assert_eq!(Uimm64(10000).to_string(), "0x2710");
|
||||
assert_eq!(Uimm64(-9999i64 as u64).to_string(), "0xffff_ffff_ffff_d8f1");
|
||||
assert_eq!(
|
||||
Uimm64(-10000i64 as u64).to_string(),
|
||||
"0xffff_ffff_ffff_d8f0"
|
||||
);
|
||||
assert_eq!(Uimm64(0xffff).to_string(), "0xffff");
|
||||
assert_eq!(Uimm64(0x10000).to_string(), "0x0001_0000");
|
||||
}
|
||||
|
||||
// Verify that `text` can be parsed as a `T` into a value that displays as `want`.
|
||||
fn parse_ok<T: FromStr + Display>(text: &str, want: &str)
|
||||
where
|
||||
|
@ -750,6 +826,46 @@ mod tests {
|
|||
parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_uimm64() {
|
||||
parse_ok::<Uimm64>("0", "0");
|
||||
parse_ok::<Uimm64>("1", "1");
|
||||
parse_ok::<Uimm64>("0x0", "0");
|
||||
parse_ok::<Uimm64>("0xf", "15");
|
||||
parse_ok::<Uimm64>("0xffffffff_fffffff7", "0xffff_ffff_ffff_fff7");
|
||||
|
||||
// Probe limits.
|
||||
parse_ok::<Uimm64>("0xffffffff_ffffffff", "0xffff_ffff_ffff_ffff");
|
||||
parse_ok::<Uimm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
|
||||
parse_ok::<Uimm64>("18446744073709551615", "0xffff_ffff_ffff_ffff");
|
||||
// Overflow both the `checked_add` and `checked_mul`.
|
||||
parse_err::<Uimm64>("18446744073709551616", "Too large decimal number");
|
||||
parse_err::<Uimm64>("184467440737095516100", "Too large decimal number");
|
||||
|
||||
// Underscores are allowed where digits go.
|
||||
parse_ok::<Uimm64>("0_0", "0");
|
||||
parse_ok::<Uimm64>("_10_", "10");
|
||||
parse_ok::<Uimm64>("0x97_88_bb", "0x0097_88bb");
|
||||
parse_ok::<Uimm64>("0x_97_", "151");
|
||||
|
||||
parse_err::<Uimm64>("", "No digits in number");
|
||||
parse_err::<Uimm64>("_", "No digits in number");
|
||||
parse_err::<Uimm64>("0x", "No digits in number");
|
||||
parse_err::<Uimm64>("0x_", "No digits in number");
|
||||
parse_err::<Uimm64>("-", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>("-0x", "Invalid character in hexadecimal number");
|
||||
parse_err::<Uimm64>(" ", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>("0 ", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>(" 0", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>("--", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>("-0x-", "Invalid character in hexadecimal number");
|
||||
parse_err::<Uimm64>("-0", "Invalid character in decimal number");
|
||||
parse_err::<Uimm64>("-1", "Invalid character in decimal number");
|
||||
|
||||
// Hex count overflow.
|
||||
parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_offset32() {
|
||||
assert_eq!(Offset32(0).to_string(), "");
|
||||
|
|
|
@ -26,6 +26,15 @@ impl MemFlags {
|
|||
Self { bits: 0 }
|
||||
}
|
||||
|
||||
/// Create a set of flags representing an access from a "trusted" address, meaning it's
|
||||
/// known to be aligned and non-trapping.
|
||||
pub fn trusted() -> Self {
|
||||
let mut result = Self::new();
|
||||
result.set_notrap();
|
||||
result.set_aligned();
|
||||
result
|
||||
}
|
||||
|
||||
/// Read a flag bit.
|
||||
fn read(self, bit: FlagBit) -> bool {
|
||||
self.bits & (1 << bit as usize) != 0
|
||||
|
|
|
@ -85,9 +85,9 @@ impl From<ValueDef> for ExpandedProgramPoint {
|
|||
impl From<ProgramPoint> for ExpandedProgramPoint {
|
||||
fn from(pp: ProgramPoint) -> Self {
|
||||
if pp.0 & 1 == 0 {
|
||||
ExpandedProgramPoint::Inst(Inst::new((pp.0 / 2) as usize))
|
||||
ExpandedProgramPoint::Inst(Inst::from_u32(pp.0 / 2))
|
||||
} else {
|
||||
ExpandedProgramPoint::Ebb(Ebb::new((pp.0 / 2) as usize))
|
||||
ExpandedProgramPoint::Ebb(Ebb::from_u32(pp.0 / 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Tables.
|
||||
|
||||
use ir::immediates::Imm64;
|
||||
use ir::immediates::Uimm64;
|
||||
use ir::{GlobalValue, Type};
|
||||
use std::fmt;
|
||||
|
||||
|
@ -12,13 +12,13 @@ pub struct TableData {
|
|||
|
||||
/// Guaranteed minimum table size in elements. Table accesses before `min_size` don't need
|
||||
/// bounds checking.
|
||||
pub min_size: Imm64,
|
||||
pub min_size: Uimm64,
|
||||
|
||||
/// Global value giving the current bound of the table, in elements.
|
||||
pub bound_gv: GlobalValue,
|
||||
|
||||
/// The size of a table element, in bytes.
|
||||
pub element_size: Imm64,
|
||||
pub element_size: Uimm64,
|
||||
|
||||
/// The index type for the table.
|
||||
pub index_type: Type,
|
||||
|
|
|
@ -17,7 +17,8 @@ pub enum TrapCode {
|
|||
/// A `heap_addr` instruction detected an out-of-bounds error.
|
||||
///
|
||||
/// Note that not all out-of-bounds heap accesses are reported this way;
|
||||
/// some are detected by a segmentation fault on the heap guard pages.
|
||||
/// some are detected by a segmentation fault on the heap unmapped or
|
||||
/// offset-guard pages.
|
||||
HeapOutOfBounds,
|
||||
|
||||
/// A `table_addr` instruction detected an out-of-bounds error.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use std::default::Default;
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use target_lexicon::{PointerWidth, Triple};
|
||||
|
||||
/// The type of an SSA value.
|
||||
///
|
||||
|
@ -271,6 +272,16 @@ impl Type {
|
|||
pub fn wider_or_equal(self, other: Self) -> bool {
|
||||
self.lane_count() == other.lane_count() && self.lane_bits() >= other.lane_bits()
|
||||
}
|
||||
|
||||
/// Return the pointer type for the given target triple.
|
||||
pub fn triple_pointer_type(triple: &Triple) -> Self {
|
||||
match triple.pointer_width() {
|
||||
Ok(PointerWidth::U16) => I16,
|
||||
Ok(PointerWidth::U32) => I32,
|
||||
Ok(PointerWidth::U64) => I64,
|
||||
Err(()) => panic!("unable to determine architecture pointer width"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
|
|
|
@ -21,7 +21,7 @@ pub enum CallConv {
|
|||
|
||||
impl CallConv {
|
||||
/// Return the default calling convention for the given target triple.
|
||||
pub fn default_for_triple(triple: &Triple) -> Self {
|
||||
pub fn triple_default(triple: &Triple) -> Self {
|
||||
match triple.default_calling_convention() {
|
||||
// Default to System V for unknown targets because most everything
|
||||
// uses System V.
|
||||
|
|
|
@ -208,7 +208,7 @@ pub trait TargetIsa: fmt::Display + Sync {
|
|||
|
||||
/// Get the default calling convention of this target.
|
||||
fn default_call_conv(&self) -> CallConv {
|
||||
CallConv::default_for_triple(self.triple())
|
||||
CallConv::triple_default(self.triple())
|
||||
}
|
||||
|
||||
/// Get the pointer type of this ISA.
|
||||
|
|
|
@ -89,7 +89,8 @@ impl RegBank {
|
|||
None
|
||||
}
|
||||
}
|
||||
}.and_then(|offset| {
|
||||
}
|
||||
.and_then(|offset| {
|
||||
if offset < self.units {
|
||||
Some(offset + self.first_unit)
|
||||
} else {
|
||||
|
|
|
@ -98,7 +98,8 @@ impl ArgAssigner for Args {
|
|||
RU::r14
|
||||
} else {
|
||||
RU::rsi
|
||||
} as RegUnit).into()
|
||||
} as RegUnit)
|
||||
.into()
|
||||
}
|
||||
// This is SpiderMonkey's `WasmTableCallSigReg`.
|
||||
ArgumentPurpose::SignatureId => return ArgumentLoc::Reg(RU::r10 as RegUnit).into(),
|
||||
|
|
|
@ -575,7 +575,8 @@ pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph
|
|||
rt.purpose == ArgumentPurpose::Link
|
||||
|| rt.purpose == ArgumentPurpose::StructReturn
|
||||
|| rt.purpose == ArgumentPurpose::VMContext
|
||||
}).count();
|
||||
})
|
||||
.count();
|
||||
let abi_args = func.signature.returns.len() - special_args;
|
||||
|
||||
let pos = &mut FuncCursor::new(func).at_inst(inst);
|
||||
|
@ -694,7 +695,8 @@ fn spill_call_arguments(pos: &mut FuncCursor) -> bool {
|
|||
}
|
||||
_ => None,
|
||||
}
|
||||
}).collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if arglist.is_empty() {
|
||||
|
|
|
@ -110,9 +110,7 @@ fn load_addr(
|
|||
};
|
||||
|
||||
// Global-value loads are always notrap and aligned. They may be readonly.
|
||||
let mut mflags = ir::MemFlags::new();
|
||||
mflags.set_notrap();
|
||||
mflags.set_aligned();
|
||||
let mut mflags = ir::MemFlags::trusted();
|
||||
if readonly {
|
||||
mflags.set_readonly();
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ fn dynamic_addr(
|
|||
bound_gv: ir::GlobalValue,
|
||||
func: &mut ir::Function,
|
||||
) {
|
||||
let access_size = i64::from(access_size);
|
||||
let access_size = u64::from(access_size);
|
||||
let offset_ty = func.dfg.value_type(offset);
|
||||
let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
|
||||
let min_size = func.heaps[heap].min_size.into();
|
||||
|
@ -67,13 +67,13 @@ fn dynamic_addr(
|
|||
} else if access_size <= min_size {
|
||||
// We know that bound >= min_size, so here we can compare `offset > bound - access_size`
|
||||
// without wrapping.
|
||||
let adj_bound = pos.ins().iadd_imm(bound, -access_size);
|
||||
let adj_bound = pos.ins().iadd_imm(bound, -(access_size as i64));
|
||||
oob = pos
|
||||
.ins()
|
||||
.icmp(IntCC::UnsignedGreaterThan, offset, adj_bound);
|
||||
} else {
|
||||
// We need an overflow check for the adjusted offset.
|
||||
let access_size_val = pos.ins().iconst(offset_ty, access_size);
|
||||
let access_size_val = pos.ins().iconst(offset_ty, access_size as i64);
|
||||
let (adj_offset, overflow) = pos.ins().iadd_cout(offset, access_size_val);
|
||||
pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
|
||||
oob = pos
|
||||
|
@ -91,11 +91,11 @@ fn static_addr(
|
|||
heap: ir::Heap,
|
||||
offset: ir::Value,
|
||||
access_size: u32,
|
||||
bound: i64,
|
||||
bound: u64,
|
||||
func: &mut ir::Function,
|
||||
cfg: &mut ControlFlowGraph,
|
||||
) {
|
||||
let access_size = i64::from(access_size);
|
||||
let access_size = u64::from(access_size);
|
||||
let offset_ty = func.dfg.value_type(offset);
|
||||
let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
|
||||
let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||
|
@ -117,7 +117,7 @@ fn static_addr(
|
|||
}
|
||||
|
||||
// Check `offset > limit` which is now known non-negative.
|
||||
let limit = bound - access_size;
|
||||
let limit = bound - u64::from(access_size);
|
||||
|
||||
// We may be able to omit the check entirely for 32-bit offsets if the heap bound is 4 GB or
|
||||
// more.
|
||||
|
@ -126,10 +126,10 @@ fn static_addr(
|
|||
// Prefer testing `offset >= limit - 1` when limit is odd because an even number is
|
||||
// likely to be a convenient constant on ARM and other RISC architectures.
|
||||
pos.ins()
|
||||
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, offset, limit - 1)
|
||||
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, offset, limit as i64 - 1)
|
||||
} else {
|
||||
pos.ins()
|
||||
.icmp_imm(IntCC::UnsignedGreaterThan, offset, limit)
|
||||
.icmp_imm(IntCC::UnsignedGreaterThan, offset, limit as i64)
|
||||
};
|
||||
pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||
}
|
||||
|
|
|
@ -400,10 +400,8 @@ fn expand_stack_load(
|
|||
|
||||
let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset);
|
||||
|
||||
let mut mflags = MemFlags::new();
|
||||
// Stack slots are required to be accessible and aligned.
|
||||
mflags.set_notrap();
|
||||
mflags.set_aligned();
|
||||
let mflags = MemFlags::trusted();
|
||||
pos.func.dfg.replace(inst).load(ty, mflags, addr, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,8 @@ fn split_any(
|
|||
.get_mut(
|
||||
num_fixed_args + repair.hi_num,
|
||||
&mut pos.func.dfg.value_lists,
|
||||
).unwrap() = hi;
|
||||
)
|
||||
.unwrap() = hi;
|
||||
} else {
|
||||
// We need to append one or more arguments. If we're adding more than one argument,
|
||||
// there must be pending repairs on the stack that will fill in the correct values
|
||||
|
|
|
@ -92,17 +92,15 @@ fn compute_addr(
|
|||
|
||||
let element_size = pos.func.tables[table].element_size;
|
||||
let mut offset;
|
||||
let element_size_i64: i64 = element_size.into();
|
||||
debug_assert!(element_size_i64 >= 0);
|
||||
let element_size_u64 = element_size_i64 as u64;
|
||||
if element_size_u64 == 1 {
|
||||
let element_size: u64 = element_size.into();
|
||||
if element_size == 1 {
|
||||
offset = index;
|
||||
} else if element_size_u64.is_power_of_two() {
|
||||
} else if element_size.is_power_of_two() {
|
||||
offset = pos
|
||||
.ins()
|
||||
.ishl_imm(index, i64::from(element_size_u64.trailing_zeros()));
|
||||
.ishl_imm(index, i64::from(element_size.trailing_zeros()));
|
||||
} else {
|
||||
offset = pos.ins().imul_imm(index, element_size);
|
||||
offset = pos.ins().imul_imm(index, element_size as i64);
|
||||
}
|
||||
|
||||
if element_offset == Offset32::new(0) {
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "std", deny(unstable_features))]
|
||||
#![cfg_attr(
|
||||
feature = "clippy",
|
||||
plugin(clippy(conf_file = "../../clippy.toml"))
|
||||
)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(feature="cargo-clippy", allow(
|
||||
// Produces only a false positive:
|
||||
while_let_loop,
|
||||
|
@ -33,14 +30,14 @@
|
|||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
float_arithmetic,
|
||||
mut_mut,
|
||||
nonminimal_bool,
|
||||
option_map_unwrap_or,
|
||||
option_map_unwrap_or_else,
|
||||
print_stdout,
|
||||
unicode_not_nfc,
|
||||
use_self
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
// Turns on no_std and alloc features if std is not available.
|
||||
|
|
|
@ -30,14 +30,16 @@ pub fn pretty_verifier_error<'a>(
|
|||
&mut w,
|
||||
func,
|
||||
isa,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(
|
||||
w,
|
||||
"\n; {} verifier error{} detected (see above). Compilation aborted.",
|
||||
num_errors,
|
||||
if num_errors == 1 { "" } else { "s" }
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
w
|
||||
}
|
||||
|
|
|
@ -914,12 +914,10 @@ impl<'a> Context<'a> {
|
|||
Table(jt, ebb) => {
|
||||
let lr = &self.liveness[value];
|
||||
!lr.is_local()
|
||||
&& (ebb.map_or(false, |ebb| lr.is_livein(ebb, ctx)) || self
|
||||
.cur
|
||||
.func
|
||||
.jump_tables[jt]
|
||||
.iter()
|
||||
.any(|ebb| lr.is_livein(*ebb, ctx)))
|
||||
&& (ebb.map_or(false, |ebb| lr.is_livein(ebb, ctx))
|
||||
|| self.cur.func.jump_tables[jt]
|
||||
.iter()
|
||||
.any(|ebb| lr.is_livein(*ebb, ctx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,7 +116,8 @@ impl Context {
|
|||
&self.liveness,
|
||||
&self.virtregs,
|
||||
&mut errors,
|
||||
).is_ok();
|
||||
)
|
||||
.is_ok();
|
||||
|
||||
if !ok {
|
||||
return Err(errors.into());
|
||||
|
@ -144,7 +145,8 @@ impl Context {
|
|||
&self.liveness,
|
||||
&self.virtregs,
|
||||
&mut errors,
|
||||
).is_ok();
|
||||
)
|
||||
.is_ok();
|
||||
|
||||
if !ok {
|
||||
return Err(errors.into());
|
||||
|
@ -171,7 +173,8 @@ impl Context {
|
|||
&self.liveness,
|
||||
&self.virtregs,
|
||||
&mut errors,
|
||||
).is_ok();
|
||||
)
|
||||
.is_ok();
|
||||
|
||||
if !ok {
|
||||
return Err(errors.into());
|
||||
|
@ -193,7 +196,8 @@ impl Context {
|
|||
&self.liveness,
|
||||
&self.virtregs,
|
||||
&mut errors,
|
||||
).is_ok();
|
||||
)
|
||||
.is_ok();
|
||||
|
||||
if !ok {
|
||||
return Err(errors.into());
|
||||
|
|
|
@ -220,7 +220,8 @@ fn get_or_create<'a>(
|
|||
func.dfg
|
||||
.call_signature(inst)
|
||||
.map(|sig| Affinity::abi(&func.dfg.signatures[sig].returns[rnum], isa))
|
||||
}).unwrap_or_default();
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
ValueDef::Param(ebb, num) => {
|
||||
def = ebb.into();
|
||||
|
|
|
@ -207,7 +207,8 @@ impl<'a> fmt::Display for DisplayRegisterSet<'a> {
|
|||
.unwrap_or_else(|| char::from_digit(
|
||||
u32::from(offset % 10),
|
||||
10
|
||||
).unwrap())
|
||||
)
|
||||
.unwrap())
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,9 +264,9 @@ impl<'a> Context<'a> {
|
|||
|
||||
// Same thing for spilled call return values.
|
||||
let retvals = &defs[self.cur.func.dfg[inst]
|
||||
.opcode()
|
||||
.constraints()
|
||||
.num_fixed_results()..];
|
||||
.opcode()
|
||||
.constraints()
|
||||
.num_fixed_results()..];
|
||||
if !retvals.is_empty() {
|
||||
let sig = self
|
||||
.cur
|
||||
|
|
|
@ -504,7 +504,8 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
None
|
||||
}).min_by(|&a, &b| {
|
||||
})
|
||||
.min_by(|&a, &b| {
|
||||
// Find the minimum candidate according to the RPO of their defs.
|
||||
self.domtree.rpo_cmp(
|
||||
self.cur.func.dfg.value_def(a),
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
use dbg::DisplayList;
|
||||
use dominator_tree::DominatorTreePreorder;
|
||||
use entity::EntityRef;
|
||||
use entity::{EntityList, ListPool};
|
||||
use entity::{Keys, PrimaryMap, SecondaryMap};
|
||||
use ir::{Function, Value};
|
||||
|
@ -258,7 +257,7 @@ impl UFEntry {
|
|||
/// Decode a table entry.
|
||||
fn decode(x: i32) -> Self {
|
||||
if x < 0 {
|
||||
UFEntry::Link(Value::new((!x) as usize))
|
||||
UFEntry::Link(Value::from_u32((!x) as u32))
|
||||
} else {
|
||||
UFEntry::Rank(x as u32)
|
||||
}
|
||||
|
@ -266,7 +265,7 @@ impl UFEntry {
|
|||
|
||||
/// Encode a link entry.
|
||||
fn encode_link(v: Value) -> i32 {
|
||||
!(v.index() as i32)
|
||||
!(v.as_u32() as i32)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ macro_rules! define_passes {
|
|||
}
|
||||
|
||||
// Pass definitions.
|
||||
define_passes!{
|
||||
define_passes! {
|
||||
Pass, NUM_PASSES, DESCRIPTIONS;
|
||||
|
||||
process_file: "Processing test file",
|
||||
|
@ -176,7 +176,7 @@ mod details {
|
|||
}
|
||||
|
||||
/// Information about passes in a single thread.
|
||||
thread_local!{
|
||||
thread_local! {
|
||||
static CURRENT_PASS: Cell<Pass> = Cell::new(Pass::None);
|
||||
static PASS_TIME: RefCell<PassTimes> = RefCell::new(Default::default());
|
||||
}
|
||||
|
|
|
@ -887,11 +887,11 @@ impl<'a> Verifier<'a> {
|
|||
);
|
||||
}
|
||||
// The defining EBB dominates the instruction using this value.
|
||||
if is_reachable && !self.expected_domtree.dominates(
|
||||
ebb,
|
||||
loc_inst,
|
||||
&self.func.layout,
|
||||
) {
|
||||
if is_reachable
|
||||
&& !self
|
||||
.expected_domtree
|
||||
.dominates(ebb, loc_inst, &self.func.layout)
|
||||
{
|
||||
return fatal!(
|
||||
errors,
|
||||
loc_inst,
|
||||
|
@ -1559,7 +1559,8 @@ impl<'a> Verifier<'a> {
|
|||
&self.func,
|
||||
&self.func.dfg[inst],
|
||||
self.func.dfg.ctrl_typevar(inst),
|
||||
).peekable();
|
||||
)
|
||||
.peekable();
|
||||
|
||||
if encodings.peek().is_none() {
|
||||
return nonfatal!(
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"18b45cd5e51eaa9c5591e303a4fcdb759e740be967d02aaa154aaafc25281daa","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/iter.rs":"cd2336dc29891e4e5060fb24f1d2f885a4606ea6580e9bd0f261843f12e31a1b","src/keys.rs":"5eca885b3e7ba19936c24066253bf47ebbd9d0a808a84dc910041e8e7be86349","src/lib.rs":"ccbf78e58d56ef1cb811e5ba451d6e8aa69a84c95f5cfe89c0d1f7ecdd26d15b","src/list.rs":"15d9762396439eb2e835401a7b85e190e097fa5eb863decfb67fb677f1093335","src/map.rs":"bcf7a78077056e4194581cbeb4b9d6bdd263ae1c6b261a0fc011ccda5f39bb4f","src/packed_option.rs":"19b2d49e0233e05e3dc39424187644af546934fe92b7200543fe10728ec831f6","src/primary.rs":"457f72222869abfc06109473d8a7435cf8acaef3888b4bd559608e135aa96395","src/set.rs":"fd687531bb01db9a22ed09486e378fdfe5842c84b603620f83fe8a42109df3cb","src/sparse.rs":"d2b7bd25c7e2b5ef2194feb08c635447953a4548d42ae26d080bb4ca44dfcc20"},"package":"fc9a0329208e5e0d7d4d6e64cd50985d4c4cbfdbeeb594ae2157a094b98e8dcc"}
|
||||
{"files":{"Cargo.toml":"a76fe4900987624504c61e99cf0c20c8dad64a42e77f0e43c0150c416679dd70","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"96ceffbfd88fb06e3b41aa4d3087cffbbf8441d04eba7ab09662a72ab600a321","src/boxed_slice.rs":"b17fae8f1bd8d970221ea0ff185a62dce0da2324abe95c8c8577b06c56cd11cb","src/iter.rs":"cd2336dc29891e4e5060fb24f1d2f885a4606ea6580e9bd0f261843f12e31a1b","src/keys.rs":"5eca885b3e7ba19936c24066253bf47ebbd9d0a808a84dc910041e8e7be86349","src/lib.rs":"dc3255cc56a089c696de14077ab7f49ceb95011c96ded22c6ca06d8418ff3b78","src/list.rs":"15d9762396439eb2e835401a7b85e190e097fa5eb863decfb67fb677f1093335","src/map.rs":"059ef89fa5022b56521162a2fe4b837d2bee84fdfcefd2c9973a910a6fa3417d","src/packed_option.rs":"19b2d49e0233e05e3dc39424187644af546934fe92b7200543fe10728ec831f6","src/primary.rs":"ccbafce1bc2fe15e35f844d32b511b3d422885dd9b4eaa20818b6f865cdb45f8","src/set.rs":"e227411e689c43c2cfea622ff46288598f05dfbe0e8ba652cfb04c6e3ecc192f","src/sparse.rs":"1a0a30f10203df406bd628aedb5242f71f51d35873142062c5b060ce3feae1ea"},"package":"d4df40e26c0cf7b4d86919cb995bb412ee3001cc18e4f3c83a903f30b7007d8b"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-entity"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Data structures using entity references as mapping keys"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
//! Boxed slices for `PrimaryMap`.
|
||||
|
||||
use iter::{Iter, IterMut};
|
||||
use keys::Keys;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::slice;
|
||||
use EntityRef;
|
||||
|
||||
/// A slice mapping `K -> V` allocating dense entity references.
|
||||
///
|
||||
/// The `BoxedSlice` data structure uses the dense index space to implement a map with a boxed
|
||||
/// slice.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
elems: Box<[V]>,
|
||||
unused: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K, V> BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
/// Create a new slice from a raw pointer. A safer way to create slices is
|
||||
/// to use `PrimaryMap::into_boxed_slice()`.
|
||||
pub unsafe fn from_raw(raw: *mut [V]) -> Self {
|
||||
Self {
|
||||
elems: Box::from_raw(raw),
|
||||
unused: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if `k` is a valid key in the map.
|
||||
pub fn is_valid(&self, k: K) -> bool {
|
||||
k.index() < self.elems.len()
|
||||
}
|
||||
|
||||
/// Get the element at `k` if it exists.
|
||||
pub fn get(&self, k: K) -> Option<&V> {
|
||||
self.elems.get(k.index())
|
||||
}
|
||||
|
||||
/// Get the element at `k` if it exists, mutable version.
|
||||
pub fn get_mut(&mut self, k: K) -> Option<&mut V> {
|
||||
self.elems.get_mut(k.index())
|
||||
}
|
||||
|
||||
/// Is this map completely empty?
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.elems.is_empty()
|
||||
}
|
||||
|
||||
/// Get the total number of entity references created.
|
||||
pub fn len(&self) -> usize {
|
||||
self.elems.len()
|
||||
}
|
||||
|
||||
/// Iterate over all the keys in this map.
|
||||
pub fn keys(&self) -> Keys<K> {
|
||||
Keys::with_len(self.elems.len())
|
||||
}
|
||||
|
||||
/// Iterate over all the values in this map.
|
||||
pub fn values(&self) -> slice::Iter<V> {
|
||||
self.elems.iter()
|
||||
}
|
||||
|
||||
/// Iterate over all the values in this map, mutable edition.
|
||||
pub fn values_mut(&mut self) -> slice::IterMut<V> {
|
||||
self.elems.iter_mut()
|
||||
}
|
||||
|
||||
/// Iterate over all the keys and values in this map.
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
|
||||
/// Iterate over all the keys and values in this map, mutable edition.
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut::new(self.elems.iter_mut())
|
||||
}
|
||||
|
||||
/// Get the key that will be assigned to the next pushed value.
|
||||
pub fn next_key(&self) -> K {
|
||||
K::new(self.elems.len())
|
||||
}
|
||||
|
||||
/// Returns the last element that was inserted in the map.
|
||||
pub fn last(&self) -> Option<&V> {
|
||||
self.elems.last()
|
||||
}
|
||||
}
|
||||
|
||||
/// Immutable indexing into a `BoxedSlice`.
|
||||
/// The indexed value must be in the map.
|
||||
impl<K, V> Index<K> for BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
fn index(&self, k: K) -> &V {
|
||||
&self.elems[k.index()]
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutable indexing into a `BoxedSlice`.
|
||||
impl<K, V> IndexMut<K> for BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
fn index_mut(&mut self, k: K) -> &mut V {
|
||||
&mut self.elems[k.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
type Item = (K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Iter::new(self.elems.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a mut BoxedSlice<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
type Item = (K, &'a mut V);
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IterMut::new(self.elems.iter_mut())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use primary::PrimaryMap;
|
||||
|
||||
// `EntityRef` impl for testing.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
struct E(u32);
|
||||
|
||||
impl EntityRef for E {
|
||||
fn new(i: usize) -> Self {
|
||||
E(i as u32)
|
||||
}
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let r0 = E(0);
|
||||
let r1 = E(1);
|
||||
let p = PrimaryMap::<E, isize>::new();
|
||||
let m = p.into_boxed_slice();
|
||||
|
||||
let v: Vec<E> = m.keys().collect();
|
||||
assert_eq!(v, []);
|
||||
|
||||
assert!(!m.is_valid(r0));
|
||||
assert!(!m.is_valid(r1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let mut m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 0;
|
||||
for (key, value) in &m {
|
||||
assert_eq!(key.index(), i);
|
||||
match i {
|
||||
0 => assert_eq!(*value, 12),
|
||||
1 => assert_eq!(*value, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
i = 0;
|
||||
for (key_mut, value_mut) in m.iter_mut() {
|
||||
assert_eq!(key_mut.index(), i);
|
||||
match i {
|
||||
0 => assert_eq!(*value_mut, 12),
|
||||
1 => assert_eq!(*value_mut, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_rev() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let mut m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 2;
|
||||
for (key, value) in m.iter().rev() {
|
||||
i -= 1;
|
||||
assert_eq!(key.index(), i);
|
||||
match i {
|
||||
0 => assert_eq!(*value, 12),
|
||||
1 => assert_eq!(*value, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
i = 2;
|
||||
for (key, value) in m.iter_mut().rev() {
|
||||
i -= 1;
|
||||
assert_eq!(key.index(), i);
|
||||
match i {
|
||||
0 => assert_eq!(*value, 12),
|
||||
1 => assert_eq!(*value, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn keys() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 0;
|
||||
for key in m.keys() {
|
||||
assert_eq!(key.index(), i);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keys_rev() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 2;
|
||||
for key in m.keys().rev() {
|
||||
i -= 1;
|
||||
assert_eq!(key.index(), i);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn values() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let mut m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 0;
|
||||
for value in m.values() {
|
||||
match i {
|
||||
0 => assert_eq!(*value, 12),
|
||||
1 => assert_eq!(*value, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
i = 0;
|
||||
for value_mut in m.values_mut() {
|
||||
match i {
|
||||
0 => assert_eq!(*value_mut, 12),
|
||||
1 => assert_eq!(*value_mut, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn values_rev() {
|
||||
let mut p: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
p.push(12);
|
||||
p.push(33);
|
||||
let mut m = p.into_boxed_slice();
|
||||
|
||||
let mut i = 2;
|
||||
for value in m.values().rev() {
|
||||
i -= 1;
|
||||
match i {
|
||||
0 => assert_eq!(*value, 12),
|
||||
1 => assert_eq!(*value, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
i = 2;
|
||||
for value_mut in m.values_mut().rev() {
|
||||
i -= 1;
|
||||
match i {
|
||||
0 => assert_eq!(*value_mut, 12),
|
||||
1 => assert_eq!(*value_mut, 33),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,10 +32,7 @@
|
|||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "std", deny(unstable_features))]
|
||||
#![cfg_attr(
|
||||
feature = "clippy",
|
||||
plugin(clippy(conf_file = "../../clippy.toml"))
|
||||
)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(new_without_default, new_without_default_derive)
|
||||
|
@ -43,14 +40,14 @@
|
|||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
float_arithmetic,
|
||||
mut_mut,
|
||||
nonminimal_bool,
|
||||
option_map_unwrap_or,
|
||||
option_map_unwrap_or_else,
|
||||
print_stdout,
|
||||
unicode_not_nfc,
|
||||
use_self
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
// Turns on no_std and alloc features if std is not available.
|
||||
|
@ -101,6 +98,21 @@ macro_rules! entity_impl {
|
|||
$entity($crate::__core::u32::MAX)
|
||||
}
|
||||
}
|
||||
|
||||
impl $entity {
|
||||
/// Return the underlying index value as a `u32`.
|
||||
#[allow(dead_code)]
|
||||
pub fn from_u32(x: u32) -> Self {
|
||||
debug_assert!(x < $crate::__core::u32::MAX);
|
||||
$entity(x)
|
||||
}
|
||||
|
||||
/// Return the underlying index value as a `u32`.
|
||||
#[allow(dead_code)]
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Include basic `Display` impl using the given display prefix.
|
||||
|
@ -124,6 +136,7 @@ macro_rules! entity_impl {
|
|||
|
||||
pub mod packed_option;
|
||||
|
||||
mod boxed_slice;
|
||||
mod iter;
|
||||
mod keys;
|
||||
mod list;
|
||||
|
@ -132,6 +145,7 @@ mod primary;
|
|||
mod set;
|
||||
mod sparse;
|
||||
|
||||
pub use self::boxed_slice::BoxedSlice;
|
||||
pub use self::iter::{Iter, IterMut};
|
||||
pub use self::keys::Keys;
|
||||
pub use self::list::{EntityList, ListPool};
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
//! Densely numbered entity references as mapping keys.
|
||||
|
||||
use iter::{Iter, IterMut};
|
||||
use keys::Keys;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::slice;
|
||||
use std::vec::Vec;
|
||||
use {EntityRef, Iter, IterMut, Keys};
|
||||
use EntityRef;
|
||||
|
||||
/// A mapping `K -> V` for densely indexed entity references.
|
||||
///
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
//! Densely numbered entity references as mapping keys.
|
||||
use boxed_slice::BoxedSlice;
|
||||
use iter::{Iter, IterMut};
|
||||
use keys::Keys;
|
||||
use std::iter::FromIterator;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::slice;
|
||||
use std::vec::Vec;
|
||||
use {EntityRef, Iter, IterMut, Keys};
|
||||
use EntityRef;
|
||||
|
||||
/// A primary mapping `K -> V` allocating dense entity references.
|
||||
///
|
||||
|
@ -18,7 +22,8 @@ use {EntityRef, Iter, IterMut, Keys};
|
|||
/// Note that `PrimaryMap` doesn't implement `Deref` or `DerefMut`, which would allow
|
||||
/// `&PrimaryMap<K, V>` to convert to `&[V]`. One of the main advantages of `PrimaryMap` is
|
||||
/// that it only allows indexing with the distinct `EntityRef` key type, so converting to a
|
||||
/// plain slice would make it easier to use incorrectly.
|
||||
/// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use
|
||||
/// `into_boxed_slice`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrimaryMap<K, V>
|
||||
where
|
||||
|
@ -40,6 +45,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new empty map with the given capacity.
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
elems: Vec::with_capacity(capacity),
|
||||
unused: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if `k` is a valid key in the map.
|
||||
pub fn is_valid(&self, k: K) -> bool {
|
||||
k.index() < self.elems.len()
|
||||
|
@ -121,6 +134,11 @@ where
|
|||
pub fn reserve_exact(&mut self, additional: usize) {
|
||||
self.elems.reserve_exact(additional)
|
||||
}
|
||||
|
||||
/// Consumes this `PrimaryMap` and produces a `BoxedSlice`.
|
||||
pub fn into_boxed_slice(self) -> BoxedSlice<K, V> {
|
||||
unsafe { BoxedSlice::<K, V>::from_raw(Box::<[V]>::into_raw(self.elems.into_boxed_slice())) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Immutable indexing into an `PrimaryMap`.
|
||||
|
@ -170,6 +188,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<K, V> FromIterator<V> for PrimaryMap<K, V>
|
||||
where
|
||||
K: EntityRef,
|
||||
{
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = V>,
|
||||
{
|
||||
Self {
|
||||
elems: Vec::from_iter(iter),
|
||||
unused: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -346,4 +379,17 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_iter() {
|
||||
let mut m: PrimaryMap<E, usize> = PrimaryMap::new();
|
||||
m.push(12);
|
||||
m.push(33);
|
||||
|
||||
let n = m.values().collect::<PrimaryMap<E, _>>();
|
||||
assert!(m.len() == n.len());
|
||||
for (me, ne) in m.values().zip(n.values()) {
|
||||
assert!(*me == **ne);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
//! Densely numbered entity references as set keys.
|
||||
|
||||
use keys::Keys;
|
||||
use std::marker::PhantomData;
|
||||
use std::vec::Vec;
|
||||
use {EntityRef, Keys};
|
||||
use EntityRef;
|
||||
|
||||
/// A set of `K` for densely indexed entity references.
|
||||
///
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//! > Briggs, Torczon, *An efficient representation for sparse sets*,
|
||||
//! ACM Letters on Programming Languages and Systems, Volume 2, Issue 1-4, March-Dec. 1993.
|
||||
|
||||
use map::SecondaryMap;
|
||||
use std::mem;
|
||||
use std::slice;
|
||||
use std::u32;
|
||||
use std::vec::Vec;
|
||||
use {EntityRef, SecondaryMap};
|
||||
use EntityRef;
|
||||
|
||||
/// Trait for extracting keys from values stored in a `SparseMap`.
|
||||
///
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"597db8d588c5ed61feb5d54e82f9750575f41211de66c965241186694aec244f","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"98fed7c08319790af423c40498ed8dd856a52b3535d2ecaf4a835392bd951996","src/lib.rs":"9c223914fb7530a669a7487b3b1cf3138df0aed79d152da3d3e03012382244f2","src/ssa.rs":"2b03fd5c88cda8a318827282ed960a61192d6685881ebd8b3d6e8fa92ca6bdc6","src/switch.rs":"bda005663d7976353250c8016ec1f46d0aa03ef289542e4db1b87a071387f7a4","src/variable.rs":"b8de0a43f72ca45bfa0833aee312f3c3f396cf3920545bbdcb9da98fb0de26df"},"package":"98d9eb4a2343435d520499236c805725c88d6d55eefb9a6ad0819b7970c76bdd"}
|
||||
{"files":{"Cargo.toml":"1f837e21c9d7fc5fa7d16477c84fb8482621ca085ed366383d486c5ae6fc5e30","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"dea43e8044284df50f8b8772e9b48ba8b109b45c74111ff73619775d57ad8d67","src/frontend.rs":"9eac4e937d75663e93d8b37d1aedff586d4fe59daec1818eec2a040f8259fcbd","src/lib.rs":"230b18a01a6b0bf7ed8be2f56fff03c5edec64029c069fcce8594a3fb8eb3368","src/ssa.rs":"1a45f96c2fd9f32c11c3eb3ab639e47a15c4b4507509125fba94e243f562b7f2","src/switch.rs":"bda005663d7976353250c8016ec1f46d0aa03ef289542e4db1b87a071387f7a4","src/variable.rs":"b8de0a43f72ca45bfa0833aee312f3c3f396cf3920545bbdcb9da98fb0de26df"},"package":"789907218eeebebcea8122c2053d71affac91c96ce72cea35ebfdbbf547e82af"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Cranelift IR builder helper"
|
||||
documentation = "https://cranelift.readthedocs.io/"
|
||||
|
@ -21,7 +21,7 @@ categories = ["no-std"]
|
|||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cranelift-codegen]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.hashmap_core]
|
||||
|
|
|
@ -514,10 +514,12 @@ impl<'a> FunctionBuilder<'a> {
|
|||
None => false,
|
||||
Some(entry) => self.position.ebb.unwrap() == entry,
|
||||
};
|
||||
!is_entry && self.func_ctx.ssa.is_sealed(self.position.ebb.unwrap()) && !self
|
||||
.func_ctx
|
||||
.ssa
|
||||
.has_any_predecessors(self.position.ebb.unwrap())
|
||||
!is_entry
|
||||
&& self.func_ctx.ssa.is_sealed(self.position.ebb.unwrap())
|
||||
&& !self
|
||||
.func_ctx
|
||||
.ssa
|
||||
.has_any_predecessors(self.position.ebb.unwrap())
|
||||
}
|
||||
|
||||
/// Returns `true` if and only if no instructions have been added since the last call to
|
||||
|
@ -769,7 +771,8 @@ impl<'a> FunctionBuilder<'a> {
|
|||
self.ins().load(config.pointer_type(), flags, src, offset),
|
||||
offset,
|
||||
)
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (value, offset) in registers {
|
||||
self.ins().store(flags, value, dest, offset);
|
||||
|
|
|
@ -164,14 +164,14 @@
|
|||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
float_arithmetic,
|
||||
mut_mut,
|
||||
nonminimal_bool,
|
||||
option_map_unwrap_or,
|
||||
option_map_unwrap_or_else,
|
||||
print_stdout,
|
||||
unicode_not_nfc,
|
||||
use_self
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
|
|
@ -192,9 +192,9 @@ impl SSABuilder {
|
|||
/// Small enum used for clarity in some functions.
|
||||
#[derive(Debug)]
|
||||
enum ZeroOneOrMore<T> {
|
||||
Zero(),
|
||||
Zero,
|
||||
One(T),
|
||||
More(),
|
||||
More,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -526,7 +526,7 @@ impl SSABuilder {
|
|||
temp_arg_var: Variable,
|
||||
dest_ebb: Ebb,
|
||||
) {
|
||||
let mut pred_values: ZeroOneOrMore<Value> = ZeroOneOrMore::Zero();
|
||||
let mut pred_values: ZeroOneOrMore<Value> = ZeroOneOrMore::Zero;
|
||||
|
||||
// Iterate over the predecessors.
|
||||
for _ in 0..self.predecessors(dest_ebb).len() {
|
||||
|
@ -534,21 +534,21 @@ impl SSABuilder {
|
|||
// to var and we put it as an argument of the branch instruction.
|
||||
let pred_val = self.results.pop().unwrap();
|
||||
match pred_values {
|
||||
ZeroOneOrMore::Zero() => {
|
||||
ZeroOneOrMore::Zero => {
|
||||
if pred_val != temp_arg_val {
|
||||
pred_values = ZeroOneOrMore::One(pred_val);
|
||||
}
|
||||
}
|
||||
ZeroOneOrMore::One(old_val) => {
|
||||
if pred_val != temp_arg_val && pred_val != old_val {
|
||||
pred_values = ZeroOneOrMore::More();
|
||||
pred_values = ZeroOneOrMore::More;
|
||||
}
|
||||
}
|
||||
ZeroOneOrMore::More() => {}
|
||||
ZeroOneOrMore::More => {}
|
||||
}
|
||||
}
|
||||
let result_val = match pred_values {
|
||||
ZeroOneOrMore::Zero() => {
|
||||
ZeroOneOrMore::Zero => {
|
||||
// The variable is used but never defined before. This is an irregularity in the
|
||||
// code, but rather than throwing an error we silently initialize the variable to
|
||||
// 0. This will have no effect since this situation happens in unreachable code.
|
||||
|
@ -583,7 +583,7 @@ impl SSABuilder {
|
|||
func.dfg.change_to_alias(temp_arg_val, resolved);
|
||||
resolved
|
||||
}
|
||||
ZeroOneOrMore::More() => {
|
||||
ZeroOneOrMore::More => {
|
||||
// There is disagreement in the predecessors on which value to use so we have
|
||||
// to keep the ebb argument. To avoid borrowing `self` for the whole loop,
|
||||
// temporarily detach the predecessors list and replace it with an empty list.
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"aca5579a3fbaa96d6cfda23012215879f7df0a07313e2e9acdc49e167d31e1c3","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"046f81212a5705bfaa925b6de195652141b727d63ef602af57d5073659deea64","src/code_translator.rs":"474d07684fee27fcbd48997a7772458d8eff0a69a31b74293066a892c87067f9","src/environ/dummy.rs":"aafca1a2cda88cb67d4c082f7ccb6296812586216f417c501224b6790d345446","src/environ/mod.rs":"8c5287366c354acb144593fadbbe45c14106e0b7ec101077c4f3f213901c584d","src/environ/spec.rs":"a627a1a92a2a652d037f63a9def019ebbf4c953de1cb194f2e73095744d07476","src/func_translator.rs":"1c6b7d0d3da14c1ff7df1c22d2ade14da5d87d0be70f647145ea180da762aa2f","src/lib.rs":"b94abdc2fe638aff7b5fc00ffb2fc4812590a68241b8462b82888aa9114c2f64","src/module_translator.rs":"8e441cc4cb05d6bdd7be41f2ba937390f85f3e3b07578e03a0f9e642f963bc02","src/sections_translator.rs":"62d7d53abc88060c4d63721a99530d26a3ed09cb99e1f19238bcefd8b86b958a","src/state.rs":"4523d611d2c4889eb809ee6c2bfbf29d4d83230580be3c724009ba8988cc25b6","src/translation_utils.rs":"363d75509bca5d87548881dcbb3c52642980be8fa6d62c2ea4b39524560ac65c","tests/wasm_testsuite.rs":"9ea05ab8d188f047f3307e5ca0c1ea10784d65d338f7ea3544d59e6fa6a202f2"},"package":"5022a3a3d1044fdc8c97909b5e8d701884982dcfb43885034d004cfdd9b7d577"}
|
||||
{"files":{"Cargo.toml":"741858026996a107f1c9fa0f0c741d615892f5f9e1789bee0da75ce53814c369","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"046f81212a5705bfaa925b6de195652141b727d63ef602af57d5073659deea64","src/code_translator.rs":"0a8d7e8b7987d825f88ebcb4298ab582d80ddad248449fe763ce5593dd3fde51","src/environ/dummy.rs":"df84b9344bda02ed001d5f1ce6a1ecf3a91bda109ff261f27dc23a988504c654","src/environ/mod.rs":"8c5287366c354acb144593fadbbe45c14106e0b7ec101077c4f3f213901c584d","src/environ/spec.rs":"ed02f232326fe998efe3fa0d324f9793dc9005eaa8e0245471e4c05070238ea1","src/func_translator.rs":"1c6b7d0d3da14c1ff7df1c22d2ade14da5d87d0be70f647145ea180da762aa2f","src/lib.rs":"cb99b6156001dbafcecc07cdd0f7c1e45f39595de8fdf08a4fde88e10c670888","src/module_translator.rs":"8e441cc4cb05d6bdd7be41f2ba937390f85f3e3b07578e03a0f9e642f963bc02","src/sections_translator.rs":"a8a348cbac99758282c96c21ed494dfb0626fe1f5c2ff320f323004b494d8f46","src/state.rs":"e34db3dd896c1a122132bcd3a080a2195f4978a7a68e948fe3d7b770c6e8a8d5","src/translation_utils.rs":"5274820a4929edeefb13143f8a8cd08b61a4f536f3933de6e05c050cc1bb1f04","tests/wasm_testsuite.rs":"896d9114984847fb257859c585b06424e0ed166845ce06c2183f4aa397bd7504"},"package":"49723365dab9a48b354bdc24cb6d9d5719bc1d3b858ffd2ea179d0d7d885804a"}
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
[package]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["The Cranelift Project Developers"]
|
||||
description = "Translator from WebAssembly to Cranelift IR"
|
||||
readme = "README.md"
|
||||
|
@ -20,16 +20,19 @@ keywords = ["webassembly", "wasm"]
|
|||
categories = ["no-std", "wasm"]
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/CraneStation/cranelift"
|
||||
[dependencies.cast]
|
||||
version = "0.2.2"
|
||||
|
||||
[dependencies.cranelift-codegen]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cranelift-entity]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cranelift-frontend]
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.failure]
|
||||
|
|
|
@ -26,7 +26,6 @@ use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
|
|||
use cranelift_codegen::ir::types::*;
|
||||
use cranelift_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags};
|
||||
use cranelift_codegen::packed_option::ReservedValue;
|
||||
use cranelift_entity::EntityRef;
|
||||
use cranelift_frontend::{FunctionBuilder, Variable};
|
||||
use environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmError, WasmResult};
|
||||
use state::{ControlStackFrame, TranslationState};
|
||||
|
@ -75,12 +74,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
Operator::GetGlobal { global_index } => {
|
||||
let val = match state.get_global(builder.func, global_index, environ) {
|
||||
GlobalVariable::Const(val) => val,
|
||||
GlobalVariable::Memory { gv, ty } => {
|
||||
GlobalVariable::Memory { gv, offset, ty } => {
|
||||
let addr = builder.ins().global_value(environ.pointer_type(), gv);
|
||||
let mut flags = ir::MemFlags::new();
|
||||
flags.set_notrap();
|
||||
flags.set_aligned();
|
||||
builder.ins().load(ty, flags, addr, 0)
|
||||
let flags = ir::MemFlags::trusted();
|
||||
builder.ins().load(ty, flags, addr, offset)
|
||||
}
|
||||
};
|
||||
state.push1(val);
|
||||
|
@ -88,13 +85,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
Operator::SetGlobal { global_index } => {
|
||||
match state.get_global(builder.func, global_index, environ) {
|
||||
GlobalVariable::Const(_) => panic!("global #{} is a constant", global_index),
|
||||
GlobalVariable::Memory { gv, .. } => {
|
||||
GlobalVariable::Memory { gv, offset, ty } => {
|
||||
let addr = builder.ins().global_value(environ.pointer_type(), gv);
|
||||
let mut flags = ir::MemFlags::new();
|
||||
flags.set_notrap();
|
||||
flags.set_aligned();
|
||||
let flags = ir::MemFlags::trusted();
|
||||
let val = state.pop1();
|
||||
builder.ins().store(flags, val, addr, 0);
|
||||
debug_assert_eq!(ty, builder.func.dfg.value_type(val));
|
||||
builder.ins().store(flags, val, addr, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -358,7 +354,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let (fref, num_args) = state.get_direct_func(builder.func, function_index, environ);
|
||||
let call = environ.translate_call(
|
||||
builder.cursor(),
|
||||
FuncIndex::new(function_index as usize),
|
||||
FuncIndex::from_u32(function_index),
|
||||
fref,
|
||||
state.peekn(num_args),
|
||||
)?;
|
||||
|
@ -381,9 +377,9 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
let callee = state.pop1();
|
||||
let call = environ.translate_call_indirect(
|
||||
builder.cursor(),
|
||||
TableIndex::new(table_index as usize),
|
||||
TableIndex::from_u32(table_index),
|
||||
table,
|
||||
SignatureIndex::new(index as usize),
|
||||
SignatureIndex::from_u32(index),
|
||||
sigref,
|
||||
callee,
|
||||
state.peekn(num_args),
|
||||
|
@ -404,13 +400,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||
Operator::MemoryGrow { reserved } => {
|
||||
// The WebAssembly MVP only supports one linear memory, but we expect the reserved
|
||||
// argument to be a memory index.
|
||||
let heap_index = MemoryIndex::new(reserved as usize);
|
||||
let heap_index = MemoryIndex::from_u32(reserved);
|
||||
let heap = state.get_heap(builder.func, reserved, environ);
|
||||
let val = state.pop1();
|
||||
state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
|
||||
}
|
||||
Operator::MemorySize { reserved } => {
|
||||
let heap_index = MemoryIndex::new(reserved as usize);
|
||||
let heap_index = MemoryIndex::from_u32(reserved);
|
||||
let heap = state.get_heap(builder.func, reserved, environ);
|
||||
state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
|
||||
}
|
||||
|
@ -992,20 +988,20 @@ fn get_heap_addr(
|
|||
) -> (ir::Value, i32) {
|
||||
use std::cmp::min;
|
||||
|
||||
let guard_size: i64 = builder.func.heaps[heap].guard_size.into();
|
||||
debug_assert!(guard_size > 0, "Heap guard pages currently required");
|
||||
let mut adjusted_offset = u64::from(offset);
|
||||
let offset_guard_size: u64 = builder.func.heaps[heap].offset_guard_size.into();
|
||||
|
||||
// Generate `heap_addr` instructions that are friendly to CSE by checking offsets that are
|
||||
// multiples of the guard size. Add one to make sure that we check the pointer itself is in
|
||||
// bounds.
|
||||
//
|
||||
// For accesses on the outer skirts of the guard pages, we expect that we get a trap
|
||||
// even if the access goes beyond the guard pages. This is because the first byte pointed to is
|
||||
// inside the guard pages.
|
||||
let check_size = min(
|
||||
i64::from(u32::MAX),
|
||||
1 + (i64::from(offset) / guard_size) * guard_size,
|
||||
) as u32;
|
||||
// multiples of the offset-guard size. Add one to make sure that we check the pointer itself
|
||||
// is in bounds.
|
||||
if offset_guard_size != 0 {
|
||||
adjusted_offset = adjusted_offset / offset_guard_size * offset_guard_size;
|
||||
}
|
||||
|
||||
// For accesses on the outer skirts of the offset-guard pages, we expect that we get a trap
|
||||
// even if the access goes beyond the offset-guard pages. This is because the first byte
|
||||
// pointed to is inside the offset-guard pages.
|
||||
let check_size = min(u64::from(u32::MAX), 1 + adjusted_offset) as u32;
|
||||
let base = builder.ins().heap_addr(addr_ty, heap, addr32, check_size);
|
||||
|
||||
// Native load/store instructions take a signed `Offset32` immediate, so adjust the base
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
//! "Dummy" implementations of `ModuleEnvironment` and `FuncEnvironment` for testing
|
||||
//! wasm translation.
|
||||
|
||||
use cast;
|
||||
use cranelift_codegen::cursor::FuncCursor;
|
||||
use cranelift_codegen::ir::immediates::{Imm64, Offset32};
|
||||
use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
|
||||
use cranelift_codegen::ir::types::*;
|
||||
use cranelift_codegen::ir::{self, InstBuilder};
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
|
@ -18,7 +19,7 @@ use translation_utils::{
|
|||
|
||||
/// Compute a `ir::ExternalName` for a given wasm function index.
|
||||
fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
|
||||
ir::ExternalName::user(0, func_index.index() as u32)
|
||||
ir::ExternalName::user(0, func_index.as_u32())
|
||||
}
|
||||
|
||||
/// A collection of names under which a given entity is exported.
|
||||
|
@ -169,15 +170,11 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||
|
||||
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
|
||||
// Just create a dummy `vmctx` global.
|
||||
let offset = ((index.index() * 8) as i64 + 8).into();
|
||||
let offset = cast::i32((index.index() * 8) + 8).unwrap().into();
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext {});
|
||||
let iadd = func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: vmctx,
|
||||
offset,
|
||||
global_type: self.pointer_type(),
|
||||
});
|
||||
GlobalVariable::Memory {
|
||||
gv: iadd,
|
||||
gv: vmctx,
|
||||
offset: offset,
|
||||
ty: self.mod_info.globals[index].entity.ty,
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +192,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||
func.create_heap(ir::HeapData {
|
||||
base: gv,
|
||||
min_size: 0.into(),
|
||||
guard_size: 0x8000_0000.into(),
|
||||
offset_guard_size: 0x8000_0000.into(),
|
||||
style: ir::HeapStyle::Static {
|
||||
bound: 0x1_0000_0000.into(),
|
||||
},
|
||||
|
@ -221,9 +218,9 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||
|
||||
func.create_table(ir::TableData {
|
||||
base_gv,
|
||||
min_size: Imm64::new(0),
|
||||
min_size: Uimm64::new(0),
|
||||
bound_gv,
|
||||
element_size: Imm64::new(i64::from(self.pointer_bytes()) * 2),
|
||||
element_size: Uimm64::from(u64::from(self.pointer_bytes()) * 2),
|
||||
index_type: I32,
|
||||
})
|
||||
}
|
||||
|
@ -273,9 +270,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||
let ext = pos.ins().uextend(I64, callee);
|
||||
pos.ins().imul_imm(ext, 4)
|
||||
};
|
||||
let mut mflags = ir::MemFlags::new();
|
||||
mflags.set_notrap();
|
||||
mflags.set_aligned();
|
||||
let mflags = ir::MemFlags::trusted();
|
||||
let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);
|
||||
|
||||
// Build a value list for the indirect call instruction containing the callee, call_args,
|
||||
|
@ -342,10 +337,6 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||
self.info.config
|
||||
}
|
||||
|
||||
fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName {
|
||||
get_func_name(func_index)
|
||||
}
|
||||
|
||||
fn declare_signature(&mut self, sig: &ir::Signature) {
|
||||
self.info.signatures.push(sig.clone());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! All the runtime support necessary for the wasm to cranelift translation is formalized by the
|
||||
//! traits `FunctionEnvironment` and `ModuleEnvironment`.
|
||||
use cranelift_codegen::cursor::FuncCursor;
|
||||
use cranelift_codegen::ir::immediates::Offset32;
|
||||
use cranelift_codegen::ir::{self, InstBuilder};
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use std::convert::From;
|
||||
|
@ -20,6 +21,8 @@ pub enum GlobalVariable {
|
|||
Memory {
|
||||
/// The address of the global variable storage.
|
||||
gv: ir::GlobalValue,
|
||||
/// An offset to add to the address.
|
||||
offset: Offset32,
|
||||
/// The global variable's type.
|
||||
ty: ir::Type,
|
||||
},
|
||||
|
@ -35,11 +38,7 @@ pub enum WasmError {
|
|||
///
|
||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||
/// code. This should never happen for validated WebAssembly code.
|
||||
#[fail(
|
||||
display = "Invalid input WebAssembly code at offset {}: {}",
|
||||
_1,
|
||||
_0
|
||||
)]
|
||||
#[fail(display = "Invalid input WebAssembly code at offset {}: {}", _1, _0)]
|
||||
InvalidWebAssembly {
|
||||
/// A string describing the validation error.
|
||||
message: &'static str,
|
||||
|
@ -239,9 +238,6 @@ pub trait ModuleEnvironment<'data> {
|
|||
/// Get the information needed to produce Cranelift IR for the current target.
|
||||
fn target_config(&self) -> TargetFrontendConfig;
|
||||
|
||||
/// Return the name for the given function index.
|
||||
fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName;
|
||||
|
||||
/// Declares a function signature to the environment.
|
||||
fn declare_signature(&mut self, sig: &ir::Signature);
|
||||
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![cfg_attr(feature = "std", deny(unstable_features))]
|
||||
#![cfg_attr(
|
||||
feature = "clippy",
|
||||
plugin(clippy(conf_file = "../../clippy.toml"))
|
||||
)]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(new_without_default, new_without_default_derive)
|
||||
|
@ -23,14 +20,14 @@
|
|||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
warn(
|
||||
float_arithmetic,
|
||||
mut_mut,
|
||||
nonminimal_bool,
|
||||
option_map_unwrap_or,
|
||||
option_map_unwrap_or_else,
|
||||
print_stdout,
|
||||
unicode_not_nfc,
|
||||
use_self
|
||||
clippy::float_arithmetic,
|
||||
clippy::mut_mut,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_map_unwrap_or,
|
||||
clippy::option_map_unwrap_or_else,
|
||||
clippy::print_stdout,
|
||||
clippy::unicode_not_nfc,
|
||||
clippy::use_self
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
@ -39,6 +36,7 @@
|
|||
extern crate cranelift_codegen;
|
||||
#[macro_use]
|
||||
extern crate cranelift_entity;
|
||||
extern crate cast;
|
||||
extern crate cranelift_frontend;
|
||||
#[cfg(test)]
|
||||
extern crate target_lexicon;
|
||||
|
@ -67,7 +65,8 @@ pub use func_translator::FuncTranslator;
|
|||
pub use module_translator::translate_module;
|
||||
pub use translation_utils::{
|
||||
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex, Global,
|
||||
GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
|
||||
GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType,
|
||||
TableIndex,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
|
|
|
@ -70,11 +70,7 @@ pub fn parse_import_section<'data>(
|
|||
|
||||
match import.ty {
|
||||
ImportSectionEntryType::Function(sig) => {
|
||||
environ.declare_func_import(
|
||||
SignatureIndex::new(sig as usize),
|
||||
module_name,
|
||||
field_name,
|
||||
);
|
||||
environ.declare_func_import(SignatureIndex::from_u32(sig), module_name, field_name);
|
||||
}
|
||||
ImportSectionEntryType::Memory(MemoryType {
|
||||
limits: ref memlimits,
|
||||
|
@ -82,8 +78,8 @@ pub fn parse_import_section<'data>(
|
|||
}) => {
|
||||
environ.declare_memory_import(
|
||||
Memory {
|
||||
pages_count: memlimits.initial as usize,
|
||||
maximum: memlimits.maximum.map(|x| x as usize),
|
||||
minimum: memlimits.initial,
|
||||
maximum: memlimits.maximum,
|
||||
shared,
|
||||
},
|
||||
module_name,
|
||||
|
@ -95,7 +91,7 @@ pub fn parse_import_section<'data>(
|
|||
Global {
|
||||
ty: type_to_type(ty.content_type).unwrap(),
|
||||
mutability: ty.mutable,
|
||||
initializer: GlobalInit::Import(),
|
||||
initializer: GlobalInit::Import,
|
||||
},
|
||||
module_name,
|
||||
field_name,
|
||||
|
@ -106,10 +102,10 @@ pub fn parse_import_section<'data>(
|
|||
Table {
|
||||
ty: match type_to_type(tab.element_type) {
|
||||
Ok(t) => TableElementType::Val(t),
|
||||
Err(()) => TableElementType::Func(),
|
||||
Err(()) => TableElementType::Func,
|
||||
},
|
||||
size: tab.limits.initial as usize,
|
||||
maximum: tab.limits.maximum.map(|x| x as usize),
|
||||
minimum: tab.limits.initial,
|
||||
maximum: tab.limits.maximum,
|
||||
},
|
||||
module_name,
|
||||
field_name,
|
||||
|
@ -127,7 +123,7 @@ pub fn parse_function_section(
|
|||
) -> WasmResult<()> {
|
||||
for entry in functions {
|
||||
let sigindex = entry?;
|
||||
environ.declare_func_type(SignatureIndex::new(sigindex as usize));
|
||||
environ.declare_func_type(SignatureIndex::from_u32(sigindex));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -142,10 +138,10 @@ pub fn parse_table_section(
|
|||
environ.declare_table(Table {
|
||||
ty: match type_to_type(table.element_type) {
|
||||
Ok(t) => TableElementType::Val(t),
|
||||
Err(()) => TableElementType::Func(),
|
||||
Err(()) => TableElementType::Func,
|
||||
},
|
||||
size: table.limits.initial as usize,
|
||||
maximum: table.limits.maximum.map(|x| x as usize),
|
||||
minimum: table.limits.initial,
|
||||
maximum: table.limits.maximum,
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
|
@ -159,8 +155,8 @@ pub fn parse_memory_section(
|
|||
for entry in memories {
|
||||
let memory = entry?;
|
||||
environ.declare_memory(Memory {
|
||||
pages_count: memory.limits.initial as usize,
|
||||
maximum: memory.limits.maximum.map(|x| x as usize),
|
||||
minimum: memory.limits.initial,
|
||||
maximum: memory.limits.maximum,
|
||||
shared: memory.shared,
|
||||
});
|
||||
}
|
||||
|
@ -187,7 +183,7 @@ pub fn parse_global_section(
|
|||
Operator::F32Const { value } => GlobalInit::F32Const(value.bits()),
|
||||
Operator::F64Const { value } => GlobalInit::F64Const(value.bits()),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
GlobalInit::GlobalRef(GlobalIndex::new(global_index as usize))
|
||||
GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
|
||||
}
|
||||
ref s => panic!("unsupported init expr in global section: {:?}", s),
|
||||
};
|
||||
|
@ -230,7 +226,7 @@ pub fn parse_export_section<'data>(
|
|||
|
||||
/// Parses the Start section of the wasm module.
|
||||
pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> {
|
||||
environ.declare_start_func(FuncIndex::new(index as usize));
|
||||
environ.declare_start_func(FuncIndex::from_u32(index));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -249,11 +245,11 @@ pub fn parse_element_section<'data>(
|
|||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => match environ
|
||||
.get_global(GlobalIndex::new(global_index as usize))
|
||||
.get_global(GlobalIndex::from_u32(global_index))
|
||||
.initializer
|
||||
{
|
||||
GlobalInit::I32Const(value) => (None, value as u32 as usize),
|
||||
GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0),
|
||||
GlobalInit::Import => (Some(GlobalIndex::from_u32(global_index)), 0),
|
||||
_ => panic!("should not happen"),
|
||||
},
|
||||
ref s => panic!("unsupported init expr in element section: {:?}", s),
|
||||
|
@ -262,9 +258,9 @@ pub fn parse_element_section<'data>(
|
|||
let mut elems = Vec::new();
|
||||
for item in items_reader {
|
||||
let x = item?;
|
||||
elems.push(FuncIndex::new(x as usize));
|
||||
elems.push(FuncIndex::from_u32(x));
|
||||
}
|
||||
environ.declare_table_elements(TableIndex::new(table_index as usize), base, offset, elems)
|
||||
environ.declare_table_elements(TableIndex::from_u32(table_index), base, offset, elems)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -297,17 +293,17 @@ pub fn parse_data_section<'data>(
|
|||
let (base, offset) = match init_expr_reader.read_operator()? {
|
||||
Operator::I32Const { value } => (None, value as u32 as usize),
|
||||
Operator::GetGlobal { global_index } => match environ
|
||||
.get_global(GlobalIndex::new(global_index as usize))
|
||||
.get_global(GlobalIndex::from_u32(global_index))
|
||||
.initializer
|
||||
{
|
||||
GlobalInit::I32Const(value) => (None, value as u32 as usize),
|
||||
GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0),
|
||||
GlobalInit::Import => (Some(GlobalIndex::from_u32(global_index)), 0),
|
||||
_ => panic!("should not happen"),
|
||||
},
|
||||
ref s => panic!("unsupported init expr in data section: {:?}", s),
|
||||
};
|
||||
environ.declare_data_initialization(
|
||||
MemoryIndex::new(memory_index as usize),
|
||||
MemoryIndex::from_u32(memory_index),
|
||||
base,
|
||||
offset,
|
||||
data,
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
//! value and control stacks during the translation of a single function.
|
||||
|
||||
use cranelift_codegen::ir::{self, Ebb, Inst, Value};
|
||||
use cranelift_entity::EntityRef;
|
||||
use environ::{FuncEnvironment, GlobalVariable};
|
||||
use std::collections::HashMap;
|
||||
use std::vec::Vec;
|
||||
|
@ -287,7 +286,7 @@ impl TranslationState {
|
|||
index: u32,
|
||||
environ: &mut FE,
|
||||
) -> GlobalVariable {
|
||||
let index = GlobalIndex::new(index as usize);
|
||||
let index = GlobalIndex::from_u32(index);
|
||||
*self
|
||||
.globals
|
||||
.entry(index)
|
||||
|
@ -302,7 +301,7 @@ impl TranslationState {
|
|||
index: u32,
|
||||
environ: &mut FE,
|
||||
) -> ir::Heap {
|
||||
let index = MemoryIndex::new(index as usize);
|
||||
let index = MemoryIndex::from_u32(index);
|
||||
*self
|
||||
.heaps
|
||||
.entry(index)
|
||||
|
@ -317,7 +316,7 @@ impl TranslationState {
|
|||
index: u32,
|
||||
environ: &mut FE,
|
||||
) -> ir::Table {
|
||||
let index = TableIndex::new(index as usize);
|
||||
let index = TableIndex::from_u32(index);
|
||||
*self
|
||||
.tables
|
||||
.entry(index)
|
||||
|
@ -334,7 +333,7 @@ impl TranslationState {
|
|||
index: u32,
|
||||
environ: &mut FE,
|
||||
) -> (ir::SigRef, usize) {
|
||||
let index = SignatureIndex::new(index as usize);
|
||||
let index = SignatureIndex::from_u32(index);
|
||||
*self.signatures.entry(index).or_insert_with(|| {
|
||||
let sig = environ.make_indirect_sig(func, index);
|
||||
(sig, normal_args(&func.dfg.signatures[sig]))
|
||||
|
@ -351,7 +350,7 @@ impl TranslationState {
|
|||
index: u32,
|
||||
environ: &mut FE,
|
||||
) -> (ir::FuncRef, usize) {
|
||||
let index = FuncIndex::new(index as usize);
|
||||
let index = FuncIndex::from_u32(index);
|
||||
*self.functions.entry(index).or_insert_with(|| {
|
||||
let fref = environ.make_direct_func(func, index);
|
||||
let sig = func.dfg.ext_funcs[fref].signature;
|
||||
|
|
|
@ -71,9 +71,9 @@ pub enum GlobalInit {
|
|||
/// An `f64.const`.
|
||||
F64Const(u64),
|
||||
/// A `get_global` of another global.
|
||||
GlobalRef(GlobalIndex),
|
||||
GetGlobal(GlobalIndex),
|
||||
///< The global is imported from, and thus initialized by, a different module.
|
||||
Import(),
|
||||
Import,
|
||||
}
|
||||
|
||||
/// WebAssembly table.
|
||||
|
@ -82,25 +82,27 @@ pub struct Table {
|
|||
/// The type of data stored in elements of the table.
|
||||
pub ty: TableElementType,
|
||||
/// The minimum number of elements in the table.
|
||||
pub size: usize,
|
||||
pub minimum: u32,
|
||||
/// The maximum number of elements in the table.
|
||||
pub maximum: Option<usize>,
|
||||
pub maximum: Option<u32>,
|
||||
}
|
||||
|
||||
/// WebAssembly table element. Can be a function or a scalar type.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum TableElementType {
|
||||
/// A scalar type.
|
||||
Val(ir::Type),
|
||||
Func(),
|
||||
/// A function.
|
||||
Func,
|
||||
}
|
||||
|
||||
/// WebAssembly linear memory.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Memory {
|
||||
/// The minimum number of pages in the memory.
|
||||
pub pages_count: usize,
|
||||
pub minimum: u32,
|
||||
/// The maximum number of pages in the memory.
|
||||
pub maximum: Option<usize>,
|
||||
pub maximum: Option<u32>,
|
||||
/// Whether the memory may be shared between multiple threads.
|
||||
pub shared: bool,
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ fn testsuite() {
|
|||
}
|
||||
}
|
||||
false
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
paths.sort_by_key(|dir| dir.path());
|
||||
let flags = Flags::new(settings::builder());
|
||||
for path in paths {
|
||||
|
|
Загрузка…
Ссылка в новой задаче