Auto-generate boilerplate for 'impl InstructionData'.
Accessors for shared fields and multiple results can be generated automatically. Add a 'boxed_storage' flag to the instruction format definitions to enable generated code to access 'data'.
This commit is contained in:
@@ -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<Value>`
|
||||
- `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<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 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)
|
||||
|
||||
Reference in New Issue
Block a user