diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 36f96ef6f5..4b8267d2d1 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -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): diff --git a/meta/gen_instr.py b/meta/gen_instr.py index 70ae0ee8e7..8c5ad8a9ce 100644 --- a/meta/gen_instr.py +++ b/meta/gen_instr.py @@ -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 => "",') 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) diff --git a/meta/srcgen.py b/meta/srcgen.py index 7895b0ea38..1ebd745286 100644 --- a/meta/srcgen.py +++ b/meta/srcgen.py @@ -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.""" - self.lines.append('{}{}\n'.format(self.indent, s)) + 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`.""" diff --git a/src/libcretonne/immediates.rs b/src/libcretonne/immediates.rs index 619d790bfe..135d3c6b65 100644 --- a/src/libcretonne/immediates.rs +++ b/src/libcretonne/immediates.rs @@ -23,6 +23,17 @@ impl Display for Opcode { } } +impl Opcode { + /// Get the instruction format for this opcode. + pub fn format(self) -> Option { + 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");