[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:
@@ -13,24 +13,21 @@ use crate::shared::types::Reference::{R32, R64};
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
use super::recipes::RecipeGroup;
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
|
||||
pub(crate) struct PerCpuModeEncodings<'defs> {
|
||||
pub inst_pred_reg: InstructionPredicateRegistry,
|
||||
pub enc32: Vec<Encoding>,
|
||||
pub enc64: Vec<Encoding>,
|
||||
recipes: &'defs Recipes,
|
||||
formats: &'defs FormatRegistry,
|
||||
}
|
||||
|
||||
impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
fn new(recipes: &'defs Recipes, formats: &'defs FormatRegistry) -> Self {
|
||||
fn new(recipes: &'defs Recipes) -> Self {
|
||||
Self {
|
||||
inst_pred_reg: InstructionPredicateRegistry::new(),
|
||||
enc32: Vec::new(),
|
||||
enc64: Vec::new(),
|
||||
recipes,
|
||||
formats,
|
||||
}
|
||||
}
|
||||
fn enc(
|
||||
@@ -39,7 +36,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
recipe: EncodingRecipeNumber,
|
||||
bits: u16,
|
||||
) -> EncodingBuilder {
|
||||
EncodingBuilder::new(inst.into(), recipe, bits, self.formats)
|
||||
EncodingBuilder::new(inst.into(), recipe, bits)
|
||||
}
|
||||
fn add32(&mut self, encoding: EncodingBuilder) {
|
||||
self.enc32
|
||||
@@ -176,7 +173,7 @@ pub(crate) fn define<'defs>(
|
||||
let use_m = isa_settings.predicate_by_name("use_m");
|
||||
|
||||
// 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.
|
||||
for &(inst, inst_imm, f3, f7) in &[
|
||||
@@ -242,7 +239,7 @@ pub(crate) fn define<'defs>(
|
||||
bound_inst.clone().into(),
|
||||
vec![Expr::Literal(cc), Expr::Var(x), Expr::Var(y)],
|
||||
)
|
||||
.inst_predicate(&shared_defs.format_registry, &var_pool)
|
||||
.inst_predicate(&var_pool)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
@@ -339,7 +336,7 @@ pub(crate) fn define<'defs>(
|
||||
Expr::Var(args),
|
||||
],
|
||||
)
|
||||
.inst_predicate(&shared_defs.format_registry, &var_pool)
|
||||
.inst_predicate(&var_pool)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::instructions::InstructionPredicate;
|
||||
use crate::cdsl::recipes::{EncodingRecipeBuilder, EncodingRecipeNumber, Recipes, Stack};
|
||||
use crate::cdsl::regs::IsaRegs;
|
||||
use crate::shared::Definitions as SharedDefinitions;
|
||||
|
||||
/// An helper to create recipes and use them when defining the RISCV encodings.
|
||||
pub(crate) struct RecipeGroup<'formats> {
|
||||
/// Memoized format registry, to pass it to the builders.
|
||||
formats: &'formats FormatRegistry,
|
||||
|
||||
pub(crate) struct RecipeGroup {
|
||||
/// The actualy list of recipes explicitly created in this file.
|
||||
pub recipes: Recipes,
|
||||
|
||||
@@ -18,10 +14,9 @@ pub(crate) struct RecipeGroup<'formats> {
|
||||
name_to_recipe: HashMap<String, EncodingRecipeNumber>,
|
||||
}
|
||||
|
||||
impl<'formats> RecipeGroup<'formats> {
|
||||
fn new(formats: &'formats FormatRegistry) -> Self {
|
||||
impl RecipeGroup {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
formats,
|
||||
recipes: Recipes::new(),
|
||||
name_to_recipe: HashMap::new(),
|
||||
}
|
||||
@@ -33,7 +28,7 @@ impl<'formats> RecipeGroup<'formats> {
|
||||
format!("riscv recipe '{}' created twice", builder.name)
|
||||
);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -50,13 +45,10 @@ impl<'formats> RecipeGroup<'formats> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn define<'formats>(
|
||||
shared_defs: &'formats SharedDefinitions,
|
||||
regs: &IsaRegs,
|
||||
) -> RecipeGroup<'formats> {
|
||||
pub(crate) fn define(shared_defs: &SharedDefinitions, regs: &IsaRegs) -> RecipeGroup {
|
||||
// Format shorthands.
|
||||
let formats = &shared_defs.format_registry;
|
||||
|
||||
// Format shorthands.
|
||||
let f_binary = formats.by_name("Binary");
|
||||
let f_binary_imm = formats.by_name("BinaryImm");
|
||||
let f_branch = formats.by_name("Branch");
|
||||
@@ -76,7 +68,7 @@ pub(crate) fn define<'formats>(
|
||||
let gpr = regs.class_by_name("GPR");
|
||||
|
||||
// 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.
|
||||
// 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);"),
|
||||
);
|
||||
|
||||
let format = formats.get(f_binary_imm);
|
||||
recipes.push(
|
||||
EncodingRecipeBuilder::new("Ii", f_binary_imm, 4)
|
||||
.operands_in(vec![gpr])
|
||||
.operands_out(vec![gpr])
|
||||
.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);"),
|
||||
);
|
||||
|
||||
// I-type instruction with a hardcoded %x0 rs1.
|
||||
let format = formats.get(f_unary_imm);
|
||||
recipes.push(
|
||||
EncodingRecipeBuilder::new("Iz", f_unary_imm, 4)
|
||||
.operands_out(vec![gpr])
|
||||
.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);"),
|
||||
);
|
||||
|
||||
// I-type encoding of an integer comparison.
|
||||
let format = formats.get(f_int_compare_imm);
|
||||
recipes.push(
|
||||
EncodingRecipeBuilder::new("Iicmp", f_int_compare_imm, 4)
|
||||
.operands_in(vec![gpr])
|
||||
.operands_out(vec![gpr])
|
||||
.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);"),
|
||||
);
|
||||
@@ -195,12 +193,14 @@ pub(crate) fn define<'formats>(
|
||||
);
|
||||
|
||||
// U-type instructions have a 20-bit immediate that targets bits 12-31.
|
||||
let format = formats.get(f_unary_imm);
|
||||
recipes.push(
|
||||
EncodingRecipeBuilder::new("U", f_unary_imm, 4)
|
||||
.operands_out(vec![gpr])
|
||||
.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);"),
|
||||
);
|
||||
|
||||
@@ -20,27 +20,24 @@ use crate::shared::Definitions as SharedDefinitions;
|
||||
use crate::isa::x86::opcodes::*;
|
||||
|
||||
use super::recipes::{RecipeGroup, Template};
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::instructions::BindParameter::Any;
|
||||
|
||||
pub(crate) struct PerCpuModeEncodings<'defs> {
|
||||
pub(crate) struct PerCpuModeEncodings {
|
||||
pub enc32: Vec<Encoding>,
|
||||
pub enc64: Vec<Encoding>,
|
||||
pub recipes: Recipes,
|
||||
recipes_by_name: HashMap<String, EncodingRecipeNumber>,
|
||||
pub inst_pred_reg: InstructionPredicateRegistry,
|
||||
formats: &'defs FormatRegistry,
|
||||
}
|
||||
|
||||
impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
fn new(formats: &'defs FormatRegistry) -> Self {
|
||||
impl PerCpuModeEncodings {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
enc32: Vec::new(),
|
||||
enc64: Vec::new(),
|
||||
recipes: Recipes::new(),
|
||||
recipes_by_name: HashMap::new(),
|
||||
inst_pred_reg: InstructionPredicateRegistry::new(),
|
||||
formats,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +70,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
{
|
||||
let (recipe, bits) = template.build();
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -105,7 +102,7 @@ impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
}
|
||||
fn enc32_rec(&mut self, inst: impl Into<InstSpec>, recipe: &EncodingRecipe, bits: u16) {
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
self.enc64.push(encoding);
|
||||
}
|
||||
@@ -370,12 +367,12 @@ impl<'defs> PerCpuModeEncodings<'defs> {
|
||||
|
||||
// Definitions.
|
||||
|
||||
pub(crate) fn define<'defs>(
|
||||
shared_defs: &'defs SharedDefinitions,
|
||||
pub(crate) fn define(
|
||||
shared_defs: &SharedDefinitions,
|
||||
settings: &SettingGroup,
|
||||
x86: &InstructionGroup,
|
||||
r: &RecipeGroup,
|
||||
) -> PerCpuModeEncodings<'defs> {
|
||||
) -> PerCpuModeEncodings {
|
||||
let shared = &shared_defs.instructions;
|
||||
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");
|
||||
|
||||
// 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!
|
||||
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));
|
||||
|
||||
// The 32-bit immediate movl also zero-extends to 64 bits.
|
||||
let f_unary_imm = formats.get(formats.by_name("UnaryImm"));
|
||||
let is_unsigned_int32 = InstructionPredicate::new_is_unsigned_int(f_unary_imm, "imm", 32, 0);
|
||||
let f_unary_imm = formats.by_name("UnaryImm");
|
||||
let is_unsigned_int32 = InstructionPredicate::new_is_unsigned_int(&*f_unary_imm, "imm", 32, 0);
|
||||
|
||||
e.enc64_func(
|
||||
iconst.bind(I64),
|
||||
@@ -883,8 +880,8 @@ pub(crate) fn define<'defs>(
|
||||
e.enc64_isap(ctz.bind(I32), rec_urm.opcodes(&TZCNT), use_bmi1);
|
||||
|
||||
// Loads and stores.
|
||||
let f_load_complex = formats.get(formats.by_name("LoadComplex"));
|
||||
let is_load_complex_length_two = InstructionPredicate::new_length_equals(f_load_complex, 2);
|
||||
let f_load_complex = formats.by_name("LoadComplex");
|
||||
let is_load_complex_length_two = InstructionPredicate::new_length_equals(&*f_load_complex, 2);
|
||||
|
||||
for recipe in &[rec_ldWithIndex, rec_ldWithIndexDisp8, rec_ldWithIndexDisp32] {
|
||||
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 is_store_complex_length_three = InstructionPredicate::new_length_equals(f_store_complex, 3);
|
||||
let f_store_complex = formats.by_name("StoreComplex");
|
||||
let is_store_complex_length_three =
|
||||
InstructionPredicate::new_length_equals(&*f_store_complex, 3);
|
||||
|
||||
for recipe in &[rec_stWithIndex, rec_stWithIndexDisp8, rec_stWithIndexDisp32] {
|
||||
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.
|
||||
let f_func_addr = formats.get(formats.by_name("FuncAddr"));
|
||||
let is_colocated_func = InstructionPredicate::new_is_colocated_func(f_func_addr, "func_ref");
|
||||
let f_func_addr = formats.by_name("FuncAddr");
|
||||
let is_colocated_func = InstructionPredicate::new_is_colocated_func(&*f_func_addr, "func_ref");
|
||||
e.enc64_instp(
|
||||
func_addr.bind(I64),
|
||||
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));
|
||||
|
||||
// 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 is_colocated_func = InstructionPredicate::new_is_colocated_func(f_call, "func_ref");
|
||||
let f_call = formats.by_name("Call");
|
||||
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);
|
||||
|
||||
// 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
|
||||
// 32-bit and 64-bit floats respectively.
|
||||
let f_unary_ieee32 = formats.get(formats.by_name("UnaryIeee32"));
|
||||
let is_zero_32_bit_float = InstructionPredicate::new_is_zero_32bit_float(f_unary_ieee32, "imm");
|
||||
let f_unary_ieee32 = formats.by_name("UnaryIeee32");
|
||||
let is_zero_32_bit_float =
|
||||
InstructionPredicate::new_is_zero_32bit_float(&*f_unary_ieee32, "imm");
|
||||
e.enc32_instp(
|
||||
f32const,
|
||||
rec_f32imm_z.opcodes(&XORPS),
|
||||
is_zero_32_bit_float.clone(),
|
||||
);
|
||||
|
||||
let f_unary_ieee64 = formats.get(formats.by_name("UnaryIeee64"));
|
||||
let is_zero_64_bit_float = InstructionPredicate::new_is_zero_64bit_float(f_unary_ieee64, "imm");
|
||||
let f_unary_ieee64 = formats.by_name("UnaryIeee64");
|
||||
let is_zero_64_bit_float =
|
||||
InstructionPredicate::new_is_zero_64bit_float(&*f_unary_ieee64, "imm");
|
||||
e.enc32_instp(
|
||||
f64const,
|
||||
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
|
||||
// encoding first
|
||||
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 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);
|
||||
e.enc_32_64_func(instruction.clone(), template, |builder| {
|
||||
builder.inst_predicate(is_zero_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);
|
||||
e.enc_32_64_func(instruction, template, |builder| {
|
||||
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 f_int_compare = formats.get(formats.by_name("IntCompare"));
|
||||
let f_int_compare = formats.by_name("IntCompare");
|
||||
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);
|
||||
e.enc_32_64_func(instruction, template, |builder| {
|
||||
let builder = builder.inst_predicate(has_eq_condition_code);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::cdsl::ast::Literal;
|
||||
use crate::cdsl::formats::{FormatRegistry, InstructionFormat};
|
||||
use crate::cdsl::formats::InstructionFormat;
|
||||
use crate::cdsl::instructions::InstructionPredicate;
|
||||
use crate::cdsl::recipes::{
|
||||
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
|
||||
/// this same directory.
|
||||
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.
|
||||
regs: &'builder IsaRegs,
|
||||
|
||||
@@ -31,19 +28,18 @@ pub(crate) struct RecipeGroup<'builder> {
|
||||
}
|
||||
|
||||
impl<'builder> RecipeGroup<'builder> {
|
||||
fn new(formats: &'builder FormatRegistry, regs: &'builder IsaRegs) -> Self {
|
||||
fn new(regs: &'builder IsaRegs) -> Self {
|
||||
Self {
|
||||
formats,
|
||||
regs,
|
||||
recipes: Vec::new(),
|
||||
templates: Vec::new(),
|
||||
}
|
||||
}
|
||||
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>> {
|
||||
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());
|
||||
template
|
||||
}
|
||||
@@ -165,9 +161,6 @@ fn replace_nonrex_constraints(
|
||||
/// reconsidered later.
|
||||
#[derive(Clone)]
|
||||
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.
|
||||
regs: &'builder IsaRegs,
|
||||
|
||||
@@ -192,13 +185,8 @@ pub(crate) struct Template<'builder> {
|
||||
}
|
||||
|
||||
impl<'builder> Template<'builder> {
|
||||
fn new(
|
||||
recipe: EncodingRecipeBuilder,
|
||||
formats: &'builder FormatRegistry,
|
||||
regs: &'builder IsaRegs,
|
||||
) -> Self {
|
||||
fn new(recipe: EncodingRecipeBuilder, regs: &'builder IsaRegs) -> Self {
|
||||
Self {
|
||||
formats,
|
||||
regs,
|
||||
recipe,
|
||||
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.build(self.formats), bits)
|
||||
(self.recipe.build(), bits)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,8 +328,6 @@ pub(crate) fn define<'shared>(
|
||||
.map(|name| Literal::enumerator_for(floatcc, name))
|
||||
.collect();
|
||||
|
||||
let formats = &shared_defs.format_registry;
|
||||
|
||||
// Register classes shorthands.
|
||||
let abcd = regs.class_by_name("ABCD");
|
||||
let gpr = regs.class_by_name("GPR");
|
||||
@@ -360,6 +346,8 @@ pub(crate) fn define<'shared>(
|
||||
let stack_fpr32 = Stack::new(fpr);
|
||||
|
||||
// Format shorthands, prefixed with f_.
|
||||
let formats = &shared_defs.format_registry;
|
||||
|
||||
let f_binary = formats.by_name("Binary");
|
||||
let f_binary_imm = formats.by_name("BinaryImm");
|
||||
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");
|
||||
|
||||
// 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
|
||||
// no-op conversions.
|
||||
@@ -501,7 +489,7 @@ pub(crate) fn define<'shared>(
|
||||
.clobbers_flags(false)
|
||||
.inst_predicate(supported_floatccs_predicate(
|
||||
&supported_floatccs,
|
||||
formats.get(f_float_cond_trap),
|
||||
&*f_float_cond_trap,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -570,13 +558,15 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /r with FPR ins and outs. A form with a byte immediate.
|
||||
{
|
||||
let format = formats.get(f_insert_lane);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("fa_ib", f_insert_lane, 2)
|
||||
.operands_in(vec![fpr, fpr])
|
||||
.operands_out(vec![0])
|
||||
.inst_predicate(InstructionPredicate::new_is_unsigned_int(
|
||||
format, "lane", 8, 0,
|
||||
&*f_insert_lane,
|
||||
"lane",
|
||||
8,
|
||||
0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -686,7 +676,6 @@ pub(crate) fn define<'shared>(
|
||||
modrm_rr(in_reg0, out_reg0, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.when_prefixed(urm_noflags),
|
||||
@@ -850,12 +839,16 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /n ib with 8-bit immediate sign-extended.
|
||||
{
|
||||
let format = formats.get(f_binary_imm);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("r_ib", f_binary_imm, 2)
|
||||
.operands_in(vec![gpr])
|
||||
.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(
|
||||
r#"
|
||||
{{PUT_OP}}(bits, rex1(in_reg0), sink);
|
||||
@@ -872,7 +865,10 @@ pub(crate) fn define<'shared>(
|
||||
.operands_in(vec![gpr])
|
||||
.operands_out(vec![0])
|
||||
.inst_predicate(InstructionPredicate::new_is_signed_int(
|
||||
format, "imm", 32, 0,
|
||||
&*f_binary_imm,
|
||||
"imm",
|
||||
32,
|
||||
0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -887,13 +883,15 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /r ib with 8-bit unsigned immediate (e.g. for pshufd)
|
||||
{
|
||||
let format = formats.get(f_extract_lane);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("r_ib_unsigned_fpr", f_extract_lane, 2)
|
||||
.operands_in(vec![fpr])
|
||||
.operands_out(vec![fpr])
|
||||
.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?
|
||||
.emit(
|
||||
r#"
|
||||
@@ -908,13 +906,12 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /r ib with 8-bit unsigned immediate (e.g. for extractlane)
|
||||
{
|
||||
let format = formats.get(f_extract_lane);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("r_ib_unsigned_gpr", f_extract_lane, 2)
|
||||
.operands_in(vec![fpr])
|
||||
.operands_out(vec![gpr])
|
||||
.inst_predicate(InstructionPredicate::new_is_unsigned_int(
|
||||
format, "lane", 8, 0,
|
||||
&*f_extract_lane, "lane", 8, 0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -929,13 +926,15 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /r ib with 8-bit unsigned immediate (e.g. for insertlane)
|
||||
{
|
||||
let format = formats.get(f_insert_lane);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("r_ib_unsigned_r", f_insert_lane, 2)
|
||||
.operands_in(vec![fpr, gpr])
|
||||
.operands_out(vec![0])
|
||||
.inst_predicate(InstructionPredicate::new_is_unsigned_int(
|
||||
format, "lane", 8, 0,
|
||||
&*f_insert_lane,
|
||||
"lane",
|
||||
8,
|
||||
0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -950,12 +949,14 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
{
|
||||
// XX /n id with 32-bit immediate sign-extended. UnaryImm version.
|
||||
let format = formats.get(f_unary_imm);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("u_id", f_unary_imm, 5)
|
||||
.operands_out(vec![gpr])
|
||||
.inst_predicate(InstructionPredicate::new_is_signed_int(
|
||||
format, "imm", 32, 0,
|
||||
&*f_unary_imm,
|
||||
"imm",
|
||||
32,
|
||||
0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -1039,11 +1040,13 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
// XX /n Unary with floating point 32-bit immediate equal to zero.
|
||||
{
|
||||
let format = formats.get(f_unary_ieee32);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("f32imm_z", f_unary_ieee32, 1)
|
||||
.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(
|
||||
r#"
|
||||
{{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.
|
||||
{
|
||||
let format = formats.get(f_unary_ieee64);
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("f64imm_z", f_unary_ieee64, 1)
|
||||
.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(
|
||||
r#"
|
||||
{{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(
|
||||
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(
|
||||
r#"
|
||||
{{PUT_OP}}(bits, rex1(RU::rsp.into()), sink);
|
||||
@@ -1131,7 +1140,10 @@ pub(crate) fn define<'shared>(
|
||||
recipes.add_template_recipe(
|
||||
EncodingRecipeBuilder::new("adjustsp_id", f_unary_imm, 5)
|
||||
.inst_predicate(InstructionPredicate::new_is_signed_int(
|
||||
format, "imm", 32, 0,
|
||||
&*f_unary_imm,
|
||||
"imm",
|
||||
32,
|
||||
0,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -1350,10 +1362,10 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
{
|
||||
// Simple stores.
|
||||
let format = formats.get(f_store);
|
||||
|
||||
// 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.
|
||||
let st = recipes.add_template_recipe(
|
||||
@@ -1407,7 +1419,6 @@ pub(crate) fn define<'shared>(
|
||||
}
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.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.
|
||||
let st_disp8 = recipes.add_template_recipe(
|
||||
@@ -1491,7 +1502,6 @@ pub(crate) fn define<'shared>(
|
||||
sink.put1(offset as u8);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.when_prefixed(st_disp8),
|
||||
@@ -1570,7 +1580,6 @@ pub(crate) fn define<'shared>(
|
||||
sink.put4(offset as u32);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.when_prefixed(st_disp32),
|
||||
@@ -1603,10 +1612,10 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
{
|
||||
// Complex stores.
|
||||
let format = formats.get(f_store_complex);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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.
|
||||
recipes.add_template_recipe(
|
||||
@@ -1890,10 +1901,10 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
{
|
||||
// Simple loads.
|
||||
let format = formats.get(f_load);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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.
|
||||
recipes.add_template_recipe(
|
||||
@@ -2060,10 +2071,10 @@ pub(crate) fn define<'shared>(
|
||||
|
||||
{
|
||||
// Complex loads.
|
||||
let format = formats.get(f_load_complex);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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.
|
||||
recipes.add_template_recipe(
|
||||
@@ -2377,7 +2390,7 @@ pub(crate) fn define<'shared>(
|
||||
.clobbers_flags(false)
|
||||
.inst_predicate(supported_floatccs_predicate(
|
||||
&supported_floatccs,
|
||||
formats.get(f_branch_float),
|
||||
&*f_branch_float,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -2394,7 +2407,7 @@ pub(crate) fn define<'shared>(
|
||||
.clobbers_flags(false)
|
||||
.inst_predicate(supported_floatccs_predicate(
|
||||
&supported_floatccs,
|
||||
formats.get(f_branch_float),
|
||||
&*f_branch_float,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
@@ -2421,7 +2434,7 @@ pub(crate) fn define<'shared>(
|
||||
.operands_in(vec![gpr, gpr])
|
||||
.operands_out(vec![gpr])
|
||||
.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")
|
||||
.emit(
|
||||
r#"
|
||||
@@ -2499,7 +2512,6 @@ pub(crate) fn define<'shared>(
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.requires_prefix(true),
|
||||
@@ -2517,7 +2529,6 @@ pub(crate) fn define<'shared>(
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.when_prefixed(seti),
|
||||
@@ -2535,7 +2546,6 @@ pub(crate) fn define<'shared>(
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.requires_prefix(true),
|
||||
@@ -2553,7 +2563,6 @@ pub(crate) fn define<'shared>(
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.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(format, "imm", 8, 0);
|
||||
let has_small_offset = InstructionPredicate::new_is_signed_int(&*f_binary_imm, "imm", 8, 0);
|
||||
|
||||
// XX /n, MI form with imm8.
|
||||
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.
|
||||
recipes.add_template_recipe(
|
||||
@@ -2798,7 +2805,6 @@ pub(crate) fn define<'shared>(
|
||||
disp1(destination, func, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.requires_prefix(true),
|
||||
@@ -2819,7 +2825,6 @@ pub(crate) fn define<'shared>(
|
||||
disp1(destination, func, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.when_prefixed(t8jccb),
|
||||
@@ -2841,7 +2846,6 @@ pub(crate) fn define<'shared>(
|
||||
disp4(destination, func, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.requires_prefix(true),
|
||||
@@ -2863,7 +2867,6 @@ pub(crate) fn define<'shared>(
|
||||
disp4(destination, func, sink);
|
||||
"#,
|
||||
),
|
||||
formats,
|
||||
regs,
|
||||
)
|
||||
.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(format, "imm", 8, 0);
|
||||
let is_small_imm =
|
||||
InstructionPredicate::new_is_signed_int(&*f_int_compare_imm, "imm", 8, 0);
|
||||
|
||||
recipes.add_template_recipe(
|
||||
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(
|
||||
EncodingRecipeBuilder::new("icscc_id", f_int_compare_imm, 5 + 3)
|
||||
@@ -3014,7 +3016,7 @@ pub(crate) fn define<'shared>(
|
||||
.operands_out(vec![abcd])
|
||||
.inst_predicate(supported_floatccs_predicate(
|
||||
&supported_floatccs,
|
||||
formats.get(f_float_compare),
|
||||
&*f_float_compare,
|
||||
))
|
||||
.emit(
|
||||
r#"
|
||||
|
||||
Reference in New Issue
Block a user