[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:
@@ -1,4 +1,3 @@
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::instructions::{InstSpec, Instruction, InstructionPredicate};
|
||||
use crate::cdsl::operands::{OperandKind, OperandKindFields};
|
||||
use crate::cdsl::types::ValueType;
|
||||
@@ -523,23 +522,23 @@ impl Apply {
|
||||
format!("{}({})", inst_name, args)
|
||||
}
|
||||
|
||||
pub fn inst_predicate(
|
||||
&self,
|
||||
format_registry: &FormatRegistry,
|
||||
var_pool: &VarPool,
|
||||
) -> InstructionPredicate {
|
||||
let iform = format_registry.get(self.inst.format);
|
||||
|
||||
pub fn inst_predicate(&self, var_pool: &VarPool) -> InstructionPredicate {
|
||||
let mut pred = InstructionPredicate::new();
|
||||
for (format_field, &op_num) in iform.imm_fields.iter().zip(self.inst.imm_opnums.iter()) {
|
||||
for (format_field, &op_num) in self
|
||||
.inst
|
||||
.format
|
||||
.imm_fields
|
||||
.iter()
|
||||
.zip(self.inst.imm_opnums.iter())
|
||||
{
|
||||
let arg = &self.args[op_num];
|
||||
if arg.maybe_var().is_some() {
|
||||
// Ignore free variables for now.
|
||||
continue;
|
||||
}
|
||||
pred = pred.and(InstructionPredicate::new_is_field_equal_ast(
|
||||
iform,
|
||||
&format_field,
|
||||
&*self.inst.format,
|
||||
format_field,
|
||||
arg.to_rust_code(var_pool),
|
||||
));
|
||||
}
|
||||
@@ -565,12 +564,8 @@ impl Apply {
|
||||
}
|
||||
|
||||
/// Same as `inst_predicate()`, but also check the controlling type variable.
|
||||
pub fn inst_predicate_with_ctrl_typevar(
|
||||
&self,
|
||||
format_registry: &FormatRegistry,
|
||||
var_pool: &VarPool,
|
||||
) -> InstructionPredicate {
|
||||
let mut pred = self.inst_predicate(format_registry, var_pool);
|
||||
pub fn inst_predicate_with_ctrl_typevar(&self, var_pool: &VarPool) -> InstructionPredicate {
|
||||
let mut pred = self.inst_predicate(var_pool);
|
||||
|
||||
if !self.value_types.is_empty() {
|
||||
let bound_type = &self.value_types[0];
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::instructions::{
|
||||
InstSpec, Instruction, InstructionPredicate, InstructionPredicateNode,
|
||||
InstructionPredicateNumber, InstructionPredicateRegistry, ValueTypeOrAny,
|
||||
@@ -62,12 +61,7 @@ pub(crate) struct EncodingBuilder {
|
||||
}
|
||||
|
||||
impl EncodingBuilder {
|
||||
pub fn new(
|
||||
inst: InstSpec,
|
||||
recipe: EncodingRecipeNumber,
|
||||
encbits: u16,
|
||||
formats: &FormatRegistry,
|
||||
) -> Self {
|
||||
pub fn new(inst: InstSpec, recipe: EncodingRecipeNumber, encbits: u16) -> Self {
|
||||
let (inst_predicate, bound_type) = match &inst {
|
||||
InstSpec::Bound(inst) => {
|
||||
let other_typevars = &inst.inst.polymorphic_info.as_ref().unwrap().other_typevars;
|
||||
@@ -98,7 +92,7 @@ impl EncodingBuilder {
|
||||
.zip(inst.inst.operands_in.iter().filter(|o| o.is_immediate()))
|
||||
{
|
||||
let immediate_predicate = InstructionPredicate::new_is_field_equal(
|
||||
formats.get(inst.inst.format),
|
||||
&inst.inst.format,
|
||||
immediate_operand.name,
|
||||
immediate_value.to_string(),
|
||||
);
|
||||
@@ -158,7 +152,7 @@ impl EncodingBuilder {
|
||||
|
||||
let inst = self.inst.inst();
|
||||
assert!(
|
||||
inst.format == recipes[self.recipe].format,
|
||||
Rc::ptr_eq(&inst.format, &recipes[self.recipe].format),
|
||||
format!(
|
||||
"Inst {} and recipe {} must have the same format!",
|
||||
inst.name, recipes[self.recipe].name
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ use std::fmt::{Display, Error, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::cdsl::camel_case;
|
||||
use crate::cdsl::formats::{
|
||||
FormatField, FormatRegistry, InstructionFormat, InstructionFormatIndex,
|
||||
};
|
||||
use crate::cdsl::formats::{FormatField, FormatRegistry, InstructionFormat};
|
||||
use crate::cdsl::operands::Operand;
|
||||
use crate::cdsl::type_inference::Constraint;
|
||||
use crate::cdsl::types::{LaneType, ReferenceType, ValueType, VectorType};
|
||||
@@ -104,7 +102,7 @@ pub(crate) struct InstructionContent {
|
||||
pub constraints: Vec<Constraint>,
|
||||
|
||||
/// Instruction format, automatically derived from the input operands.
|
||||
pub format: InstructionFormatIndex,
|
||||
pub format: Rc<InstructionFormat>,
|
||||
|
||||
/// One of the input or output operands is a free type variable. None if the instruction is not
|
||||
/// polymorphic, set otherwise.
|
||||
@@ -321,8 +319,7 @@ impl InstructionBuilder {
|
||||
.filter_map(|(i, op)| if op.is_value() { Some(i) } else { None })
|
||||
.collect();
|
||||
|
||||
let format_index = format_registry.lookup(&operands_in);
|
||||
let format = format_registry.get(format_index);
|
||||
let format = format_registry.lookup(&operands_in).clone();
|
||||
let polymorphic_info =
|
||||
verify_polymorphic(&operands_in, &operands_out, &format, &value_opnums);
|
||||
|
||||
@@ -339,7 +336,7 @@ impl InstructionBuilder {
|
||||
operands_in,
|
||||
operands_out,
|
||||
constraints: self.constraints.unwrap_or_else(Vec::new),
|
||||
format: format_index,
|
||||
format,
|
||||
polymorphic_info,
|
||||
value_opnums,
|
||||
value_results,
|
||||
@@ -1093,9 +1090,9 @@ impl InstructionPredicate {
|
||||
}
|
||||
|
||||
pub fn new_is_colocated_data(format_registry: &FormatRegistry) -> InstructionPredicateNode {
|
||||
let format = format_registry.get(format_registry.by_name("UnaryGlobalValue"));
|
||||
let format = format_registry.by_name("UnaryGlobalValue");
|
||||
InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
|
||||
format,
|
||||
&*format,
|
||||
"global_value",
|
||||
FormatPredicateKind::IsColocatedData,
|
||||
))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use cranelift_entity::{entity_impl, PrimaryMap};
|
||||
|
||||
use crate::cdsl::formats::{FormatRegistry, InstructionFormatIndex};
|
||||
use crate::cdsl::formats::InstructionFormat;
|
||||
use crate::cdsl::instructions::InstructionPredicate;
|
||||
use crate::cdsl::regs::RegClassIndex;
|
||||
use crate::cdsl::settings::SettingPredicateNumber;
|
||||
@@ -108,7 +110,7 @@ pub(crate) struct EncodingRecipe {
|
||||
pub name: String,
|
||||
|
||||
/// Associated instruction format.
|
||||
pub format: InstructionFormatIndex,
|
||||
pub format: Rc<InstructionFormat>,
|
||||
|
||||
/// Base number of bytes in the binary encoded instruction.
|
||||
pub base_size: u64,
|
||||
@@ -141,7 +143,7 @@ pub(crate) struct EncodingRecipe {
|
||||
// Implement PartialEq ourselves: take all the fields into account but the name.
|
||||
impl PartialEq for EncodingRecipe {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.format == other.format
|
||||
Rc::ptr_eq(&self.format, &other.format)
|
||||
&& self.base_size == other.base_size
|
||||
&& self.operands_in == other.operands_in
|
||||
&& self.operands_out == other.operands_out
|
||||
@@ -166,7 +168,7 @@ pub(crate) type Recipes = PrimaryMap<EncodingRecipeNumber, EncodingRecipe>;
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct EncodingRecipeBuilder {
|
||||
pub name: String,
|
||||
format: InstructionFormatIndex,
|
||||
format: Rc<InstructionFormat>,
|
||||
pub base_size: u64,
|
||||
pub operands_in: Option<Vec<OperandConstraint>>,
|
||||
pub operands_out: Option<Vec<OperandConstraint>>,
|
||||
@@ -179,10 +181,10 @@ pub(crate) struct EncodingRecipeBuilder {
|
||||
}
|
||||
|
||||
impl EncodingRecipeBuilder {
|
||||
pub fn new(name: impl Into<String>, format: InstructionFormatIndex, base_size: u64) -> Self {
|
||||
pub fn new(name: impl Into<String>, format: &Rc<InstructionFormat>, base_size: u64) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
format,
|
||||
format: format.clone(),
|
||||
base_size,
|
||||
operands_in: None,
|
||||
operands_out: None,
|
||||
@@ -250,18 +252,17 @@ impl EncodingRecipeBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self, formats: &FormatRegistry) -> EncodingRecipe {
|
||||
pub fn build(self) -> EncodingRecipe {
|
||||
let operands_in = self.operands_in.unwrap_or(Vec::new());
|
||||
let operands_out = self.operands_out.unwrap_or(Vec::new());
|
||||
|
||||
// The number of input constraints must match the number of format input operands.
|
||||
if !formats.get(self.format).has_value_list {
|
||||
let format = formats.get(self.format);
|
||||
if !self.format.has_value_list {
|
||||
assert!(
|
||||
operands_in.len() == format.num_value_operands,
|
||||
operands_in.len() == self.format.num_value_operands,
|
||||
format!(
|
||||
"missing operand constraints for recipe {} (format {})",
|
||||
self.name, format.name
|
||||
self.name, self.format.name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user