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..47f40afb3f320909bf3038d022fa42f1b4e99fd7 |
--- /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) |
+ |
+ |