[meta] Uniquely number every instruction in the Rust crate;
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
|
use cranelift_entity::{entity_impl, PrimaryMap};
|
||||||
|
|
||||||
use crate::cdsl::camel_case;
|
use crate::cdsl::camel_case;
|
||||||
use crate::cdsl::formats::{
|
use crate::cdsl::formats::{
|
||||||
FormatField, FormatRegistry, InstructionFormat, InstructionFormatIndex,
|
FormatField, FormatRegistry, InstructionFormat, InstructionFormatIndex,
|
||||||
@@ -7,41 +14,49 @@ use crate::cdsl::type_inference::Constraint;
|
|||||||
use crate::cdsl::types::{LaneType, ValueType};
|
use crate::cdsl::types::{LaneType, ValueType};
|
||||||
use crate::cdsl::typevar::TypeVar;
|
use crate::cdsl::typevar::TypeVar;
|
||||||
|
|
||||||
use std::fmt;
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
use std::ops;
|
pub struct OpcodeNumber(u32);
|
||||||
use std::rc::Rc;
|
entity_impl!(OpcodeNumber);
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
pub struct InstructionGroupBuilder<'format_reg> {
|
pub type AllInstructions = PrimaryMap<OpcodeNumber, Instruction>;
|
||||||
|
|
||||||
|
pub struct InstructionGroupBuilder<'format_reg, 'all_inst> {
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_doc: &'static str,
|
_doc: &'static str,
|
||||||
format_registry: &'format_reg FormatRegistry,
|
format_registry: &'format_reg FormatRegistry,
|
||||||
instructions: Vec<Instruction>,
|
all_instructions: &'all_inst mut AllInstructions,
|
||||||
|
own_instructions: Vec<Instruction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'format_reg> InstructionGroupBuilder<'format_reg> {
|
impl<'format_reg, 'all_inst> InstructionGroupBuilder<'format_reg, 'all_inst> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
doc: &'static str,
|
doc: &'static str,
|
||||||
|
all_instructions: &'all_inst mut AllInstructions,
|
||||||
format_registry: &'format_reg FormatRegistry,
|
format_registry: &'format_reg FormatRegistry,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_name: name,
|
_name: name,
|
||||||
_doc: doc,
|
_doc: doc,
|
||||||
format_registry,
|
format_registry,
|
||||||
instructions: Vec::new(),
|
all_instructions,
|
||||||
|
own_instructions: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, builder: InstructionBuilder) {
|
pub fn push(&mut self, builder: InstructionBuilder) {
|
||||||
self.instructions.push(builder.build(self.format_registry));
|
let opcode_number = OpcodeNumber(self.all_instructions.next_key().as_u32());
|
||||||
|
let inst = builder.build(self.format_registry, opcode_number);
|
||||||
|
// Note this clone is cheap, since Instruction is a Rc<> wrapper for InstructionContent.
|
||||||
|
self.own_instructions.push(inst.clone());
|
||||||
|
self.all_instructions.push(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> InstructionGroup {
|
pub fn build(self) -> InstructionGroup {
|
||||||
InstructionGroup {
|
InstructionGroup {
|
||||||
_name: self._name,
|
_name: self._name,
|
||||||
_doc: self._doc,
|
_doc: self._doc,
|
||||||
instructions: self.instructions,
|
instructions: self.own_instructions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,6 +93,7 @@ pub struct InstructionContent {
|
|||||||
/// Instruction mnemonic, also becomes opcode name.
|
/// Instruction mnemonic, also becomes opcode name.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub camel_name: String,
|
pub camel_name: String,
|
||||||
|
pub opcode_number: OpcodeNumber,
|
||||||
|
|
||||||
/// Documentation string.
|
/// Documentation string.
|
||||||
doc: String,
|
doc: String,
|
||||||
@@ -300,7 +316,7 @@ impl InstructionBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(self, format_registry: &FormatRegistry) -> Instruction {
|
fn build(self, format_registry: &FormatRegistry, opcode_number: OpcodeNumber) -> Instruction {
|
||||||
let operands_in = self.operands_in.unwrap_or_else(Vec::new);
|
let operands_in = self.operands_in.unwrap_or_else(Vec::new);
|
||||||
let operands_out = self.operands_out.unwrap_or_else(Vec::new);
|
let operands_out = self.operands_out.unwrap_or_else(Vec::new);
|
||||||
|
|
||||||
@@ -333,10 +349,12 @@ impl InstructionBuilder {
|
|||||||
let writes_cpu_flags = operands_out.iter().any(|op| op.is_cpu_flags());
|
let writes_cpu_flags = operands_out.iter().any(|op| op.is_cpu_flags());
|
||||||
|
|
||||||
let camel_name = camel_case(&self.name);
|
let camel_name = camel_case(&self.name);
|
||||||
|
|
||||||
Instruction {
|
Instruction {
|
||||||
content: Rc::new(InstructionContent {
|
content: Rc::new(InstructionContent {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
camel_name,
|
camel_name,
|
||||||
|
opcode_number,
|
||||||
doc: self.doc,
|
doc: self.doc,
|
||||||
operands_in,
|
operands_in,
|
||||||
operands_out,
|
operands_out,
|
||||||
|
|||||||
@@ -404,11 +404,12 @@ impl TransformGroups {
|
|||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_double_custom_legalization() {
|
fn test_double_custom_legalization() {
|
||||||
use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder};
|
use crate::cdsl::formats::{FormatRegistry, InstructionFormatBuilder};
|
||||||
use crate::cdsl::instructions::{InstructionBuilder, InstructionGroupBuilder};
|
use crate::cdsl::instructions::{AllInstructions, InstructionBuilder, InstructionGroupBuilder};
|
||||||
|
|
||||||
|
let mut dummy_all = AllInstructions::new();
|
||||||
let mut format = FormatRegistry::new();
|
let mut format = FormatRegistry::new();
|
||||||
format.insert(InstructionFormatBuilder::new("nullary"));
|
format.insert(InstructionFormatBuilder::new("nullary"));
|
||||||
let mut inst_group = InstructionGroupBuilder::new("test", "", &format);
|
let mut inst_group = InstructionGroupBuilder::new("test", "", &mut dummy_all, &format);
|
||||||
inst_group.push(InstructionBuilder::new("dummy", "doc"));
|
inst_group.push(InstructionBuilder::new("dummy", "doc"));
|
||||||
let inst_group = inst_group.build();
|
let inst_group = inst_group.build();
|
||||||
let dummy_inst = inst_group.by_name("dummy");
|
let dummy_inst = inst_group.by_name("dummy");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::iter;
|
||||||
|
|
||||||
pub fn simple_hash(s: &str) -> usize {
|
pub fn simple_hash(s: &str) -> usize {
|
||||||
let mut h: u32 = 5381;
|
let mut h: u32 = 5381;
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
@@ -9,8 +11,12 @@ pub fn simple_hash(s: &str) -> usize {
|
|||||||
/// Compute an open addressed, quadratically probed hash table containing
|
/// Compute an open addressed, quadratically probed hash table containing
|
||||||
/// `items`. The returned table is a list containing the elements of the
|
/// `items`. The returned table is a list containing the elements of the
|
||||||
/// iterable `items` and `None` in unused slots.
|
/// iterable `items` and `None` in unused slots.
|
||||||
pub fn generate_table<T, H: Fn(&T) -> usize>(items: &Vec<T>, hash_function: H) -> Vec<Option<&T>> {
|
pub fn generate_table<'cont, T, I: iter::Iterator<Item = &'cont T>, H: Fn(&T) -> usize>(
|
||||||
let size = (1.20 * items.len() as f64) as usize;
|
items: I,
|
||||||
|
num_items: usize,
|
||||||
|
hash_function: H,
|
||||||
|
) -> Vec<Option<&'cont T>> {
|
||||||
|
let size = (1.20 * num_items as f64) as usize;
|
||||||
// TODO do we really need the multiply by two here?
|
// TODO do we really need the multiply by two here?
|
||||||
let size = if size.is_power_of_two() {
|
let size = if size.is_power_of_two() {
|
||||||
size * 2
|
size * 2
|
||||||
@@ -18,10 +24,10 @@ pub fn generate_table<T, H: Fn(&T) -> usize>(items: &Vec<T>, hash_function: H) -
|
|||||||
size.next_power_of_two()
|
size.next_power_of_two()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut table: Vec<Option<&T>> = vec![None; size];
|
let mut table = vec![None; size];
|
||||||
|
|
||||||
for i in items {
|
for i in items {
|
||||||
let mut h = hash_function(i) % size;
|
let mut h = hash_function(&i) % size;
|
||||||
let mut s = 0;
|
let mut s = 0;
|
||||||
while table[h].is_some() {
|
while table[h].is_some() {
|
||||||
s += 1;
|
s += 1;
|
||||||
@@ -36,7 +42,7 @@ pub fn generate_table<T, H: Fn(&T) -> usize>(items: &Vec<T>, hash_function: H) -
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_generate_table() {
|
fn test_generate_table() {
|
||||||
let v = vec!["Hello".to_string(), "world".to_string()];
|
let v = vec!["Hello".to_string(), "world".to_string()];
|
||||||
let table = generate_table(&v, |s| simple_hash(&s));
|
let table = generate_table(v.iter(), v.len(), |s| simple_hash(&s));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table,
|
table,
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use cranelift_entity::EntityRef;
|
||||||
|
|
||||||
use crate::cdsl::camel_case;
|
use crate::cdsl::camel_case;
|
||||||
use crate::cdsl::formats::{FormatRegistry, InstructionFormat};
|
use crate::cdsl::formats::{FormatRegistry, InstructionFormat};
|
||||||
use crate::cdsl::instructions::{Instruction, InstructionGroup};
|
use crate::cdsl::instructions::{AllInstructions, Instruction};
|
||||||
use crate::cdsl::operands::Operand;
|
use crate::cdsl::operands::Operand;
|
||||||
use crate::cdsl::typevar::{TypeSet, TypeVar};
|
use crate::cdsl::typevar::{TypeSet, TypeVar};
|
||||||
|
|
||||||
|
use crate::shared::Definitions as SharedDefinitions;
|
||||||
|
|
||||||
use crate::constant_hash;
|
use crate::constant_hash;
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::srcgen::{Formatter, Match};
|
use crate::srcgen::{Formatter, Match};
|
||||||
use crate::unique_table::{UniqueSeqTable, UniqueTable};
|
use crate::unique_table::{UniqueSeqTable, UniqueTable};
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
// TypeSet indexes are encoded in 8 bits, with `0xff` reserved.
|
// TypeSet indexes are encoded in 8 bits, with `0xff` reserved.
|
||||||
const TYPESET_LIMIT: usize = 0xff;
|
const TYPESET_LIMIT: usize = 0xff;
|
||||||
|
|
||||||
@@ -368,7 +373,7 @@ fn gen_instruction_data_impl(registry: &FormatRegistry, fmt: &mut Formatter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
|
fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
|
||||||
instruction_groups: &Vec<&InstructionGroup>,
|
all_inst: &AllInstructions,
|
||||||
get_attr: T,
|
get_attr: T,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
doc: &'static str,
|
doc: &'static str,
|
||||||
@@ -378,13 +383,11 @@ fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
|
|||||||
fmtln!(fmt, "pub fn {}(self) -> bool {{", name);
|
fmtln!(fmt, "pub fn {}(self) -> bool {{", name);
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
let mut m = Match::new("self");
|
let mut m = Match::new("self");
|
||||||
for group in instruction_groups.iter() {
|
for inst in all_inst.values() {
|
||||||
for inst in group.iter() {
|
|
||||||
if get_attr(inst) {
|
if get_attr(inst) {
|
||||||
m.arm_no_fields(format!("Opcode::{}", inst.camel_name), "true");
|
m.arm_no_fields(format!("Opcode::{}", inst.camel_name), "true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
m.arm_no_fields("_", "false");
|
m.arm_no_fields("_", "false");
|
||||||
fmt.add_match(m);
|
fmt.add_match(m);
|
||||||
});
|
});
|
||||||
@@ -392,18 +395,7 @@ fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
|
|||||||
fmt.empty_line();
|
fmt.empty_line();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_opcodes<'a>(
|
fn gen_opcodes<'a>(all_inst: &AllInstructions, formats: &FormatRegistry, fmt: &mut Formatter) {
|
||||||
formats: &FormatRegistry,
|
|
||||||
igroups: &Vec<&'a InstructionGroup>,
|
|
||||||
fmt: &mut Formatter,
|
|
||||||
) -> Vec<&'a Instruction> {
|
|
||||||
let mut all_inst = Vec::new();
|
|
||||||
for group in igroups {
|
|
||||||
for inst in group.iter() {
|
|
||||||
all_inst.push(inst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.doc_comment(
|
fmt.doc_comment(
|
||||||
r#"
|
r#"
|
||||||
An instruction opcode.
|
An instruction opcode.
|
||||||
@@ -420,10 +412,7 @@ fn gen_opcodes<'a>(
|
|||||||
fmt.line("pub enum Opcode {");
|
fmt.line("pub enum Opcode {");
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
let mut is_first_opcode = true;
|
let mut is_first_opcode = true;
|
||||||
for inst in &all_inst {
|
for inst in all_inst.values() {
|
||||||
// TODO we might need to set an instruction number here. Probably can do in the
|
|
||||||
// InstructionGroup itself when adding instruction (would need to remember last
|
|
||||||
// instruction number in the SharedDefinitions or somewhere else).
|
|
||||||
let format = formats.get(inst.format);
|
let format = formats.get(inst.format);
|
||||||
fmt.doc_comment(format!("`{}`. ({})", inst, format.name));
|
fmt.doc_comment(format!("`{}`. ({})", inst, format.name));
|
||||||
|
|
||||||
@@ -440,6 +429,8 @@ fn gen_opcodes<'a>(
|
|||||||
|
|
||||||
// Enum variant itself.
|
// Enum variant itself.
|
||||||
if is_first_opcode {
|
if is_first_opcode {
|
||||||
|
assert!(inst.opcode_number.index() == 0);
|
||||||
|
// TODO the python crate requires opcode numbers to start from one.
|
||||||
fmtln!(fmt, "{} = 1,", inst.camel_name);
|
fmtln!(fmt, "{} = 1,", inst.camel_name);
|
||||||
is_first_opcode = false;
|
is_first_opcode = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -453,77 +444,77 @@ fn gen_opcodes<'a>(
|
|||||||
fmt.line("impl Opcode {");
|
fmt.line("impl Opcode {");
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_terminator,
|
|inst| inst.is_terminator,
|
||||||
"is_terminator",
|
"is_terminator",
|
||||||
"True for instructions that terminate the EBB",
|
"True for instructions that terminate the EBB",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_branch,
|
|inst| inst.is_branch,
|
||||||
"is_branch",
|
"is_branch",
|
||||||
"True for all branch or jump instructions.",
|
"True for all branch or jump instructions.",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_indirect_branch,
|
|inst| inst.is_indirect_branch,
|
||||||
"is_indirect_branch",
|
"is_indirect_branch",
|
||||||
"True for all indirect branch or jump instructions.",
|
"True for all indirect branch or jump instructions.",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_call,
|
|inst| inst.is_call,
|
||||||
"is_call",
|
"is_call",
|
||||||
"Is this a call instruction?",
|
"Is this a call instruction?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_return,
|
|inst| inst.is_return,
|
||||||
"is_return",
|
"is_return",
|
||||||
"Is this a return instruction?",
|
"Is this a return instruction?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.is_ghost,
|
|inst| inst.is_ghost,
|
||||||
"is_ghost",
|
"is_ghost",
|
||||||
"Is this a ghost instruction?",
|
"Is this a ghost instruction?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.can_load,
|
|inst| inst.can_load,
|
||||||
"can_load",
|
"can_load",
|
||||||
"Can this instruction read from memory?",
|
"Can this instruction read from memory?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.can_store,
|
|inst| inst.can_store,
|
||||||
"can_store",
|
"can_store",
|
||||||
"Can this instruction write to memory?",
|
"Can this instruction write to memory?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.can_trap,
|
|inst| inst.can_trap,
|
||||||
"can_trap",
|
"can_trap",
|
||||||
"Can this instruction cause a trap?",
|
"Can this instruction cause a trap?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.other_side_effects,
|
|inst| inst.other_side_effects,
|
||||||
"other_side_effects",
|
"other_side_effects",
|
||||||
"Does this instruction have other side effects besides can_* flags?",
|
"Does this instruction have other side effects besides can_* flags?",
|
||||||
fmt,
|
fmt,
|
||||||
);
|
);
|
||||||
gen_bool_accessor(
|
gen_bool_accessor(
|
||||||
igroups,
|
all_inst,
|
||||||
|inst| inst.writes_cpu_flags,
|
|inst| inst.writes_cpu_flags,
|
||||||
"writes_cpu_flags",
|
"writes_cpu_flags",
|
||||||
"Does this instruction write to CPU flags?",
|
"Does this instruction write to CPU flags?",
|
||||||
@@ -540,7 +531,7 @@ fn gen_opcodes<'a>(
|
|||||||
all_inst.len()
|
all_inst.len()
|
||||||
);
|
);
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
for inst in &all_inst {
|
for inst in all_inst.values() {
|
||||||
let format = formats.get(inst.format);
|
let format = formats.get(inst.format);
|
||||||
fmtln!(fmt, "InstructionFormat::{}, // {}", format.name, inst.name);
|
fmtln!(fmt, "InstructionFormat::{}, // {}", format.name, inst.name);
|
||||||
}
|
}
|
||||||
@@ -552,7 +543,7 @@ fn gen_opcodes<'a>(
|
|||||||
fmt.line("fn opcode_name(opc: Opcode) -> &\'static str {");
|
fmt.line("fn opcode_name(opc: Opcode) -> &\'static str {");
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
let mut m = Match::new("opc");
|
let mut m = Match::new("opc");
|
||||||
for inst in &all_inst {
|
for inst in all_inst.values() {
|
||||||
m.arm_no_fields(
|
m.arm_no_fields(
|
||||||
format!("Opcode::{}", inst.camel_name),
|
format!("Opcode::{}", inst.camel_name),
|
||||||
format!("\"{}\"", inst.name),
|
format!("\"{}\"", inst.name),
|
||||||
@@ -564,8 +555,9 @@ fn gen_opcodes<'a>(
|
|||||||
fmt.empty_line();
|
fmt.empty_line();
|
||||||
|
|
||||||
// Generate an opcode hash table for looking up opcodes by name.
|
// Generate an opcode hash table for looking up opcodes by name.
|
||||||
let hash_table =
|
let hash_table = constant_hash::generate_table(all_inst.values(), all_inst.len(), |inst| {
|
||||||
constant_hash::generate_table(&all_inst, |inst| constant_hash::simple_hash(&inst.name));
|
constant_hash::simple_hash(&inst.name)
|
||||||
|
});
|
||||||
fmtln!(
|
fmtln!(
|
||||||
fmt,
|
fmt,
|
||||||
"const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
|
"const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
|
||||||
@@ -581,8 +573,6 @@ fn gen_opcodes<'a>(
|
|||||||
});
|
});
|
||||||
fmtln!(fmt, "];");
|
fmtln!(fmt, "];");
|
||||||
fmt.empty_line();
|
fmt.empty_line();
|
||||||
|
|
||||||
all_inst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value type constraint for an SSA value operand, where
|
/// Get the value type constraint for an SSA value operand, where
|
||||||
@@ -698,7 +688,7 @@ pub fn gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter)
|
|||||||
/// - Emit a compact constant table of ValueTypeSet objects.
|
/// - Emit a compact constant table of ValueTypeSet objects.
|
||||||
/// - Emit a compact constant table of OperandConstraint objects.
|
/// - Emit a compact constant table of OperandConstraint objects.
|
||||||
/// - Emit an opcode-indexed table of instruction constraints.
|
/// - Emit an opcode-indexed table of instruction constraints.
|
||||||
fn gen_type_constraints(all_inst: &Vec<&Instruction>, fmt: &mut Formatter) {
|
fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) {
|
||||||
// Table of TypeSet instances.
|
// Table of TypeSet instances.
|
||||||
let mut type_sets = UniqueTable::new();
|
let mut type_sets = UniqueTable::new();
|
||||||
|
|
||||||
@@ -719,7 +709,7 @@ fn gen_type_constraints(all_inst: &Vec<&Instruction>, fmt: &mut Formatter) {
|
|||||||
all_inst.len()
|
all_inst.len()
|
||||||
);
|
);
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
for inst in all_inst {
|
for inst in all_inst.values() {
|
||||||
let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
|
let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
|
||||||
let index = type_sets.add(&*poly.ctrl_typevar.get_raw_typeset());
|
let index = type_sets.add(&*poly.ctrl_typevar.get_raw_typeset());
|
||||||
(Some(&poly.ctrl_typevar), index)
|
(Some(&poly.ctrl_typevar), index)
|
||||||
@@ -1035,7 +1025,7 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a Builder trait with methods for all instructions.
|
/// Generate a Builder trait with methods for all instructions.
|
||||||
fn gen_builder(instructions: &Vec<&Instruction>, formats: &FormatRegistry, fmt: &mut Formatter) {
|
fn gen_builder(instructions: &AllInstructions, formats: &FormatRegistry, fmt: &mut Formatter) {
|
||||||
fmt.doc_comment(
|
fmt.doc_comment(
|
||||||
r#"
|
r#"
|
||||||
Convenience methods for building instructions.
|
Convenience methods for building instructions.
|
||||||
@@ -1055,7 +1045,7 @@ fn gen_builder(instructions: &Vec<&Instruction>, formats: &FormatRegistry, fmt:
|
|||||||
);
|
);
|
||||||
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 {
|
for inst in instructions.values() {
|
||||||
gen_inst_builder(inst, formats.get(inst.format), fmt);
|
gen_inst_builder(inst, formats.get(inst.format), fmt);
|
||||||
}
|
}
|
||||||
for format in formats.iter() {
|
for format in formats.iter() {
|
||||||
@@ -1066,12 +1056,14 @@ fn gen_builder(instructions: &Vec<&Instruction>, formats: &FormatRegistry, fmt:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(
|
pub fn generate(
|
||||||
all_inst_groups: Vec<&InstructionGroup>,
|
shared_defs: &SharedDefinitions,
|
||||||
format_registry: &FormatRegistry,
|
|
||||||
opcode_filename: &str,
|
opcode_filename: &str,
|
||||||
inst_builder_filename: &str,
|
inst_builder_filename: &str,
|
||||||
out_dir: &str,
|
out_dir: &str,
|
||||||
) -> Result<(), error::Error> {
|
) -> Result<(), error::Error> {
|
||||||
|
let format_registry = &shared_defs.format_registry;
|
||||||
|
let all_inst = &shared_defs.all_instructions;
|
||||||
|
|
||||||
// Opcodes.
|
// Opcodes.
|
||||||
let mut fmt = Formatter::new();
|
let mut fmt = Formatter::new();
|
||||||
gen_formats(format_registry, &mut fmt);
|
gen_formats(format_registry, &mut fmt);
|
||||||
@@ -1079,13 +1071,13 @@ pub 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();
|
||||||
let all_inst = gen_opcodes(format_registry, &all_inst_groups, &mut fmt);
|
gen_opcodes(all_inst, format_registry, &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)?;
|
||||||
|
|
||||||
// Instruction builder.
|
// Instruction builder.
|
||||||
let mut fmt = Formatter::new();
|
let mut fmt = Formatter::new();
|
||||||
gen_builder(&all_inst, format_registry, &mut fmt);
|
gen_builder(all_inst, format_registry, &mut fmt);
|
||||||
fmt.update_file(inst_builder_filename, out_dir)?;
|
fmt.update_file(inst_builder_filename, out_dir)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -308,7 +308,9 @@ fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
|
|||||||
hash_entries.extend(group.settings.iter().map(|x| SettingOrPreset::Setting(x)));
|
hash_entries.extend(group.settings.iter().map(|x| SettingOrPreset::Setting(x)));
|
||||||
hash_entries.extend(group.presets.iter().map(|x| SettingOrPreset::Preset(x)));
|
hash_entries.extend(group.presets.iter().map(|x| SettingOrPreset::Preset(x)));
|
||||||
|
|
||||||
let hash_table = generate_table(&hash_entries, |entry| simple_hash(entry.name()));
|
let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| {
|
||||||
|
simple_hash(entry.name())
|
||||||
|
});
|
||||||
fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());
|
fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());
|
||||||
fmt.indent(|fmt| {
|
fmt.indent(|fmt| {
|
||||||
for h in &hash_table {
|
for h in &hash_table {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
|||||||
let inst_group = InstructionGroupBuilder::new(
|
let inst_group = InstructionGroupBuilder::new(
|
||||||
"arm32",
|
"arm32",
|
||||||
"arm32 specific instruction set",
|
"arm32 specific instruction set",
|
||||||
|
&mut shared_defs.all_instructions,
|
||||||
&shared_defs.format_registry,
|
&shared_defs.format_registry,
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
|||||||
let inst_group = InstructionGroupBuilder::new(
|
let inst_group = InstructionGroupBuilder::new(
|
||||||
"arm64",
|
"arm64",
|
||||||
"arm64 specific instruction set",
|
"arm64 specific instruction set",
|
||||||
|
&mut shared_defs.all_instructions,
|
||||||
&shared_defs.format_registry,
|
&shared_defs.format_registry,
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
|||||||
let inst_group = InstructionGroupBuilder::new(
|
let inst_group = InstructionGroupBuilder::new(
|
||||||
"riscv",
|
"riscv",
|
||||||
"riscv specific instruction set",
|
"riscv specific instruction set",
|
||||||
|
&mut shared_defs.all_instructions,
|
||||||
&shared_defs.format_registry,
|
&shared_defs.format_registry,
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -2,16 +2,23 @@
|
|||||||
|
|
||||||
use crate::cdsl::formats::FormatRegistry;
|
use crate::cdsl::formats::FormatRegistry;
|
||||||
use crate::cdsl::instructions::{
|
use crate::cdsl::instructions::{
|
||||||
InstructionBuilder as Inst, InstructionGroup, InstructionGroupBuilder,
|
AllInstructions, InstructionBuilder as Inst, InstructionGroup, InstructionGroupBuilder,
|
||||||
};
|
};
|
||||||
use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc};
|
use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc};
|
||||||
use crate::cdsl::types::ValueType;
|
use crate::cdsl::types::ValueType;
|
||||||
use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
|
use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
|
||||||
use crate::shared::types;
|
use crate::shared::types;
|
||||||
|
|
||||||
pub fn define(format_registry: &FormatRegistry) -> InstructionGroup {
|
pub fn define(
|
||||||
let mut ig =
|
mut all_instructions: &mut AllInstructions,
|
||||||
InstructionGroupBuilder::new("x86", "x86 specific instruction set", format_registry);
|
format_registry: &FormatRegistry,
|
||||||
|
) -> InstructionGroup {
|
||||||
|
let mut ig = InstructionGroupBuilder::new(
|
||||||
|
"x86",
|
||||||
|
"x86 specific instruction set",
|
||||||
|
&mut all_instructions,
|
||||||
|
format_registry,
|
||||||
|
);
|
||||||
|
|
||||||
let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
|
let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ pub fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
|
|||||||
let settings = settings::define(&shared_defs.settings);
|
let settings = settings::define(&shared_defs.settings);
|
||||||
let regs = registers::define();
|
let regs = registers::define();
|
||||||
|
|
||||||
let inst_group = instructions::define(&shared_defs.format_registry);
|
let inst_group = instructions::define(
|
||||||
|
&mut shared_defs.all_instructions,
|
||||||
|
&shared_defs.format_registry,
|
||||||
|
);
|
||||||
legalize::define(shared_defs, &inst_group);
|
legalize::define(shared_defs, &inst_group);
|
||||||
|
|
||||||
// CPU modes for 32-bit and 64-bit operations.
|
// CPU modes for 32-bit and 64-bit operations.
|
||||||
|
|||||||
@@ -35,16 +35,7 @@ pub fn generate(isas: &Vec<isa::Isa>, out_dir: &str) -> Result<(), error::Error>
|
|||||||
// Per ISA definitions.
|
// Per ISA definitions.
|
||||||
let isas = isa::define(isas, &mut shared_defs);
|
let isas = isa::define(isas, &mut shared_defs);
|
||||||
|
|
||||||
let mut all_inst_groups = vec![&shared_defs.instructions];
|
gen_inst::generate(&shared_defs, "opcodes.rs", "inst_builder.rs", &out_dir)?;
|
||||||
all_inst_groups.extend(isas.iter().map(|isa| &isa.instructions));
|
|
||||||
|
|
||||||
gen_inst::generate(
|
|
||||||
all_inst_groups,
|
|
||||||
&shared_defs.format_registry,
|
|
||||||
"opcodes.rs",
|
|
||||||
"inst_builder.rs",
|
|
||||||
&out_dir,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
gen_legalizer::generate(
|
gen_legalizer::generate(
|
||||||
&isas,
|
&isas,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::cdsl::formats::FormatRegistry;
|
use crate::cdsl::formats::FormatRegistry;
|
||||||
use crate::cdsl::instructions::{
|
use crate::cdsl::instructions::{
|
||||||
InstructionBuilder as Inst, InstructionGroup, InstructionGroupBuilder,
|
AllInstructions, InstructionBuilder as Inst, InstructionGroup, InstructionGroupBuilder,
|
||||||
};
|
};
|
||||||
use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc};
|
use crate::cdsl::operands::{create_operand as operand, create_operand_doc as operand_doc};
|
||||||
use crate::cdsl::type_inference::Constraint::WiderOrEq;
|
use crate::cdsl::type_inference::Constraint::WiderOrEq;
|
||||||
@@ -11,12 +11,17 @@ use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
|
|||||||
use crate::shared::{types, OperandKinds};
|
use crate::shared::{types, OperandKinds};
|
||||||
|
|
||||||
pub fn define(
|
pub fn define(
|
||||||
|
all_instructions: &mut AllInstructions,
|
||||||
format_registry: &FormatRegistry,
|
format_registry: &FormatRegistry,
|
||||||
immediates: &OperandKinds,
|
immediates: &OperandKinds,
|
||||||
entities: &OperandKinds,
|
entities: &OperandKinds,
|
||||||
) -> InstructionGroup {
|
) -> InstructionGroup {
|
||||||
let mut ig =
|
let mut ig = InstructionGroupBuilder::new(
|
||||||
InstructionGroupBuilder::new("base", "Shared base instruction set", format_registry);
|
"base",
|
||||||
|
"Shared base instruction set",
|
||||||
|
all_instructions,
|
||||||
|
format_registry,
|
||||||
|
);
|
||||||
|
|
||||||
// Operand kind shorthands.
|
// Operand kind shorthands.
|
||||||
let intcc = immediates.by_name("intcc");
|
let intcc = immediates.by_name("intcc");
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ pub mod settings;
|
|||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
use crate::cdsl::formats::FormatRegistry;
|
use crate::cdsl::formats::FormatRegistry;
|
||||||
use crate::cdsl::instructions::InstructionGroup;
|
use crate::cdsl::instructions::{AllInstructions, InstructionGroup};
|
||||||
use crate::cdsl::operands::OperandKind;
|
use crate::cdsl::operands::OperandKind;
|
||||||
use crate::cdsl::settings::SettingGroup;
|
use crate::cdsl::settings::SettingGroup;
|
||||||
use crate::cdsl::xform::TransformGroups;
|
use crate::cdsl::xform::TransformGroups;
|
||||||
|
|
||||||
pub struct Definitions {
|
pub struct Definitions {
|
||||||
pub settings: SettingGroup,
|
pub settings: SettingGroup,
|
||||||
|
pub all_instructions: AllInstructions,
|
||||||
pub instructions: InstructionGroup,
|
pub instructions: InstructionGroup,
|
||||||
pub operand_kinds: OperandKinds,
|
pub operand_kinds: OperandKinds,
|
||||||
pub format_registry: FormatRegistry,
|
pub format_registry: FormatRegistry,
|
||||||
@@ -50,14 +51,22 @@ impl OperandKinds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn define() -> Definitions {
|
pub fn define() -> Definitions {
|
||||||
|
let mut all_instructions = AllInstructions::new();
|
||||||
|
|
||||||
let immediates = OperandKinds(immediates::define());
|
let immediates = OperandKinds(immediates::define());
|
||||||
let entities = OperandKinds(entities::define());
|
let entities = OperandKinds(entities::define());
|
||||||
let format_registry = formats::define(&immediates, &entities);
|
let format_registry = formats::define(&immediates, &entities);
|
||||||
let instructions = instructions::define(&format_registry, &immediates, &entities);
|
let instructions = instructions::define(
|
||||||
|
&mut all_instructions,
|
||||||
|
&format_registry,
|
||||||
|
&immediates,
|
||||||
|
&entities,
|
||||||
|
);
|
||||||
let transform_groups = legalize::define(&instructions, &immediates);
|
let transform_groups = legalize::define(&instructions, &immediates);
|
||||||
|
|
||||||
Definitions {
|
Definitions {
|
||||||
settings: settings::define(),
|
settings: settings::define(),
|
||||||
|
all_instructions,
|
||||||
instructions,
|
instructions,
|
||||||
operand_kinds: immediates,
|
operand_kinds: immediates,
|
||||||
format_registry,
|
format_registry,
|
||||||
|
|||||||
Reference in New Issue
Block a user