[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

@@ -1,4 +1,3 @@
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::instructions::{InstSpec, Instruction, InstructionPredicate}; use crate::cdsl::instructions::{InstSpec, Instruction, InstructionPredicate};
use crate::cdsl::operands::{OperandKind, OperandKindFields}; use crate::cdsl::operands::{OperandKind, OperandKindFields};
use crate::cdsl::types::ValueType; use crate::cdsl::types::ValueType;
@@ -523,23 +522,23 @@ impl Apply {
format!("{}({})", inst_name, args) format!("{}({})", inst_name, args)
} }
pub fn inst_predicate( pub fn inst_predicate(&self, var_pool: &VarPool) -> InstructionPredicate {
&self,
format_registry: &FormatRegistry,
var_pool: &VarPool,
) -> InstructionPredicate {
let iform = format_registry.get(self.inst.format);
let mut pred = InstructionPredicate::new(); 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]; let arg = &self.args[op_num];
if arg.maybe_var().is_some() { if arg.maybe_var().is_some() {
// Ignore free variables for now. // Ignore free variables for now.
continue; continue;
} }
pred = pred.and(InstructionPredicate::new_is_field_equal_ast( pred = pred.and(InstructionPredicate::new_is_field_equal_ast(
iform, &*self.inst.format,
&format_field, format_field,
arg.to_rust_code(var_pool), arg.to_rust_code(var_pool),
)); ));
} }
@@ -565,12 +564,8 @@ impl Apply {
} }
/// Same as `inst_predicate()`, but also check the controlling type variable. /// Same as `inst_predicate()`, but also check the controlling type variable.
pub fn inst_predicate_with_ctrl_typevar( pub fn inst_predicate_with_ctrl_typevar(&self, var_pool: &VarPool) -> InstructionPredicate {
&self, let mut pred = self.inst_predicate(var_pool);
format_registry: &FormatRegistry,
var_pool: &VarPool,
) -> InstructionPredicate {
let mut pred = self.inst_predicate(format_registry, var_pool);
if !self.value_types.is_empty() { if !self.value_types.is_empty() {
let bound_type = &self.value_types[0]; let bound_type = &self.value_types[0];

View File

@@ -1,4 +1,3 @@
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::instructions::{ use crate::cdsl::instructions::{
InstSpec, Instruction, InstructionPredicate, InstructionPredicateNode, InstSpec, Instruction, InstructionPredicate, InstructionPredicateNode,
InstructionPredicateNumber, InstructionPredicateRegistry, ValueTypeOrAny, InstructionPredicateNumber, InstructionPredicateRegistry, ValueTypeOrAny,
@@ -62,12 +61,7 @@ pub(crate) struct EncodingBuilder {
} }
impl EncodingBuilder { impl EncodingBuilder {
pub fn new( pub fn new(inst: InstSpec, recipe: EncodingRecipeNumber, encbits: u16) -> Self {
inst: InstSpec,
recipe: EncodingRecipeNumber,
encbits: u16,
formats: &FormatRegistry,
) -> Self {
let (inst_predicate, bound_type) = match &inst { let (inst_predicate, bound_type) = match &inst {
InstSpec::Bound(inst) => { InstSpec::Bound(inst) => {
let other_typevars = &inst.inst.polymorphic_info.as_ref().unwrap().other_typevars; 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())) .zip(inst.inst.operands_in.iter().filter(|o| o.is_immediate()))
{ {
let immediate_predicate = InstructionPredicate::new_is_field_equal( let immediate_predicate = InstructionPredicate::new_is_field_equal(
formats.get(inst.inst.format), &inst.inst.format,
immediate_operand.name, immediate_operand.name,
immediate_value.to_string(), immediate_value.to_string(),
); );
@@ -158,7 +152,7 @@ impl EncodingBuilder {
let inst = self.inst.inst(); let inst = self.inst.inst();
assert!( assert!(
inst.format == recipes[self.recipe].format, Rc::ptr_eq(&inst.format, &recipes[self.recipe].format),
format!( format!(
"Inst {} and recipe {} must have the same format!", "Inst {} and recipe {} must have the same format!",
inst.name, recipes[self.recipe].name inst.name, recipes[self.recipe].name

View File

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

View File

@@ -6,9 +6,7 @@ use std::fmt::{Display, Error, Formatter};
use std::rc::Rc; use std::rc::Rc;
use crate::cdsl::camel_case; use crate::cdsl::camel_case;
use crate::cdsl::formats::{ use crate::cdsl::formats::{FormatField, FormatRegistry, InstructionFormat};
FormatField, FormatRegistry, InstructionFormat, InstructionFormatIndex,
};
use crate::cdsl::operands::Operand; use crate::cdsl::operands::Operand;
use crate::cdsl::type_inference::Constraint; use crate::cdsl::type_inference::Constraint;
use crate::cdsl::types::{LaneType, ReferenceType, ValueType, VectorType}; use crate::cdsl::types::{LaneType, ReferenceType, ValueType, VectorType};
@@ -104,7 +102,7 @@ pub(crate) struct InstructionContent {
pub constraints: Vec<Constraint>, pub constraints: Vec<Constraint>,
/// Instruction format, automatically derived from the input operands. /// 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 /// One of the input or output operands is a free type variable. None if the instruction is not
/// polymorphic, set otherwise. /// polymorphic, set otherwise.
@@ -321,8 +319,7 @@ impl InstructionBuilder {
.filter_map(|(i, op)| if op.is_value() { Some(i) } else { None }) .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None })
.collect(); .collect();
let format_index = format_registry.lookup(&operands_in); let format = format_registry.lookup(&operands_in).clone();
let format = format_registry.get(format_index);
let polymorphic_info = let polymorphic_info =
verify_polymorphic(&operands_in, &operands_out, &format, &value_opnums); verify_polymorphic(&operands_in, &operands_out, &format, &value_opnums);
@@ -339,7 +336,7 @@ impl InstructionBuilder {
operands_in, operands_in,
operands_out, operands_out,
constraints: self.constraints.unwrap_or_else(Vec::new), constraints: self.constraints.unwrap_or_else(Vec::new),
format: format_index, format,
polymorphic_info, polymorphic_info,
value_opnums, value_opnums,
value_results, value_results,
@@ -1093,9 +1090,9 @@ impl InstructionPredicate {
} }
pub fn new_is_colocated_data(format_registry: &FormatRegistry) -> InstructionPredicateNode { 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( InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
format, &*format,
"global_value", "global_value",
FormatPredicateKind::IsColocatedData, FormatPredicateKind::IsColocatedData,
)) ))

View File

@@ -1,6 +1,8 @@
use std::rc::Rc;
use cranelift_entity::{entity_impl, PrimaryMap}; 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::instructions::InstructionPredicate;
use crate::cdsl::regs::RegClassIndex; use crate::cdsl::regs::RegClassIndex;
use crate::cdsl::settings::SettingPredicateNumber; use crate::cdsl::settings::SettingPredicateNumber;
@@ -108,7 +110,7 @@ pub(crate) struct EncodingRecipe {
pub name: String, pub name: String,
/// Associated instruction format. /// Associated instruction format.
pub format: InstructionFormatIndex, pub format: Rc<InstructionFormat>,
/// Base number of bytes in the binary encoded instruction. /// Base number of bytes in the binary encoded instruction.
pub base_size: u64, pub base_size: u64,
@@ -141,7 +143,7 @@ pub(crate) struct EncodingRecipe {
// Implement PartialEq ourselves: take all the fields into account but the name. // Implement PartialEq ourselves: take all the fields into account but the name.
impl PartialEq for EncodingRecipe { impl PartialEq for EncodingRecipe {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.format == other.format Rc::ptr_eq(&self.format, &other.format)
&& self.base_size == other.base_size && self.base_size == other.base_size
&& self.operands_in == other.operands_in && self.operands_in == other.operands_in
&& self.operands_out == other.operands_out && self.operands_out == other.operands_out
@@ -166,7 +168,7 @@ pub(crate) type Recipes = PrimaryMap<EncodingRecipeNumber, EncodingRecipe>;
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct EncodingRecipeBuilder { pub(crate) struct EncodingRecipeBuilder {
pub name: String, pub name: String,
format: InstructionFormatIndex, format: Rc<InstructionFormat>,
pub base_size: u64, pub base_size: u64,
pub operands_in: Option<Vec<OperandConstraint>>, pub operands_in: Option<Vec<OperandConstraint>>,
pub operands_out: Option<Vec<OperandConstraint>>, pub operands_out: Option<Vec<OperandConstraint>>,
@@ -179,10 +181,10 @@ pub(crate) struct EncodingRecipeBuilder {
} }
impl 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 { Self {
name: name.into(), name: name.into(),
format, format: format.clone(),
base_size, base_size,
operands_in: None, operands_in: None,
operands_out: None, operands_out: None,
@@ -250,18 +252,17 @@ impl EncodingRecipeBuilder {
self 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_in = self.operands_in.unwrap_or(Vec::new());
let operands_out = self.operands_out.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. // The number of input constraints must match the number of format input operands.
if !formats.get(self.format).has_value_list { if !self.format.has_value_list {
let format = formats.get(self.format);
assert!( assert!(
operands_in.len() == format.num_value_operands, operands_in.len() == self.format.num_value_operands,
format!( format!(
"missing operand constraints for recipe {} (format {})", "missing operand constraints for recipe {} (format {})",
self.name, format.name self.name, self.format.name
) )
); );
} }

View File

@@ -5,7 +5,6 @@ use cranelift_entity::EntityRef;
use crate::error; use crate::error;
use crate::srcgen::Formatter; use crate::srcgen::Formatter;
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::recipes::{EncodingRecipe, OperandConstraint, Recipes}; use crate::cdsl::recipes::{EncodingRecipe, OperandConstraint, Recipes};
/// Generate code to handle a single recipe. /// Generate code to handle a single recipe.
@@ -14,11 +13,12 @@ use crate::cdsl::recipes::{EncodingRecipe, OperandConstraint, Recipes};
/// - Determine register locations for operands with register constraints. /// - Determine register locations for operands with register constraints.
/// - Determine stack slot locations for operands with stack constraints. /// - Determine stack slot locations for operands with stack constraints.
/// - Call hand-written code for the actual emission. /// - Call hand-written code for the actual emission.
fn gen_recipe(formats: &FormatRegistry, recipe: &EncodingRecipe, fmt: &mut Formatter) { fn gen_recipe(recipe: &EncodingRecipe, fmt: &mut Formatter) {
let inst_format = formats.get(recipe.format); let inst_format = &recipe.format;
let num_value_ops = inst_format.num_value_operands; let num_value_ops = inst_format.num_value_operands;
// TODO: Set want_args to true for only MultiAry instructions instead of all formats with value list. // TODO: Set want_args to true for only MultiAry instructions instead of all formats with value
// list.
let want_args = inst_format.has_value_list let want_args = inst_format.has_value_list
|| recipe.operands_in.iter().any(|c| match c { || recipe.operands_in.iter().any(|c| match c {
OperandConstraint::RegClass(_) | OperandConstraint::Stack(_) => true, OperandConstraint::RegClass(_) | OperandConstraint::Stack(_) => true,
@@ -148,7 +148,7 @@ fn unwrap_values(
varlist varlist
} }
fn gen_isa(formats: &FormatRegistry, isa_name: &str, recipes: &Recipes, fmt: &mut Formatter) { fn gen_isa(isa_name: &str, recipes: &Recipes, fmt: &mut Formatter) {
fmt.doc_comment(format!( fmt.doc_comment(format!(
"Emit binary machine code for `inst` for the {} ISA.", "Emit binary machine code for `inst` for the {} ISA.",
isa_name isa_name
@@ -193,7 +193,7 @@ fn gen_isa(formats: &FormatRegistry, isa_name: &str, recipes: &Recipes, fmt: &mu
fmt.comment(format!("Recipe {}", recipe.name)); fmt.comment(format!("Recipe {}", recipe.name));
fmtln!(fmt, "{} => {{", i.index()); fmtln!(fmt, "{} => {{", i.index());
fmt.indent(|fmt| { fmt.indent(|fmt| {
gen_recipe(formats, recipe, fmt); gen_recipe(recipe, fmt);
}); });
fmt.line("}"); fmt.line("}");
} }
@@ -212,14 +212,13 @@ fn gen_isa(formats: &FormatRegistry, isa_name: &str, recipes: &Recipes, fmt: &mu
} }
pub(crate) fn generate( pub(crate) fn generate(
formats: &FormatRegistry,
isa_name: &str, isa_name: &str,
recipes: &Recipes, recipes: &Recipes,
binemit_filename: &str, binemit_filename: &str,
out_dir: &str, out_dir: &str,
) -> Result<(), error::Error> { ) -> Result<(), error::Error> {
let mut fmt = Formatter::new(); let mut fmt = Formatter::new();
gen_isa(formats, isa_name, recipes, &mut fmt); gen_isa(isa_name, recipes, &mut fmt);
fmt.update_file(binemit_filename, out_dir)?; fmt.update_file(binemit_filename, out_dir)?;
Ok(()) Ok(())
} }

View File

@@ -400,7 +400,7 @@ fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
fmt.empty_line(); fmt.empty_line();
} }
fn gen_opcodes<'a>(all_inst: &AllInstructions, formats: &FormatRegistry, fmt: &mut Formatter) { fn gen_opcodes<'a>(all_inst: &AllInstructions, fmt: &mut Formatter) {
fmt.doc_comment( fmt.doc_comment(
r#" r#"
An instruction opcode. An instruction opcode.
@@ -418,13 +418,12 @@ fn gen_opcodes<'a>(all_inst: &AllInstructions, formats: &FormatRegistry, fmt: &m
fmt.indent(|fmt| { fmt.indent(|fmt| {
let mut is_first_opcode = true; let mut is_first_opcode = true;
for inst in all_inst.values() { for inst in all_inst.values() {
let format = formats.get(inst.format); fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name));
fmt.doc_comment(format!("`{}`. ({})", inst, format.name));
// Document polymorphism. // Document polymorphism.
if let Some(poly) = &inst.polymorphic_info { if let Some(poly) = &inst.polymorphic_info {
if poly.use_typevar_operand { if poly.use_typevar_operand {
let op_num = inst.value_opnums[format.typevar_operand.unwrap()]; let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()];
fmt.doc_comment(format!( fmt.doc_comment(format!(
"Type inferred from `{}`.", "Type inferred from `{}`.",
inst.operands_in[op_num].name inst.operands_in[op_num].name
@@ -537,8 +536,12 @@ fn gen_opcodes<'a>(all_inst: &AllInstructions, formats: &FormatRegistry, fmt: &m
); );
fmt.indent(|fmt| { fmt.indent(|fmt| {
for inst in all_inst.values() { for inst in all_inst.values() {
let format = formats.get(inst.format); fmtln!(
fmtln!(fmt, "InstructionFormat::{}, // {}", format.name, inst.name); fmt,
"InstructionFormat::{}, // {}",
inst.format.name,
inst.name
);
} }
}); });
fmtln!(fmt, "];"); fmtln!(fmt, "];");
@@ -1055,7 +1058,7 @@ fn gen_builder(instructions: &AllInstructions, formats: &FormatRegistry, fmt: &m
fmt.line("pub trait InstBuilder<'f>: InstBuilderBase<'f> {"); fmt.line("pub trait InstBuilder<'f>: InstBuilderBase<'f> {");
fmt.indent(|fmt| { fmt.indent(|fmt| {
for inst in instructions.values() { for inst in instructions.values() {
gen_inst_builder(inst, formats.get(inst.format), fmt); gen_inst_builder(inst, &*inst.format, fmt);
} }
for format in formats.iter() { for format in formats.iter() {
gen_format_constructor(format, fmt); gen_format_constructor(format, fmt);
@@ -1080,7 +1083,7 @@ pub(crate) fn generate(
fmt.empty_line(); fmt.empty_line();
gen_instruction_data_impl(format_registry, &mut fmt); gen_instruction_data_impl(format_registry, &mut fmt);
fmt.empty_line(); fmt.empty_line();
gen_opcodes(all_inst, format_registry, &mut fmt); gen_opcodes(all_inst, &mut fmt);
gen_type_constraints(all_inst, &mut fmt); gen_type_constraints(all_inst, &mut fmt);
fmt.update_file(opcode_filename, out_dir)?; fmt.update_file(opcode_filename, out_dir)?;

View File

@@ -1,5 +1,4 @@
use crate::cdsl::ast::{Def, DefPool, Expr, VarPool}; use crate::cdsl::ast::{Def, DefPool, Expr, VarPool};
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::isa::TargetIsa; use crate::cdsl::isa::TargetIsa;
use crate::cdsl::operands::Operand; use crate::cdsl::operands::Operand;
use crate::cdsl::type_inference::Constraint; use crate::cdsl::type_inference::Constraint;
@@ -21,18 +20,14 @@ use std::iter::FromIterator;
/// ///
/// Also create a local variable named `predicate` with the value of the evaluated instruction /// Also create a local variable named `predicate` with the value of the evaluated instruction
/// predicate, or `true` if the node has no predicate. /// predicate, or `true` if the node has no predicate.
fn unwrap_inst( fn unwrap_inst(transform: &Transform, fmt: &mut Formatter) -> bool {
transform: &Transform,
format_registry: &FormatRegistry,
fmt: &mut Formatter,
) -> bool {
let var_pool = &transform.var_pool; let var_pool = &transform.var_pool;
let def_pool = &transform.def_pool; let def_pool = &transform.def_pool;
let def = def_pool.get(transform.src); let def = def_pool.get(transform.src);
let apply = &def.apply; let apply = &def.apply;
let inst = &apply.inst; let inst = &apply.inst;
let iform = format_registry.get(inst.format); let iform = &inst.format;
fmt.comment(format!( fmt.comment(format!(
"Unwrap fields from instruction format {}", "Unwrap fields from instruction format {}",
@@ -438,7 +433,6 @@ fn emit_dst_inst(def: &Def, def_pool: &DefPool, var_pool: &VarPool, fmt: &mut Fo
fn gen_transform<'a>( fn gen_transform<'a>(
replace_inst: bool, replace_inst: bool,
transform: &'a Transform, transform: &'a Transform,
format_registry: &FormatRegistry,
type_sets: &mut UniqueTable<'a, TypeSet>, type_sets: &mut UniqueTable<'a, TypeSet>,
fmt: &mut Formatter, fmt: &mut Formatter,
) { ) {
@@ -446,7 +440,7 @@ fn gen_transform<'a>(
let apply = &transform.def_pool.get(transform.src).apply; let apply = &transform.def_pool.get(transform.src).apply;
let inst_predicate = apply let inst_predicate = apply
.inst_predicate_with_ctrl_typevar(format_registry, &transform.var_pool) .inst_predicate_with_ctrl_typevar(&transform.var_pool)
.rust_predicate("pos.func"); .rust_predicate("pos.func");
let has_extra_constraints = !transform.type_env.constraints.is_empty(); let has_extra_constraints = !transform.type_env.constraints.is_empty();
@@ -560,7 +554,6 @@ fn gen_transform<'a>(
fn gen_transform_group<'a>( fn gen_transform_group<'a>(
group: &'a TransformGroup, group: &'a TransformGroup,
format_registry: &FormatRegistry,
transform_groups: &TransformGroups, transform_groups: &TransformGroups,
type_sets: &mut UniqueTable<'a, TypeSet>, type_sets: &mut UniqueTable<'a, TypeSet>,
fmt: &mut Formatter, fmt: &mut Formatter,
@@ -610,14 +603,14 @@ fn gen_transform_group<'a>(
let transforms = inst_to_transforms.get(camel_name).unwrap(); let transforms = inst_to_transforms.get(camel_name).unwrap();
// Unwrap the source instruction, create local variables for the input variables. // Unwrap the source instruction, create local variables for the input variables.
let replace_inst = unwrap_inst(&transforms[0], format_registry, fmt); let replace_inst = unwrap_inst(&transforms[0], fmt);
fmt.empty_line(); fmt.empty_line();
for (i, transform) in transforms.into_iter().enumerate() { for (i, transform) in transforms.into_iter().enumerate() {
if i > 0 { if i > 0 {
fmt.empty_line(); fmt.empty_line();
} }
gen_transform(replace_inst, transform, format_registry, type_sets, fmt); gen_transform(replace_inst, transform, type_sets, fmt);
} }
}); });
fmtln!(fmt, "}"); fmtln!(fmt, "}");
@@ -665,7 +658,6 @@ fn gen_transform_group<'a>(
/// Generate `TYPE_SETS` and `LEGALIZE_ACTIONS` tables. /// Generate `TYPE_SETS` and `LEGALIZE_ACTIONS` tables.
fn gen_isa( fn gen_isa(
isa: &TargetIsa, isa: &TargetIsa,
format_registry: &FormatRegistry,
transform_groups: &TransformGroups, transform_groups: &TransformGroups,
shared_group_names: &mut HashSet<&'static str>, shared_group_names: &mut HashSet<&'static str>,
fmt: &mut Formatter, fmt: &mut Formatter,
@@ -679,13 +671,7 @@ fn gen_isa(
isa_name == isa.name, isa_name == isa.name,
"ISA-specific legalizations must be used by the same ISA" "ISA-specific legalizations must be used by the same ISA"
); );
gen_transform_group( gen_transform_group(group, transform_groups, &mut type_sets, fmt);
group,
format_registry,
transform_groups,
&mut type_sets,
fmt,
);
} }
None => { None => {
shared_group_names.insert(group.name); shared_group_names.insert(group.name);
@@ -712,7 +698,6 @@ fn gen_isa(
/// Generate the legalizer files. /// Generate the legalizer files.
pub(crate) fn generate( pub(crate) fn generate(
isas: &Vec<TargetIsa>, isas: &Vec<TargetIsa>,
format_registry: &FormatRegistry,
transform_groups: &TransformGroups, transform_groups: &TransformGroups,
filename_prefix: &str, filename_prefix: &str,
out_dir: &str, out_dir: &str,
@@ -721,13 +706,7 @@ pub(crate) fn generate(
for isa in isas { for isa in isas {
let mut fmt = Formatter::new(); let mut fmt = Formatter::new();
gen_isa( gen_isa(isa, transform_groups, &mut shared_group_names, &mut fmt);
isa,
format_registry,
transform_groups,
&mut shared_group_names,
&mut fmt,
);
fmt.update_file(format!("{}-{}.rs", filename_prefix, isa.name), out_dir)?; fmt.update_file(format!("{}-{}.rs", filename_prefix, isa.name), out_dir)?;
} }
@@ -738,13 +717,7 @@ pub(crate) fn generate(
sorted_shared_group_names.sort(); sorted_shared_group_names.sort();
for group_name in &sorted_shared_group_names { for group_name in &sorted_shared_group_names {
let group = transform_groups.by_name(group_name); let group = transform_groups.by_name(group_name);
gen_transform_group( gen_transform_group(group, transform_groups, &mut type_sets, &mut fmt);
group,
format_registry,
transform_groups,
&mut type_sets,
&mut fmt,
);
} }
gen_typesets_table(&type_sets, &mut fmt); gen_typesets_table(&type_sets, &mut fmt);
fmt.update_file(format!("{}r.rs", filename_prefix), out_dir)?; fmt.update_file(format!("{}r.rs", filename_prefix), out_dir)?;

View File

@@ -13,24 +13,21 @@ use crate::shared::types::Reference::{R32, R64};
use crate::shared::Definitions as SharedDefinitions; use crate::shared::Definitions as SharedDefinitions;
use super::recipes::RecipeGroup; use super::recipes::RecipeGroup;
use crate::cdsl::formats::FormatRegistry;
pub(crate) struct PerCpuModeEncodings<'defs> { pub(crate) struct PerCpuModeEncodings<'defs> {
pub inst_pred_reg: InstructionPredicateRegistry, pub inst_pred_reg: InstructionPredicateRegistry,
pub enc32: Vec<Encoding>, pub enc32: Vec<Encoding>,
pub enc64: Vec<Encoding>, pub enc64: Vec<Encoding>,
recipes: &'defs Recipes, recipes: &'defs Recipes,
formats: &'defs FormatRegistry,
} }
impl<'defs> PerCpuModeEncodings<'defs> { impl<'defs> PerCpuModeEncodings<'defs> {
fn new(recipes: &'defs Recipes, formats: &'defs FormatRegistry) -> Self { fn new(recipes: &'defs Recipes) -> Self {
Self { Self {
inst_pred_reg: InstructionPredicateRegistry::new(), inst_pred_reg: InstructionPredicateRegistry::new(),
enc32: Vec::new(), enc32: Vec::new(),
enc64: Vec::new(), enc64: Vec::new(),
recipes, recipes,
formats,
} }
} }
fn enc( fn enc(
@@ -39,7 +36,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
recipe: EncodingRecipeNumber, recipe: EncodingRecipeNumber,
bits: u16, bits: u16,
) -> EncodingBuilder { ) -> EncodingBuilder {
EncodingBuilder::new(inst.into(), recipe, bits, self.formats) EncodingBuilder::new(inst.into(), recipe, bits)
} }
fn add32(&mut self, encoding: EncodingBuilder) { fn add32(&mut self, encoding: EncodingBuilder) {
self.enc32 self.enc32
@@ -176,7 +173,7 @@ pub(crate) fn define<'defs>(
let use_m = isa_settings.predicate_by_name("use_m"); let use_m = isa_settings.predicate_by_name("use_m");
// Definitions. // Definitions.
let mut e = PerCpuModeEncodings::new(&recipes.recipes, &shared_defs.format_registry); let mut e = PerCpuModeEncodings::new(&recipes.recipes);
// Basic arithmetic binary instructions are encoded in an R-type instruction. // Basic arithmetic binary instructions are encoded in an R-type instruction.
for &(inst, inst_imm, f3, f7) in &[ for &(inst, inst_imm, f3, f7) in &[
@@ -242,7 +239,7 @@ pub(crate) fn define<'defs>(
bound_inst.clone().into(), bound_inst.clone().into(),
vec![Expr::Literal(cc), Expr::Var(x), Expr::Var(y)], vec![Expr::Literal(cc), Expr::Var(x), Expr::Var(y)],
) )
.inst_predicate(&shared_defs.format_registry, &var_pool) .inst_predicate(&var_pool)
.unwrap() .unwrap()
}; };
@@ -339,7 +336,7 @@ pub(crate) fn define<'defs>(
Expr::Var(args), Expr::Var(args),
], ],
) )
.inst_predicate(&shared_defs.format_registry, &var_pool) .inst_predicate(&var_pool)
.unwrap() .unwrap()
}; };

View File

@@ -1,16 +1,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::instructions::InstructionPredicate; use crate::cdsl::instructions::InstructionPredicate;
use crate::cdsl::recipes::{EncodingRecipeBuilder, EncodingRecipeNumber, Recipes, Stack}; use crate::cdsl::recipes::{EncodingRecipeBuilder, EncodingRecipeNumber, Recipes, Stack};
use crate::cdsl::regs::IsaRegs; use crate::cdsl::regs::IsaRegs;
use crate::shared::Definitions as SharedDefinitions; use crate::shared::Definitions as SharedDefinitions;
/// An helper to create recipes and use them when defining the RISCV encodings. /// An helper to create recipes and use them when defining the RISCV encodings.
pub(crate) struct RecipeGroup<'formats> { pub(crate) struct RecipeGroup {
/// Memoized format registry, to pass it to the builders.
formats: &'formats FormatRegistry,
/// The actualy list of recipes explicitly created in this file. /// The actualy list of recipes explicitly created in this file.
pub recipes: Recipes, pub recipes: Recipes,
@@ -18,10 +14,9 @@ pub(crate) struct RecipeGroup<'formats> {
name_to_recipe: HashMap<String, EncodingRecipeNumber>, name_to_recipe: HashMap<String, EncodingRecipeNumber>,
} }
impl<'formats> RecipeGroup<'formats> { impl RecipeGroup {
fn new(formats: &'formats FormatRegistry) -> Self { fn new() -> Self {
Self { Self {
formats,
recipes: Recipes::new(), recipes: Recipes::new(),
name_to_recipe: HashMap::new(), name_to_recipe: HashMap::new(),
} }
@@ -33,7 +28,7 @@ impl<'formats> RecipeGroup<'formats> {
format!("riscv recipe '{}' created twice", builder.name) format!("riscv recipe '{}' created twice", builder.name)
); );
let name = builder.name.clone(); let name = builder.name.clone();
let number = self.recipes.push(builder.build(self.formats)); let number = self.recipes.push(builder.build());
self.name_to_recipe.insert(name, number); self.name_to_recipe.insert(name, number);
} }
@@ -50,13 +45,10 @@ impl<'formats> RecipeGroup<'formats> {
} }
} }
pub(crate) fn define<'formats>( pub(crate) fn define(shared_defs: &SharedDefinitions, regs: &IsaRegs) -> RecipeGroup {
shared_defs: &'formats SharedDefinitions, // Format shorthands.
regs: &IsaRegs,
) -> RecipeGroup<'formats> {
let formats = &shared_defs.format_registry; let formats = &shared_defs.format_registry;
// Format shorthands.
let f_binary = formats.by_name("Binary"); let f_binary = formats.by_name("Binary");
let f_binary_imm = formats.by_name("BinaryImm"); let f_binary_imm = formats.by_name("BinaryImm");
let f_branch = formats.by_name("Branch"); let f_branch = formats.by_name("Branch");
@@ -76,7 +68,7 @@ pub(crate) fn define<'formats>(
let gpr = regs.class_by_name("GPR"); let gpr = regs.class_by_name("GPR");
// Definitions. // Definitions.
let mut recipes = RecipeGroup::new(&shared_defs.format_registry); let mut recipes = RecipeGroup::new();
// R-type 32-bit instructions: These are mostly binary arithmetic instructions. // R-type 32-bit instructions: These are mostly binary arithmetic instructions.
// The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8) // The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8)
@@ -103,36 +95,42 @@ pub(crate) fn define<'formats>(
.emit("put_r(bits, in_reg0, in_reg1, out_reg0, sink);"), .emit("put_r(bits, in_reg0, in_reg1, out_reg0, sink);"),
); );
let format = formats.get(f_binary_imm);
recipes.push( recipes.push(
EncodingRecipeBuilder::new("Ii", f_binary_imm, 4) EncodingRecipeBuilder::new("Ii", f_binary_imm, 4)
.operands_in(vec![gpr]) .operands_in(vec![gpr])
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 12, 0, &*f_binary_imm,
"imm",
12,
0,
)) ))
.emit("put_i(bits, in_reg0, imm.into(), out_reg0, sink);"), .emit("put_i(bits, in_reg0, imm.into(), out_reg0, sink);"),
); );
// I-type instruction with a hardcoded %x0 rs1. // I-type instruction with a hardcoded %x0 rs1.
let format = formats.get(f_unary_imm);
recipes.push( recipes.push(
EncodingRecipeBuilder::new("Iz", f_unary_imm, 4) EncodingRecipeBuilder::new("Iz", f_unary_imm, 4)
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 12, 0, &*f_unary_imm,
"imm",
12,
0,
)) ))
.emit("put_i(bits, 0, imm.into(), out_reg0, sink);"), .emit("put_i(bits, 0, imm.into(), out_reg0, sink);"),
); );
// I-type encoding of an integer comparison. // I-type encoding of an integer comparison.
let format = formats.get(f_int_compare_imm);
recipes.push( recipes.push(
EncodingRecipeBuilder::new("Iicmp", f_int_compare_imm, 4) EncodingRecipeBuilder::new("Iicmp", f_int_compare_imm, 4)
.operands_in(vec![gpr]) .operands_in(vec![gpr])
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 12, 0, &*f_int_compare_imm,
"imm",
12,
0,
)) ))
.emit("put_i(bits, in_reg0, imm.into(), out_reg0, sink);"), .emit("put_i(bits, in_reg0, imm.into(), out_reg0, sink);"),
); );
@@ -195,12 +193,14 @@ pub(crate) fn define<'formats>(
); );
// U-type instructions have a 20-bit immediate that targets bits 12-31. // U-type instructions have a 20-bit immediate that targets bits 12-31.
let format = formats.get(f_unary_imm);
recipes.push( recipes.push(
EncodingRecipeBuilder::new("U", f_unary_imm, 4) EncodingRecipeBuilder::new("U", f_unary_imm, 4)
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 32, 12, &*f_unary_imm,
"imm",
32,
12,
)) ))
.emit("put_u(bits, imm.into(), out_reg0, sink);"), .emit("put_u(bits, imm.into(), out_reg0, sink);"),
); );

View File

@@ -20,27 +20,24 @@ use crate::shared::Definitions as SharedDefinitions;
use crate::isa::x86::opcodes::*; use crate::isa::x86::opcodes::*;
use super::recipes::{RecipeGroup, Template}; use super::recipes::{RecipeGroup, Template};
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::instructions::BindParameter::Any; use crate::cdsl::instructions::BindParameter::Any;
pub(crate) struct PerCpuModeEncodings<'defs> { pub(crate) struct PerCpuModeEncodings {
pub enc32: Vec<Encoding>, pub enc32: Vec<Encoding>,
pub enc64: Vec<Encoding>, pub enc64: Vec<Encoding>,
pub recipes: Recipes, pub recipes: Recipes,
recipes_by_name: HashMap<String, EncodingRecipeNumber>, recipes_by_name: HashMap<String, EncodingRecipeNumber>,
pub inst_pred_reg: InstructionPredicateRegistry, pub inst_pred_reg: InstructionPredicateRegistry,
formats: &'defs FormatRegistry,
} }
impl<'defs> PerCpuModeEncodings<'defs> { impl PerCpuModeEncodings {
fn new(formats: &'defs FormatRegistry) -> Self { fn new() -> Self {
Self { Self {
enc32: Vec::new(), enc32: Vec::new(),
enc64: Vec::new(), enc64: Vec::new(),
recipes: Recipes::new(), recipes: Recipes::new(),
recipes_by_name: HashMap::new(), recipes_by_name: HashMap::new(),
inst_pred_reg: InstructionPredicateRegistry::new(), inst_pred_reg: InstructionPredicateRegistry::new(),
formats,
} }
} }
@@ -73,7 +70,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
{ {
let (recipe, bits) = template.build(); let (recipe, bits) = template.build();
let recipe_number = self.add_recipe(recipe); let recipe_number = self.add_recipe(recipe);
let builder = EncodingBuilder::new(inst.into(), recipe_number, bits, self.formats); let builder = EncodingBuilder::new(inst.into(), recipe_number, bits);
builder_closure(builder).build(&self.recipes, &mut self.inst_pred_reg) builder_closure(builder).build(&self.recipes, &mut self.inst_pred_reg)
} }
@@ -105,7 +102,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
} }
fn enc32_rec(&mut self, inst: impl Into<InstSpec>, recipe: &EncodingRecipe, bits: u16) { fn enc32_rec(&mut self, inst: impl Into<InstSpec>, recipe: &EncodingRecipe, bits: u16) {
let recipe_number = self.add_recipe(recipe.clone()); let recipe_number = self.add_recipe(recipe.clone());
let builder = EncodingBuilder::new(inst.into(), recipe_number, bits, self.formats); let builder = EncodingBuilder::new(inst.into(), recipe_number, bits);
let encoding = builder.build(&self.recipes, &mut self.inst_pred_reg); let encoding = builder.build(&self.recipes, &mut self.inst_pred_reg);
self.enc32.push(encoding); self.enc32.push(encoding);
} }
@@ -138,7 +135,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
} }
fn enc64_rec(&mut self, inst: impl Into<InstSpec>, recipe: &EncodingRecipe, bits: u16) { fn enc64_rec(&mut self, inst: impl Into<InstSpec>, recipe: &EncodingRecipe, bits: u16) {
let recipe_number = self.add_recipe(recipe.clone()); let recipe_number = self.add_recipe(recipe.clone());
let builder = EncodingBuilder::new(inst.into(), recipe_number, bits, self.formats); let builder = EncodingBuilder::new(inst.into(), recipe_number, bits);
let encoding = builder.build(&self.recipes, &mut self.inst_pred_reg); let encoding = builder.build(&self.recipes, &mut self.inst_pred_reg);
self.enc64.push(encoding); self.enc64.push(encoding);
} }
@@ -370,12 +367,12 @@ impl<'defs> PerCpuModeEncodings<'defs> {
// Definitions. // Definitions.
pub(crate) fn define<'defs>( pub(crate) fn define(
shared_defs: &'defs SharedDefinitions, shared_defs: &SharedDefinitions,
settings: &SettingGroup, settings: &SettingGroup,
x86: &InstructionGroup, x86: &InstructionGroup,
r: &RecipeGroup, r: &RecipeGroup,
) -> PerCpuModeEncodings<'defs> { ) -> PerCpuModeEncodings {
let shared = &shared_defs.instructions; let shared = &shared_defs.instructions;
let formats = &shared_defs.format_registry; let formats = &shared_defs.format_registry;
@@ -688,7 +685,7 @@ pub(crate) fn define<'defs>(
let use_sse41_simd = settings.predicate_by_name("use_sse41_simd"); let use_sse41_simd = settings.predicate_by_name("use_sse41_simd");
// Definitions. // Definitions.
let mut e = PerCpuModeEncodings::new(formats); let mut e = PerCpuModeEncodings::new();
// The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing! // The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing!
e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0); e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0);
@@ -777,8 +774,8 @@ pub(crate) fn define<'defs>(
e.enc64(iconst.bind(I32), rec_pu_id.opcodes(&MOV_IMM)); e.enc64(iconst.bind(I32), rec_pu_id.opcodes(&MOV_IMM));
// The 32-bit immediate movl also zero-extends to 64 bits. // The 32-bit immediate movl also zero-extends to 64 bits.
let f_unary_imm = formats.get(formats.by_name("UnaryImm")); let f_unary_imm = formats.by_name("UnaryImm");
let is_unsigned_int32 = InstructionPredicate::new_is_unsigned_int(f_unary_imm, "imm", 32, 0); let is_unsigned_int32 = InstructionPredicate::new_is_unsigned_int(&*f_unary_imm, "imm", 32, 0);
e.enc64_func( e.enc64_func(
iconst.bind(I64), iconst.bind(I64),
@@ -883,8 +880,8 @@ pub(crate) fn define<'defs>(
e.enc64_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT), use_bmi1); e.enc64_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT), use_bmi1);
// Loads and stores. // Loads and stores.
let f_load_complex = formats.get(formats.by_name("LoadComplex")); let f_load_complex = formats.by_name("LoadComplex");
let is_load_complex_length_two = InstructionPredicate::new_length_equals(f_load_complex, 2); let is_load_complex_length_two = InstructionPredicate::new_length_equals(&*f_load_complex, 2);
for recipe in &[rec_ldWithIndex, rec_ldWithIndexDisp8, rec_ldWithIndexDisp32] { for recipe in &[rec_ldWithIndex, rec_ldWithIndexDisp8, rec_ldWithIndexDisp32] {
e.enc_i32_i64_instp( e.enc_i32_i64_instp(
@@ -928,8 +925,9 @@ pub(crate) fn define<'defs>(
); );
} }
let f_store_complex = formats.get(formats.by_name("StoreComplex")); let f_store_complex = formats.by_name("StoreComplex");
let is_store_complex_length_three = InstructionPredicate::new_length_equals(f_store_complex, 3); let is_store_complex_length_three =
InstructionPredicate::new_length_equals(&*f_store_complex, 3);
for recipe in &[rec_stWithIndex, rec_stWithIndexDisp8, rec_stWithIndexDisp32] { for recipe in &[rec_stWithIndex, rec_stWithIndexDisp8, rec_stWithIndexDisp32] {
e.enc_i32_i64_instp( e.enc_i32_i64_instp(
@@ -1235,8 +1233,8 @@ pub(crate) fn define<'defs>(
); );
// 64-bit, colocated, both PIC and non-PIC. Use the lea instruction's pc-relative field. // 64-bit, colocated, both PIC and non-PIC. Use the lea instruction's pc-relative field.
let f_func_addr = formats.get(formats.by_name("FuncAddr")); let f_func_addr = formats.by_name("FuncAddr");
let is_colocated_func = InstructionPredicate::new_is_colocated_func(f_func_addr, "func_ref"); let is_colocated_func = InstructionPredicate::new_is_colocated_func(&*f_func_addr, "func_ref");
e.enc64_instp( e.enc64_instp(
func_addr.bind(I64), func_addr.bind(I64),
rec_pcrel_fnaddr8.opcodes(&LEA).rex().w(), rec_pcrel_fnaddr8.opcodes(&LEA).rex().w(),
@@ -1295,8 +1293,8 @@ pub(crate) fn define<'defs>(
e.enc32(call, rec_call_id.opcodes(&CALL_RELATIVE)); e.enc32(call, rec_call_id.opcodes(&CALL_RELATIVE));
// 64-bit, colocated, both PIC and non-PIC. Use the call instruction's pc-relative field. // 64-bit, colocated, both PIC and non-PIC. Use the call instruction's pc-relative field.
let f_call = formats.get(formats.by_name("Call")); let f_call = formats.by_name("Call");
let is_colocated_func = InstructionPredicate::new_is_colocated_func(f_call, "func_ref"); let is_colocated_func = InstructionPredicate::new_is_colocated_func(&*f_call, "func_ref");
e.enc64_instp(call, rec_call_id.opcodes(&CALL_RELATIVE), is_colocated_func); e.enc64_instp(call, rec_call_id.opcodes(&CALL_RELATIVE), is_colocated_func);
// 64-bit, non-colocated, PIC. There is no 64-bit non-colocated non-PIC version, since non-PIC // 64-bit, non-colocated, PIC. There is no 64-bit non-colocated non-PIC version, since non-PIC
@@ -1566,16 +1564,18 @@ pub(crate) fn define<'defs>(
// Floating-point constants equal to 0.0 can be encoded using either `xorps` or `xorpd`, for // Floating-point constants equal to 0.0 can be encoded using either `xorps` or `xorpd`, for
// 32-bit and 64-bit floats respectively. // 32-bit and 64-bit floats respectively.
let f_unary_ieee32 = formats.get(formats.by_name("UnaryIeee32")); let f_unary_ieee32 = formats.by_name("UnaryIeee32");
let is_zero_32_bit_float = InstructionPredicate::new_is_zero_32bit_float(f_unary_ieee32, "imm"); let is_zero_32_bit_float =
InstructionPredicate::new_is_zero_32bit_float(&*f_unary_ieee32, "imm");
e.enc32_instp( e.enc32_instp(
f32const, f32const,
rec_f32imm_z.opcodes(&XORPS), rec_f32imm_z.opcodes(&XORPS),
is_zero_32_bit_float.clone(), is_zero_32_bit_float.clone(),
); );
let f_unary_ieee64 = formats.get(formats.by_name("UnaryIeee64")); let f_unary_ieee64 = formats.by_name("UnaryIeee64");
let is_zero_64_bit_float = InstructionPredicate::new_is_zero_64bit_float(f_unary_ieee64, "imm"); let is_zero_64_bit_float =
InstructionPredicate::new_is_zero_64bit_float(&*f_unary_ieee64, "imm");
e.enc32_instp( e.enc32_instp(
f64const, f64const,
rec_f64imm_z.opcodes(&XORPD), rec_f64imm_z.opcodes(&XORPD),
@@ -1847,18 +1847,18 @@ pub(crate) fn define<'defs>(
// this must be encoded prior to the MOVUPS implementation (below) so the compiler sees this // this must be encoded prior to the MOVUPS implementation (below) so the compiler sees this
// encoding first // encoding first
for ty in ValueType::all_lane_types().filter(allowed_simd_type) { for ty in ValueType::all_lane_types().filter(allowed_simd_type) {
let f_unary_const = formats.get(formats.by_name("UnaryConst")); let f_unary_const = formats.by_name("UnaryConst");
let instruction = vconst.bind(vector(ty, sse_vector_size)); let instruction = vconst.bind(vector(ty, sse_vector_size));
let is_zero_128bit = let is_zero_128bit =
InstructionPredicate::new_is_all_zeroes(f_unary_const, "constant_handle"); InstructionPredicate::new_is_all_zeroes(&*f_unary_const, "constant_handle");
let template = rec_vconst_optimized.nonrex().opcodes(&PXOR); let template = rec_vconst_optimized.nonrex().opcodes(&PXOR);
e.enc_32_64_func(instruction.clone(), template, |builder| { e.enc_32_64_func(instruction.clone(), template, |builder| {
builder.inst_predicate(is_zero_128bit) builder.inst_predicate(is_zero_128bit)
}); });
let is_ones_128bit = let is_ones_128bit =
InstructionPredicate::new_is_all_ones(f_unary_const, "constant_handle"); InstructionPredicate::new_is_all_ones(&*f_unary_const, "constant_handle");
let template = rec_vconst_optimized.nonrex().opcodes(&PCMPEQB); let template = rec_vconst_optimized.nonrex().opcodes(&PCMPEQB);
e.enc_32_64_func(instruction, template, |builder| { e.enc_32_64_func(instruction, template, |builder| {
builder.inst_predicate(is_ones_128bit) builder.inst_predicate(is_ones_128bit)
@@ -2038,9 +2038,9 @@ pub(crate) fn define<'defs>(
}; };
let instruction = icmp.bind(vector(ty, sse_vector_size)); let instruction = icmp.bind(vector(ty, sse_vector_size));
let f_int_compare = formats.get(formats.by_name("IntCompare")); let f_int_compare = formats.by_name("IntCompare");
let has_eq_condition_code = let has_eq_condition_code =
InstructionPredicate::new_has_condition_code(f_int_compare, IntCC::Equal, "cond"); InstructionPredicate::new_has_condition_code(&*f_int_compare, IntCC::Equal, "cond");
let template = rec_icscc_fpr.nonrex().opcodes(opcodes); let template = rec_icscc_fpr.nonrex().opcodes(opcodes);
e.enc_32_64_func(instruction, template, |builder| { e.enc_32_64_func(instruction, template, |builder| {
let builder = builder.inst_predicate(has_eq_condition_code); let builder = builder.inst_predicate(has_eq_condition_code);

View File

@@ -1,7 +1,7 @@
use std::rc::Rc; use std::rc::Rc;
use crate::cdsl::ast::Literal; use crate::cdsl::ast::Literal;
use crate::cdsl::formats::{FormatRegistry, InstructionFormat}; use crate::cdsl::formats::InstructionFormat;
use crate::cdsl::instructions::InstructionPredicate; use crate::cdsl::instructions::InstructionPredicate;
use crate::cdsl::recipes::{ use crate::cdsl::recipes::{
EncodingRecipe, EncodingRecipeBuilder, OperandConstraint, Register, Stack, EncodingRecipe, EncodingRecipeBuilder, OperandConstraint, Register, Stack,
@@ -16,9 +16,6 @@ use crate::isa::x86::opcodes;
/// It contains all the recipes and recipe templates that might be used in the encodings crate of /// It contains all the recipes and recipe templates that might be used in the encodings crate of
/// this same directory. /// this same directory.
pub(crate) struct RecipeGroup<'builder> { pub(crate) struct RecipeGroup<'builder> {
/// Memoized format pointer, to pass it to builders later.
formats: &'builder FormatRegistry,
/// Memoized registers description, to pass it to builders later. /// Memoized registers description, to pass it to builders later.
regs: &'builder IsaRegs, regs: &'builder IsaRegs,
@@ -31,19 +28,18 @@ pub(crate) struct RecipeGroup<'builder> {
} }
impl<'builder> RecipeGroup<'builder> { impl<'builder> RecipeGroup<'builder> {
fn new(formats: &'builder FormatRegistry, regs: &'builder IsaRegs) -> Self { fn new(regs: &'builder IsaRegs) -> Self {
Self { Self {
formats,
regs, regs,
recipes: Vec::new(), recipes: Vec::new(),
templates: Vec::new(), templates: Vec::new(),
} }
} }
fn add_recipe(&mut self, recipe: EncodingRecipeBuilder) { fn add_recipe(&mut self, recipe: EncodingRecipeBuilder) {
self.recipes.push(recipe.build(self.formats)); self.recipes.push(recipe.build());
} }
fn add_template_recipe(&mut self, recipe: EncodingRecipeBuilder) -> Rc<Template<'builder>> { fn add_template_recipe(&mut self, recipe: EncodingRecipeBuilder) -> Rc<Template<'builder>> {
let template = Rc::new(Template::new(recipe, self.formats, self.regs)); let template = Rc::new(Template::new(recipe, self.regs));
self.templates.push(template.clone()); self.templates.push(template.clone());
template template
} }
@@ -165,9 +161,6 @@ fn replace_nonrex_constraints(
/// reconsidered later. /// reconsidered later.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Template<'builder> { pub(crate) struct Template<'builder> {
/// Mapping of format indexes to format data, used in the build() method.
formats: &'builder FormatRegistry,
/// Description of registers, used in the build() method. /// Description of registers, used in the build() method.
regs: &'builder IsaRegs, regs: &'builder IsaRegs,
@@ -192,13 +185,8 @@ pub(crate) struct Template<'builder> {
} }
impl<'builder> Template<'builder> { impl<'builder> Template<'builder> {
fn new( fn new(recipe: EncodingRecipeBuilder, regs: &'builder IsaRegs) -> Self {
recipe: EncodingRecipeBuilder,
formats: &'builder FormatRegistry,
regs: &'builder IsaRegs,
) -> Self {
Self { Self {
formats,
regs, regs,
recipe, recipe,
requires_prefix: false, requires_prefix: false,
@@ -293,7 +281,7 @@ impl<'builder> Template<'builder> {
self.recipe.operands_out = Some(replace_nonrex_constraints(self.regs, operands_out)); self.recipe.operands_out = Some(replace_nonrex_constraints(self.regs, operands_out));
} }
(self.recipe.build(self.formats), bits) (self.recipe.build(), bits)
} }
} }
@@ -340,8 +328,6 @@ pub(crate) fn define<'shared>(
.map(|name| Literal::enumerator_for(floatcc, name)) .map(|name| Literal::enumerator_for(floatcc, name))
.collect(); .collect();
let formats = &shared_defs.format_registry;
// Register classes shorthands. // Register classes shorthands.
let abcd = regs.class_by_name("ABCD"); let abcd = regs.class_by_name("ABCD");
let gpr = regs.class_by_name("GPR"); let gpr = regs.class_by_name("GPR");
@@ -360,6 +346,8 @@ pub(crate) fn define<'shared>(
let stack_fpr32 = Stack::new(fpr); let stack_fpr32 = Stack::new(fpr);
// Format shorthands, prefixed with f_. // Format shorthands, prefixed with f_.
let formats = &shared_defs.format_registry;
let f_binary = formats.by_name("Binary"); let f_binary = formats.by_name("Binary");
let f_binary_imm = formats.by_name("BinaryImm"); let f_binary_imm = formats.by_name("BinaryImm");
let f_branch = formats.by_name("Branch"); let f_branch = formats.by_name("Branch");
@@ -408,7 +396,7 @@ pub(crate) fn define<'shared>(
let use_sse41 = settings.predicate_by_name("use_sse41"); let use_sse41 = settings.predicate_by_name("use_sse41");
// Definitions. // Definitions.
let mut recipes = RecipeGroup::new(formats, regs); let mut recipes = RecipeGroup::new(regs);
// A null unary instruction that takes a GPR register. Can be used for identity copies and // A null unary instruction that takes a GPR register. Can be used for identity copies and
// no-op conversions. // no-op conversions.
@@ -501,7 +489,7 @@ pub(crate) fn define<'shared>(
.clobbers_flags(false) .clobbers_flags(false)
.inst_predicate(supported_floatccs_predicate( .inst_predicate(supported_floatccs_predicate(
&supported_floatccs, &supported_floatccs,
formats.get(f_float_cond_trap), &*f_float_cond_trap,
)) ))
.emit( .emit(
r#" r#"
@@ -570,13 +558,15 @@ pub(crate) fn define<'shared>(
// XX /r with FPR ins and outs. A form with a byte immediate. // XX /r with FPR ins and outs. A form with a byte immediate.
{ {
let format = formats.get(f_insert_lane);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("fa_ib", f_insert_lane, 2) EncodingRecipeBuilder::new("fa_ib", f_insert_lane, 2)
.operands_in(vec![fpr, fpr]) .operands_in(vec![fpr, fpr])
.operands_out(vec![0]) .operands_out(vec![0])
.inst_predicate(InstructionPredicate::new_is_unsigned_int( .inst_predicate(InstructionPredicate::new_is_unsigned_int(
format, "lane", 8, 0, &*f_insert_lane,
"lane",
8,
0,
)) ))
.emit( .emit(
r#" r#"
@@ -686,7 +676,6 @@ pub(crate) fn define<'shared>(
modrm_rr(in_reg0, out_reg0, sink); modrm_rr(in_reg0, out_reg0, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(urm_noflags), .when_prefixed(urm_noflags),
@@ -850,12 +839,16 @@ pub(crate) fn define<'shared>(
// XX /n ib with 8-bit immediate sign-extended. // XX /n ib with 8-bit immediate sign-extended.
{ {
let format = formats.get(f_binary_imm);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("r_ib", f_binary_imm, 2) EncodingRecipeBuilder::new("r_ib", f_binary_imm, 2)
.operands_in(vec![gpr]) .operands_in(vec![gpr])
.operands_out(vec![0]) .operands_out(vec![0])
.inst_predicate(InstructionPredicate::new_is_signed_int(format, "imm", 8, 0)) .inst_predicate(InstructionPredicate::new_is_signed_int(
&*f_binary_imm,
"imm",
8,
0,
))
.emit( .emit(
r#" r#"
{{PUT_OP}}(bits, rex1(in_reg0), sink); {{PUT_OP}}(bits, rex1(in_reg0), sink);
@@ -872,7 +865,10 @@ pub(crate) fn define<'shared>(
.operands_in(vec![gpr]) .operands_in(vec![gpr])
.operands_out(vec![0]) .operands_out(vec![0])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 32, 0, &*f_binary_imm,
"imm",
32,
0,
)) ))
.emit( .emit(
r#" r#"
@@ -887,13 +883,15 @@ pub(crate) fn define<'shared>(
// XX /r ib with 8-bit unsigned immediate (e.g. for pshufd) // XX /r ib with 8-bit unsigned immediate (e.g. for pshufd)
{ {
let format = formats.get(f_extract_lane);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("r_ib_unsigned_fpr", f_extract_lane, 2) EncodingRecipeBuilder::new("r_ib_unsigned_fpr", f_extract_lane, 2)
.operands_in(vec![fpr]) .operands_in(vec![fpr])
.operands_out(vec![fpr]) .operands_out(vec![fpr])
.inst_predicate(InstructionPredicate::new_is_unsigned_int( .inst_predicate(InstructionPredicate::new_is_unsigned_int(
format, "lane", 8, 0, &*f_extract_lane,
"lane",
8,
0,
)) // TODO if the format name is changed then "lane" should be renamed to something more appropriate--ordering mask? broadcast immediate? )) // TODO if the format name is changed then "lane" should be renamed to something more appropriate--ordering mask? broadcast immediate?
.emit( .emit(
r#" r#"
@@ -908,13 +906,12 @@ pub(crate) fn define<'shared>(
// XX /r ib with 8-bit unsigned immediate (e.g. for extractlane) // XX /r ib with 8-bit unsigned immediate (e.g. for extractlane)
{ {
let format = formats.get(f_extract_lane);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("r_ib_unsigned_gpr", f_extract_lane, 2) EncodingRecipeBuilder::new("r_ib_unsigned_gpr", f_extract_lane, 2)
.operands_in(vec![fpr]) .operands_in(vec![fpr])
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_unsigned_int( .inst_predicate(InstructionPredicate::new_is_unsigned_int(
format, "lane", 8, 0, &*f_extract_lane, "lane", 8, 0,
)) ))
.emit( .emit(
r#" r#"
@@ -929,13 +926,15 @@ pub(crate) fn define<'shared>(
// XX /r ib with 8-bit unsigned immediate (e.g. for insertlane) // XX /r ib with 8-bit unsigned immediate (e.g. for insertlane)
{ {
let format = formats.get(f_insert_lane);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("r_ib_unsigned_r", f_insert_lane, 2) EncodingRecipeBuilder::new("r_ib_unsigned_r", f_insert_lane, 2)
.operands_in(vec![fpr, gpr]) .operands_in(vec![fpr, gpr])
.operands_out(vec![0]) .operands_out(vec![0])
.inst_predicate(InstructionPredicate::new_is_unsigned_int( .inst_predicate(InstructionPredicate::new_is_unsigned_int(
format, "lane", 8, 0, &*f_insert_lane,
"lane",
8,
0,
)) ))
.emit( .emit(
r#" r#"
@@ -950,12 +949,14 @@ pub(crate) fn define<'shared>(
{ {
// XX /n id with 32-bit immediate sign-extended. UnaryImm version. // XX /n id with 32-bit immediate sign-extended. UnaryImm version.
let format = formats.get(f_unary_imm);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("u_id", f_unary_imm, 5) EncodingRecipeBuilder::new("u_id", f_unary_imm, 5)
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 32, 0, &*f_unary_imm,
"imm",
32,
0,
)) ))
.emit( .emit(
r#" r#"
@@ -1039,11 +1040,13 @@ pub(crate) fn define<'shared>(
// XX /n Unary with floating point 32-bit immediate equal to zero. // XX /n Unary with floating point 32-bit immediate equal to zero.
{ {
let format = formats.get(f_unary_ieee32);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("f32imm_z", f_unary_ieee32, 1) EncodingRecipeBuilder::new("f32imm_z", f_unary_ieee32, 1)
.operands_out(vec![fpr]) .operands_out(vec![fpr])
.inst_predicate(InstructionPredicate::new_is_zero_32bit_float(format, "imm")) .inst_predicate(InstructionPredicate::new_is_zero_32bit_float(
&*f_unary_ieee32,
"imm",
))
.emit( .emit(
r#" r#"
{{PUT_OP}}(bits, rex2(out_reg0, out_reg0), sink); {{PUT_OP}}(bits, rex2(out_reg0, out_reg0), sink);
@@ -1055,11 +1058,13 @@ pub(crate) fn define<'shared>(
// XX /n Unary with floating point 64-bit immediate equal to zero. // XX /n Unary with floating point 64-bit immediate equal to zero.
{ {
let format = formats.get(f_unary_ieee64);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("f64imm_z", f_unary_ieee64, 1) EncodingRecipeBuilder::new("f64imm_z", f_unary_ieee64, 1)
.operands_out(vec![fpr]) .operands_out(vec![fpr])
.inst_predicate(InstructionPredicate::new_is_zero_64bit_float(format, "imm")) .inst_predicate(InstructionPredicate::new_is_zero_64bit_float(
&*f_unary_ieee64,
"imm",
))
.emit( .emit(
r#" r#"
{{PUT_OP}}(bits, rex2(out_reg0, out_reg0), sink); {{PUT_OP}}(bits, rex2(out_reg0, out_reg0), sink);
@@ -1114,10 +1119,14 @@ pub(crate) fn define<'shared>(
); );
{ {
let format = formats.get(f_unary_imm);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("adjustsp_ib", f_unary_imm, 2) EncodingRecipeBuilder::new("adjustsp_ib", f_unary_imm, 2)
.inst_predicate(InstructionPredicate::new_is_signed_int(format, "imm", 8, 0)) .inst_predicate(InstructionPredicate::new_is_signed_int(
&*f_unary_imm,
"imm",
8,
0,
))
.emit( .emit(
r#" r#"
{{PUT_OP}}(bits, rex1(RU::rsp.into()), sink); {{PUT_OP}}(bits, rex1(RU::rsp.into()), sink);
@@ -1131,7 +1140,10 @@ pub(crate) fn define<'shared>(
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("adjustsp_id", f_unary_imm, 5) EncodingRecipeBuilder::new("adjustsp_id", f_unary_imm, 5)
.inst_predicate(InstructionPredicate::new_is_signed_int( .inst_predicate(InstructionPredicate::new_is_signed_int(
format, "imm", 32, 0, &*f_unary_imm,
"imm",
32,
0,
)) ))
.emit( .emit(
r#" r#"
@@ -1350,10 +1362,10 @@ pub(crate) fn define<'shared>(
{ {
// Simple stores. // Simple stores.
let format = formats.get(f_store);
// A predicate asking if the offset is zero. // A predicate asking if the offset is zero.
let has_no_offset = InstructionPredicate::new_is_field_equal(format, "offset", "0".into()); let has_no_offset =
InstructionPredicate::new_is_field_equal(&*f_store, "offset", "0".into());
// XX /r register-indirect store with no offset. // XX /r register-indirect store with no offset.
let st = recipes.add_template_recipe( let st = recipes.add_template_recipe(
@@ -1407,7 +1419,6 @@ pub(crate) fn define<'shared>(
} }
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(st), .when_prefixed(st),
@@ -1439,7 +1450,7 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_small_offset = InstructionPredicate::new_is_signed_int(format, "offset", 8, 0); let has_small_offset = InstructionPredicate::new_is_signed_int(&*f_store, "offset", 8, 0);
// XX /r register-indirect store with 8-bit offset. // XX /r register-indirect store with 8-bit offset.
let st_disp8 = recipes.add_template_recipe( let st_disp8 = recipes.add_template_recipe(
@@ -1491,7 +1502,6 @@ pub(crate) fn define<'shared>(
sink.put1(offset as u8); sink.put1(offset as u8);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(st_disp8), .when_prefixed(st_disp8),
@@ -1570,7 +1580,6 @@ pub(crate) fn define<'shared>(
sink.put4(offset as u32); sink.put4(offset as u32);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(st_disp32), .when_prefixed(st_disp32),
@@ -1603,10 +1612,10 @@ pub(crate) fn define<'shared>(
{ {
// Complex stores. // Complex stores.
let format = formats.get(f_store_complex);
// A predicate asking if the offset is zero. // A predicate asking if the offset is zero.
let has_no_offset = InstructionPredicate::new_is_field_equal(format, "offset", "0".into()); let has_no_offset =
InstructionPredicate::new_is_field_equal(&*f_store_complex, "offset", "0".into());
// XX /r register-indirect store with index and no offset. // XX /r register-indirect store with index and no offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -1687,7 +1696,8 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_small_offset = InstructionPredicate::new_is_signed_int(format, "offset", 8, 0); let has_small_offset =
InstructionPredicate::new_is_signed_int(&*f_store_complex, "offset", 8, 0);
// XX /r register-indirect store with index and 8-bit offset. // XX /r register-indirect store with index and 8-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -1750,7 +1760,8 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_big_offset = InstructionPredicate::new_is_signed_int(format, "offset", 32, 0); let has_big_offset =
InstructionPredicate::new_is_signed_int(&*f_store_complex, "offset", 32, 0);
// XX /r register-indirect store with index and 32-bit offset. // XX /r register-indirect store with index and 32-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -1890,10 +1901,10 @@ pub(crate) fn define<'shared>(
{ {
// Simple loads. // Simple loads.
let format = formats.get(f_load);
// A predicate asking if the offset is zero. // A predicate asking if the offset is zero.
let has_no_offset = InstructionPredicate::new_is_field_equal(format, "offset", "0".into()); let has_no_offset =
InstructionPredicate::new_is_field_equal(&*f_load, "offset", "0".into());
// XX /r load with no offset. // XX /r load with no offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -1949,7 +1960,7 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_small_offset = InstructionPredicate::new_is_signed_int(format, "offset", 8, 0); let has_small_offset = InstructionPredicate::new_is_signed_int(&*f_load, "offset", 8, 0);
// XX /r load with 8-bit offset. // XX /r load with 8-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2003,7 +2014,7 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_big_offset = InstructionPredicate::new_is_signed_int(format, "offset", 32, 0); let has_big_offset = InstructionPredicate::new_is_signed_int(&*f_load, "offset", 32, 0);
// XX /r load with 32-bit offset. // XX /r load with 32-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2060,10 +2071,10 @@ pub(crate) fn define<'shared>(
{ {
// Complex loads. // Complex loads.
let format = formats.get(f_load_complex);
// A predicate asking if the offset is zero. // A predicate asking if the offset is zero.
let has_no_offset = InstructionPredicate::new_is_field_equal(format, "offset", "0".into()); let has_no_offset =
InstructionPredicate::new_is_field_equal(&*f_load_complex, "offset", "0".into());
// XX /r load with index and no offset. // XX /r load with index and no offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2119,7 +2130,8 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_small_offset = InstructionPredicate::new_is_signed_int(format, "offset", 8, 0); let has_small_offset =
InstructionPredicate::new_is_signed_int(&*f_load_complex, "offset", 8, 0);
// XX /r load with index and 8-bit offset. // XX /r load with index and 8-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2163,7 +2175,8 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_big_offset = InstructionPredicate::new_is_signed_int(format, "offset", 32, 0); let has_big_offset =
InstructionPredicate::new_is_signed_int(&*f_load_complex, "offset", 32, 0);
// XX /r load with index and 32-bit offset. // XX /r load with index and 32-bit offset.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2377,7 +2390,7 @@ pub(crate) fn define<'shared>(
.clobbers_flags(false) .clobbers_flags(false)
.inst_predicate(supported_floatccs_predicate( .inst_predicate(supported_floatccs_predicate(
&supported_floatccs, &supported_floatccs,
formats.get(f_branch_float), &*f_branch_float,
)) ))
.emit( .emit(
r#" r#"
@@ -2394,7 +2407,7 @@ pub(crate) fn define<'shared>(
.clobbers_flags(false) .clobbers_flags(false)
.inst_predicate(supported_floatccs_predicate( .inst_predicate(supported_floatccs_predicate(
&supported_floatccs, &supported_floatccs,
formats.get(f_branch_float), &*f_branch_float,
)) ))
.emit( .emit(
r#" r#"
@@ -2421,7 +2434,7 @@ pub(crate) fn define<'shared>(
.operands_in(vec![gpr, gpr]) .operands_in(vec![gpr, gpr])
.operands_out(vec![gpr]) .operands_out(vec![gpr])
.clobbers_flags(false) .clobbers_flags(false)
.inst_predicate(valid_scale(formats.get(f_branch_table_entry))) .inst_predicate(valid_scale(&*f_branch_table_entry))
.compute_size("size_plus_maybe_offset_for_in_reg_1") .compute_size("size_plus_maybe_offset_for_in_reg_1")
.emit( .emit(
r#" r#"
@@ -2499,7 +2512,6 @@ pub(crate) fn define<'shared>(
modrm_r_bits(out_reg0, bits, sink); modrm_r_bits(out_reg0, bits, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.requires_prefix(true), .requires_prefix(true),
@@ -2517,7 +2529,6 @@ pub(crate) fn define<'shared>(
modrm_r_bits(out_reg0, bits, sink); modrm_r_bits(out_reg0, bits, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(seti), .when_prefixed(seti),
@@ -2535,7 +2546,6 @@ pub(crate) fn define<'shared>(
modrm_r_bits(out_reg0, bits, sink); modrm_r_bits(out_reg0, bits, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.requires_prefix(true), .requires_prefix(true),
@@ -2553,7 +2563,6 @@ pub(crate) fn define<'shared>(
modrm_r_bits(out_reg0, bits, sink); modrm_r_bits(out_reg0, bits, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(setf), .when_prefixed(setf),
@@ -2695,9 +2704,7 @@ pub(crate) fn define<'shared>(
); );
{ {
let format = formats.get(f_binary_imm); let has_small_offset = InstructionPredicate::new_is_signed_int(&*f_binary_imm, "imm", 8, 0);
let has_small_offset = InstructionPredicate::new_is_signed_int(format, "imm", 8, 0);
// XX /n, MI form with imm8. // XX /n, MI form with imm8.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2715,7 +2722,7 @@ pub(crate) fn define<'shared>(
), ),
); );
let has_big_offset = InstructionPredicate::new_is_signed_int(format, "imm", 32, 0); let has_big_offset = InstructionPredicate::new_is_signed_int(&*f_binary_imm, "imm", 32, 0);
// XX /n, MI form with imm32. // XX /n, MI form with imm32.
recipes.add_template_recipe( recipes.add_template_recipe(
@@ -2798,7 +2805,6 @@ pub(crate) fn define<'shared>(
disp1(destination, func, sink); disp1(destination, func, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.requires_prefix(true), .requires_prefix(true),
@@ -2819,7 +2825,6 @@ pub(crate) fn define<'shared>(
disp1(destination, func, sink); disp1(destination, func, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(t8jccb), .when_prefixed(t8jccb),
@@ -2841,7 +2846,6 @@ pub(crate) fn define<'shared>(
disp4(destination, func, sink); disp4(destination, func, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.requires_prefix(true), .requires_prefix(true),
@@ -2863,7 +2867,6 @@ pub(crate) fn define<'shared>(
disp4(destination, func, sink); disp4(destination, func, sink);
"#, "#,
), ),
formats,
regs, regs,
) )
.when_prefixed(t8jccd), .when_prefixed(t8jccd),
@@ -2944,9 +2947,8 @@ pub(crate) fn define<'shared>(
); );
{ {
let format = formats.get(f_int_compare_imm); let is_small_imm =
InstructionPredicate::new_is_signed_int(&*f_int_compare_imm, "imm", 8, 0);
let is_small_imm = InstructionPredicate::new_is_signed_int(format, "imm", 8, 0);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("icscc_ib", f_int_compare_imm, 2 + 3) EncodingRecipeBuilder::new("icscc_ib", f_int_compare_imm, 2 + 3)
@@ -2969,7 +2971,7 @@ pub(crate) fn define<'shared>(
), ),
); );
let is_big_imm = InstructionPredicate::new_is_signed_int(format, "imm", 32, 0); let is_big_imm = InstructionPredicate::new_is_signed_int(&*f_int_compare_imm, "imm", 32, 0);
recipes.add_template_recipe( recipes.add_template_recipe(
EncodingRecipeBuilder::new("icscc_id", f_int_compare_imm, 5 + 3) EncodingRecipeBuilder::new("icscc_id", f_int_compare_imm, 5 + 3)
@@ -3014,7 +3016,7 @@ pub(crate) fn define<'shared>(
.operands_out(vec![abcd]) .operands_out(vec![abcd])
.inst_predicate(supported_floatccs_predicate( .inst_predicate(supported_floatccs_predicate(
&supported_floatccs, &supported_floatccs,
formats.get(f_float_compare), &*f_float_compare,
)) ))
.emit( .emit(
r#" r#"

View File

@@ -39,13 +39,7 @@ pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error>
gen_inst::generate(&shared_defs, "opcodes.rs", "inst_builder.rs", &out_dir)?; gen_inst::generate(&shared_defs, "opcodes.rs", "inst_builder.rs", &out_dir)?;
gen_legalizer::generate( gen_legalizer::generate(&isas, &shared_defs.transform_groups, "legalize", &out_dir)?;
&isas,
&shared_defs.format_registry,
&shared_defs.transform_groups,
"legalize",
&out_dir,
)?;
for isa in isas { for isa in isas {
gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?; gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
@@ -65,7 +59,6 @@ pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error>
)?; )?;
gen_binemit::generate( gen_binemit::generate(
&shared_defs.format_registry,
&isa.name, &isa.name,
&isa.recipes, &isa.recipes,
&format!("binemit-{}.rs", isa.name), &format!("binemit-{}.rs", isa.name),