diff --git a/cranelift/isle/isle/src/codegen.rs b/cranelift/isle/isle/src/codegen.rs index c157b1dd15..c94c0e97cd 100644 --- a/cranelift/isle/isle/src/codegen.rs +++ b/cranelift/isle/isle/src/codegen.rs @@ -5,7 +5,8 @@ use crate::log; use crate::sema::ExternalSig; use crate::sema::{TermEnv, TermId, Type, TypeEnv, TypeId, Variant}; use crate::trie::{TrieEdge, TrieNode, TrieSymbol}; -use std::collections::{BTreeMap, BTreeSet}; +use crate::{StableMap, StableSet}; +use std::collections::BTreeMap; use std::fmt::Write; /// Options for code generation. @@ -36,7 +37,7 @@ struct Codegen<'a> { #[derive(Clone, Debug, Default)] struct BodyContext { /// For each value: (is_ref, ty). - values: BTreeMap, + values: StableMap, } impl<'a> Codegen<'a> { @@ -720,7 +721,7 @@ impl<'a> Codegen<'a> { // Gather adjacent match variants so that we can turn these // into a `match` rather than a sequence of `if let`s. let mut last = i; - let mut adjacent_variants = BTreeSet::new(); + let mut adjacent_variants = StableSet::new(); let mut adjacent_variant_input = None; log!( "edge: prio = {:?}, symbol = {:?}", diff --git a/cranelift/isle/isle/src/ir.rs b/cranelift/isle/isle/src/ir.rs index 58c7d410a1..2cf50d63fc 100644 --- a/cranelift/isle/isle/src/ir.rs +++ b/cranelift/isle/isle/src/ir.rs @@ -3,7 +3,7 @@ use crate::lexer::Pos; use crate::log; use crate::sema::*; -use std::collections::BTreeMap; +use crate::StableMap; declare_id!( /// The id of an instruction in a `PatternSequence`. @@ -341,7 +341,7 @@ impl PatternSequence { typeenv: &TypeEnv, termenv: &TermEnv, pat: &Pattern, - vars: &mut BTreeMap, + vars: &mut StableMap, ) { match pat { &Pattern::BindPattern(_ty, var, ref subpat) => { @@ -548,7 +548,7 @@ impl ExprSequence { typeenv: &TypeEnv, termenv: &TermEnv, expr: &Expr, - vars: &BTreeMap, + vars: &StableMap, ) -> Value { log!("gen_expr: expr {:?}", expr); match expr { @@ -622,7 +622,7 @@ pub fn lower_rule( expr_seq.pos = termenv.rules[rule.index()].pos; let ruledata = &termenv.rules[rule.index()]; - let mut vars = BTreeMap::new(); + let mut vars = StableMap::new(); let root_term = ruledata .lhs .root_term() diff --git a/cranelift/isle/isle/src/lib.rs b/cranelift/isle/isle/src/lib.rs index 38d8f81a31..1164dafc3d 100644 --- a/cranelift/isle/isle/src/lib.rs +++ b/cranelift/isle/isle/src/lib.rs @@ -1,6 +1,11 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs)] +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; +use std::hash::Hash; +use std::ops::Index; + macro_rules! declare_id { ( $(#[$attr:meta])* @@ -18,6 +23,74 @@ macro_rules! declare_id { }; } +/// A wrapper around a [HashSet] which prevents accidentally observing the non-deterministic +/// iteration order. +#[derive(Clone, Debug)] +struct StableSet(HashSet); + +impl StableSet { + fn new() -> Self { + StableSet(HashSet::new()) + } +} + +impl StableSet { + fn insert(&mut self, val: T) -> bool { + self.0.insert(val) + } + + fn contains(&self, val: &T) -> bool { + self.0.contains(val) + } +} + +/// A wrapper around a [HashMap] which prevents accidentally observing the non-deterministic +/// iteration order. +#[derive(Clone, Debug)] +pub struct StableMap(HashMap); + +impl StableMap { + fn new() -> Self { + StableMap(HashMap::new()) + } + + fn len(&self) -> usize { + self.0.len() + } +} + +impl Default for StableMap { + fn default() -> Self { + StableMap(HashMap::new()) + } +} + +impl StableMap { + fn insert(&mut self, k: K, v: V) -> Option { + self.0.insert(k, v) + } + + fn contains_key(&self, k: &K) -> bool { + self.0.contains_key(k) + } + + fn get(&self, k: &K) -> Option<&V> { + self.0.get(k) + } + + fn entry(&mut self, k: K) -> Entry { + self.0.entry(k) + } +} + +impl Index<&K> for StableMap { + type Output = V; + + fn index(&self, index: &K) -> &Self::Output { + self.0.index(index) + } +} + pub mod ast; pub mod codegen; pub mod compile; diff --git a/cranelift/isle/isle/src/sema.rs b/cranelift/isle/isle/src/sema.rs index 784fbb5bdd..07c861e3b5 100644 --- a/cranelift/isle/isle/src/sema.rs +++ b/cranelift/isle/isle/src/sema.rs @@ -18,7 +18,8 @@ use crate::ast::Ident; use crate::error::*; use crate::lexer::Pos; use crate::log; -use std::collections::btree_map::Entry; +use crate::{StableMap, StableSet}; +use std::collections::hash_map::Entry; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::sync::Arc; @@ -73,7 +74,7 @@ pub struct TypeEnv { pub syms: Vec, /// Map of already-interned symbol names to their `Sym` ids. - pub sym_map: BTreeMap, + pub sym_map: StableMap, /// Arena of type definitions. /// @@ -81,10 +82,10 @@ pub struct TypeEnv { pub types: Vec, /// A map from a type name symbol to its `TypeId`. - pub type_map: BTreeMap, + pub type_map: StableMap, /// The types of constant symbols. - pub const_types: BTreeMap, + pub const_types: StableMap, /// Type errors that we've found so far during type checking. pub errors: Vec, @@ -188,7 +189,7 @@ pub struct TermEnv { pub terms: Vec, /// A map from am interned `Term`'s name to its `TermId`. - pub term_map: BTreeMap, + pub term_map: StableMap, /// Arena of interned rules defined in this ISLE program. /// @@ -198,7 +199,7 @@ pub struct TermEnv { /// Map from (inner_ty, outer_ty) pairs to term IDs, giving the /// defined implicit type-converter terms we can try to use to fit /// types together. - pub converters: BTreeMap<(TypeId, TypeId), TermId>, + pub converters: StableMap<(TypeId, TypeId), TermId>, } /// A term. @@ -548,10 +549,10 @@ impl TypeEnv { filenames: defs.filenames.clone(), file_texts: defs.file_texts.clone(), syms: vec![], - sym_map: BTreeMap::new(), + sym_map: StableMap::new(), types: vec![], - type_map: BTreeMap::new(), - const_types: BTreeMap::new(), + type_map: StableMap::new(), + const_types: StableMap::new(), errors: vec![], }; @@ -771,9 +772,9 @@ impl TermEnv { pub fn from_ast(tyenv: &mut TypeEnv, defs: &ast::Defs) -> Result { let mut env = TermEnv { terms: vec![], - term_map: BTreeMap::new(), + term_map: StableMap::new(), rules: vec![], - converters: BTreeMap::new(), + converters: StableMap::new(), }; env.collect_term_sigs(tyenv, defs); @@ -1041,7 +1042,7 @@ impl TermEnv { let mut stack = vec![]; 'outer: for root in extractor_call_graph.keys().copied() { stack.clear(); - stack.push((root, vec![root], BTreeSet::new())); + stack.push((root, vec![root], StableSet::new())); while let Some((caller, path, mut seen)) = stack.pop() { let is_new = seen.insert(caller);