Share constant_hash code between the meta and codegen crates;
This commit is contained in:
@@ -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<Item = &'cont T>, H: Fn(&T) -> usize>(
|
|
||||||
items: I,
|
|
||||||
num_items: usize,
|
|
||||||
hash_function: H,
|
|
||||||
) -> Vec<Option<&'cont T>> {
|
|
||||||
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
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -49,6 +49,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
use cranelift_codegen_shared::constant_hash::generate_table;
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
@@ -66,7 +67,6 @@ use crate::cdsl::xform::TransformGroupIndex;
|
|||||||
|
|
||||||
use crate::shared::Definitions as SharedDefinitions;
|
use crate::shared::Definitions as SharedDefinitions;
|
||||||
|
|
||||||
use crate::constant_hash::generate_table;
|
|
||||||
use crate::default_map::MapWithDefault;
|
use crate::default_map::MapWithDefault;
|
||||||
use crate::unique_table::UniqueSeqTable;
|
use crate::unique_table::UniqueSeqTable;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use cranelift_codegen_shared::constant_hash;
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
|
|
||||||
use crate::cdsl::camel_case;
|
use crate::cdsl::camel_case;
|
||||||
@@ -10,7 +11,6 @@ use crate::cdsl::typevar::{TypeSet, TypeVar};
|
|||||||
|
|
||||||
use crate::shared::Definitions as SharedDefinitions;
|
use crate::shared::Definitions as SharedDefinitions;
|
||||||
|
|
||||||
use crate::constant_hash;
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::srcgen::{Formatter, Match};
|
use crate::srcgen::{Formatter, Match};
|
||||||
use crate::unique_table::{UniqueSeqTable, UniqueTable};
|
use crate::unique_table::{UniqueSeqTable, UniqueTable};
|
||||||
|
|||||||
@@ -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::camel_case;
|
||||||
use crate::cdsl::settings::{
|
use crate::cdsl::settings::{
|
||||||
BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
|
BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
|
||||||
};
|
};
|
||||||
use crate::constant_hash::{generate_table, simple_hash};
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::srcgen::{Formatter, Match};
|
use crate::srcgen::{Formatter, Match};
|
||||||
use crate::unique_table::UniqueSeqTable;
|
use crate::unique_table::UniqueSeqTable;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub enum ParentGroup {
|
pub enum ParentGroup {
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ mod gen_registers;
|
|||||||
mod gen_settings;
|
mod gen_settings;
|
||||||
mod gen_types;
|
mod gen_types;
|
||||||
|
|
||||||
mod constant_hash;
|
|
||||||
mod default_map;
|
mod default_map;
|
||||||
mod shared;
|
mod shared;
|
||||||
mod unique_table;
|
mod unique_table;
|
||||||
|
|||||||
79
cranelift/codegen/shared/src/constant_hash.rs
Normal file
79
cranelift/codegen/shared/src/constant_hash.rs
Normal file
@@ -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<Item = &'cont T>, H: Fn(&T) -> usize>(
|
||||||
|
items: I,
|
||||||
|
num_items: usize,
|
||||||
|
hash_function: H,
|
||||||
|
) -> Vec<Option<&'cont T>> {
|
||||||
|
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
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
pub mod condcodes;
|
pub mod condcodes;
|
||||||
|
pub mod constant_hash;
|
||||||
|
|
||||||
/// Version number of this crate.
|
/// Version number of this crate.
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
//! Runtime support for precomputed constant hash tables.
|
//! Runtime support for precomputed constant hash tables.
|
||||||
//!
|
//!
|
||||||
//! The `cranelift-codegen/meta/src/constant_hash.rs` Rust crate can generate constant hash tables
|
//! The shared module with the same name can generate constant hash tables using open addressing
|
||||||
//! using open addressing and quadratic probing. The hash tables are arrays that are guaranteed to:
|
//! and quadratic probing.
|
||||||
|
//!
|
||||||
|
//! The hash tables are arrays that are guaranteed to:
|
||||||
//!
|
//!
|
||||||
//! - Have a power-of-two size.
|
//! - Have a power-of-two size.
|
||||||
//! - Contain at least one empty slot.
|
//! - Contain at least one empty slot.
|
||||||
//!
|
//!
|
||||||
//! This module provides runtime support for lookups in these tables.
|
//! 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.
|
/// Trait that must be implemented by the entries in a constant hash table.
|
||||||
pub trait Table<K: Copy + Eq> {
|
pub trait Table<K: Copy + Eq> {
|
||||||
/// Get the number of entries in this table which must be a power of two.
|
/// Get the number of entries in this table which must be a power of two.
|
||||||
@@ -47,6 +52,7 @@ pub fn probe<K: Copy + Eq, T: Table<K> + ?Sized>(
|
|||||||
|
|
||||||
// Quadratic probing.
|
// Quadratic probing.
|
||||||
step += 1;
|
step += 1;
|
||||||
|
|
||||||
// When `table.len()` is a power of two, it can be proven that `idx` will visit all
|
// 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
|
// entries. This means that this loop will always terminate if the hash table has even
|
||||||
// one unused entry.
|
// one unused entry.
|
||||||
@@ -54,25 +60,3 @@ pub fn probe<K: Copy + Eq, T: Table<K> + ?Sized>(
|
|||||||
idx += step;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user