diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index d50da4096a..61e522da31 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -5,6 +5,7 @@ use crate::attr::{AggregatedSpirvAttributes, IntrinsicType}; use crate::codegen_cx::CodegenCx; use crate::spirv_type::SpirvType; use rspirv::spirv::{Capability, StorageClass, Word}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout}; @@ -18,7 +19,6 @@ use rustc_target::abi::{ }; use std::cell::RefCell; use std::collections::hash_map::Entry; -use std::collections::HashMap; use std::fmt; /// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk @@ -28,7 +28,7 @@ use std::fmt; /// tracking. #[derive(Default)] pub struct RecursivePointeeCache<'tcx> { - map: RefCell, PointeeDefState>>, + map: RefCell, PointeeDefState>>, } impl<'tcx> RecursivePointeeCache<'tcx> { diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 4a3fce14fe..1238156613 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -12,14 +12,14 @@ use rspirv::spirv::{ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{AsmBuilderMethods, InlineAsmOperandRef}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::LlvmInlineAsmInner; use rustc_middle::bug; use rustc_span::source_map::Span; use rustc_target::asm::{InlineAsmRegClass, InlineAsmRegOrRegClass, SpirVInlineAsmRegClass}; -use std::collections::{HashMap, HashSet}; pub struct InstructionTable { - table: HashMap<&'static str, &'static rspirv::grammar::Instruction<'static>>, + table: FxHashMap<&'static str, &'static rspirv::grammar::Instruction<'static>>, } impl InstructionTable { @@ -133,9 +133,9 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { } } - let mut id_map = HashMap::new(); - let mut defined_ids = HashSet::new(); - let mut id_to_type_map = HashMap::new(); + let mut id_map = FxHashMap::default(); + let mut defined_ids = FxHashSet::default(); + let mut id_to_type_map = FxHashMap::default(); for operand in operands { if let InlineAsmOperandRef::In { reg: _, value } = operand { let value = value.immediate(); @@ -241,8 +241,8 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn insert_inst( &mut self, - id_map: &mut HashMap<&str, Word>, - defined_ids: &mut HashSet, + id_map: &mut FxHashMap<&str, Word>, + defined_ids: &mut FxHashSet, inst: dr::Instruction, ) { // Types declared must be registered in our type system. @@ -339,9 +339,9 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn codegen_asm<'a>( &mut self, - id_map: &mut HashMap<&'a str, Word>, - defined_ids: &mut HashSet, - id_to_type_map: &mut HashMap, + id_map: &mut FxHashMap<&'a str, Word>, + defined_ids: &mut FxHashSet, + id_to_type_map: &mut FxHashMap, mut tokens: impl Iterator>, ) where 'cx: 'a, @@ -433,8 +433,8 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn parse_operands<'a>( &mut self, - id_map: &mut HashMap<&'a str, Word>, - id_to_type_map: &HashMap, + id_map: &mut FxHashMap<&'a str, Word>, + id_to_type_map: &FxHashMap, mut tokens: impl Iterator>, instruction: &mut dr::Instruction, ) where @@ -537,7 +537,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn infer_result_type( &self, - id_to_type_map: &HashMap, + id_to_type_map: &FxHashMap, instruction: &dr::Instruction, ) -> Option { use crate::spirv_type_constraints::{instruction_signatures, InstSig, TyListPat, TyPat}; @@ -673,8 +673,8 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn parse_id_out<'a>( &mut self, - id_map: &mut HashMap<&'a str, Word>, - defined_ids: &mut HashSet, + id_map: &mut FxHashMap<&'a str, Word>, + defined_ids: &mut FxHashSet, token: Token<'a, 'cx, 'tcx>, ) -> Option> { match token { @@ -762,7 +762,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn parse_id_in<'a>( &mut self, - id_map: &mut HashMap<&'a str, Word>, + id_map: &mut FxHashMap<&'a str, Word>, token: Token<'a, 'cx, 'tcx>, ) -> Option { match token { @@ -904,7 +904,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { fn parse_one_operand<'a>( &mut self, - id_map: &mut HashMap<&'a str, Word>, + id_map: &mut FxHashMap<&'a str, Word>, inst: &mut dr::Instruction, kind: OperandKind, tokens: &mut impl Iterator>, diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs index d96ed8d991..414949f7dd 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs @@ -7,6 +7,7 @@ use crate::spirv_type::SpirvType; use rspirv::dr::Operand; use rspirv::spirv::{Decoration, ExecutionModel, FunctionControl, StorageClass, Word}; use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Instance, Ty, TyKind}; @@ -15,7 +16,6 @@ use rustc_target::abi::{ call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode}, LayoutOf, Size, }; -use std::collections::HashMap; impl<'tcx> CodegenCx<'tcx> { // Entry points declare their "interface" (all uniforms, inputs, outputs, etc.) as parameters. @@ -132,7 +132,7 @@ impl<'tcx> CodegenCx<'tcx> { let mut bx = Builder::new_block(self, stub_fn, ""); let mut call_args = vec![]; - let mut decoration_locations = HashMap::new(); + let mut decoration_locations = FxHashMap::default(); for (entry_arg_abi, hir_param) in arg_abis.iter().zip(hir_params) { bx.set_span(hir_param.span); self.declare_shader_interface_for_param( @@ -262,7 +262,7 @@ impl<'tcx> CodegenCx<'tcx> { op_entry_point_interface_operands: &mut Vec, bx: &mut Builder<'_, 'tcx>, call_args: &mut Vec, - decoration_locations: &mut HashMap, + decoration_locations: &mut FxHashMap, ) { let attrs = AggregatedSpirvAttributes::parse(self, self.tcx.hir().attrs(hir_param.hir_id)); diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs index 087412ab5e..5223677601 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs @@ -30,7 +30,6 @@ use rustc_target::abi::call::FnAbi; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; use rustc_target::spec::{HasTargetSpec, Target}; use std::cell::{Cell, RefCell}; -use std::collections::HashMap; use std::iter::once; use std::rc::Rc; use std::str::FromStr; @@ -41,9 +40,9 @@ pub struct CodegenCx<'tcx> { /// Spir-v module builder pub builder: BuilderSpirv, /// Map from MIR function to spir-v function ID - pub instances: RefCell, SpirvValue>>, + pub instances: RefCell, SpirvValue>>, /// Map from function ID to parameter list - pub function_parameter_values: RefCell>>, + pub function_parameter_values: RefCell>>, pub type_cache: TypeCache<'tcx>, /// Cache generated vtables pub vtables: RefCell, Option>), SpirvValue>>, @@ -51,17 +50,17 @@ pub struct CodegenCx<'tcx> { /// Invalid spir-v IDs that should be stripped from the final binary, /// each with its own reason and span that should be used for reporting /// (in the event that the value is actually needed) - zombie_decorations: RefCell>, + zombie_decorations: RefCell>, /// Functions that have `#[spirv(unroll_loops)]`, and therefore should /// get `LoopControl::UNROLL` applied to all of their loops' `OpLoopMerge` /// instructions, during structuralization. - unroll_loops_decorations: RefCell>, + unroll_loops_decorations: RefCell>, pub kernel_mode: bool, /// Cache of all the builtin symbols we need pub sym: Rc, pub instruction_table: InstructionTable, - pub zombie_undefs_for_system_fn_addrs: RefCell>, - pub libm_intrinsics: RefCell>, + pub zombie_undefs_for_system_fn_addrs: RefCell>, + pub libm_intrinsics: RefCell>, /// Simple `panic!("...")` and builtin panics (from MIR `Assert`s) call `#[lang = "panic"]`. pub panic_fn_id: Cell>, diff --git a/crates/rustc_codegen_spirv/src/link.rs b/crates/rustc_codegen_spirv/src/link.rs index ea47508e83..e9ae7613de 100644 --- a/crates/rustc_codegen_spirv/src/link.rs +++ b/crates/rustc_codegen_spirv/src/link.rs @@ -2,6 +2,7 @@ use crate::{linker, SpirvCodegenBackend, SpirvModuleBuffer, SpirvThinBuffer}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::write::CodegenContext; use rustc_codegen_ssa::{CodegenResults, NativeLib}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; @@ -13,7 +14,6 @@ use rustc_session::config::{CrateType, DebugInfo, Lto, OptLevel, OutputFilenames use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::utils::NativeLibKind; use rustc_session::Session; -use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{CString, OsStr}; use std::fs::File; @@ -143,7 +143,7 @@ fn link_exe( if !out_dir.is_dir() { std::fs::create_dir_all(&out_dir).unwrap(); } - let mut hashmap = HashMap::new(); + let mut hashmap = FxHashMap::default(); for (name, spv_binary) in map { let mut module_filename = out_dir.clone(); module_filename.push(sanitize_filename::sanitize(&name)); @@ -374,7 +374,7 @@ fn create_archive(files: &[&Path], metadata: &[u8], out_filename: &Path) { header.set_cksum(); builder.append(&header, metadata).unwrap(); } - let mut filenames = HashSet::new(); + let mut filenames = FxHashSet::default(); filenames.insert(OsStr::new(".metadata")); for file in files { assert!( diff --git a/crates/rustc_codegen_spirv/src/linker/capability_computation.rs b/crates/rustc_codegen_spirv/src/linker/capability_computation.rs index 75c5765c2f..4276ed3ba1 100644 --- a/crates/rustc_codegen_spirv/src/linker/capability_computation.rs +++ b/crates/rustc_codegen_spirv/src/linker/capability_computation.rs @@ -1,10 +1,10 @@ use rspirv::dr::{Instruction, Module}; use rspirv::spirv::{Capability, Op}; -use std::collections::HashSet; +use rustc_data_structures::fx::FxHashSet; pub fn remove_extra_capabilities(module: &mut Module) { let used_capabilities = used_capabilities(module); - let removable_capabilities: HashSet = [ + let removable_capabilities: FxHashSet = [ Capability::Int8, Capability::Int16, Capability::Int64, @@ -24,8 +24,8 @@ pub fn remove_extra_capabilities(module: &mut Module) { remove_capabilities(module, &to_remove); } -fn used_capabilities(module: &Module) -> HashSet { - let mut set = HashSet::new(); +fn used_capabilities(module: &Module) -> FxHashSet { + let mut set = FxHashSet::default(); for inst in module.all_inst_iter() { set.extend(inst.class.capabilities); match inst.class.opcode { @@ -56,7 +56,7 @@ fn used_capabilities(module: &Module) -> HashSet { set } -fn remove_capabilities(module: &mut Module, set: &HashSet) { +fn remove_capabilities(module: &mut Module, set: &FxHashSet) { module.capabilities.retain(|inst| { inst.class.opcode != Op::Capability || !set.contains(&inst.operands[0].unwrap_capability()) }); @@ -87,7 +87,7 @@ fn additional_extensions(module: &Module, inst: &Instruction) -> &'static [&'sta } pub fn remove_extra_extensions(module: &mut Module) { - let set: HashSet<&str> = module + let set: FxHashSet<&str> = module .all_inst_iter() .flat_map(|inst| { let extensions = inst.class.extensions.iter().copied(); diff --git a/crates/rustc_codegen_spirv/src/linker/dce.rs b/crates/rustc_codegen_spirv/src/linker/dce.rs index a20f6121c1..3341205497 100644 --- a/crates/rustc_codegen_spirv/src/linker/dce.rs +++ b/crates/rustc_codegen_spirv/src/linker/dce.rs @@ -9,7 +9,7 @@ use rspirv::dr::{Function, Instruction, Module}; use rspirv::spirv::{Op, Word}; -use std::collections::HashSet; +use rustc_data_structures::fx::FxHashSet; pub fn dce(module: &mut Module) { let mut rooted = collect_roots(module); @@ -17,15 +17,15 @@ pub fn dce(module: &mut Module) { kill_unrooted(module, &rooted); } -pub fn collect_roots(module: &Module) -> HashSet { - let mut rooted = HashSet::new(); +pub fn collect_roots(module: &Module) -> FxHashSet { + let mut rooted = FxHashSet::default(); for inst in &module.entry_points { root(inst, &mut rooted); } rooted } -fn spread_roots(module: &Module, rooted: &mut HashSet) -> bool { +fn spread_roots(module: &Module, rooted: &mut FxHashSet) -> bool { let mut any = false; for inst in module.global_inst_iter() { if let Some(id) = inst.result_id { @@ -44,7 +44,7 @@ fn spread_roots(module: &Module, rooted: &mut HashSet) -> bool { any } -fn root(inst: &Instruction, rooted: &mut HashSet) -> bool { +fn root(inst: &Instruction, rooted: &mut FxHashSet) -> bool { let mut any = false; if let Some(id) = inst.result_type { any |= rooted.insert(id); @@ -57,7 +57,7 @@ fn root(inst: &Instruction, rooted: &mut HashSet) -> bool { any } -fn is_rooted(inst: &Instruction, rooted: &HashSet) -> bool { +fn is_rooted(inst: &Instruction, rooted: &FxHashSet) -> bool { if let Some(result_id) = inst.result_id { rooted.contains(&result_id) } else { @@ -69,7 +69,7 @@ fn is_rooted(inst: &Instruction, rooted: &HashSet) -> bool { } } -fn kill_unrooted(module: &mut Module, rooted: &HashSet) { +fn kill_unrooted(module: &mut Module, rooted: &FxHashSet) { module .ext_inst_imports .retain(|inst| is_rooted(inst, rooted)); @@ -87,7 +87,7 @@ fn kill_unrooted(module: &mut Module, rooted: &HashSet) { } pub fn dce_phi(func: &mut Function) { - let mut used = HashSet::new(); + let mut used = FxHashSet::default(); loop { let mut changed = false; for inst in func.all_inst_iter() { diff --git a/crates/rustc_codegen_spirv/src/linker/duplicates.rs b/crates/rustc_codegen_spirv/src/linker/duplicates.rs index 3d8d1645f6..9b08c9fd08 100644 --- a/crates/rustc_codegen_spirv/src/linker/duplicates.rs +++ b/crates/rustc_codegen_spirv/src/linker/duplicates.rs @@ -2,11 +2,12 @@ use crate::decorations::{CustomDecoration, ZombieDecoration}; use rspirv::binary::Assemble; use rspirv::dr::{Instruction, Module, Operand}; use rspirv::spirv::{Op, Word}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::bug; -use std::collections::{hash_map, HashMap, HashSet}; +use std::collections::hash_map; pub fn remove_duplicate_extensions(module: &mut Module) { - let mut set = HashSet::new(); + let mut set = FxHashSet::default(); module.extensions.retain(|inst| { inst.class.opcode != Op::Extension @@ -15,7 +16,7 @@ pub fn remove_duplicate_extensions(module: &mut Module) { } pub fn remove_duplicate_capablities(module: &mut Module) { - let mut set = HashSet::new(); + let mut set = FxHashSet::default(); module.capabilities.retain(|inst| { inst.class.opcode != Op::Capability || set.insert(inst.operands[0].unwrap_capability()) }); @@ -23,8 +24,8 @@ pub fn remove_duplicate_capablities(module: &mut Module) { pub fn remove_duplicate_ext_inst_imports(module: &mut Module) { // This is a simpler version of remove_duplicate_types, see that for comments - let mut ext_to_id = HashMap::new(); - let mut rewrite_rules = HashMap::new(); + let mut ext_to_id = FxHashMap::default(); + let mut rewrite_rules = FxHashMap::default(); // First deduplicate the imports for inst in &mut module.ext_inst_imports { @@ -69,8 +70,8 @@ fn make_annotation_key(inst: &Instruction) -> Vec { data } -fn gather_annotations(annotations: &[Instruction]) -> HashMap> { - let mut map = HashMap::new(); +fn gather_annotations(annotations: &[Instruction]) -> FxHashMap> { + let mut map = FxHashMap::default(); for inst in annotations { if inst.class.opcode == Op::Decorate || inst.class.opcode == Op::MemberDecorate { match map.entry(inst.operands[0].id_ref_any().unwrap()) { @@ -93,7 +94,7 @@ fn gather_annotations(annotations: &[Instruction]) -> HashMap> { .collect() } -fn gather_names(debugs: &[Instruction]) -> HashMap { +fn gather_names(debugs: &[Instruction]) -> FxHashMap { debugs .iter() .filter(|inst| inst.class.opcode == Op::Name) @@ -108,10 +109,10 @@ fn gather_names(debugs: &[Instruction]) -> HashMap { fn make_dedupe_key( inst: &Instruction, - unresolved_forward_pointers: &HashSet, - zombies: &HashSet, - annotations: &HashMap>, - names: &HashMap, + unresolved_forward_pointers: &FxHashSet, + zombies: &FxHashSet, + annotations: &FxHashMap>, + names: &FxHashMap, ) -> Vec { let mut data = vec![inst.class.opcode as u32]; @@ -168,7 +169,7 @@ fn make_dedupe_key( data } -fn rewrite_inst_with_rules(inst: &mut Instruction, rules: &HashMap) { +fn rewrite_inst_with_rules(inst: &mut Instruction, rules: &FxHashMap) { if let Some(ref mut id) = inst.result_type { // If the rewrite rules contain this ID, replace with the mapped value, otherwise don't touch it. *id = rules.get(id).copied().unwrap_or(*id); @@ -184,18 +185,18 @@ pub fn remove_duplicate_types(module: &mut Module) { // Keep in mind, this algorithm requires forward type references to not exist - i.e. it's a valid spir-v module. // Include zombies in the key to not merge zombies with non-zombies - let zombies: HashSet = ZombieDecoration::decode_all(module) + let zombies: FxHashSet = ZombieDecoration::decode_all(module) .map(|(z, _)| z) .collect(); // When a duplicate type is encountered, then this is a map from the deleted ID, to the new, deduplicated ID. - let mut rewrite_rules = HashMap::new(); + let mut rewrite_rules = FxHashMap::default(); // Instructions are encoded into "keys": their opcode, followed by arguments, then annotations. // Importantly, result_id is left out. This means that any instruction that declares the same // type, but with different result_id, will result in the same key. - let mut key_to_result_id = HashMap::new(); + let mut key_to_result_id = FxHashMap::default(); // TODO: This is implementing forward pointers incorrectly. - let mut unresolved_forward_pointers = HashSet::new(); + let mut unresolved_forward_pointers = FxHashSet::default(); // Collect a map from type ID to an annotation "key blob" (to append to the type key) let annotations = gather_annotations(&module.annotations); @@ -262,12 +263,12 @@ pub fn remove_duplicate_types(module: &mut Module) { // The same decorations for duplicated types will cause those different types to merge // together. So, we need to deduplicate the annotations as well. (Note we *do* care about the // ID of the type being applied to here, unlike `gather_annotations`) - let mut anno_set = HashSet::new(); + let mut anno_set = FxHashSet::default(); module .annotations .retain(|inst| anno_set.insert(inst.assemble())); // Same thing with OpName - let mut name_ids = HashSet::new(); + let mut name_ids = FxHashSet::default(); module.debugs.retain(|inst| { inst.class.opcode != Op::Name || name_ids.insert(inst.operands[0].unwrap_id_ref()) }); diff --git a/crates/rustc_codegen_spirv/src/linker/import_export_link.rs b/crates/rustc_codegen_spirv/src/linker/import_export_link.rs index c45960a729..dea472cf6b 100644 --- a/crates/rustc_codegen_spirv/src/linker/import_export_link.rs +++ b/crates/rustc_codegen_spirv/src/linker/import_export_link.rs @@ -1,9 +1,9 @@ use super::Result; use rspirv::dr::{Instruction, Module}; use rspirv::spirv::{Capability, Decoration, LinkageType, Op, Word}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorReported; use rustc_session::Session; -use std::collections::{HashMap, HashSet}; pub fn run(sess: &Session, module: &mut Module) -> Result<()> { let (rewrite_rules, killed_parameters) = @@ -17,15 +17,15 @@ pub fn run(sess: &Session, module: &mut Module) -> Result<()> { fn find_import_export_pairs_and_killed_params( sess: &Session, module: &Module, -) -> Result<(HashMap, HashSet)> { +) -> Result<(FxHashMap, FxHashSet)> { let type_map = get_type_map(module); let fn_parameters = fn_parameters(module); // Map from name -> (definition, type) - let mut exports = HashMap::new(); + let mut exports = FxHashMap::default(); // Rules to rewrite the module with - let mut rewrite_rules = HashMap::new(); - let mut killed_parameters = HashSet::new(); + let mut rewrite_rules = FxHashMap::default(); + let mut killed_parameters = FxHashSet::default(); // First, collect all the exports. for annotation in &module.annotations { @@ -84,7 +84,7 @@ fn get_linkage_inst(inst: &Instruction) -> Option<(Word, &str, LinkageType)> { } } -fn get_type_map(module: &Module) -> HashMap { +fn get_type_map(module: &Module) -> FxHashMap { let vars = module .types_global_values .iter() @@ -97,7 +97,7 @@ fn get_type_map(module: &Module) -> HashMap { vars.chain(fns).collect() } -fn fn_parameters(module: &Module) -> HashMap> { +fn fn_parameters(module: &Module) -> FxHashMap> { module .functions .iter() @@ -117,7 +117,7 @@ fn check_tys_equal(sess: &Session, name: &str, import_type: Word, export_type: W } } -fn replace_all_uses_with(module: &mut Module, rules: &HashMap) { +fn replace_all_uses_with(module: &mut Module, rules: &FxHashMap) { module.all_inst_iter_mut().for_each(|inst| { if let Some(ref mut result_type) = &mut inst.result_type { if let Some(&rewrite) = rules.get(result_type) { @@ -135,7 +135,7 @@ fn replace_all_uses_with(module: &mut Module, rules: &HashMap) { }); } -fn kill_linkage_instructions(module: &mut Module, rewrite_rules: &HashMap) { +fn kill_linkage_instructions(module: &mut Module, rewrite_rules: &FxHashMap) { // drop imported functions module .functions @@ -161,8 +161,8 @@ fn kill_linkage_instructions(module: &mut Module, rewrite_rules: &HashMap, - killed_parameters: &HashSet, + rewrite_rules: &FxHashMap, + killed_parameters: &FxHashSet, ) { module.annotations.retain(|inst| { inst.operands.is_empty() diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index 5e0f164ebb..4b16c723a8 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -8,10 +8,10 @@ use super::apply_rewrite_rules; use super::simple_passes::outgoing_edges; use rspirv::dr::{Block, Function, Instruction, Module, ModuleHeader, Operand}; use rspirv::spirv::{FunctionControl, Op, StorageClass, Word}; -use std::collections::{HashMap, HashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::mem::replace; -type FunctionMap = HashMap; +type FunctionMap = FxHashMap; pub fn inline(module: &mut Module) { let functions = module @@ -28,7 +28,7 @@ pub fn inline(module: &mut Module) { .unwrap_or(0); // Drop all the functions we'll be inlining. (This also means we won't waste time processing // inlines in functions that will get inlined) - let mut dropped_ids = HashSet::new(); + let mut dropped_ids = FxHashSet::default(); module.functions.retain(|f| { if should_inline(&disallowed_argument_types, f) { // TODO: We should insert all defined IDs in this function. @@ -58,7 +58,7 @@ pub fn inline(module: &mut Module) { } } -fn compute_disallowed_argument_types(module: &Module) -> HashSet { +fn compute_disallowed_argument_types(module: &Module) -> FxHashSet { let allowed_argument_storage_classes = &[ StorageClass::UniformConstant, StorageClass::Function, @@ -67,8 +67,8 @@ fn compute_disallowed_argument_types(module: &Module) -> HashSet { StorageClass::AtomicCounter, // TODO: StorageBuffer is allowed if VariablePointers is enabled ]; - let mut disallowed_argument_types = HashSet::new(); - let mut disallowed_pointees = HashSet::new(); + let mut disallowed_argument_types = FxHashSet::default(); + let mut disallowed_pointees = FxHashSet::default(); for inst in &module.types_global_values { match inst.class.opcode { Op::TypePointer => { @@ -115,7 +115,7 @@ fn compute_disallowed_argument_types(module: &Module) -> HashSet { disallowed_argument_types } -fn should_inline(disallowed_argument_types: &HashSet, function: &Function) -> bool { +fn should_inline(disallowed_argument_types: &FxHashSet, function: &Function) -> bool { let def = function.def.as_ref().unwrap(); let control = def.operands[0].unwrap_function_control(); control.contains(FunctionControl::INLINE) @@ -136,8 +136,8 @@ struct Inliner<'m, 'map> { types_global_values: &'m mut Vec, void: Word, functions: &'map FunctionMap, - disallowed_argument_types: &'map HashSet, - // rewrite_rules: HashMap, + disallowed_argument_types: &'map FxHashSet, + // rewrite_rules: FxHashMap, } impl Inliner<'_, '_> { @@ -298,7 +298,7 @@ impl Inliner<'_, '_> { true } - fn add_clone_id_rules(&mut self, rewrite_rules: &mut HashMap, blocks: &[Block]) { + fn add_clone_id_rules(&mut self, rewrite_rules: &mut FxHashMap, blocks: &[Block]) { for block in blocks { for inst in block.label.iter().chain(&block.instructions) { if let Some(result_id) = inst.result_id { diff --git a/crates/rustc_codegen_spirv/src/linker/mem2reg.rs b/crates/rustc_codegen_spirv/src/linker/mem2reg.rs index f92e970d1c..3716566061 100644 --- a/crates/rustc_codegen_spirv/src/linker/mem2reg.rs +++ b/crates/rustc_codegen_spirv/src/linker/mem2reg.rs @@ -13,13 +13,14 @@ use super::simple_passes::outgoing_edges; use super::{apply_rewrite_rules, id}; use rspirv::dr::{Block, Function, Instruction, ModuleHeader, Operand}; use rspirv::spirv::{Op, Word}; -use std::collections::{hash_map, HashMap, HashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use std::collections::hash_map; pub fn mem2reg( header: &mut ModuleHeader, types_global_values: &mut Vec, - pointer_to_pointee: &HashMap, - constants: &HashMap, + pointer_to_pointee: &FxHashMap, + constants: &FxHashMap, func: &mut Function, ) { let reachable = compute_reachable(&func.blocks); @@ -124,9 +125,12 @@ fn compute_idom(preds: &[Vec], reachable_blocks: &[bool]) -> Vec], idom: &[Option]) -> Vec> { +fn compute_dominance_frontier( + preds: &[Vec], + idom: &[Option], +) -> Vec> { assert_eq!(preds.len(), idom.len()); - let mut dominance_frontier = vec![HashSet::new(); preds.len()]; + let mut dominance_frontier = vec![FxHashSet::default(); preds.len()]; for node in 0..preds.len() { if preds[node].len() >= 2 { let node_idom = idom[node].unwrap(); @@ -145,10 +149,10 @@ fn compute_dominance_frontier(preds: &[Vec], idom: &[Option]) -> V fn insert_phis_all( header: &mut ModuleHeader, types_global_values: &mut Vec, - pointer_to_pointee: &HashMap, - constants: &HashMap, + pointer_to_pointee: &FxHashMap, + constants: &FxHashMap, blocks: &mut [Block], - dominance_frontier: Vec>, + dominance_frontier: Vec>, ) { let thing = blocks[0] .instructions @@ -172,10 +176,10 @@ fn insert_phis_all( blocks_with_phi, base_var_type, var_map, - phi_defs: HashSet::new(), - visited: HashSet::new(), + phi_defs: FxHashSet::default(), + visited: FxHashSet::default(), stack: Vec::new(), - rewrite_rules: HashMap::new(), + rewrite_rules: FxHashMap::default(), }; renamer.rename(0, None); apply_rewrite_rules(&renamer.rewrite_rules, blocks); @@ -193,15 +197,15 @@ struct VarInfo { } fn collect_access_chains( - pointer_to_pointee: &HashMap, - constants: &HashMap, + pointer_to_pointee: &FxHashMap, + constants: &FxHashMap, blocks: &[Block], base_var: Word, base_var_ty: Word, -) -> Option> { +) -> Option> { fn construct_access_chain_info( - pointer_to_pointee: &HashMap, - constants: &HashMap, + pointer_to_pointee: &FxHashMap, + constants: &FxHashMap, inst: &Instruction, base: &VarInfo, ) -> Option { @@ -217,7 +221,7 @@ fn collect_access_chains( }) } - let mut variables = HashMap::new(); + let mut variables = FxHashMap::default(); variables.insert( base_var, VarInfo { @@ -262,7 +266,7 @@ fn collect_access_chains( Some(variables) } -fn has_store(block: &Block, var_map: &HashMap) -> bool { +fn has_store(block: &Block, var_map: &FxHashMap) -> bool { block.instructions.iter().any(|inst| { let ptr = match inst.class.opcode { Op::Store => inst.operands[0].id_ref_any().unwrap(), @@ -276,14 +280,14 @@ fn has_store(block: &Block, var_map: &HashMap) -> bool { fn insert_phis( blocks: &[Block], - dominance_frontier: &[HashSet], - var_map: &HashMap, -) -> HashSet { + dominance_frontier: &[FxHashSet], + var_map: &FxHashMap, +) -> FxHashSet { // TODO: Some algorithms check if the var is trivial in some way, e.g. all loads and stores are // in a single block. We should probably do that too. - let mut ever_on_work_list = HashSet::new(); + let mut ever_on_work_list = FxHashSet::default(); let mut work_list = Vec::new(); - let mut blocks_with_phi = HashSet::new(); + let mut blocks_with_phi = FxHashSet::default(); for (block_idx, block) in blocks.iter().enumerate() { if has_store(block, var_map) { ever_on_work_list.insert(block_idx); @@ -333,13 +337,13 @@ struct Renamer<'a> { header: &'a mut ModuleHeader, types_global_values: &'a mut Vec, blocks: &'a mut [Block], - blocks_with_phi: HashSet, + blocks_with_phi: FxHashSet, base_var_type: Word, - var_map: &'a HashMap, - phi_defs: HashSet, - visited: HashSet, + var_map: &'a FxHashMap, + phi_defs: FxHashSet, + visited: FxHashSet, stack: Vec, - rewrite_rules: HashMap, + rewrite_rules: FxHashMap, } impl Renamer<'_> { @@ -484,7 +488,7 @@ fn remove_nops(blocks: &mut [Block]) { } } -fn remove_old_variables(blocks: &mut [Block], thing: &[(HashMap, u32)]) { +fn remove_old_variables(blocks: &mut [Block], thing: &[(FxHashMap, u32)]) { blocks[0].instructions.retain(|inst| { inst.class.opcode != Op::Variable || { let result_id = inst.result_id.unwrap(); diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 1387a2b430..3f739381ef 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -17,9 +17,9 @@ use crate::decorations::{CustomDecoration, UnrollLoopsDecoration}; use rspirv::binary::Consumer; use rspirv::dr::{Block, Instruction, Loader, Module, ModuleHeader, Operand}; use rspirv::spirv::{Op, StorageClass, Word}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; use rustc_session::Session; -use std::collections::HashMap; pub type Result = std::result::Result; @@ -35,7 +35,7 @@ pub struct Options { pub enum LinkResult { SingleModule(Module), - MultipleModules(HashMap), + MultipleModules(FxHashMap), } fn id(header: &mut ModuleHeader) -> Word { @@ -44,7 +44,7 @@ fn id(header: &mut ModuleHeader) -> Word { result } -fn apply_rewrite_rules(rewrite_rules: &HashMap, blocks: &mut [Block]) { +fn apply_rewrite_rules(rewrite_rules: &FxHashMap, blocks: &mut [Block]) { let apply = |inst: &mut Instruction| { if let Some(ref mut id) = &mut inst.result_id { if let Some(&rewrite) = rewrite_rules.get(id) { @@ -185,7 +185,7 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result>(); + .collect::>(); UnrollLoopsDecoration::remove_all(&mut output); let mut output = if opts.structurize { @@ -201,8 +201,8 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result { pub fn structurize( module: Module, - unroll_loops_decorations: HashMap, + unroll_loops_decorations: FxHashMap, ) -> Module { let mut builder = Builder::new_from_module(module); @@ -100,7 +100,7 @@ pub fn structurize( block_id_to_idx, loop_control, incoming_edge_count: vec![], - regions: HashMap::new(), + regions: FxHashMap::default(), } .structurize_func(); } @@ -140,7 +140,7 @@ struct Structurizer<'a> { globals: Globals, func: FuncBuilder<'a>, - block_id_to_idx: HashMap, + block_id_to_idx: FxHashMap, /// `LoopControl` to use in all loops' `OpLoopMerge` instruction. /// Currently only affected by function-scoped `#[spirv(unroll_loops)]`. @@ -151,7 +151,7 @@ struct Structurizer<'a> { /// (backedge count is subtracted to hide them from outer regions). incoming_edge_count: Vec, - regions: HashMap, + regions: FxHashMap, } impl Structurizer<'_> { diff --git a/crates/rustc_codegen_spirv/src/linker/simple_passes.rs b/crates/rustc_codegen_spirv/src/linker/simple_passes.rs index 9dfb987e93..b7e4676126 100644 --- a/crates/rustc_codegen_spirv/src/linker/simple_passes.rs +++ b/crates/rustc_codegen_spirv/src/linker/simple_passes.rs @@ -1,6 +1,6 @@ use rspirv::dr::{Block, Function, Module}; use rspirv::spirv::{Op, Word}; -use std::collections::{HashMap, HashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::mem::replace; pub fn shift_ids(module: &mut Module, add: u32) { @@ -31,7 +31,7 @@ pub fn block_ordering_pass(func: &mut Function) { } fn visit_postorder( func: &Function, - visited: &mut HashSet, + visited: &mut FxHashSet, postorder: &mut Vec, current: Word, ) { @@ -60,7 +60,7 @@ pub fn block_ordering_pass(func: &mut Function) { postorder.push(current); } - let mut visited = HashSet::new(); + let mut visited = FxHashSet::default(); let mut postorder = Vec::new(); let entry_label = func.blocks[0].label_id().unwrap(); @@ -93,7 +93,7 @@ pub fn outgoing_edges(block: &Block) -> impl Iterator + '_ { } pub fn compact_ids(module: &mut Module) -> u32 { - let mut remap = HashMap::new(); + let mut remap = FxHashMap::default(); let mut insert = |current_id: u32| -> u32 { let len = remap.len(); diff --git a/crates/rustc_codegen_spirv/src/linker/specializer.rs b/crates/rustc_codegen_spirv/src/linker/specializer.rs index fa2d686715..5a9a441f2c 100644 --- a/crates/rustc_codegen_spirv/src/linker/specializer.rs +++ b/crates/rustc_codegen_spirv/src/linker/specializer.rs @@ -54,8 +54,9 @@ use indexmap::{IndexMap, IndexSet}; use rspirv::dr::{Builder, Function, Instruction, Module, Operand}; use rspirv::spirv::{Op, StorageClass, Word}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use smallvec::SmallVec; -use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; +use std::collections::{BTreeMap, VecDeque}; use std::convert::{TryFrom, TryInto}; use std::ops::{Range, RangeTo}; use std::{fmt, io, iter, mem, slice}; @@ -109,7 +110,7 @@ pub fn specialize(module: Module, specialization: impl Specialization) -> Module let debug = std::env::var("SPECIALIZER_DEBUG").is_ok(); let dump_instances = std::env::var("SPECIALIZER_DUMP_INSTANCES").ok(); - let mut debug_names = HashMap::new(); + let mut debug_names = FxHashMap::default(); if debug || dump_instances.is_some() { debug_names = module .debugs @@ -131,7 +132,7 @@ pub fn specialize(module: Module, specialization: impl Specialization) -> Module debug_names, generics: IndexMap::new(), - int_consts: HashMap::new(), + int_consts: FxHashMap::default(), }; specializer.collect_generics(&module); @@ -197,7 +198,7 @@ struct CallGraph { impl CallGraph { fn collect(module: &Module) -> Self { - let func_id_to_idx: HashMap<_, _> = module + let func_id_to_idx: FxHashMap<_, _> = module .functions .iter() .enumerate() @@ -579,14 +580,14 @@ struct Specializer { debug: bool, // HACK(eddyb) if debugging is requested, this is used to quickly get `OpName`s. - debug_names: HashMap, + debug_names: FxHashMap, // FIXME(eddyb) compact SPIR-V IDs to allow flatter maps. generics: IndexMap, /// Integer `OpConstant`s (i.e. containing a `LiteralInt32`), to be used /// for interpreting `TyPat::IndexComposite` (such as for `OpAccessChain`). - int_consts: HashMap, + int_consts: FxHashMap, } impl Specializer { @@ -616,7 +617,7 @@ impl Specializer { .iter() .chain(module.functions.iter().filter_map(|f| f.def.as_ref())); - let mut forward_declared_pointers = HashSet::new(); + let mut forward_declared_pointers = FxHashSet::default(); for inst in types_global_values_and_functions { let result_id = inst.result_id.unwrap_or_else(|| { unreachable!( @@ -2478,7 +2479,7 @@ impl<'a, S: Specialization> Expander<'a, S> { if newly_expanded_functions.len() > 1 { // NOTE(eddyb) this is defined outside the loop to avoid // allocating it for every expanded copy of the function. - let mut rewrite_rules = HashMap::new(); + let mut rewrite_rules = FxHashMap::default(); for func in newly_expanded_functions { rewrite_rules.extend(func.parameters.iter_mut().map(|param| { diff --git a/crates/rustc_codegen_spirv/src/linker/structurizer.rs b/crates/rustc_codegen_spirv/src/linker/structurizer.rs index 510c70bd06..d2f59bb896 100644 --- a/crates/rustc_codegen_spirv/src/linker/structurizer.rs +++ b/crates/rustc_codegen_spirv/src/linker/structurizer.rs @@ -7,8 +7,9 @@ use rspirv::{ dr::{Block, Builder, InsertPoint, Module, Operand}, spirv::LoopControl, }; +use rustc_data_structures::fx::FxHashMap; use rustc_session::Session; -use std::collections::{HashMap, VecDeque}; +use std::collections::VecDeque; pub struct LoopInfo { merge_id: Word, @@ -127,7 +128,7 @@ impl ControlFlowInfo { pub fn structurize( sess: &Session, module: Module, - unroll_loops_decorations: HashMap, + unroll_loops_decorations: FxHashMap, ) -> Module { let mut builder = Builder::new_from_module(module); @@ -686,7 +687,7 @@ pub fn insert_selection_merge_on_conditional_branch( } } - let mut modified_ids = HashMap::new(); + let mut modified_ids = FxHashMap::default(); // Find convergence point. for id in branch_conditional_ops.iter() { @@ -798,7 +799,7 @@ pub fn insert_loop_merge_on_conditional_branch( } } } - let mut modified_ids = HashMap::new(); + let mut modified_ids = FxHashMap::default(); // Figure out which branch loops and which branch should merge, also find any potential break ops. for (id, looping_branch_idx) in branch_conditional_ops.iter() { diff --git a/crates/rustc_codegen_spirv/src/linker/zombies.rs b/crates/rustc_codegen_spirv/src/linker/zombies.rs index 6ad616e90d..26e75c3b2a 100644 --- a/crates/rustc_codegen_spirv/src/linker/zombies.rs +++ b/crates/rustc_codegen_spirv/src/linker/zombies.rs @@ -3,9 +3,9 @@ use crate::decorations::{CustomDecoration, ZombieDecoration}; use rspirv::dr::{Instruction, Module}; use rspirv::spirv::{Op, Word}; +use rustc_data_structures::fx::FxHashMap; use rustc_session::Session; use rustc_span::{Span, DUMMY_SP}; -use std::collections::HashMap; use std::env; use std::iter::once; @@ -35,7 +35,7 @@ impl<'a> ZombieInfo<'a> { fn contains_zombie<'h, 'a>( inst: &Instruction, - zombie: &'h HashMap>, + zombie: &'h FxHashMap>, ) -> Option<&'h ZombieInfo<'a>> { if let Some(result_type) = inst.result_type { if let Some(reason) = zombie.get(&result_type) { @@ -49,7 +49,7 @@ fn contains_zombie<'h, 'a>( fn is_zombie<'h, 'a>( inst: &Instruction, - zombie: &'h HashMap>, + zombie: &'h FxHashMap>, ) -> Option<&'h ZombieInfo<'a>> { if let Some(result_id) = inst.result_id { zombie.get(&result_id) @@ -60,13 +60,13 @@ fn is_zombie<'h, 'a>( fn is_or_contains_zombie<'h, 'a>( inst: &Instruction, - zombie: &'h HashMap>, + zombie: &'h FxHashMap>, ) -> Option<&'h ZombieInfo<'a>> { let result_zombie = inst.result_id.and_then(|result_id| zombie.get(&result_id)); result_zombie.or_else(|| contains_zombie(inst, zombie)) } -fn spread_zombie(module: &mut Module, zombie: &mut HashMap>) -> bool { +fn spread_zombie(module: &mut Module, zombie: &mut FxHashMap>) -> bool { let mut any = false; // globals are easy for inst in module.global_inst_iter() { @@ -103,7 +103,7 @@ fn spread_zombie(module: &mut Module, zombie: &mut HashMap> any } -fn get_names(module: &Module) -> HashMap { +fn get_names(module: &Module) -> FxHashMap { module .debugs .iter() @@ -120,7 +120,7 @@ fn get_names(module: &Module) -> HashMap { // If an entry point references a zombie'd value, then the entry point would normally get removed. // That's an absolutely horrible experience to debug, though, so instead, create a nice error // message containing the stack trace of how the entry point got to the zombie value. -fn report_error_zombies(sess: &Session, module: &Module, zombie: &HashMap>) { +fn report_error_zombies(sess: &Session, module: &Module, zombie: &FxHashMap>) { let mut names = None; for root in super::dce::collect_roots(module) { if let Some(reason) = zombie.get(&root) { diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index f95e511133..ef00e916d0 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -7,11 +7,11 @@ use rspirv::dr::Operand; use rspirv::spirv::{ AccessQualifier, Capability, Decoration, Dim, ImageFormat, StorageClass, Word, }; +use rustc_data_structures::fx::FxHashMap; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_target::abi::{Align, Size}; use std::cell::RefCell; -use std::collections::HashMap; use std::fmt; use std::iter; use std::lazy::SyncLazy; @@ -690,7 +690,7 @@ pub struct TypeCache<'tcx> { /// Set of names for a type (only `SpirvType::Adt` currently). /// The same `OpType*` may have multiple names if it's e.g. a generic /// `struct` where the generic parameters result in the same field types. - type_names: RefCell>>>, + type_names: RefCell>>>, } impl TypeCache<'_> { diff --git a/crates/rustc_codegen_spirv/src/symbols.rs b/crates/rustc_codegen_spirv/src/symbols.rs index af99e12ae7..daaeacdb42 100644 --- a/crates/rustc_codegen_spirv/src/symbols.rs +++ b/crates/rustc_codegen_spirv/src/symbols.rs @@ -2,9 +2,9 @@ use crate::attr::{Entry, ExecutionModeExtra, IntrinsicType, SpirvAttribute}; use crate::builder::libm_intrinsics; use rspirv::spirv::{BuiltIn, ExecutionMode, ExecutionModel, StorageClass}; use rustc_ast::ast::{AttrKind, Attribute, Lit, LitIntType, LitKind, NestedMetaItem}; +use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; -use std::collections::HashMap; use std::rc::Rc; /// Various places in the codebase (mostly attribute parsing) need to compare rustc Symbols to particular keywords. @@ -41,9 +41,9 @@ pub struct Symbols { sampled: Symbol, image_format: Symbol, access_qualifier: Symbol, - attributes: HashMap, - execution_modes: HashMap, - pub libm_intrinsics: HashMap, + attributes: FxHashMap, + execution_modes: FxHashMap, + pub libm_intrinsics: FxHashMap, } const BUILTINS: &[(&str, BuiltIn)] = { @@ -350,20 +350,20 @@ impl Symbols { .chain(execution_models) .chain(custom_attributes) .map(|(a, b)| (Symbol::intern(a), b)); - let mut attributes = HashMap::new(); + let mut attributes = FxHashMap::default(); for (a, b) in attributes_iter { let old = attributes.insert(a, b); - // `.collect()` into a HashMap does not error on duplicates, so manually write out the + // `.collect()` into a FxHashMap does not error on duplicates, so manually write out the // loop here to error on duplicates. assert!(old.is_none()); } - let mut execution_modes = HashMap::new(); + let mut execution_modes = FxHashMap::default(); for &(key, mode, dim) in EXECUTION_MODES { let old = execution_modes.insert(Symbol::intern(key), (mode, dim)); assert!(old.is_none()); } - let mut libm_intrinsics = HashMap::new(); + let mut libm_intrinsics = FxHashMap::default(); for &(a, b) in libm_intrinsics::TABLE { let old = libm_intrinsics.insert(Symbol::intern(a), b); assert!(old.is_none());