diff --git a/cranelift/src/libcretonne/immediates.rs b/cranelift/src/libcretonne/immediates.rs index efd84cd606..0034139f50 100644 --- a/cranelift/src/libcretonne/immediates.rs +++ b/cranelift/src/libcretonne/immediates.rs @@ -8,6 +8,9 @@ use std::fmt::{self, Display, Formatter}; use std::mem; +// The `Opcode` enum is generated from the meta instruction descriptions. +include!(concat!(env!("OUT_DIR"), "/opcodes.rs")); + /// 64-bit immediate integer operand. /// #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -41,11 +44,13 @@ impl Display for Imm64 { /// An IEEE binary32 immediate floating point value. /// /// All bit patterns are allowed. +#[derive(Copy, Clone, Debug)] pub struct Ieee32(f32); /// An IEEE binary64 immediate floating point value. /// /// All bit patterns are allowed. +#[derive(Copy, Clone, Debug)] pub struct Ieee64(f64); // Format a floating point number in a way that is reasonably human-readable, and that can be @@ -155,6 +160,19 @@ mod tests { use super::*; use std::{f32, f64}; + #[test] + fn opcodes() { + let x = Opcode::Iadd; + let mut y = Opcode::Isub; + + assert!(x != y); + y = Opcode::Iadd; + assert_eq!(x, y); + + assert_eq!(format!("{:?}", Opcode::IaddImm), "IaddImm"); + assert_eq!(format!("{}", Opcode::IaddImm), "iadd_imm"); + } + #[test] fn format_imm64() { assert_eq!(format!("{}", Imm64(0)), "0"); diff --git a/meta/gen_instr.py b/meta/gen_instr.py index a92609c861..cd50b4ee8a 100644 --- a/meta/gen_instr.py +++ b/meta/gen_instr.py @@ -17,13 +17,31 @@ def collect_instr_groups(targets): def gen_opcodes(groups, out_dir): """Generate opcode enumerations.""" fmt = srcgen.Formatter() - fmt.line('enum Opcode {') - fmt.indent_push() - for g in groups: - for i in g.instructions: - fmt.line(i.camel_name + ',') - fmt.indent_pop() - fmt.line('}') + + fmt.doc_comment('An instruction opcode.') + fmt.doc_comment('') + fmt.doc_comment('All instructions from all supported targets are present.') + fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]') + instrs = [] + with fmt.indented('pub enum Opcode {', '}'): + for g in groups: + for i in g.instructions: + instrs.append(i) + # Build a doc comment. + prefix = ', '.join(o.name for o in i.outs) + if prefix: + prefix = prefix + ' = ' + suffix = ', '.join(o.name for o in i.ins) + fmt.doc_comment('`{}{} {}`.'.format(prefix, i.name, suffix)) + # Enum variant itself. + fmt.line(i.camel_name + ',') + + with fmt.indented('impl Display for Opcode {', '}'): + with fmt.indented('fn fmt(&self, f: &mut Formatter) -> fmt::Result {', '}'): + with fmt.indented('f.write_str(match *self {', '})'): + for i in instrs: + fmt.format('Opcode::{} => "{}",', i.camel_name, i.name) + fmt.update_file('opcodes.rs', out_dir) def generate(targets, out_dir): diff --git a/meta/srcgen.py b/meta/srcgen.py index 9778e2c518..125ae0a63a 100644 --- a/meta/srcgen.py +++ b/meta/srcgen.py @@ -25,15 +25,15 @@ class Formatter(object): >>> f.indent_push() >>> f.comment('Nested comment') >>> f.indent_pop() - >>> f.line('Back again') + >>> f.format('Back {} again', 'home') >>> f.writelines() Hello line 1 - // Nested comment - Back again + // Nested comment + Back home again """ - shiftwidth = 2 + shiftwidth = 4 def __init__(self): self.indent = '' @@ -64,10 +64,49 @@ class Formatter(object): with open(filename, 'w') as f: self.writelines(f) + class _IndentedScope(object): + def __init__(self, fmt, after): + self.fmt = fmt + self.after = after + + def __enter__(self): + self.fmt.indent_push(); + + def __exit__(self, t, v, tb): + self.fmt.indent_pop() + if self.after: + self.fmt.line(self.after) + + def indented(self, before=None, after=None): + """ + Return a scope object for use with a `with` statement: + + >>> f = Formatter() + >>> with f.indented('prefix {', '} suffix'): + ... f.line('hello') + >>> f.writelines() + prefix { + hello + } suffix + + The optional `before` and `after` parameters are surrounding lines + which are *not* indented. + """ + if before: + self.line(before) + return self._IndentedScope(self, after) + + def format(self, fmt, *args): + self.line(fmt.format(*args)) + def comment(self, s): """Add a comment line.""" self.line('// ' + s) + def doc_comment(self, s): + """Add a documentation comment line.""" + self.line('/// ' + s) + if __name__ == "__main__": import doctest doctest.testmod()