| Index: src/trusted/validator_mips/dgen/dgen_output.py
|
| diff --git a/src/trusted/validator_mips/dgen/dgen_output.py b/src/trusted/validator_mips/dgen/dgen_output.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..ff6f4bc1e90dc3cc04ae8cd448b6919fd4254b9c
|
| --- /dev/null
|
| +++ b/src/trusted/validator_mips/dgen/dgen_output.py
|
| @@ -0,0 +1,188 @@
|
| +#!/usr/bin/python
|
| +#
|
| +# Copyright 2012 The Native Client Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can
|
| +# be found in the LICENSE file.
|
| +# Copyright 2012, Google Inc.
|
| +#
|
| +
|
| +"""
|
| +Responsible for generating the decoder based on parsed table representations.
|
| +"""
|
| +
|
| +import dgen_opt
|
| +
|
| +def generate_decoder(tables, out):
|
| + """Entry point to the decoder.
|
| +
|
| + Args:
|
| + tables: list of Table objects to process.
|
| + out: a COutput object to write to.
|
| + """
|
| + if len(tables) == 0: raise Exception('No tables provided.')
|
| +
|
| + _generate_header(out)
|
| + out.line()
|
| + out.line('namespace nacl_mips_dec {')
|
| + out.line()
|
| + _generate_decoder_state_type(tables, out)
|
| + out.line()
|
| + _generate_prototypes(tables, out)
|
| + out.line()
|
| + _generate_implementations(tables, out)
|
| + out.line()
|
| + _generate_init_function(out)
|
| + out.line()
|
| + _generate_entry_point(tables[0].name, out)
|
| + out.line()
|
| + out.line('} // namespace')
|
| +
|
| +def _generate_header(out):
|
| + # TODO do we need a big ridiculous license banner in generated code?
|
| + out.block_comment('DO NOT EDIT: GENERATED CODE')
|
| + out.line('#include <stdio.h>')
|
| + out.line('#include "native_client/src/trusted/validator_mips/decode.h"')
|
| +
|
| +
|
| +def _generate_decoder_state_type(tables, out):
|
| + out.block_comment(
|
| + 'This beast holds a bunch of pre-created ClassDecoder instances, which',
|
| + 'we create in init_decode(). Because ClassDecoders are stateless, we',
|
| + 'can freely reuse them -- even across threads -- and avoid allocating',
|
| + 'in the inner decoder loop.'
|
| + )
|
| + terminals = set()
|
| + for t in tables:
|
| + for r in t.rows:
|
| + if r.action.startswith('='):
|
| + terminals.add(r.action[1:])
|
| +
|
| + out.enter_block('struct DecoderState')
|
| +
|
| + for t in terminals:
|
| + out.line('const %s _%s_instance;' % (t, t))
|
| +
|
| + out.line('DecoderState() :')
|
| + first = True
|
| + for t in terminals:
|
| + if first:
|
| + out.line('_%s_instance()' % t)
|
| + else:
|
| + out.line(',_%s_instance()' % t)
|
| + first = False
|
| + out.line('{}')
|
| +
|
| + out.exit_block(';')
|
| +
|
| +
|
| +def _generate_prototypes(tables, out):
|
| + out.block_comment('Prototypes for static table-matching functions.')
|
| + for t in tables:
|
| + out.line('static inline const ClassDecoder &decode_%s('
|
| + 'const Instruction insn, const DecoderState *state);' % t.name)
|
| +
|
| +def _generate_implementations(tables, out):
|
| + out.block_comment('Table-matching function implementations.')
|
| + for t in tables:
|
| + out.line()
|
| + _generate_table(t, out)
|
| +
|
| +
|
| +def _generate_init_function(out):
|
| + out.enter_block('const DecoderState *init_decode()')
|
| + out.line('return new DecoderState;')
|
| + out.exit_block()
|
| +
|
| + out.enter_block('void delete_state(const DecoderState *state)')
|
| + out.line('delete (DecoderState *)state;')
|
| + out.exit_block()
|
| +
|
| +def _generate_entry_point(initial_table_name, out):
|
| + out.enter_block('const ClassDecoder &decode(const Instruction insn, '
|
| + 'const DecoderState *state)')
|
| + out.line('return decode_%s(insn, (DecoderState *)state);'
|
| + % initial_table_name)
|
| + out.exit_block()
|
| +
|
| +
|
| +def _generate_table(table, out):
|
| + """Generates the implementation of a single table."""
|
| + out.block_comment(
|
| + 'Implementation of table %s.' % table.name,
|
| + 'Specified by: %s.' % table.citation
|
| + )
|
| + out.enter_block('static inline const ClassDecoder &decode_%s('
|
| + 'const Instruction insn, const DecoderState *state)' % table.name)
|
| +
|
| + optimized = dgen_opt.optimize_rows(table.rows)
|
| + print ("Table %s: %d rows minimized to %d"
|
| + % (table.name, len(table.rows), len(optimized)))
|
| + for row in sorted(optimized):
|
| + exprs = ["(%s)" % p.to_c_expr('insn') for p in row.patterns]
|
| + out.enter_block('if (%s)' % ' && '.join(exprs))
|
| +
|
| + if row.action.startswith('='):
|
| + _generate_terminal(row.action[1:], out)
|
| + elif row.action.startswith('->'):
|
| + _generate_table_change(row.action[2:], out)
|
| + else:
|
| + raise Exception('Bad table action: %s' % row.action)
|
| +
|
| + out.exit_block()
|
| + out.line()
|
| +
|
| + _generate_safety_net(table, out)
|
| + out.exit_block()
|
| +
|
| +
|
| +def _generate_terminal(name, out):
|
| + out.line('return state->_%s_instance;' % name)
|
| +
|
| +
|
| +def _generate_table_change(name, out):
|
| + out.line('return decode_%s(insn, state);' % name)
|
| +
|
| +
|
| +def _generate_safety_net(table, out):
|
| + out.line('// Catch any attempt to fall through...')
|
| + out.line('fprintf(stderr, "TABLE IS INCOMPLETE: %s could not parse %%08X",'
|
| + 'insn.bits(31,0));' % table.name)
|
| + _generate_terminal('Forbidden', out)
|
| +
|
| +
|
| +class COutput(object):
|
| + """Provides nicely-formatted C++ output."""
|
| +
|
| + def __init__(self, out):
|
| + self._out = out
|
| + self._indent = 0
|
| +
|
| + def line(self, str = ''):
|
| + self._out.write(self._tabs())
|
| + self._out.write(str + '\n')
|
| +
|
| + def enter_block(self, headline):
|
| + self.line(headline + ' {')
|
| + self._indent += 1
|
| +
|
| + def exit_block(self, footer = ''):
|
| + self._indent -= 1
|
| + self.line('}' + footer)
|
| +
|
| + def block_comment(self, *lines):
|
| + self.line('/*')
|
| + for s in lines:
|
| + self.line(' * ' + s)
|
| + self.line(' */')
|
| +
|
| + def _tabs(self):
|
| + return ' ' * self._indent
|
| +
|
| +
|
| +def each_index_pair(sequence):
|
| + """Utility method: Generates each unique index pair in sequence."""
|
| + for i in range(0, len(sequence)):
|
| + for j in range(i + 1, len(sequence)):
|
| + yield (i, j)
|
| +
|
| +
|
|
|