Generate an InstructionFormat enum.
This is a no-payload enum which will have the same variants as InstructionData. This makes it possible to talk about the format of an instruction without actually creating an InstructionData instance.
This commit is contained in:
@@ -335,6 +335,9 @@ class InstructionFormat(object):
|
||||
# Map (multiple_results, kind, kind, ...) -> InstructionFormat
|
||||
_registry = dict()
|
||||
|
||||
# All existing formats.
|
||||
all_formats = list()
|
||||
|
||||
def __init__(self, *kinds, **kwargs):
|
||||
self.name = kwargs.get('name', None)
|
||||
self.kinds = kinds
|
||||
@@ -346,6 +349,7 @@ class InstructionFormat(object):
|
||||
"Format '{}' has the same signature as existing format '{}'"
|
||||
.format(self.name, InstructionFormat._registry[sig]))
|
||||
InstructionFormat._registry[sig] = self
|
||||
InstructionFormat.all_formats.append(self)
|
||||
|
||||
@staticmethod
|
||||
def lookup(ins, outs):
|
||||
|
||||
@@ -4,6 +4,22 @@ Generate sources with instruction info.
|
||||
|
||||
import srcgen
|
||||
import constant_hash
|
||||
import cretonne
|
||||
|
||||
|
||||
def gen_formats(fmt):
|
||||
"""Generate an instruction format enumeration"""
|
||||
|
||||
fmt.doc_comment('An instruction format')
|
||||
fmt.doc_comment('')
|
||||
fmt.doc_comment('Every opcode has a corresponding instruction format')
|
||||
fmt.doc_comment('which is represented by both the `InstructionFormat`')
|
||||
fmt.doc_comment('and the `InstructionData` enums.')
|
||||
fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
|
||||
with fmt.indented('pub enum InstructionFormat {', '}'):
|
||||
for f in cretonne.InstructionFormat.all_formats:
|
||||
fmt.line(f.name + ',')
|
||||
fmt.line()
|
||||
|
||||
|
||||
def collect_instr_groups(targets):
|
||||
@@ -17,9 +33,8 @@ def collect_instr_groups(targets):
|
||||
return groups
|
||||
|
||||
|
||||
def gen_opcodes(groups, out_dir):
|
||||
def gen_opcodes(groups, fmt):
|
||||
"""Generate opcode enumerations."""
|
||||
fmt = srcgen.Formatter()
|
||||
|
||||
fmt.doc_comment('An instruction opcode.')
|
||||
fmt.doc_comment('')
|
||||
@@ -41,6 +56,18 @@ def gen_opcodes(groups, out_dir):
|
||||
.format(prefix, i.name, suffix, i.format.name))
|
||||
# Enum variant itself.
|
||||
fmt.line(i.camel_name + ',')
|
||||
fmt.line()
|
||||
|
||||
# Generate a private opcode_format table.
|
||||
with fmt.indented(
|
||||
'const OPCODE_FORMAT: [InstructionFormat; {}] = ['
|
||||
.format(len(instrs)),
|
||||
'];'):
|
||||
for i in instrs:
|
||||
fmt.format(
|
||||
'InstructionFormat::{}, // {}',
|
||||
i.format.name, i.name)
|
||||
fmt.line()
|
||||
|
||||
# Generate a private opcode_name function.
|
||||
with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
|
||||
@@ -48,6 +75,7 @@ def gen_opcodes(groups, out_dir):
|
||||
fmt.line('Opcode::NotAnOpcode => "<not an opcode>",')
|
||||
for i in instrs:
|
||||
fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
|
||||
fmt.line()
|
||||
|
||||
# Generate an opcode hash table for looking up opcodes by name.
|
||||
hash_table = constant_hash.compute_quadratic(
|
||||
@@ -61,10 +89,13 @@ def gen_opcodes(groups, out_dir):
|
||||
fmt.line('Opcode::NotAnOpcode,')
|
||||
else:
|
||||
fmt.format('Opcode::{},', i.camel_name)
|
||||
|
||||
fmt.update_file('opcodes.rs', out_dir)
|
||||
fmt.line()
|
||||
|
||||
|
||||
def generate(targets, out_dir):
|
||||
groups = collect_instr_groups(targets)
|
||||
gen_opcodes(groups, out_dir)
|
||||
# opcodes.rs
|
||||
fmt = srcgen.Formatter()
|
||||
gen_formats(fmt)
|
||||
gen_opcodes(groups, fmt)
|
||||
fmt.update_file('opcodes.rs', out_dir)
|
||||
|
||||
@@ -49,9 +49,12 @@ class Formatter(object):
|
||||
assert self.indent != '', 'Already at top level indentation'
|
||||
self.indent = self.indent[0:-self.shiftwidth]
|
||||
|
||||
def line(self, s):
|
||||
def line(self, s=None):
|
||||
"""And an indented line."""
|
||||
if s:
|
||||
self.lines.append('{}{}\n'.format(self.indent, s))
|
||||
else:
|
||||
self.lines.append('\n')
|
||||
|
||||
def writelines(self, f=None):
|
||||
"""Write all lines to `f`."""
|
||||
|
||||
@@ -23,6 +23,17 @@ impl Display for Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
/// Get the instruction format for this opcode.
|
||||
pub fn format(self) -> Option<InstructionFormat> {
|
||||
if self == Opcode::NotAnOpcode {
|
||||
None
|
||||
} else {
|
||||
Some(OPCODE_FORMAT[self as usize - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A primitive hash function for matching opcodes.
|
||||
// Must match `meta/constant_hash.py`.
|
||||
fn simple_hash(s: &str) -> u32 {
|
||||
@@ -491,6 +502,7 @@ mod tests {
|
||||
assert!(x != y);
|
||||
y = Opcode::Iadd;
|
||||
assert_eq!(x, y);
|
||||
assert_eq!(x.format(), Some(InstructionFormat::Binary));
|
||||
|
||||
assert_eq!(format!("{:?}", Opcode::IaddImm), "IaddImm");
|
||||
assert_eq!(Opcode::IaddImm.to_string(), "iadd_imm");
|
||||
|
||||
Reference in New Issue
Block a user