[meta] Remove name lookups in formats;
This does a lot at once, since there was no clear way to split the three commits: - Instruction need to be passed an explicit InstructionFormat, - InstructionFormat deduplication is checked once all entities have been defined;
This commit is contained in:
@@ -1,226 +1,303 @@
|
||||
use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder as Builder};
|
||||
use crate::cdsl::formats::{InstructionFormat, InstructionFormatBuilder as Builder};
|
||||
use crate::shared::{entities::EntityRefs, immediates::Immediates};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) fn define(imm: &Immediates, entities: &EntityRefs) -> FormatRegistry {
|
||||
let mut registry = FormatRegistry::new();
|
||||
|
||||
registry.insert(Builder::new("Unary").value());
|
||||
registry.insert(Builder::new("UnaryImm").imm(&imm.imm64));
|
||||
registry.insert(Builder::new("UnaryIeee32").imm(&imm.ieee32));
|
||||
registry.insert(Builder::new("UnaryIeee64").imm(&imm.ieee64));
|
||||
registry.insert(Builder::new("UnaryBool").imm(&imm.boolean));
|
||||
registry.insert(Builder::new("UnaryConst").imm(&imm.pool_constant));
|
||||
registry.insert(Builder::new("UnaryGlobalValue").imm(&entities.global_value));
|
||||
|
||||
registry.insert(Builder::new("Binary").value().value());
|
||||
registry.insert(Builder::new("BinaryImm").value().imm(&imm.imm64));
|
||||
|
||||
// The select instructions are controlled by the second VALUE operand.
|
||||
// The first VALUE operand is the controlling flag which has a derived type.
|
||||
// The fma instruction has the same constraint on all inputs.
|
||||
registry.insert(
|
||||
Builder::new("Ternary")
|
||||
.value()
|
||||
.value()
|
||||
.value()
|
||||
.typevar_operand(1),
|
||||
);
|
||||
|
||||
// Catch-all for instructions with many outputs and inputs and no immediate
|
||||
// operands.
|
||||
registry.insert(Builder::new("MultiAry").varargs());
|
||||
|
||||
registry.insert(Builder::new("NullAry"));
|
||||
|
||||
registry.insert(
|
||||
Builder::new("InsertLane")
|
||||
.value()
|
||||
.imm_with_name("lane", &imm.uimm8)
|
||||
.value(),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("ExtractLane")
|
||||
.value()
|
||||
.imm_with_name("lane", &imm.uimm8),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("Shuffle")
|
||||
.value()
|
||||
.value()
|
||||
.imm_with_name("mask", &imm.uimm128),
|
||||
);
|
||||
|
||||
registry.insert(Builder::new("IntCompare").imm(&imm.intcc).value().value());
|
||||
registry.insert(
|
||||
Builder::new("IntCompareImm")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&imm.imm64),
|
||||
);
|
||||
registry.insert(Builder::new("IntCond").imm(&imm.intcc).value());
|
||||
|
||||
registry.insert(
|
||||
Builder::new("FloatCompare")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.value(),
|
||||
);
|
||||
registry.insert(Builder::new("FloatCond").imm(&imm.floatcc).value());
|
||||
|
||||
registry.insert(
|
||||
Builder::new("IntSelect")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.value()
|
||||
.value(),
|
||||
);
|
||||
|
||||
registry.insert(Builder::new("Jump").imm(&entities.ebb).varargs());
|
||||
registry.insert(Builder::new("Branch").value().imm(&entities.ebb).varargs());
|
||||
registry.insert(
|
||||
Builder::new("BranchInt")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs(),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("BranchFloat")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs(),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("BranchIcmp")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs(),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("BranchTable")
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.imm(&entities.jump_table),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("BranchTableEntry")
|
||||
.value()
|
||||
.value()
|
||||
.imm(&imm.uimm8)
|
||||
.imm(&entities.jump_table),
|
||||
);
|
||||
registry.insert(Builder::new("BranchTableBase").imm(&entities.jump_table));
|
||||
registry.insert(
|
||||
Builder::new("IndirectJump")
|
||||
.value()
|
||||
.imm(&entities.jump_table),
|
||||
);
|
||||
|
||||
registry.insert(Builder::new("Call").imm(&entities.func_ref).varargs());
|
||||
registry.insert(
|
||||
Builder::new("CallIndirect")
|
||||
.imm(&entities.sig_ref)
|
||||
.value()
|
||||
.varargs(),
|
||||
);
|
||||
registry.insert(Builder::new("FuncAddr").imm(&entities.func_ref));
|
||||
|
||||
registry.insert(
|
||||
Builder::new("Load")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("LoadComplex")
|
||||
.imm(&imm.memflags)
|
||||
.varargs()
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("Store")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.value()
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("StoreComplex")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.varargs()
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("StackLoad")
|
||||
.imm(&entities.stack_slot)
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("StackStore")
|
||||
.value()
|
||||
.imm(&entities.stack_slot)
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
|
||||
// Accessing a WebAssembly heap.
|
||||
registry.insert(
|
||||
Builder::new("HeapAddr")
|
||||
.imm(&entities.heap)
|
||||
.value()
|
||||
.imm(&imm.uimm32),
|
||||
);
|
||||
|
||||
// Accessing a WebAssembly table.
|
||||
registry.insert(
|
||||
Builder::new("TableAddr")
|
||||
.imm(&entities.table)
|
||||
.value()
|
||||
.imm(&imm.offset32),
|
||||
);
|
||||
|
||||
registry.insert(
|
||||
Builder::new("RegMove")
|
||||
.value()
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &imm.regunit),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("CopySpecial")
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &imm.regunit),
|
||||
);
|
||||
registry.insert(Builder::new("CopyToSsa").imm_with_name("src", &imm.regunit));
|
||||
registry.insert(
|
||||
Builder::new("RegSpill")
|
||||
.value()
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &entities.stack_slot),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("RegFill")
|
||||
.value()
|
||||
.imm_with_name("src", &entities.stack_slot)
|
||||
.imm_with_name("dst", &imm.regunit),
|
||||
);
|
||||
|
||||
registry.insert(Builder::new("Trap").imm(&imm.trapcode));
|
||||
registry.insert(Builder::new("CondTrap").value().imm(&imm.trapcode));
|
||||
registry.insert(
|
||||
Builder::new("IntCondTrap")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&imm.trapcode),
|
||||
);
|
||||
registry.insert(
|
||||
Builder::new("FloatCondTrap")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.imm(&imm.trapcode),
|
||||
);
|
||||
|
||||
registry
|
||||
pub(crate) struct Formats {
|
||||
pub(crate) binary: Rc<InstructionFormat>,
|
||||
pub(crate) binary_imm: Rc<InstructionFormat>,
|
||||
pub(crate) branch: Rc<InstructionFormat>,
|
||||
pub(crate) branch_float: Rc<InstructionFormat>,
|
||||
pub(crate) branch_icmp: Rc<InstructionFormat>,
|
||||
pub(crate) branch_int: Rc<InstructionFormat>,
|
||||
pub(crate) branch_table: Rc<InstructionFormat>,
|
||||
pub(crate) branch_table_base: Rc<InstructionFormat>,
|
||||
pub(crate) branch_table_entry: Rc<InstructionFormat>,
|
||||
pub(crate) call: Rc<InstructionFormat>,
|
||||
pub(crate) call_indirect: Rc<InstructionFormat>,
|
||||
pub(crate) cond_trap: Rc<InstructionFormat>,
|
||||
pub(crate) copy_special: Rc<InstructionFormat>,
|
||||
pub(crate) copy_to_ssa: Rc<InstructionFormat>,
|
||||
pub(crate) extract_lane: Rc<InstructionFormat>,
|
||||
pub(crate) float_compare: Rc<InstructionFormat>,
|
||||
pub(crate) float_cond: Rc<InstructionFormat>,
|
||||
pub(crate) float_cond_trap: Rc<InstructionFormat>,
|
||||
pub(crate) func_addr: Rc<InstructionFormat>,
|
||||
pub(crate) heap_addr: Rc<InstructionFormat>,
|
||||
pub(crate) indirect_jump: Rc<InstructionFormat>,
|
||||
pub(crate) insert_lane: Rc<InstructionFormat>,
|
||||
pub(crate) int_compare: Rc<InstructionFormat>,
|
||||
pub(crate) int_compare_imm: Rc<InstructionFormat>,
|
||||
pub(crate) int_cond: Rc<InstructionFormat>,
|
||||
pub(crate) int_cond_trap: Rc<InstructionFormat>,
|
||||
pub(crate) int_select: Rc<InstructionFormat>,
|
||||
pub(crate) jump: Rc<InstructionFormat>,
|
||||
pub(crate) load: Rc<InstructionFormat>,
|
||||
pub(crate) load_complex: Rc<InstructionFormat>,
|
||||
pub(crate) multiary: Rc<InstructionFormat>,
|
||||
pub(crate) nullary: Rc<InstructionFormat>,
|
||||
pub(crate) reg_fill: Rc<InstructionFormat>,
|
||||
pub(crate) reg_move: Rc<InstructionFormat>,
|
||||
pub(crate) reg_spill: Rc<InstructionFormat>,
|
||||
pub(crate) shuffle: Rc<InstructionFormat>,
|
||||
pub(crate) stack_load: Rc<InstructionFormat>,
|
||||
pub(crate) stack_store: Rc<InstructionFormat>,
|
||||
pub(crate) store: Rc<InstructionFormat>,
|
||||
pub(crate) store_complex: Rc<InstructionFormat>,
|
||||
pub(crate) table_addr: Rc<InstructionFormat>,
|
||||
pub(crate) ternary: Rc<InstructionFormat>,
|
||||
pub(crate) trap: Rc<InstructionFormat>,
|
||||
pub(crate) unary: Rc<InstructionFormat>,
|
||||
pub(crate) unary_bool: Rc<InstructionFormat>,
|
||||
pub(crate) unary_const: Rc<InstructionFormat>,
|
||||
pub(crate) unary_global_value: Rc<InstructionFormat>,
|
||||
pub(crate) unary_ieee32: Rc<InstructionFormat>,
|
||||
pub(crate) unary_ieee64: Rc<InstructionFormat>,
|
||||
pub(crate) unary_imm: Rc<InstructionFormat>,
|
||||
}
|
||||
|
||||
impl Formats {
|
||||
pub fn new(imm: &Immediates, entities: &EntityRefs) -> Self {
|
||||
Self {
|
||||
unary: Builder::new("Unary").value().build(),
|
||||
|
||||
unary_imm: Builder::new("UnaryImm").imm(&imm.imm64).build(),
|
||||
|
||||
unary_ieee32: Builder::new("UnaryIeee32").imm(&imm.ieee32).build(),
|
||||
|
||||
unary_ieee64: Builder::new("UnaryIeee64").imm(&imm.ieee64).build(),
|
||||
|
||||
unary_bool: Builder::new("UnaryBool").imm(&imm.boolean).build(),
|
||||
|
||||
unary_const: Builder::new("UnaryConst").imm(&imm.pool_constant).build(),
|
||||
|
||||
unary_global_value: Builder::new("UnaryGlobalValue")
|
||||
.imm(&entities.global_value)
|
||||
.build(),
|
||||
|
||||
binary: Builder::new("Binary").value().value().build(),
|
||||
|
||||
binary_imm: Builder::new("BinaryImm").value().imm(&imm.imm64).build(),
|
||||
|
||||
// The select instructions are controlled by the second VALUE operand.
|
||||
// The first VALUE operand is the controlling flag which has a derived type.
|
||||
// The fma instruction has the same constraint on all inputs.
|
||||
ternary: Builder::new("Ternary")
|
||||
.value()
|
||||
.value()
|
||||
.value()
|
||||
.typevar_operand(1)
|
||||
.build(),
|
||||
|
||||
// Catch-all for instructions with many outputs and inputs and no immediate
|
||||
// operands.
|
||||
multiary: Builder::new("MultiAry").varargs().build(),
|
||||
|
||||
nullary: Builder::new("NullAry").build(),
|
||||
|
||||
insert_lane: Builder::new("InsertLane")
|
||||
.value()
|
||||
.imm_with_name("lane", &imm.uimm8)
|
||||
.value()
|
||||
.build(),
|
||||
|
||||
extract_lane: Builder::new("ExtractLane")
|
||||
.value()
|
||||
.imm_with_name("lane", &imm.uimm8)
|
||||
.build(),
|
||||
|
||||
shuffle: Builder::new("Shuffle")
|
||||
.value()
|
||||
.value()
|
||||
.imm_with_name("mask", &imm.uimm128)
|
||||
.build(),
|
||||
|
||||
int_compare: Builder::new("IntCompare")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.value()
|
||||
.build(),
|
||||
|
||||
int_compare_imm: Builder::new("IntCompareImm")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&imm.imm64)
|
||||
.build(),
|
||||
|
||||
int_cond: Builder::new("IntCond").imm(&imm.intcc).value().build(),
|
||||
|
||||
float_compare: Builder::new("FloatCompare")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.value()
|
||||
.build(),
|
||||
|
||||
float_cond: Builder::new("FloatCond").imm(&imm.floatcc).value().build(),
|
||||
|
||||
int_select: Builder::new("IntSelect")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.value()
|
||||
.value()
|
||||
.build(),
|
||||
|
||||
jump: Builder::new("Jump").imm(&entities.ebb).varargs().build(),
|
||||
|
||||
branch: Builder::new("Branch")
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
branch_int: Builder::new("BranchInt")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
branch_float: Builder::new("BranchFloat")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
branch_icmp: Builder::new("BranchIcmp")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
branch_table: Builder::new("BranchTable")
|
||||
.value()
|
||||
.imm(&entities.ebb)
|
||||
.imm(&entities.jump_table)
|
||||
.build(),
|
||||
|
||||
branch_table_entry: Builder::new("BranchTableEntry")
|
||||
.value()
|
||||
.value()
|
||||
.imm(&imm.uimm8)
|
||||
.imm(&entities.jump_table)
|
||||
.build(),
|
||||
|
||||
branch_table_base: Builder::new("BranchTableBase")
|
||||
.imm(&entities.jump_table)
|
||||
.build(),
|
||||
|
||||
indirect_jump: Builder::new("IndirectJump")
|
||||
.value()
|
||||
.imm(&entities.jump_table)
|
||||
.build(),
|
||||
|
||||
call: Builder::new("Call")
|
||||
.imm(&entities.func_ref)
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
call_indirect: Builder::new("CallIndirect")
|
||||
.imm(&entities.sig_ref)
|
||||
.value()
|
||||
.varargs()
|
||||
.build(),
|
||||
|
||||
func_addr: Builder::new("FuncAddr").imm(&entities.func_ref).build(),
|
||||
|
||||
load: Builder::new("Load")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
load_complex: Builder::new("LoadComplex")
|
||||
.imm(&imm.memflags)
|
||||
.varargs()
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
store: Builder::new("Store")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.value()
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
store_complex: Builder::new("StoreComplex")
|
||||
.imm(&imm.memflags)
|
||||
.value()
|
||||
.varargs()
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
stack_load: Builder::new("StackLoad")
|
||||
.imm(&entities.stack_slot)
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
stack_store: Builder::new("StackStore")
|
||||
.value()
|
||||
.imm(&entities.stack_slot)
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
// Accessing a WebAssembly heap.
|
||||
heap_addr: Builder::new("HeapAddr")
|
||||
.imm(&entities.heap)
|
||||
.value()
|
||||
.imm(&imm.uimm32)
|
||||
.build(),
|
||||
|
||||
// Accessing a WebAssembly table.
|
||||
table_addr: Builder::new("TableAddr")
|
||||
.imm(&entities.table)
|
||||
.value()
|
||||
.imm(&imm.offset32)
|
||||
.build(),
|
||||
|
||||
reg_move: Builder::new("RegMove")
|
||||
.value()
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &imm.regunit)
|
||||
.build(),
|
||||
|
||||
copy_special: Builder::new("CopySpecial")
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &imm.regunit)
|
||||
.build(),
|
||||
|
||||
copy_to_ssa: Builder::new("CopyToSsa")
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.build(),
|
||||
|
||||
reg_spill: Builder::new("RegSpill")
|
||||
.value()
|
||||
.imm_with_name("src", &imm.regunit)
|
||||
.imm_with_name("dst", &entities.stack_slot)
|
||||
.build(),
|
||||
|
||||
reg_fill: Builder::new("RegFill")
|
||||
.value()
|
||||
.imm_with_name("src", &entities.stack_slot)
|
||||
.imm_with_name("dst", &imm.regunit)
|
||||
.build(),
|
||||
|
||||
trap: Builder::new("Trap").imm(&imm.trapcode).build(),
|
||||
|
||||
cond_trap: Builder::new("CondTrap").value().imm(&imm.trapcode).build(),
|
||||
|
||||
int_cond_trap: Builder::new("IntCondTrap")
|
||||
.imm(&imm.intcc)
|
||||
.value()
|
||||
.imm(&imm.trapcode)
|
||||
.build(),
|
||||
|
||||
float_cond_trap: Builder::new("FloatCondTrap")
|
||||
.imm(&imm.floatcc)
|
||||
.value()
|
||||
.imm(&imm.trapcode)
|
||||
.build(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,20 +8,25 @@ pub mod legalize;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
||||
use crate::cdsl::formats::FormatRegistry;
|
||||
use crate::cdsl::formats::{FormatStructure, InstructionFormat};
|
||||
use crate::cdsl::instructions::{AllInstructions, InstructionGroup};
|
||||
use crate::cdsl::settings::SettingGroup;
|
||||
use crate::cdsl::xform::TransformGroups;
|
||||
|
||||
use crate::shared::entities::EntityRefs;
|
||||
use crate::shared::formats::Formats;
|
||||
use crate::shared::immediates::Immediates;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::iter::FromIterator;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) struct Definitions {
|
||||
pub settings: SettingGroup,
|
||||
pub all_instructions: AllInstructions,
|
||||
pub instructions: InstructionGroup,
|
||||
pub imm: Immediates,
|
||||
pub format_registry: FormatRegistry,
|
||||
pub formats: Formats,
|
||||
pub transform_groups: TransformGroups,
|
||||
}
|
||||
|
||||
@@ -30,13 +35,9 @@ pub(crate) fn define() -> Definitions {
|
||||
|
||||
let immediates = Immediates::new();
|
||||
let entities = EntityRefs::new();
|
||||
let format_registry = formats::define(&immediates, &entities);
|
||||
let instructions = instructions::define(
|
||||
&mut all_instructions,
|
||||
&format_registry,
|
||||
&immediates,
|
||||
&entities,
|
||||
);
|
||||
let formats = Formats::new(&immediates, &entities);
|
||||
let instructions =
|
||||
instructions::define(&mut all_instructions, &formats, &immediates, &entities);
|
||||
let transform_groups = legalize::define(&instructions, &immediates);
|
||||
|
||||
Definitions {
|
||||
@@ -44,7 +45,53 @@ pub(crate) fn define() -> Definitions {
|
||||
all_instructions,
|
||||
instructions,
|
||||
imm: immediates,
|
||||
format_registry,
|
||||
formats,
|
||||
transform_groups,
|
||||
}
|
||||
}
|
||||
|
||||
impl Definitions {
|
||||
/// Verifies certain properties of formats.
|
||||
///
|
||||
/// - Formats must be uniquely named: if two formats have the same name, they must refer to the
|
||||
/// same data. Otherwise, two format variants in the codegen crate would have the same name.
|
||||
/// - Formats must be structurally different from each other. Otherwise, this would lead to
|
||||
/// code duplicate in the codegen crate.
|
||||
///
|
||||
/// Returns a list of all the instruction formats effectively used.
|
||||
pub fn verify_instruction_formats(&self) -> Vec<&InstructionFormat> {
|
||||
let mut format_names: HashMap<&'static str, &Rc<InstructionFormat>> = HashMap::new();
|
||||
|
||||
// A structure is: number of input value operands / whether there's varargs or not / names
|
||||
// of immediate fields.
|
||||
let mut format_structures: HashMap<FormatStructure, &InstructionFormat> = HashMap::new();
|
||||
|
||||
for inst in self.all_instructions.values() {
|
||||
// Check name.
|
||||
if let Some(existing_format) = format_names.get(&inst.format.name) {
|
||||
assert!(
|
||||
Rc::ptr_eq(&existing_format, &inst.format),
|
||||
"formats must uniquely named; there's a\
|
||||
conflict on the name '{}', please make sure it is used only once.",
|
||||
existing_format.name
|
||||
);
|
||||
} else {
|
||||
format_names.insert(inst.format.name, &inst.format);
|
||||
}
|
||||
|
||||
// Check structure.
|
||||
let key = inst.format.structure();
|
||||
if let Some(existing_format) = format_structures.get(&key) {
|
||||
assert_eq!(
|
||||
existing_format.name, inst.format.name,
|
||||
"duplicate instruction formats {} and {}; please remove one.",
|
||||
existing_format.name, inst.format.name
|
||||
);
|
||||
} else {
|
||||
format_structures.insert(key, &inst.format);
|
||||
}
|
||||
}
|
||||
|
||||
Vec::from_iter(format_structures.into_iter().map(|(_, v)| v))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user