diff --git a/cranelift/codegen/meta/src/constant_hash.rs b/cranelift/codegen/meta/src/constant_hash.rs deleted file mode 100644 index ce6214efa8..0000000000 --- a/cranelift/codegen/meta/src/constant_hash.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::iter; - -pub(crate) 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(crate) fn generate_table<'cont, T, I: iter::Iterator, H: Fn(&T) -> usize>( - items: I, - num_items: usize, - hash_function: H, -) -> Vec> { - let size = (1.20 * num_items 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![None; size]; - - 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.iter(), v.len(), |s| simple_hash(&s)); - assert_eq!( - table, - vec![ - None, - Some(&"Hello".to_string()), - Some(&"world".to_string()), - None - ] - ); -} diff --git a/cranelift/codegen/meta/src/gen_encodings.rs b/cranelift/codegen/meta/src/gen_encodings.rs index cfaa63f087..a2d1da62a7 100644 --- a/cranelift/codegen/meta/src/gen_encodings.rs +++ b/cranelift/codegen/meta/src/gen_encodings.rs @@ -49,6 +49,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::convert::TryFrom; use std::iter::FromIterator; +use cranelift_codegen_shared::constant_hash::generate_table; use cranelift_entity::EntityRef; use crate::error; @@ -66,7 +67,6 @@ use crate::cdsl::xform::TransformGroupIndex; use crate::shared::Definitions as SharedDefinitions; -use crate::constant_hash::generate_table; use crate::default_map::MapWithDefault; use crate::unique_table::UniqueSeqTable; diff --git a/cranelift/codegen/meta/src/gen_inst.rs b/cranelift/codegen/meta/src/gen_inst.rs index ed28a83794..85a853150e 100644 --- a/cranelift/codegen/meta/src/gen_inst.rs +++ b/cranelift/codegen/meta/src/gen_inst.rs @@ -1,5 +1,6 @@ use std::fmt; +use cranelift_codegen_shared::constant_hash; use cranelift_entity::EntityRef; use crate::cdsl::camel_case; @@ -10,7 +11,6 @@ use crate::cdsl::typevar::{TypeSet, TypeVar}; use crate::shared::Definitions as SharedDefinitions; -use crate::constant_hash; use crate::error; use crate::srcgen::{Formatter, Match}; use crate::unique_table::{UniqueSeqTable, UniqueTable}; diff --git a/cranelift/codegen/meta/src/gen_settings.rs b/cranelift/codegen/meta/src/gen_settings.rs index 84c81cddc4..f17a7ea0eb 100644 --- a/cranelift/codegen/meta/src/gen_settings.rs +++ b/cranelift/codegen/meta/src/gen_settings.rs @@ -1,12 +1,14 @@ +use std::collections::HashMap; + +use cranelift_codegen_shared::constant_hash::{generate_table, simple_hash}; + use crate::cdsl::camel_case; use crate::cdsl::settings::{ BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting, }; -use crate::constant_hash::{generate_table, simple_hash}; use crate::error; use crate::srcgen::{Formatter, Match}; use crate::unique_table::UniqueSeqTable; -use std::collections::HashMap; pub enum ParentGroup { None, diff --git a/cranelift/codegen/meta/src/lib.rs b/cranelift/codegen/meta/src/lib.rs index ef450e7875..92d8721334 100644 --- a/cranelift/codegen/meta/src/lib.rs +++ b/cranelift/codegen/meta/src/lib.rs @@ -13,7 +13,6 @@ mod gen_registers; mod gen_settings; mod gen_types; -mod constant_hash; mod default_map; mod shared; mod unique_table; diff --git a/cranelift/codegen/shared/src/constant_hash.rs b/cranelift/codegen/shared/src/constant_hash.rs new file mode 100644 index 0000000000..668dc9f657 --- /dev/null +++ b/cranelift/codegen/shared/src/constant_hash.rs @@ -0,0 +1,79 @@ +//! Build support for precomputed constant hash tables. +//! +//! This module can generate constant hash tables using open addressing and quadratic probing. +//! +//! The hash tables are arrays that are guaranteed to: +//! +//! - Have a power-of-two size. +//! - Contain at least one empty slot. +//! +//! This module provides build meta support for lookups in these tables, as well as the shared hash +//! function used for probing. + +use std::iter; + +/// A primitive hash function for matching opcodes. +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<'cont, T, I: iter::Iterator, H: Fn(&T) -> usize>( + items: I, + num_items: usize, + hash_function: H, +) -> Vec> { + let size = (1.20 * num_items 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![None; size]; + + 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 +} + +#[cfg(test)] +mod tests { + use super::{generate_table, simple_hash}; + + #[test] + fn basic() { + assert_eq!(simple_hash("Hello"), 0x2fa70c01); + assert_eq!(simple_hash("world"), 0x5b0c31d5); + } + + #[test] + fn test_generate_table() { + let v = vec!["Hello".to_string(), "world".to_string()]; + let table = generate_table(v.iter(), v.len(), |s| simple_hash(&s)); + assert_eq!( + table, + vec![ + None, + Some(&"Hello".to_string()), + Some(&"world".to_string()), + None + ] + ); + } +} diff --git a/cranelift/codegen/shared/src/lib.rs b/cranelift/codegen/shared/src/lib.rs index 87de6e7951..478fb0526f 100644 --- a/cranelift/codegen/shared/src/lib.rs +++ b/cranelift/codegen/shared/src/lib.rs @@ -21,6 +21,7 @@ )] pub mod condcodes; +pub mod constant_hash; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/cranelift/codegen/src/constant_hash.rs b/cranelift/codegen/src/constant_hash.rs index 5785a89825..1de2a2edb4 100644 --- a/cranelift/codegen/src/constant_hash.rs +++ b/cranelift/codegen/src/constant_hash.rs @@ -1,13 +1,18 @@ //! Runtime support for precomputed constant hash tables. //! -//! The `cranelift-codegen/meta/src/constant_hash.rs` Rust crate can generate constant hash tables -//! using open addressing and quadratic probing. The hash tables are arrays that are guaranteed to: +//! The shared module with the same name can generate constant hash tables using open addressing +//! and quadratic probing. +//! +//! The hash tables are arrays that are guaranteed to: //! //! - Have a power-of-two size. //! - Contain at least one empty slot. //! //! This module provides runtime support for lookups in these tables. +// Re-export entities from constant_hash for simplicity of use. +pub use cranelift_codegen_shared::constant_hash::*; + /// Trait that must be implemented by the entries in a constant hash table. pub trait Table { /// Get the number of entries in this table which must be a power of two. @@ -47,6 +52,7 @@ pub fn probe + ?Sized>( // Quadratic probing. step += 1; + // When `table.len()` is a power of two, it can be proven that `idx` will visit all // entries. This means that this loop will always terminate if the hash table has even // one unused entry. @@ -54,25 +60,3 @@ pub fn probe + ?Sized>( idx += step; } } - -/// A primitive hash function for matching opcodes. -/// Must match `cranelift-codegen/meta/src/constant_hash.rs`. -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 -} - -#[cfg(test)] -mod tests { - use super::simple_hash; - - #[test] - fn basic() { - // c.f. `meta/src/constant_hash.rs` tests. - assert_eq!(simple_hash("Hello"), 0x2fa70c01); - assert_eq!(simple_hash("world"), 0x5b0c31d5); - } -}