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:
@@ -384,6 +384,9 @@ class InstructionFormat(object):
|
|||||||
enums.
|
enums.
|
||||||
:param multiple_results: Set to `True` if this instruction format allows
|
:param multiple_results: Set to `True` if this instruction format allows
|
||||||
more than one result to be produced.
|
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
|
# Map (multiple_results, kind, kind, ...) -> InstructionFormat
|
||||||
@@ -396,6 +399,7 @@ class InstructionFormat(object):
|
|||||||
self.name = kwargs.get('name', None)
|
self.name = kwargs.get('name', None)
|
||||||
self.kinds = kinds
|
self.kinds = kinds
|
||||||
self.multiple_results = kwargs.get('multiple_results', False)
|
self.multiple_results = kwargs.get('multiple_results', False)
|
||||||
|
self.boxed_storage = kwargs.get('boxed_storage', False)
|
||||||
# Compute a signature for the global registry.
|
# Compute a signature for the global registry.
|
||||||
sig = (self.multiple_results,) + kinds
|
sig = (self.multiple_results,) + kinds
|
||||||
if sig in InstructionFormat._registry:
|
if sig in InstructionFormat._registry:
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ Binary = InstructionFormat(value, value)
|
|||||||
BinaryImm = InstructionFormat(value, imm64)
|
BinaryImm = InstructionFormat(value, imm64)
|
||||||
BinaryImmRev = InstructionFormat(imm64, value)
|
BinaryImmRev = InstructionFormat(imm64, value)
|
||||||
|
|
||||||
Jump = InstructionFormat(ebb, variable_args)
|
Jump = InstructionFormat(ebb, variable_args, boxed_storage=True)
|
||||||
Branch = InstructionFormat(value, ebb, variable_args)
|
Branch = InstructionFormat(value, ebb, variable_args, boxed_storage=True)
|
||||||
BranchTable = InstructionFormat(value, jump_table)
|
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.
|
# Finally extract the names of global variables in this module.
|
||||||
InstructionFormat.extract_names(globals())
|
InstructionFormat.extract_names(globals())
|
||||||
|
|||||||
@@ -36,6 +36,89 @@ def gen_formats(fmt):
|
|||||||
fmt.line()
|
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):
|
def collect_instr_groups(targets):
|
||||||
seen = set()
|
seen = set()
|
||||||
groups = []
|
groups = []
|
||||||
@@ -108,8 +191,10 @@ def gen_opcodes(groups, fmt):
|
|||||||
|
|
||||||
def generate(targets, out_dir):
|
def generate(targets, out_dir):
|
||||||
groups = collect_instr_groups(targets)
|
groups = collect_instr_groups(targets)
|
||||||
|
|
||||||
# opcodes.rs
|
# opcodes.rs
|
||||||
fmt = srcgen.Formatter()
|
fmt = srcgen.Formatter()
|
||||||
gen_formats(fmt)
|
gen_formats(fmt)
|
||||||
|
gen_instruction_data_impl(fmt)
|
||||||
gen_opcodes(groups, fmt)
|
gen_opcodes(groups, fmt)
|
||||||
fmt.update_file('opcodes.rs', out_dir)
|
fmt.update_file('opcodes.rs', out_dir)
|
||||||
|
|||||||
@@ -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<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 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)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user