@ -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 )