Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright 2012 The Native Client Authors. All rights reserved. | 3 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # be found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 # | 6 # |
| 7 | 7 |
| 8 """ | 8 """ |
| 9 Responsible for generating the decoder based on parsed table representations. | 9 Responsible for generating the decoder based on parsed table representations. |
|
robertm
2012/04/17 17:12:19
may need updating
Karl
2012/04/17 19:28:31
Done.
| |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 import dgen_opt | 12 HEADER_BOILERPLATE =""" |
| 13 /* | |
| 14 * Copyright 2012 The Native Client Authors. All rights reserved. | |
| 15 * Use of this source code is governed by a BSD-style license that can | |
| 16 * be found in the LICENSE file. | |
| 17 */ | |
| 13 | 18 |
| 14 def generate_decoder_h(tables, decoder_name, filename, named_decoders, out): | 19 // DO NOT EDIT: GENERATED CODE |
| 15 """Entry point to the decoder for .h file. | 20 """ |
| 16 | 21 |
| 17 Args: | 22 NOT_TCB_BOILERPLATE=""" |
| 18 tables: list of Table objects to process. | 23 #ifndef NACL_TRUSTED_BUT_NOT_TCB |
| 19 decoder_name: The name of the decoder state to build. | 24 #error This file is not meant for use in the TCB |
| 20 filename: The (localized) name for the .h file. | 25 #endif |
| 21 named_decoders: If true, generate a decoder state with named instances. | |
| 22 out: a COutput object to write to. | |
| 23 """ | |
| 24 if len(tables) == 0: raise Exception('No tables provided.') | |
| 25 | 26 |
| 26 ifdef_name = _generate_ifdef_name(filename) | 27 """ |
| 27 named_prefix = '' | |
| 28 if named_decoders: | |
| 29 named_prefix = 'Named' | |
| 30 | 28 |
| 31 _generate_header(out) | 29 def ifdef_name(filename): |
| 32 out.line() | 30 """ Generates the ifdef name to use for the given filename""" |
| 33 out.line("#ifndef %s" % ifdef_name) | |
| 34 out.line("#define %s" % ifdef_name) | |
| 35 out.line() | |
| 36 out.line('#include "native_client/src/trusted/validator_arm/decode.h"') | |
| 37 out.line() | |
| 38 out.line('namespace nacl_arm_dec {') | |
| 39 out.line() | |
| 40 if named_decoders: | |
| 41 _generate_named_decoder_classes(tables, named_prefix, out) | |
| 42 _generate_decoder_state_type(tables, decoder_name, named_prefix, out) | |
| 43 out.line('} // namespace') | |
| 44 out.line("#endif // %s" % ifdef_name) | |
| 45 | |
| 46 | |
| 47 def generate_decoder_cc(tables, decoder_name, filename, named_decoders, out): | |
| 48 """Entry point to the decoder for .cc file | |
| 49 | |
| 50 Args: | |
| 51 tables: list of Table objects to process. | |
| 52 decoder_name: The name of the decoder state to build. | |
| 53 filename: The (localized) name for the .h file. | |
| 54 named_decoders: If true, generate a decoder state with named instances. | |
| 55 out: a COutput object to write to. | |
| 56 """ | |
| 57 if len(tables) == 0: raise Exception('No tables provided.') | |
| 58 | |
| 59 named_prefix = '' | |
| 60 if named_decoders: | |
| 61 named_prefix = 'Named' | |
| 62 | |
| 63 _generate_header(out) | |
| 64 out.line() | |
| 65 out.line('#include "%s"' % (filename[:-2] + 'h')) | |
| 66 out.line(); | |
| 67 out.line('#include <stdio.h>') | |
| 68 out.line() | |
| 69 out.line('namespace nacl_arm_dec {') | |
| 70 out.line() | |
| 71 if named_decoders: | |
| 72 _generate_named_decoder_classes_impls(tables, named_prefix, out) | |
| 73 _generate_prototypes(tables, decoder_name, named_prefix, out) | |
| 74 _generate_implementations(tables, decoder_name, named_prefix, out) | |
| 75 _generate_constructors(tables, decoder_name, named_prefix, out) | |
| 76 _generate_entry_point(decoder_name, named_prefix, tables[0].name, out) | |
| 77 out.line('} // namespace') | |
| 78 | |
| 79 | |
| 80 def _generate_ifdef_name(filename): | |
| 81 return filename.replace("/", "_").replace(".", "_").upper() + "_" | 31 return filename.replace("/", "_").replace(".", "_").upper() + "_" |
| 82 | |
| 83 def _generate_header(out): | |
| 84 out.block_comment( | |
| 85 'Copyright 2012 The Native Client Authors. All rights reserved.', | |
| 86 'Use of this source code is governed by a BSD-style license that can', | |
| 87 'be found in the LICENSE file.', | |
| 88 ) | |
| 89 out.line() | |
| 90 out.block_comment('DO NOT EDIT: GENERATED CODE') | |
| 91 | |
| 92 def _table_terminals(tables): | |
| 93 terminals = set() | |
| 94 for t in tables: | |
| 95 for r in t.rows: | |
| 96 if r.action.startswith('='): | |
| 97 terminals.add(r.action[1:]) | |
| 98 return terminals | |
| 99 | |
| 100 def _generate_named_decoder_classes(tables, named_prefix, out): | |
| 101 for t in _table_terminals(tables): | |
| 102 out.enter_block('struct %s%s : public %s' % (named_prefix, t, t)) | |
| 103 out.line('virtual ~%s%s() {}' % (named_prefix, t)) | |
| 104 out.line('virtual const char* name() const;') | |
| 105 out.exit_block(';') | |
| 106 out.line() | |
| 107 | |
| 108 def _generate_named_decoder_classes_impls(tables, named_prefix, out): | |
| 109 for t in _table_terminals(tables): | |
| 110 out.enter_block('const char* %s%s::name() const' % (named_prefix, t)); | |
| 111 out.line('return "%s";' % t) | |
| 112 out.exit_block() | |
| 113 out.line() | |
| 114 | |
| 115 def _generate_decoder_state_type(tables, decoder_name, named_prefix, out): | |
| 116 cls_name = '%s%s' % (named_prefix, decoder_name) | |
| 117 out.block_comment( | |
| 118 'Defines a stateless decoder class selector for instructions' | |
| 119 ) | |
| 120 out.block_comment('Define the class decoders used by this decoder state.') | |
| 121 out.enter_block('class %s : DecoderState' % cls_name) | |
| 122 out.visibility('public') | |
| 123 out.comment('Generates an instance of a decoder state.') | |
| 124 out.line('explicit %s();' % cls_name) | |
| 125 out.line('virtual ~%s();' % cls_name) | |
| 126 out.line() | |
| 127 out.comment('Parses the given instruction, returning the decoder to use.') | |
| 128 out.line('virtual const class ClassDecoder ' | |
| 129 '&decode(const Instruction) const;') | |
| 130 out.line() | |
| 131 out.comment('Define the decoders to use in this decoder state') | |
| 132 for t in _table_terminals(tables): | |
| 133 out.line('%s%s %s_instance_;' % (named_prefix, t, t)) | |
| 134 out.line() | |
| 135 out.visibility('private') | |
| 136 out.comment("Don't allow the following!") | |
| 137 out.line('explicit %s(const %s&);' % (cls_name, cls_name)) | |
| 138 out.line('void operator=(const %s&);' % cls_name) | |
| 139 out.exit_block(';') | |
| 140 out.line() | |
| 141 | |
| 142 def _generate_prototypes(tables, decoder_name, named_prefix, out): | |
| 143 out.block_comment('Prototypes for static table-matching functions.') | |
| 144 for t in tables: | |
| 145 | |
| 146 out.line('static inline const ClassDecoder &decode_%s(' % t.name) | |
| 147 out.line(' const Instruction insn, const %s%s *state);' % | |
| 148 (named_prefix, decoder_name)) | |
| 149 out.line() | |
| 150 | |
| 151 def _generate_implementations(tables, decoder_name, named_prefix, out): | |
| 152 out.block_comment('Table-matching function implementations.') | |
| 153 for t in tables: | |
| 154 out.line() | |
| 155 _generate_table(t, decoder_name, named_prefix, out) | |
| 156 out.line() | |
| 157 | |
| 158 def _generate_constructors(tables, decoder_name, named_prefix, out): | |
| 159 out.enter_constructor_header('%s%s::%s%s()' % (named_prefix, decoder_name, | |
| 160 named_prefix, decoder_name)) | |
| 161 out.line('DecoderState()') | |
| 162 for t in _table_terminals(tables): | |
| 163 out.line(', %s_instance_()' % t) | |
| 164 out.exit_constructor_header() | |
| 165 out.enter_block() | |
| 166 out.exit_block() | |
| 167 out.line() | |
| 168 out.enter_block('%s%s::~%s%s()' % (named_prefix, decoder_name, | |
| 169 named_prefix, decoder_name)) | |
| 170 out.exit_block() | |
| 171 out.line() | |
| 172 | |
| 173 def _generate_entry_point(decoder_name, named_prefix, initial_table_name, out): | |
| 174 out.enter_block( | |
| 175 'const ClassDecoder &%s%s::decode(const Instruction insn) const' % | |
| 176 (named_prefix, decoder_name)) | |
| 177 out.line('return decode_%s(insn, this);' | |
| 178 % initial_table_name) | |
| 179 out.exit_block() | |
| 180 out.line() | |
| 181 | |
| 182 | |
| 183 def _generate_table(table, decoder_name, named_prefix, out): | |
| 184 """Generates the implementation of a single table.""" | |
| 185 out.block_comment( | |
| 186 'Implementation of table %s.' % table.name, | |
| 187 'Specified by: %s.' % table.citation | |
| 188 ) | |
| 189 out.line('static inline const ClassDecoder &decode_%s(' %table.name) | |
| 190 out.enter_block(' const Instruction insn, const %s%s *state)' % | |
| 191 (named_prefix, decoder_name)) | |
| 192 | |
| 193 optimized = dgen_opt.optimize_rows(table.rows) | |
| 194 print ("Table %s: %d rows minimized to %d" | |
| 195 % (table.name, len(table.rows), len(optimized))) | |
| 196 for row in sorted(optimized): | |
| 197 exprs = ["(%s)" % p.to_c_expr('insn') for p in row.patterns] | |
| 198 out.enter_block('if (%s)' % ' && '.join(exprs)) | |
| 199 | |
| 200 if row.action.startswith('='): | |
| 201 _generate_terminal(row.action[1:], out) | |
| 202 elif row.action.startswith('->'): | |
| 203 _generate_table_change(row.action[2:], out) | |
| 204 else: | |
| 205 raise Exception('Bad table action: %s' % row.action) | |
| 206 | |
| 207 out.exit_block() | |
| 208 out.line() | |
| 209 | |
| 210 _generate_safety_net(table, out) | |
| 211 out.exit_block() | |
| 212 | |
| 213 def _generate_terminal(name, out): | |
| 214 out.line('return state->%s_instance_;' % name) | |
| 215 | |
| 216 def _generate_table_change(name, out): | |
| 217 out.line('return decode_%s(insn, state);' % name) | |
| 218 | |
| 219 def _generate_safety_net(table, out): | |
| 220 out.line('// Catch any attempt to fall through...') | |
| 221 out.line('fprintf(stderr, "TABLE IS INCOMPLETE: %s could not parse %%08X",' | |
| 222 'insn.bits(31,0));' % table.name) | |
| 223 _generate_terminal('Forbidden', out) | |
| 224 | |
| 225 | |
| 226 class COutput(object): | |
| 227 """Provides nicely-formatted C++ output.""" | |
| 228 | |
| 229 def __init__(self, out): | |
| 230 self._out = out | |
| 231 self._indent = 0 | |
| 232 | |
| 233 def line(self, str = ''): | |
| 234 self._out.write(self._tabs()) | |
| 235 self._out.write(str + '\n') | |
| 236 | |
| 237 def enter_constructor_header(self, headline): | |
| 238 self.line(headline + ' :') | |
| 239 self._indent += 1 | |
| 240 | |
| 241 def exit_constructor_header(self): | |
| 242 self._indent -= 1 | |
| 243 | |
| 244 def visibility(self, spec): | |
| 245 self._indent -= 1 | |
| 246 self.line(' %s:' % spec) | |
| 247 self._indent += 1 | |
| 248 | |
| 249 def comment(self, line_comment): | |
| 250 self.line('// %s' % line_comment) | |
| 251 | |
| 252 def enter_block(self, headline=''): | |
| 253 self.line(headline + ' {') | |
| 254 self._indent += 1 | |
| 255 | |
| 256 def exit_block(self, footer = ''): | |
| 257 self._indent -= 1 | |
| 258 self.line('}' + footer) | |
| 259 | |
| 260 def block_comment(self, *lines): | |
| 261 self.line('/*') | |
| 262 for s in lines: | |
| 263 self.line(' * ' + s) | |
| 264 self.line(' */') | |
| 265 | |
| 266 def _tabs(self): | |
| 267 return ' ' * self._indent | |
| 268 | |
| 269 | |
| 270 def each_index_pair(sequence): | |
| 271 """Utility method: Generates each unique index pair in sequence.""" | |
| 272 for i in range(0, len(sequence)): | |
| 273 for j in range(i + 1, len(sequence)): | |
| 274 yield (i, j) | |
| OLD | NEW |