Bug 1517752: Update to Cranelift 0.26; r=sunfish

This commit is contained in:
Benjamin Bouvier 2019-01-04 16:19:48 +01:00
Родитель 67343a1ac8
Коммит 1542471486
100 изменённых файлов: 3455 добавлений и 448 удалений

53
Cargo.lock сгенерированный
Просмотреть файл

@ -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,
})
}

1
third_party/rust/cast/.cargo-checksum.json поставляемый Normal file
Просмотреть файл

@ -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"}

42
third_party/rust/cast/CHANGELOG.md поставляемый Normal file
Просмотреть файл

@ -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

21
third_party/rust/cast/Cargo.toml поставляемый Normal file
Просмотреть файл

@ -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"

201
third_party/rust/cast/LICENSE-APACHE поставляемый Normal file
Просмотреть файл

@ -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.

25
third_party/rust/cast/LICENSE-MIT поставляемый Normal file
Просмотреть файл

@ -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.

44
third_party/rust/cast/README.md поставляемый Normal file
Просмотреть файл

@ -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.

21
third_party/rust/cast/ci/install.sh поставляемый Normal file
Просмотреть файл

@ -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

14
third_party/rust/cast/ci/script.sh поставляемый Normal file
Просмотреть файл

@ -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

523
third_party/rust/cast/src/lib.rs поставляемый Normal file
Просмотреть файл

@ -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)
}
}
}

191
third_party/rust/cast/src/test.rs поставляемый Normal file
Просмотреть файл

@ -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]

21
third_party/rust/cranelift-bforest/src/lib.rs поставляемый
Просмотреть файл

@ -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;

164
third_party/rust/cranelift-codegen-meta/src/base/settings.rs поставляемый Normal file
Просмотреть файл

@ -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() {

386
third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs поставляемый Normal file
Просмотреть файл

@ -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,
}
}
}

50
third_party/rust/cranelift-codegen-meta/src/constant_hash.rs поставляемый Normal file
Просмотреть файл

@ -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(())
}

447
third_party/rust/cranelift-codegen-meta/src/gen_settings.rs поставляемый Normal file
Просмотреть файл

@ -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);
}
}

68
third_party/rust/cranelift-codegen-meta/src/unique_table.rs поставляемый Normal file
Просмотреть файл

@ -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"]

31
third_party/rust/cranelift-codegen/build.rs поставляемый
Просмотреть файл

@ -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) {

21
third_party/rust/cranelift-codegen/src/lib.rs поставляемый
Просмотреть файл

@ -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/"

315
third_party/rust/cranelift-entity/src/boxed_slice.rs поставляемый Normal file
Просмотреть файл

@ -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!(),
}
}
}
}

38
third_party/rust/cranelift-entity/src/lib.rs поставляемый
Просмотреть файл

@ -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"}

11
third_party/rust/cranelift-wasm/Cargo.toml поставляемый
Просмотреть файл

@ -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);

25
third_party/rust/cranelift-wasm/src/lib.rs поставляемый
Просмотреть файл

@ -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,

11
third_party/rust/cranelift-wasm/src/state.rs поставляемый
Просмотреть файл

@ -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 {