diff --git a/cranelift/README.md b/cranelift/README.md index 2ce83df9f6..b325058da1 100644 --- a/cranelift/README.md +++ b/cranelift/README.md @@ -79,6 +79,7 @@ Building with no\_std The following crates support \`no\_std\`: - cranelift-entity + - cranelift-bforest - cranelift-codegen - cranelift-frontend - cranelift-native diff --git a/cranelift/publish-all.sh b/cranelift/publish-all.sh index 67311f5f6f..089e7f27cb 100755 --- a/cranelift/publish-all.sh +++ b/cranelift/publish-all.sh @@ -36,7 +36,7 @@ cargo update echo git commit -a -m "\"Bump version to $version"\" echo git push for crate in \ - entity codegen/meta codegen frontend native \ + entity bforest codegen/meta codegen frontend native \ reader wasm module simplejit \ faerie umbrella do diff --git a/lib/bforest/Cargo.toml b/lib/bforest/Cargo.toml new file mode 100644 index 0000000000..8598d7439b --- /dev/null +++ b/lib/bforest/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Cranelift Project Developers"] +name = "cranelift-bforest" +version = "0.18.1" +description = "A forest of B+-trees" +license = "Apache-2.0 WITH LLVM-exception" +documentation = "https://cranelift.readthedocs.io/" +repository = "https://github.com/CraneStation/cranelift" +readme = "README.md" +keywords = ["btree", "forest", "set", "map"] + +[dependencies] +cranelift-entity = { path = "../entity", version = "0.18.1", default-features = false } + +[features] +default = ["std"] +std = ["cranelift-entity/std"] + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/lib/bforest/LICENSE b/lib/bforest/LICENSE new file mode 100644 index 0000000000..be1d7c438a --- /dev/null +++ b/lib/bforest/LICENSE @@ -0,0 +1,219 @@ + + 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. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. diff --git a/lib/bforest/README.md b/lib/bforest/README.md new file mode 100644 index 0000000000..391d6287d2 --- /dev/null +++ b/lib/bforest/README.md @@ -0,0 +1,12 @@ +This crate contains array-based data structures used by the core Cranelift code +generator which represent a set of small ordered sets or maps. + +**These are not general purpose data structures that are somehow magically faster that the +standard library's `BTreeSet` and `BTreeMap` types.** + +The tradeoffs are different: + +- Keys and values are expected to be small and copyable. We optimize for 32-bit types. +- A comparator object is used to compare keys, allowing smaller "context free" keys. +- Empty trees have a very small 32-bit footprint. +- All the trees in a forest can be cleared in constant time. diff --git a/lib/codegen/src/bforest/mod.rs b/lib/bforest/src/lib.rs similarity index 79% rename from lib/codegen/src/bforest/mod.rs rename to lib/bforest/src/lib.rs index bc22cf88c0..2a1c5f8436 100644 --- a/lib/codegen/src/bforest/mod.rs +++ b/lib/bforest/src/lib.rs @@ -1,6 +1,6 @@ //! A forest of B+-trees. //! -//! This module provides a data structures representing a set of small ordered sets or maps. +//! This crate provides a data structures representing a set of small ordered sets or maps. //! It is implemented as a forest of B+-trees all allocating nodes out of the same pool. //! //! **These are not general purpose data structures that are somehow magically faster that the @@ -13,6 +13,34 @@ //! - Empty trees have a very small 32-bit footprint. //! - All the trees in a forest can be cleared in constant time. +#![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 = "cargo-clippy", allow(new_without_default, new_without_default_derive))] +#![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 + ) +)] +// Turns on no_std and alloc features if std is not available. +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc))] + +/// This replaces `std` in builds with `core`. +#[cfg(not(feature = "std"))] +mod std { + extern crate alloc; + pub use self::alloc::{boxed, string, vec}; + pub use core::*; +} + +#[macro_use] +extern crate cranelift_entity as entity; +use entity::packed_option; + use std::borrow::BorrowMut; use std::cmp::Ordering; @@ -86,9 +114,6 @@ trait Forest { /// An array of values for the leaf nodes. type LeafValues: Copy + BorrowMut<[Self::Value]>; - /// Type used for key comparisons. - type Comparator: Comparator; - /// Splat a single key into a whole array. fn splat_key(key: Self::Key) -> Self::LeafKeys; @@ -124,7 +149,11 @@ fn slice_shift(s: &mut [T], n: usize) { mod test { use super::*; use entity::EntityRef; - use ir::Ebb; + + /// An opaque reference to an extended basic block in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Ebb(u32); + entity_impl!(Ebb, "ebb"); #[test] fn comparator() { diff --git a/lib/codegen/src/bforest/map.rs b/lib/bforest/src/map.rs similarity index 90% rename from lib/codegen/src/bforest/map.rs rename to lib/bforest/src/map.rs index 270d186230..497ca2c112 100644 --- a/lib/codegen/src/bforest/map.rs +++ b/lib/bforest/src/map.rs @@ -9,19 +9,17 @@ use std::marker::PhantomData; use std::string::String; /// Tag type defining forest types for a map. -struct MapTypes(PhantomData<(K, V, C)>); +struct MapTypes(PhantomData<(K, V)>); -impl Forest for MapTypes +impl Forest for MapTypes where K: Copy, V: Copy, - C: Comparator, { type Key = K; type Value = V; type LeafKeys = [K; INNER_SIZE - 1]; type LeafValues = [V; INNER_SIZE - 1]; - type Comparator = C; fn splat_key(key: Self::Key) -> Self::LeafKeys { [key; INNER_SIZE - 1] @@ -33,20 +31,18 @@ where } /// Memory pool for a forest of `Map` instances. -pub struct MapForest +pub struct MapForest where K: Copy, V: Copy, - C: Comparator, { - nodes: NodePool>, + nodes: NodePool>, } -impl MapForest +impl MapForest where K: Copy, V: Copy, - C: Comparator, { /// Create a new empty forest. pub fn new() -> Self { @@ -63,7 +59,7 @@ where } } -/// B-tree mapping from `K` to `V` using `C` for comparing keys. +/// B-tree mapping from `K` to `V`. /// /// This is not a general-purpose replacement for `BTreeMap`. See the [module /// documentation](index.html) for more information about design tradeoffs. @@ -72,21 +68,19 @@ where /// they belong to. *Cloning a map does not allocate new memory for the clone*. It creates an alias /// of the same memory. #[derive(Clone)] -pub struct Map +pub struct Map where K: Copy, V: Copy, - C: Comparator, { root: PackedOption, - unused: PhantomData<(K, V, C)>, + unused: PhantomData<(K, V)>, } -impl Map +impl Map where K: Copy, V: Copy, - C: Comparator, { /// Make an empty map. pub fn new() -> Self { @@ -102,7 +96,7 @@ where } /// Get the value stored for `key`. - pub fn get(&self, key: K, forest: &MapForest, comp: &C) -> Option { + pub fn get>(&self, key: K, forest: &MapForest, comp: &C) -> Option { self.root .expand() .and_then(|root| Path::default().find(key, root, &forest.nodes, comp)) @@ -115,7 +109,12 @@ where /// Otherwise, return the last key-value pair with a key that is less than or equal to `key`. /// /// If no stored keys are less than or equal to `key`, return `None`. - pub fn get_or_less(&self, key: K, forest: &MapForest, comp: &C) -> Option<(K, V)> { + pub fn get_or_less>( + &self, + key: K, + forest: &MapForest, + comp: &C, + ) -> Option<(K, V)> { self.root.expand().and_then(|root| { let mut path = Path::default(); match path.find(key, root, &forest.nodes, comp) { @@ -126,18 +125,23 @@ where } /// Insert `key, value` into the map and return the old value stored for `key`, if any. - pub fn insert( + pub fn insert>( &mut self, key: K, value: V, - forest: &mut MapForest, + forest: &mut MapForest, comp: &C, ) -> Option { self.cursor(forest, comp).insert(key, value) } /// Remove `key` from the map and return the removed value for `key`, if any. - pub fn remove(&mut self, key: K, forest: &mut MapForest, comp: &C) -> Option { + pub fn remove>( + &mut self, + key: K, + forest: &mut MapForest, + comp: &C, + ) -> Option { let mut c = self.cursor(forest, comp); if c.goto(key).is_some() { c.remove() @@ -147,7 +151,7 @@ where } /// Remove all entries. - pub fn clear(&mut self, forest: &mut MapForest) { + pub fn clear(&mut self, forest: &mut MapForest) { if let Some(root) = self.root.take() { forest.nodes.free_tree(root); } @@ -158,7 +162,7 @@ where /// Remove all key-value pairs where the predicate returns false. /// /// The predicate is allowed to update the values stored in the map. - pub fn retain(&mut self, forest: &mut MapForest, mut predicate: F) + pub fn retain(&mut self, forest: &mut MapForest, mut predicate: F) where F: FnMut(K, &mut V) -> bool, { @@ -181,16 +185,16 @@ where /// Create a cursor for navigating this map. The cursor is initially positioned off the end of /// the map. - pub fn cursor<'a>( + pub fn cursor<'a, C: Comparator>( &'a mut self, - forest: &'a mut MapForest, + forest: &'a mut MapForest, comp: &'a C, ) -> MapCursor<'a, K, V, C> { MapCursor::new(self, forest, comp) } /// Create an iterator traversing this map. The iterator type is `(K, V)`. - pub fn iter<'a>(&'a self, forest: &'a MapForest) -> MapIter<'a, K, V, C> { + pub fn iter<'a>(&'a self, forest: &'a MapForest) -> MapIter<'a, K, V> { MapIter { root: self.root, pool: &forest.nodes, @@ -199,11 +203,10 @@ where } } -impl Default for Map +impl Default for Map where K: Copy, V: Copy, - C: Comparator, { fn default() -> Self { Self::new() @@ -211,16 +214,15 @@ where } #[cfg(test)] -impl Map +impl Map where K: Copy + fmt::Display, V: Copy, - C: Comparator, { /// Verify consistency. - fn verify(&self, forest: &MapForest, comp: &C) + fn verify>(&self, forest: &MapForest, comp: &C) where - NodeData>: fmt::Display, + NodeData>: fmt::Display, { if let Some(root) = self.root.expand() { forest.nodes.verify_tree(root, comp); @@ -228,7 +230,7 @@ where } /// Get a text version of the path to `key`. - fn tpath(&self, key: K, forest: &MapForest, comp: &C) -> String { + fn tpath>(&self, key: K, forest: &MapForest, comp: &C) -> String { use std::string::ToString; match self.root.expand() { None => "map(empty)".to_string(), @@ -252,9 +254,9 @@ where C: 'a + Comparator, { root: &'a mut PackedOption, - pool: &'a mut NodePool>, + pool: &'a mut NodePool>, comp: &'a C, - path: Path>, + path: Path>, } impl<'a, K, V, C> MapCursor<'a, K, V, C> @@ -265,8 +267,8 @@ where { /// Create a cursor with a default (off-the-end) location. fn new( - container: &'a mut Map, - forest: &'a mut MapForest, + container: &'a mut Map, + forest: &'a mut MapForest, comp: &'a C, ) -> MapCursor<'a, K, V, C> { MapCursor { @@ -379,22 +381,20 @@ where } /// An iterator visiting the key-value pairs of a `Map`. -pub struct MapIter<'a, K, V, C> +pub struct MapIter<'a, K, V> where K: 'a + Copy, V: 'a + Copy, - C: 'a + Comparator, { root: PackedOption, - pool: &'a NodePool>, - path: Path>, + pool: &'a NodePool>, + path: Path>, } -impl<'a, K, V, C> Iterator for MapIter<'a, K, V, C> +impl<'a, K, V> Iterator for MapIter<'a, K, V> where K: 'a + Copy, V: 'a + Copy, - C: 'a + Comparator, { type Item = (K, V); @@ -438,16 +438,16 @@ mod test { #[test] fn node_size() { // check that nodes are cache line sized when keys and values are 32 bits. - type F = MapTypes; + type F = MapTypes; assert_eq!(mem::size_of::>(), 64); } #[test] fn empty() { - let mut f = MapForest::::new(); + let mut f = MapForest::::new(); f.clear(); - let mut m = Map::::new(); + let mut m = Map::::new(); assert!(m.is_empty()); m.clear(&mut f); @@ -470,8 +470,8 @@ mod test { #[test] fn inserting() { - let f = &mut MapForest::::new(); - let mut m = Map::::new(); + let f = &mut MapForest::::new(); + let mut m = Map::::new(); // The first seven values stay in a single leaf node. assert_eq!(m.insert(50, 5.0, f, &()), None); @@ -577,9 +577,9 @@ mod test { #[test] fn split_level0_leaf() { // Various ways of splitting a full leaf node at level 0. - let f = &mut MapForest::::new(); + let f = &mut MapForest::::new(); - fn full_leaf(f: &mut MapForest) -> Map { + fn full_leaf(f: &mut MapForest) -> Map { let mut m = Map::new(); for n in 1..8 { m.insert(n * 10, n as f32 * 1.1, f, &()); @@ -628,7 +628,7 @@ mod test { #[test] fn split_level1_leaf() { // Various ways of splitting a full leaf node at level 1. - let f = &mut MapForest::::new(); + let f = &mut MapForest::::new(); // Return a map whose root node is a full inner node, and the leaf nodes are all full // containing: @@ -637,7 +637,7 @@ mod test { // 210, 220, ..., 270 // ... // 810, 820, ..., 870 - fn full(f: &mut MapForest) -> Map { + fn full(f: &mut MapForest) -> Map { let mut m = Map::new(); // Start by inserting elements in order. @@ -756,7 +756,7 @@ mod test { // Make a tree with two barely healthy leaf nodes: // [ 10 20 30 40 ] [ 50 60 70 80 ] - fn two_leaf(f: &mut MapForest) -> Map { + fn two_leaf(f: &mut MapForest) -> Map { f.clear(); let mut m = Map::new(); for n in 1..9 { @@ -767,7 +767,7 @@ mod test { #[test] fn remove_level1() { - let f = &mut MapForest::::new(); + let f = &mut MapForest::::new(); let mut m = two_leaf(f); // Verify geometry. @@ -830,7 +830,7 @@ mod test { #[test] fn remove_level1_rightmost() { - let f = &mut MapForest::::new(); + let f = &mut MapForest::::new(); let mut m = two_leaf(f); // [ 10 20 30 40 ] [ 50 60 70 80 ] @@ -852,7 +852,7 @@ mod test { // Make a 3-level tree with barely healthy nodes. // 1 root, 8 inner nodes, 7*4+5=33 leaf nodes, 4 entries each. - fn level3_sparse(f: &mut MapForest) -> Map { + fn level3_sparse(f: &mut MapForest) -> Map { f.clear(); let mut m = Map::new(); for n in 1..133 { @@ -863,7 +863,7 @@ mod test { #[test] fn level3_removes() { - let f = &mut MapForest::::new(); + let f = &mut MapForest::::new(); let mut m = level3_sparse(f); m.verify(f, &()); @@ -894,8 +894,8 @@ mod test { #[test] fn insert_many() { - let f = &mut MapForest::::new(); - let mut m = Map::::new(); + let f = &mut MapForest::::new(); + let mut m = Map::::new(); let mm = 4096; let mut x = 0; diff --git a/lib/codegen/src/bforest/node.rs b/lib/bforest/src/node.rs similarity index 99% rename from lib/codegen/src/bforest/node.rs rename to lib/bforest/src/node.rs index b529816afb..de5337053d 100644 --- a/lib/codegen/src/bforest/node.rs +++ b/lib/bforest/src/node.rs @@ -595,7 +595,6 @@ mod test { type Value = SetValue; type LeafKeys = [char; 15]; type LeafValues = [SetValue; 15]; - type Comparator = (); fn splat_key(key: Self::Key) -> Self::LeafKeys { [key; 15] diff --git a/lib/codegen/src/bforest/path.rs b/lib/bforest/src/path.rs similarity index 99% rename from lib/codegen/src/bforest/path.rs rename to lib/bforest/src/path.rs index c0e4a089af..153c487547 100644 --- a/lib/codegen/src/bforest/path.rs +++ b/lib/bforest/src/path.rs @@ -49,7 +49,7 @@ impl Path { key: F::Key, root: Node, pool: &NodePool, - comp: &F::Comparator, + comp: &Comparator, ) -> Option { let mut node = root; for level in 0.. { @@ -723,7 +723,6 @@ mod test { type Value = char; type LeafKeys = [i32; 7]; type LeafValues = [char; 7]; - type Comparator = TC; fn splat_key(key: Self::Key) -> Self::LeafKeys { [key; 7] diff --git a/lib/codegen/src/bforest/pool.rs b/lib/bforest/src/pool.rs similarity index 98% rename from lib/codegen/src/bforest/pool.rs rename to lib/bforest/src/pool.rs index e6b08e4f1c..ceab96d38c 100644 --- a/lib/codegen/src/bforest/pool.rs +++ b/lib/bforest/src/pool.rs @@ -1,5 +1,7 @@ //! B+-tree node pool. +#[cfg(test)] +use super::Comparator; use super::{Forest, Node, NodeData}; use entity::PrimaryMap; #[cfg(test)] @@ -76,12 +78,11 @@ impl NodePool { #[cfg(test)] impl NodePool { /// Verify the consistency of the tree rooted at `node`. - pub fn verify_tree(&self, node: Node, comp: &F::Comparator) + pub fn verify_tree>(&self, node: Node, comp: &C) where NodeData: fmt::Display, F::Key: fmt::Display, { - use super::Comparator; use entity::SparseSet; use std::borrow::Borrow; use std::cmp::Ordering; diff --git a/lib/codegen/src/bforest/set.rs b/lib/bforest/src/set.rs similarity index 88% rename from lib/codegen/src/bforest/set.rs rename to lib/bforest/src/set.rs index 8371fd3bc6..911907ee61 100644 --- a/lib/codegen/src/bforest/set.rs +++ b/lib/bforest/src/set.rs @@ -9,18 +9,16 @@ use std::marker::PhantomData; use std::string::String; /// Tag type defining forest types for a set. -struct SetTypes(PhantomData<(K, C)>); +struct SetTypes(PhantomData); -impl Forest for SetTypes +impl Forest for SetTypes where K: Copy, - C: Comparator, { type Key = K; type Value = SetValue; type LeafKeys = [K; 2 * INNER_SIZE - 1]; type LeafValues = [SetValue; 2 * INNER_SIZE - 1]; - type Comparator = C; fn splat_key(key: Self::Key) -> Self::LeafKeys { [key; 2 * INNER_SIZE - 1] @@ -32,18 +30,16 @@ where } /// Memory pool for a forest of `Set` instances. -pub struct SetForest +pub struct SetForest where K: Copy, - C: Comparator, { - nodes: NodePool>, + nodes: NodePool>, } -impl SetForest +impl SetForest where K: Copy, - C: Comparator, { /// Create a new empty forest. pub fn new() -> Self { @@ -69,19 +65,17 @@ where /// they belong to. *Cloning a set does not allocate new memory for the clone*. It creates an alias /// of the same memory. #[derive(Clone)] -pub struct Set +pub struct Set where K: Copy, - C: Comparator, { root: PackedOption, - unused: PhantomData<(K, C)>, + unused: PhantomData, } -impl Set +impl Set where K: Copy, - C: Comparator, { /// Make an empty set. pub fn new() -> Self { @@ -97,7 +91,7 @@ where } /// Does the set contain `key`?. - pub fn contains(&self, key: K, forest: &SetForest, comp: &C) -> bool { + pub fn contains>(&self, key: K, forest: &SetForest, comp: &C) -> bool { self.root .expand() .and_then(|root| Path::default().find(key, root, &forest.nodes, comp)) @@ -109,14 +103,24 @@ where /// If the set did not contain `key`, insert it and return true. /// /// If `key` is already present, don't change the set and return false. - pub fn insert(&mut self, key: K, forest: &mut SetForest, comp: &C) -> bool { + pub fn insert>( + &mut self, + key: K, + forest: &mut SetForest, + comp: &C, + ) -> bool { self.cursor(forest, comp).insert(key) } /// Remove `key` from the set and return true. /// /// If `key` was not present in the set, return false. - pub fn remove(&mut self, key: K, forest: &mut SetForest, comp: &C) -> bool { + pub fn remove>( + &mut self, + key: K, + forest: &mut SetForest, + comp: &C, + ) -> bool { let mut c = self.cursor(forest, comp); if c.goto(key) { c.remove(); @@ -127,7 +131,7 @@ where } /// Remove all entries. - pub fn clear(&mut self, forest: &mut SetForest) { + pub fn clear(&mut self, forest: &mut SetForest) { if let Some(root) = self.root.take() { forest.nodes.free_tree(root); } @@ -136,7 +140,7 @@ where /// Retains only the elements specified by the predicate. /// /// Remove all elements where the predicate returns false. - pub fn retain(&mut self, forest: &mut SetForest, mut predicate: F) + pub fn retain(&mut self, forest: &mut SetForest, mut predicate: F) where F: FnMut(K) -> bool, { @@ -155,16 +159,16 @@ where /// Create a cursor for navigating this set. The cursor is initially positioned off the end of /// the set. - pub fn cursor<'a>( + pub fn cursor<'a, C: Comparator>( &'a mut self, - forest: &'a mut SetForest, + forest: &'a mut SetForest, comp: &'a C, ) -> SetCursor<'a, K, C> { SetCursor::new(self, forest, comp) } /// Create an iterator traversing this set. The iterator type is `K`. - pub fn iter<'a>(&'a self, forest: &'a SetForest) -> SetIter<'a, K, C> { + pub fn iter<'a>(&'a self, forest: &'a SetForest) -> SetIter<'a, K> { SetIter { root: self.root, pool: &forest.nodes, @@ -173,10 +177,9 @@ where } } -impl Default for Set +impl Default for Set where K: Copy, - C: Comparator, { fn default() -> Self { Self::new() @@ -193,9 +196,9 @@ where C: 'a + Comparator, { root: &'a mut PackedOption, - pool: &'a mut NodePool>, + pool: &'a mut NodePool>, comp: &'a C, - path: Path>, + path: Path>, } impl<'a, K, C> SetCursor<'a, K, C> @@ -205,8 +208,8 @@ where { /// Create a cursor with a default (invalid) location. fn new( - container: &'a mut Set, - forest: &'a mut SetForest, + container: &'a mut Set, + forest: &'a mut SetForest, comp: &'a C, ) -> SetCursor<'a, K, C> { SetCursor { @@ -327,20 +330,18 @@ where } /// An iterator visiting the elements of a `Set`. -pub struct SetIter<'a, K, C> +pub struct SetIter<'a, K> where K: 'a + Copy, - C: 'a + Comparator, { root: PackedOption, - pool: &'a NodePool>, - path: Path>, + pool: &'a NodePool>, + path: Path>, } -impl<'a, K, C> Iterator for SetIter<'a, K, C> +impl<'a, K> Iterator for SetIter<'a, K> where K: 'a + Copy, - C: 'a + Comparator, { type Item = K; @@ -365,16 +366,16 @@ mod test { #[test] fn node_size() { // check that nodes are cache line sized when keys are 32 bits. - type F = SetTypes; + type F = SetTypes; assert_eq!(mem::size_of::>(), 64); } #[test] fn empty() { - let mut f = SetForest::::new(); + let mut f = SetForest::::new(); f.clear(); - let mut s = Set::::new(); + let mut s = Set::::new(); assert!(s.is_empty()); s.clear(&mut f); assert!(!s.contains(7, &f, &())); @@ -394,8 +395,8 @@ mod test { #[test] fn simple_cursor() { - let mut f = SetForest::::new(); - let mut s = Set::::new(); + let mut f = SetForest::::new(); + let mut s = Set::::new(); let mut c = SetCursor::new(&mut s, &mut f, &()); assert!(c.insert(50)); @@ -436,8 +437,8 @@ mod test { #[test] fn two_level_sparse_tree() { - let mut f = SetForest::::new(); - let mut s = Set::::new(); + let mut f = SetForest::::new(); + let mut s = Set::::new(); let mut c = SetCursor::new(&mut s, &mut f, &()); // Insert enough elements that we get a two-level tree. @@ -482,8 +483,8 @@ mod test { #[test] fn three_level_sparse_tree() { - let mut f = SetForest::::new(); - let mut s = Set::::new(); + let mut f = SetForest::::new(); + let mut s = Set::::new(); let mut c = SetCursor::new(&mut s, &mut f, &()); // Insert enough elements that we get a 3-level tree. @@ -535,7 +536,7 @@ mod test { // Level 4: 512 leafs, up to 7680 elements // // A 3-level tree can hold at most 960 elements. - fn dense4l(f: &mut SetForest) -> Set { + fn dense4l(f: &mut SetForest) -> Set { f.clear(); let mut s = Set::new(); @@ -549,7 +550,7 @@ mod test { #[test] fn four_level() { - let mut f = SetForest::::new(); + let mut f = SetForest::::new(); let mut s = dense4l(&mut f); assert_eq!( @@ -593,7 +594,7 @@ mod test { #[test] fn four_level_clear() { - let mut f = SetForest::::new(); + let mut f = SetForest::::new(); let mut s = dense4l(&mut f); s.clear(&mut f); } diff --git a/lib/codegen/Cargo.toml b/lib/codegen/Cargo.toml index 70ab856cf3..4d8f48f012 100644 --- a/lib/codegen/Cargo.toml +++ b/lib/codegen/Cargo.toml @@ -12,6 +12,7 @@ build = "build.rs" [dependencies] cranelift-entity = { path = "../entity", version = "0.18.1", default-features = false } +cranelift-bforest = { path = "../bforest", version = "0.18.1", default-features = false } failure = { version = "0.1.1", default-features = false, features = ["derive"] } failure_derive = { version = "0.1.1", default-features = false } hashmap_core = { version = "0.1.9", optional = true } @@ -30,7 +31,7 @@ cranelift-codegen-meta = { path = "meta", version = "0.18.1" } # of some minimal std-like replacement libraries. At least one of these two # features need to be enabled. default = ["std"] -std = ["cranelift-entity/std", "target-lexicon/std"] +std = ["cranelift-entity/std", "cranelift-bforest/std", "target-lexicon/std"] core = ["hashmap_core"] [badges] diff --git a/lib/codegen/src/flowgraph.rs b/lib/codegen/src/flowgraph.rs index 9eda2741af..b84da7cd0b 100644 --- a/lib/codegen/src/flowgraph.rs +++ b/lib/codegen/src/flowgraph.rs @@ -61,11 +61,11 @@ struct CFGNode { /// /// The redundant EBB stored here is always consistent with the CFG successor lists, even after /// the IR has been edited. - pub predecessors: bforest::Map, + pub predecessors: bforest::Map, /// Set of EBBs that are the targets of branches and jumps in this EBB. /// The set is ordered by EBB number, indicated by the `()` comparator type. - pub successors: bforest::Set, + pub successors: bforest::Set, } /// The Control Flow Graph maintains a mapping of ebbs to their predecessors @@ -73,8 +73,8 @@ struct CFGNode { /// extended basic blocks. pub struct ControlFlowGraph { data: EntityMap, - pred_forest: bforest::MapForest, - succ_forest: bforest::SetForest, + pred_forest: bforest::MapForest, + succ_forest: bforest::SetForest, valid: bool, } @@ -193,7 +193,7 @@ impl ControlFlowGraph { /// An iterator over EBB predecessors. The iterator type is `BasicBlock`. /// /// Each predecessor is an instruction that branches to the EBB. -pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Ebb, ()>); +pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Ebb>); impl<'a> Iterator for PredIter<'a> { type Item = BasicBlock; @@ -204,7 +204,7 @@ impl<'a> Iterator for PredIter<'a> { } /// An iterator over EBB successors. The iterator type is `Ebb`. -pub type SuccIter<'a> = bforest::SetIter<'a, Ebb, ()>; +pub type SuccIter<'a> = bforest::SetIter<'a, Ebb>; #[cfg(test)] mod tests { diff --git a/lib/codegen/src/lib.rs b/lib/codegen/src/lib.rs index 5ba44b8a81..10e8a7a461 100644 --- a/lib/codegen/src/lib.rs +++ b/lib/codegen/src/lib.rs @@ -62,8 +62,8 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[macro_use] pub extern crate cranelift_entity as entity; +pub extern crate cranelift_bforest as bforest; -pub mod bforest; pub mod binemit; pub mod cfg_printer; pub mod cursor; diff --git a/lib/codegen/src/regalloc/liverange.rs b/lib/codegen/src/regalloc/liverange.rs index f330fb12b5..cc6a985641 100644 --- a/lib/codegen/src/regalloc/liverange.rs +++ b/lib/codegen/src/regalloc/liverange.rs @@ -112,6 +112,7 @@ use entity::SparseMapValue; use ir::{Ebb, ExpandedProgramPoint, Inst, Layout, ProgramOrder, ProgramPoint, Value}; use regalloc::affinity::Affinity; use std::cmp::Ordering; +use std::marker::PhantomData; /// Global live range of a single SSA value. /// @@ -172,7 +173,9 @@ pub struct GenLiveRange { /// /// The entries are non-overlapping, and none of them overlap the EBB where the value is /// defined. - liveins: bforest::Map, + liveins: bforest::Map, + + po: PhantomData<*const PO>, } /// Context information needed to query a `LiveRange`. @@ -180,14 +183,14 @@ pub struct LiveRangeContext<'a, PO: 'a + ProgramOrder> { /// Ordering of EBBs. pub order: &'a PO, /// Memory pool. - pub forest: &'a bforest::MapForest, + pub forest: &'a bforest::MapForest, } impl<'a, PO: ProgramOrder> LiveRangeContext<'a, PO> { /// Make a new context. pub fn new( order: &'a PO, - forest: &'a bforest::MapForest, + forest: &'a bforest::MapForest, ) -> LiveRangeContext<'a, PO> { LiveRangeContext { order, forest } } @@ -205,11 +208,13 @@ impl<'a, PO: ProgramOrder> Clone for LiveRangeContext<'a, PO> { impl<'a, PO: ProgramOrder> Copy for LiveRangeContext<'a, PO> {} /// Forest of B-trees used for storing live ranges. -pub type LiveRangeForest = bforest::MapForest; +pub type LiveRangeForest = bforest::MapForest; -impl bforest::Comparator for PO { +struct Cmp<'a, PO: ProgramOrder + 'a>(&'a PO); + +impl<'a, PO: ProgramOrder> bforest::Comparator for Cmp<'a, PO> { fn cmp(&self, a: Ebb, b: Ebb) -> Ordering { - self.cmp(a, b) + self.0.cmp(a, b) } } @@ -224,6 +229,7 @@ impl GenLiveRange { def_begin: def, def_end: def, liveins: bforest::Map::new(), + po: PhantomData, } } @@ -243,7 +249,7 @@ impl GenLiveRange { ebb: Ebb, to: Inst, order: &PO, - forest: &mut bforest::MapForest, + forest: &mut bforest::MapForest, ) -> bool { // First check if we're extending the def interval. // @@ -264,7 +270,8 @@ impl GenLiveRange { } // Now check if we're extending any of the existing live-in intervals. - let mut c = self.liveins.cursor(forest, order); + let cmp = Cmp(order); + let mut c = self.liveins.cursor(forest, &cmp); let first_time_livein; if let Some(end) = c.goto(ebb) { @@ -367,8 +374,9 @@ impl GenLiveRange { /// answer, but it is also possible that an even later program point is returned. So don't /// depend on the returned `Inst` to belong to `ebb`. pub fn livein_local_end(&self, ebb: Ebb, ctx: LiveRangeContext) -> Option { + let cmp = Cmp(ctx.order); self.liveins - .get_or_less(ebb, ctx.forest, ctx.order) + .get_or_less(ebb, ctx.forest, &cmp) .and_then(|(_, inst)| { // We have an entry that ends at `inst`. if ctx.order.cmp(inst, ebb) == Ordering::Greater { @@ -390,10 +398,7 @@ impl GenLiveRange { /// /// Note that the intervals are stored in a compressed form so each entry may span multiple /// EBBs where the value is live in. - pub fn liveins<'a>( - &'a self, - ctx: LiveRangeContext<'a, PO>, - ) -> bforest::MapIter<'a, Ebb, Inst, PO> { + pub fn liveins<'a>(&'a self, ctx: LiveRangeContext<'a, PO>) -> bforest::MapIter<'a, Ebb, Inst> { self.liveins.iter(ctx.forest) } @@ -507,11 +512,7 @@ mod tests { } // Validate the live range invariants. - fn validate( - &self, - lr: &GenLiveRange, - forest: &bforest::MapForest, - ) { + fn validate(&self, lr: &GenLiveRange, forest: &bforest::MapForest) { // The def interval must cover a single EBB. let def_ebb = self.pp_ebb(lr.def_begin); assert_eq!(def_ebb, self.pp_ebb(lr.def_end));