diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 961a3a500c..5df6931aec 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -384,6 +384,9 @@ class InstructionFormat(object): enums. :param multiple_results: Set to `True` if this instruction format allows more than one result to be produced. + :param boxed_storage: Set to `True` is this instruction format requires a + `data: Box<...>` pointer to additional storage in its `InstructionData` + variant. """ # Map (multiple_results, kind, kind, ...) -> InstructionFormat @@ -396,6 +399,7 @@ class InstructionFormat(object): self.name = kwargs.get('name', None) self.kinds = kinds self.multiple_results = kwargs.get('multiple_results', False) + self.boxed_storage = kwargs.get('boxed_storage', False) # Compute a signature for the global registry. sig = (self.multiple_results,) + kinds if sig in InstructionFormat._registry: diff --git a/meta/cretonne/formats.py b/meta/cretonne/formats.py index 8b32936d7c..319dc6fb69 100644 --- a/meta/cretonne/formats.py +++ b/meta/cretonne/formats.py @@ -23,11 +23,12 @@ Binary = InstructionFormat(value, value) BinaryImm = InstructionFormat(value, imm64) BinaryImmRev = InstructionFormat(imm64, value) -Jump = InstructionFormat(ebb, variable_args) -Branch = InstructionFormat(value, ebb, variable_args) +Jump = InstructionFormat(ebb, variable_args, boxed_storage=True) +Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True) BranchTable = InstructionFormat(value, jump_table) -Call = InstructionFormat(function, variable_args, multiple_results=True) +Call = InstructionFormat( + function, variable_args, multiple_results=True, boxed_storage=True) # Finally extract the names of global variables in this module. InstructionFormat.extract_names(globals()) diff --git a/meta/gen_instr.py b/meta/gen_instr.py index 8fe63cb932..c055e87ffa 100644 --- a/meta/gen_instr.py +++ b/meta/gen_instr.py @@ -36,6 +36,89 @@ def gen_formats(fmt): fmt.line() +def gen_instruction_data_impl(fmt): + """ + Generate the boring parts of the InstructionData implementation. + + These methods in `impl InstructionData` can be generated automatically from + the instruction formats: + + - `pub fn opcode(&self) -> Opcode` + - `pub fn first_type(&self) -> Type` + - `pub fn second_result(&self) -> Option` + - `pub fn second_result_mut<'a>(&'a mut self) -> Option<&'a mut Value>` + """ + + # The `opcode` and `first_type` methods simply read the `opcode` and `ty` + # members. This is really a workaround for Rust's enum types missing shared + # members. + with fmt.indented('impl InstructionData {', '}'): + fmt.doc_comment('Get the opcode of this instruction.') + with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'): + with fmt.indented('match *self {', '}'): + for f in cretonne.InstructionFormat.all_formats: + fmt.line( + 'InstructionData::{} {{ opcode, .. }} => opcode,' + .format(f.name)) + + fmt.doc_comment('Type of the first result, or `VOID`.') + with fmt.indented('pub fn first_type(&self) -> Type {', '}'): + with fmt.indented('match *self {', '}'): + for f in cretonne.InstructionFormat.all_formats: + fmt.line( + 'InstructionData::{} {{ ty, .. }} => ty,' + .format(f.name)) + + # Generate shared and mutable accessors for `second_result` which only + # applies to instruction formats that can produce multiple results. + # Everything else returns `None`. + fmt.doc_comment('Second result value, if any.') + with fmt.indented( + 'pub fn second_result(&self) -> Option {', '}'): + with fmt.indented('match *self {', '}'): + for f in cretonne.InstructionFormat.all_formats: + if not f.multiple_results: + # Single or no results. + fmt.line( + 'InstructionData::{} {{ .. }} => None,' + .format(f.name)) + elif f.boxed_storage: + # Multiple results, boxed storage. + fmt.line( + 'InstructionData::' + f.name + + ' { ref data, .. }' + + ' => Some(data.second_result),') + else: + # Multiple results, inline storage. + fmt.line( + 'InstructionData::' + f.name + + ' { second_result, .. }' + + ' => Some(second_result),') + + fmt.doc_comment('Mutable reference to second result value, if any.') + with fmt.indented( + "pub fn second_result_mut<'a>(&'a mut self) -> Option<&'a mut Value> {", '}'): + with fmt.indented('match *self {', '}'): + for f in cretonne.InstructionFormat.all_formats: + if not f.multiple_results: + # Single or no results. + fmt.line( + 'InstructionData::{} {{ .. }} => None,' + .format(f.name)) + elif f.boxed_storage: + # Multiple results, boxed storage. + fmt.line( + 'InstructionData::' + f.name + + ' { ref mut data, .. }' + + ' => Some(&mut data.second_result),') + else: + # Multiple results, inline storage. + fmt.line( + 'InstructionData::' + f.name + + ' { ref mut second_result, .. }' + + ' => Some(second_result),') + + def collect_instr_groups(targets): seen = set() groups = [] @@ -108,8 +191,10 @@ def gen_opcodes(groups, fmt): def generate(targets, out_dir): groups = collect_instr_groups(targets) + # opcodes.rs fmt = srcgen.Formatter() gen_formats(fmt) + gen_instruction_data_impl(fmt) gen_opcodes(groups, fmt) fmt.update_file('opcodes.rs', out_dir) diff --git a/src/libcretonne/instructions.rs b/src/libcretonne/instructions.rs index 3cb1ba5378..50cd4d8aad 100644 --- a/src/libcretonne/instructions.rs +++ b/src/libcretonne/instructions.rs @@ -251,85 +251,6 @@ impl InstructionData { }), } } - - /// Get the opcode of this instruction. - pub fn opcode(&self) -> Opcode { - use self::InstructionData::*; - match *self { - Nullary { opcode, .. } => opcode, - Unary { opcode, .. } => opcode, - UnaryImm { opcode, .. } => opcode, - UnaryIeee32 { opcode, .. } => opcode, - UnaryIeee64 { opcode, .. } => opcode, - UnaryImmVector { opcode, .. } => opcode, - Binary { opcode, .. } => opcode, - BinaryImm { opcode, .. } => opcode, - BinaryImmRev { opcode, .. } => opcode, - Jump { opcode, .. } => opcode, - Branch { opcode, .. } => opcode, - BranchTable { opcode, .. } => opcode, - Call { opcode, .. } => opcode, - } - } - - /// Type of the first result. - pub fn first_type(&self) -> Type { - use self::InstructionData::*; - match *self { - Nullary { ty, .. } => ty, - Unary { ty, .. } => ty, - UnaryImm { ty, .. } => ty, - UnaryIeee32 { ty, .. } => ty, - UnaryIeee64 { ty, .. } => ty, - UnaryImmVector { ty, .. } => ty, - Binary { ty, .. } => ty, - BinaryImm { ty, .. } => ty, - BinaryImmRev { ty, .. } => ty, - Jump { ty, .. } => ty, - Branch { ty, .. } => ty, - BranchTable { ty, .. } => ty, - Call { ty, .. } => ty, - } - } - - /// Second result value, if any. - pub fn second_result(&self) -> Option { - use self::InstructionData::*; - match *self { - Nullary { .. } => None, - Unary { .. } => None, - UnaryImm { .. } => None, - UnaryIeee32 { .. } => None, - UnaryIeee64 { .. } => None, - UnaryImmVector { .. } => None, - Binary { .. } => None, - BinaryImm { .. } => None, - BinaryImmRev { .. } => None, - Jump { .. } => None, - Branch { .. } => None, - BranchTable { .. } => None, - Call { ref data, .. } => Some(data.second_result), - } - } - - pub fn second_result_mut<'a>(&'a mut self) -> Option<&'a mut Value> { - use self::InstructionData::*; - match *self { - Nullary { .. } => None, - Unary { .. } => None, - UnaryImm { .. } => None, - UnaryIeee32 { .. } => None, - UnaryIeee64 { .. } => None, - UnaryImmVector { .. } => None, - Binary { .. } => None, - BinaryImm { .. } => None, - BinaryImmRev { .. } => None, - Jump { .. } => None, - Branch { .. } => None, - BranchTable { .. } => None, - Call { ref mut data, .. } => Some(&mut data.second_result), - } - } } #[cfg(test)]