[meta] Use a ref-counted pointer to an InstructionFormat in instructions;

This avoids a lot of dereferences, and InstructionFormat are immutable
once they're created. It removes a lot of code that was keeping the
FormatRegistry around, just in case we needed the format. This is more
in line with the way we create Instructions, and make it easy to
reference InstructionFormats in general.
This commit is contained in:
Benjamin Bouvier
2019-10-18 16:45:51 +02:00
parent d3e694fbe7
commit 9e9a7626d7
13 changed files with 222 additions and 276 deletions

View File

@@ -2,10 +2,9 @@ use crate::cdsl::operands::{Operand, OperandKind};
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::rc::Rc;
use std::slice;
use cranelift_entity::{entity_impl, PrimaryMap};
/// An immediate field in an instruction format.
///
/// This corresponds to a single member of a variant of the `InstructionData`
@@ -152,15 +151,10 @@ impl InstructionFormatBuilder {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct InstructionFormatIndex(u32);
entity_impl!(InstructionFormatIndex);
pub struct FormatRegistry {
/// Map (immediate kinds names, number of values, has varargs) to an instruction format index
/// in the actual map.
sig_to_index: HashMap<(Vec<String>, usize, bool), InstructionFormatIndex>,
map: PrimaryMap<InstructionFormatIndex, InstructionFormat>,
/// Map (immediate kinds names, number of values, has varargs) to an instruction format.
sig_to_index: HashMap<(Vec<String>, usize, bool), usize>,
formats: Vec<Rc<InstructionFormat>>,
name_set: HashSet<&'static str>,
}
@@ -168,14 +162,14 @@ impl FormatRegistry {
pub fn new() -> Self {
Self {
sig_to_index: HashMap::new(),
map: PrimaryMap::new(),
formats: Vec::new(),
name_set: HashSet::new(),
}
}
/// Find an existing instruction format that matches the given lists of instruction inputs and
/// outputs.
pub fn lookup(&self, operands_in: &Vec<Operand>) -> InstructionFormatIndex {
pub fn lookup(&self, operands_in: &Vec<Operand>) -> &Rc<InstructionFormat> {
let mut imm_keys = Vec::new();
let mut num_values = 0;
let mut has_varargs = false;
@@ -193,22 +187,19 @@ impl FormatRegistry {
}
let sig = (imm_keys, num_values, has_varargs);
*self
let index = *self
.sig_to_index
.get(&sig)
.expect("unknown InstructionFormat; please define it in shared/formats.rs first")
.expect("unknown InstructionFormat; please define it in shared/formats.rs first");
&self.formats[index]
}
pub fn by_name(&self, name: &str) -> InstructionFormatIndex {
self.map
pub fn by_name(&self, name: &str) -> &Rc<InstructionFormat> {
&self
.formats
.iter()
.find(|(_key, value)| value.name == name)
.find(|format| format.name == name)
.unwrap_or_else(|| panic!("format with name '{}' doesn't exist", name))
.0
}
pub fn get(&self, index: InstructionFormatIndex) -> &InstructionFormat {
self.map.get(index).unwrap()
}
pub fn insert(&mut self, inst_format: InstructionFormatBuilder) {
@@ -230,17 +221,18 @@ impl FormatRegistry {
.collect();
let key = (imm_keys, format.num_value_operands, format.has_value_list);
let index = self.map.push(format);
let index = self.formats.len();
self.formats.push(Rc::new(format));
if let Some(already_inserted) = self.sig_to_index.insert(key, index) {
panic!(
"duplicate InstructionFormat: trying to insert '{}' while '{}' already has the same structure.",
self.map.get(index).unwrap().name,
self.map.get(already_inserted).unwrap().name
self.formats[index].name,
self.formats[already_inserted].name
);
}
}
pub fn iter(&self) -> slice::Iter<InstructionFormat> {
self.map.values()
pub fn iter(&self) -> slice::Iter<Rc<InstructionFormat>> {
self.formats.iter()
}
}