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. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 import dgen_opt | 12 import dgen_opt |
| 13 | 13 |
| 14 def generate_decoder_h(tables, decoder_name, filename, named_decoders, out): | 14 def generate_decoder_h(tables, decoder_name, filename, named_decoders, out): |
| 15 """Entry point to the decoder for .h file. | 15 """Entry point to the decoder for .h file. |
| 16 | 16 |
| 17 Args: | 17 Args: |
| 18 tables: list of Table objects to process. | 18 tables: list of Table objects to process. |
| 19 decoder_name: The name of the decoder state to build. | 19 decoder_name: The name of the decoder state to build. |
| 20 filename: The (localized) name for the .h file. | 20 filename: The (localized) name for the .h file. |
| 21 named_decoders: If true, generate a decoder state with named instances. | 21 named_decoders: If true, generate a decoder state with named instances. |
| 22 out: a COutput object to write to. | 22 out: a COutput object to write to. |
| 23 """ | 23 """ |
| 24 if len(tables) == 0: raise Exception('No tables provided.') | 24 if len(tables) == 0: raise Exception('No tables provided.') |
| 25 | 25 |
| 26 ifdef_name = _generate_ifdef_name(filename) | 26 ifdef_name = _generate_ifdef_name(filename) |
| 27 named_prefix = '' | |
| 28 if named_decoders: | |
| 29 named_prefix = 'Named' | |
| 30 | 27 |
| 31 _generate_header(out) | 28 _generate_header(out) |
| 32 out.line() | 29 if named_decoders: |
|
robertm
2012/04/11 01:28:43
this is getting really hard to understand, maybe i
Karl
2012/04/16 23:18:10
Done.
| |
| 30 _generate_not_tcb(out) | |
| 33 out.line("#ifndef %s" % ifdef_name) | 31 out.line("#ifndef %s" % ifdef_name) |
| 34 out.line("#define %s" % ifdef_name) | 32 out.line("#define %s" % ifdef_name) |
| 35 out.line() | 33 out.line() |
| 36 out.line('#include "native_client/src/trusted/validator_arm/decode.h"') | 34 out.line('#include "native_client/src/trusted/validator_arm/decode.h"') |
| 37 out.line() | 35 if named_decoders: |
| 38 out.line('namespace nacl_arm_dec {') | 36 out.line('#include "native_client/src/trusted/validator_arm/' |
| 37 'named_class_decoder.h"') | |
| 39 out.line() | 38 out.line() |
| 40 if named_decoders: | 39 if named_decoders: |
| 41 _generate_named_decoder_classes(tables, named_prefix, out) | 40 _generate_rule_classes(tables, out) |
| 42 _generate_decoder_state_type(tables, decoder_name, named_prefix, out) | 41 out.line('namespace nacl_arm_%s {' % ('test' if named_decoders else 'dec')) |
| 42 out.line() | |
| 43 if named_decoders: | |
| 44 _generate_named_decoder_classes(tables, out) | |
| 45 _generate_decoder_state_type(tables, decoder_name, named_decoders, out) | |
| 43 out.line('} // namespace') | 46 out.line('} // namespace') |
| 44 out.line("#endif // %s" % ifdef_name) | 47 out.line("#endif // %s" % ifdef_name) |
| 45 | 48 |
| 46 | 49 |
| 47 def generate_decoder_cc(tables, decoder_name, filename, named_decoders, out): | 50 def generate_decoder_cc(tables, decoder_name, filename, named_decoders, out): |
| 48 """Entry point to the decoder for .cc file | 51 """Entry point to the decoder for .cc file |
| 49 | 52 |
| 50 Args: | 53 Args: |
| 51 tables: list of Table objects to process. | 54 tables: list of Table objects to process. |
| 52 decoder_name: The name of the decoder state to build. | 55 decoder_name: The name of the decoder state to build. |
| 53 filename: The (localized) name for the .h file. | 56 filename: The (localized) name for the .h file. |
| 54 named_decoders: If true, generate a decoder state with named instances. | 57 named_decoders: If true, generate a decoder state with named instances. |
| 55 out: a COutput object to write to. | 58 out: a COutput object to write to. |
| 56 """ | 59 """ |
| 57 if len(tables) == 0: raise Exception('No tables provided.') | 60 if len(tables) == 0: raise Exception('No tables provided.') |
| 58 | 61 |
| 59 named_prefix = '' | 62 _generate_header(out) |
| 60 if named_decoders: | 63 if named_decoders: |
| 61 named_prefix = 'Named' | 64 _generate_not_tcb(out) |
| 62 | |
| 63 _generate_header(out) | |
| 64 out.line() | |
| 65 out.line('#include "%s"' % (filename[:-2] + 'h')) | 65 out.line('#include "%s"' % (filename[:-2] + 'h')) |
| 66 out.line(); | 66 out.line(); |
| 67 out.line('#include <stdio.h>') | 67 out.line('#include <stdio.h>') |
| 68 out.line() | 68 out.line() |
| 69 out.line('namespace nacl_arm_dec {') | 69 if named_decoders: |
| 70 out.line('using nacl_arm_dec::ClassDecoder;') | |
| 71 out.line('using nacl_arm_dec::Instruction;') | |
| 72 out.line() | |
| 73 out.line('namespace nacl_arm_%s {' % ('test' if named_decoders else 'dec')) | |
| 70 out.line() | 74 out.line() |
| 71 if named_decoders: | 75 if named_decoders: |
| 72 _generate_named_decoder_classes_impls(tables, named_prefix, out) | 76 _generate_named_decoder_classes_impls(tables, out) |
| 73 _generate_prototypes(tables, decoder_name, named_prefix, out) | 77 _generate_implementations(tables, decoder_name, named_decoders, out) |
| 74 _generate_implementations(tables, decoder_name, named_prefix, out) | 78 _generate_constructors(tables, decoder_name, named_decoders, out) |
| 75 _generate_constructors(tables, decoder_name, named_prefix, out) | 79 _generate_entry_point(decoder_name, named_decoders, tables[0].name, out) |
| 76 _generate_entry_point(decoder_name, named_prefix, tables[0].name, out) | |
| 77 out.line('} // namespace') | 80 out.line('} // namespace') |
| 78 | 81 |
| 79 | 82 |
| 83 def generate_tests_cc(tables, out): | |
| 84 if len(tables) == 0: raise Exception('No tables provided.') | |
| 85 | |
| 86 _generate_header(out) | |
| 87 _generate_not_tcb(out) | |
| 88 out.line('#include "gtest/gtest.h"') | |
| 89 out.line('#include "native_client/src/trusted/validator_arm/' | |
| 90 'inst_classes_testers.h"') | |
| 91 out.line() | |
| 92 out.line('namespace nacl_arm_test {') | |
| 93 out.line() | |
| 94 _generate_rule_testers(tables, out) | |
| 95 _generate_tester(out) | |
| 96 _generate_test_patterns(tables, out) | |
| 97 out.line('} // namespace') | |
| 98 out.line() | |
| 99 _generate_test_main(out) | |
| 100 | |
| 101 def _named(name, named_decoders): | |
| 102 """ Adds 'Named' prefix to name if named_decoders """ | |
| 103 return 'Named' + name if named_decoders else name | |
| 104 | |
| 80 def _generate_ifdef_name(filename): | 105 def _generate_ifdef_name(filename): |
| 106 """ Generates the ifdef name to use for the given filename""" | |
| 81 return filename.replace("/", "_").replace(".", "_").upper() + "_" | 107 return filename.replace("/", "_").replace(".", "_").upper() + "_" |
| 82 | 108 |
| 109 def _internalize_component(components): | |
| 110 """ Removes an element from components, internalizes the value, and | |
| 111 returns the internalized value" | |
| 112 """ | |
| 113 if components: | |
| 114 c = components[0] | |
| 115 components.remove(c) | |
| 116 return None if c == "None" else c | |
| 117 | |
| 118 def _terminal_components(terminal): | |
| 119 """ Returns the components of a terminal. That is, a four tuple | |
| 120 of the form: | |
| 121 (class, rule_name, pattern, constraints) | |
| 122 where | |
| 123 class - The decoder class to return. | |
| 124 rule_name - The arm rule that applies | |
| 125 pattern - The bit pattern associated with the arm rule | |
| 126 constrainst - Name defining constraints to apply. | |
| 127 """ | |
| 128 components = terminal.split() | |
| 129 cls = _internalize_component(components) | |
| 130 rule = _internalize_component(components) | |
| 131 pattern = _internalize_component(components) | |
| 132 constraints = _internalize_component(components) | |
| 133 return (cls, rule, pattern, constraints) | |
| 134 | |
| 135 def _terminal_name(terminal, named_decoders = False): | |
| 136 """ Returns the terminal name from the terminal action components, | |
| 137 unless named_decoders is true and there is a rule name in the | |
| 138 action components. In the latter case, the rule name is returned. | |
| 139 """ | |
| 140 components = _terminal_components(terminal) | |
| 141 return components[1] if named_decoders and components[1] else components[0] | |
| 142 | |
| 143 def _table_terminals(tables): | |
| 144 """ Returns the set of terminals (i.e. actions) defined in the given | |
| 145 tables. | |
| 146 """ | |
| 147 terminals = set() | |
| 148 for t in tables: | |
| 149 for r in t.rows: | |
| 150 if r.action.startswith('='): | |
| 151 terminals.add(r.action[1:]) | |
| 152 return terminals | |
| 153 | |
| 154 def _named_terminals(tables, named_decoders): | |
| 155 """ Returns the set of (named) class names in the given tables. """ | |
| 156 terminals = set() | |
| 157 for t in _table_terminals(tables): | |
| 158 terminals.add(_terminal_name(t, named_decoders)) | |
| 159 return terminals | |
| 160 | |
| 83 def _generate_header(out): | 161 def _generate_header(out): |
| 84 out.block_comment( | 162 out.block_comment( |
| 85 'Copyright 2012 The Native Client Authors. All rights reserved.', | 163 'Copyright 2012 The Native Client Authors. All rights reserved.', |
| 86 'Use of this source code is governed by a BSD-style license that can', | 164 'Use of this source code is governed by a BSD-style license that can', |
| 87 'be found in the LICENSE file.', | 165 'be found in the LICENSE file.', |
| 88 ) | 166 ) |
| 89 out.line() | 167 out.line() |
| 90 out.block_comment('DO NOT EDIT: GENERATED CODE') | 168 out.block_comment('DO NOT EDIT: GENERATED CODE') |
| 169 out.line() | |
| 91 | 170 |
| 92 def _table_terminals(tables): | 171 def _generate_not_tcb(out): |
| 93 terminals = set() | 172 out.line('#ifndef NACL_TRUSTED_BUT_NOT_TCB') |
| 94 for t in tables: | 173 out.line('#error("This file is not meant for use in the TCB")') |
| 95 for r in t.rows: | 174 out.line('#endif') |
| 96 if r.action.startswith('='): | 175 out.line() |
| 97 terminals.add(r.action[1:]) | |
| 98 return terminals | |
| 99 | 176 |
| 100 def _generate_named_decoder_classes(tables, named_prefix, out): | 177 def _generate_rule_class(term, out): |
| 101 for t in _table_terminals(tables): | 178 """ Generates an instance class for the rule name of the terminal, |
| 102 out.enter_block('struct %s%s : public %s' % (named_prefix, t, t)) | 179 if the terminal has one. This ensures that it will have a different |
| 103 out.line('virtual ~%s%s() {}' % (named_prefix, t)) | 180 name than the terminal class, making it easier to identify rules |
| 104 out.line('virtual const char* name() const;') | 181 that overlap. |
| 182 """ | |
| 183 components = _terminal_components(term) | |
| 184 if components[1]: | |
| 185 out.enter_block('class %s : public %s' % (components[1], components[0])) | |
| 186 out.visibility('public') | |
| 187 out.line('virtual ~%s() {}' % components[1]) | |
| 105 out.exit_block(';') | 188 out.exit_block(';') |
| 106 out.line() | 189 out.line() |
| 107 | 190 |
| 108 def _generate_named_decoder_classes_impls(tables, named_prefix, out): | 191 def _generate_rule_classes(tables, out): |
| 192 """ Generates an instance class for each rule name defined in the tables. | |
| 193 This ensures that each rule name will define a decoder class with the | |
| 194 same name as the rule, making test errors easier to understand. | |
| 195 """ | |
| 196 out.block_comment('Define rule decoder classes') | |
| 197 out.line('namespace nacl_arm_dec {'); | |
| 198 out.line() | |
| 109 for t in _table_terminals(tables): | 199 for t in _table_terminals(tables): |
| 110 out.enter_block('const char* %s%s::name() const' % (named_prefix, t)); | 200 _generate_rule_class(t, out) |
| 111 out.line('return "%s";' % t) | 201 out.line('} // namespace nacl_arm_dec') |
| 202 out.line() | |
| 203 | |
| 204 def _generate_named_decoder_classes(tables, out): | |
| 205 """ Generates a named decoder class for each type of generated | |
| 206 decoder class in the decoder state. | |
| 207 """ | |
| 208 out.block_comment('Define name class decoders for each class decoder') | |
| 209 out.line() | |
| 210 for t in _named_terminals(tables, True): | |
| 211 out.enter_block('class %s : public NamedClassDecoder' % | |
|
robertm
2012/04/11 01:28:43
this would also benefit from a template
Karl
2012/04/16 23:18:10
Done.
| |
| 212 _named(t, True)) | |
| 213 out.visibility('public'); | |
| 214 out.line('%s();' % _named(t, True)) | |
| 215 out.line('virtual ~%s() {}' % _named(t, True)) | |
| 216 out.visibility('private') | |
| 217 out.line('nacl_arm_dec::%s named_decoder_;' % t) | |
| 218 out.exit_block(';') | |
| 219 out.line() | |
| 220 | |
| 221 def _generate_named_decoder_classes_impls(tables, out): | |
| 222 """ Generates method implementations for each generated | |
| 223 named decoder class | |
| 224 """ | |
| 225 for t in _named_terminals(tables, True): | |
| 226 out.enter_constructor_header('%s::%s()' % | |
| 227 (_named(t, True), | |
| 228 _named(t, True))) | |
| 229 out.line('NamedClassDecoder(named_decoder_, "%s")' % t) | |
| 230 out.exit_constructor_header() | |
| 231 out.enter_block() | |
| 112 out.exit_block() | 232 out.exit_block() |
| 113 out.line() | 233 out.line() |
| 114 | 234 |
| 115 def _generate_decoder_state_type(tables, decoder_name, named_prefix, out): | 235 def _generate_decoder_state_type(tables, decoder_name, named_decoders, out): |
| 116 cls_name = '%s%s' % (named_prefix, decoder_name) | 236 """ Generates the deocder state that dispatches the correct class |
| 237 decoder for any instruction. | |
| 238 """ | |
| 117 out.block_comment( | 239 out.block_comment( |
| 118 'Defines a stateless decoder class selector for instructions' | 240 'Defines a stateless decoder class selector for instructions' |
| 119 ) | 241 ) |
| 120 out.block_comment('Define the class decoders used by this decoder state.') | 242 out.enter_block('class %s : nacl_arm_dec::DecoderState' % |
| 121 out.enter_block('class %s : DecoderState' % cls_name) | 243 _named(decoder_name, named_decoders)) |
| 122 out.visibility('public') | 244 out.visibility('public') |
| 123 out.comment('Generates an instance of a decoder state.') | 245 out.block_comment('Generates an instance of a decoder state.') |
| 124 out.line('explicit %s();' % cls_name) | 246 out.line('explicit %s();' % _named(decoder_name, named_decoders)) |
| 125 out.line('virtual ~%s();' % cls_name) | 247 out.line('virtual ~%s();' % _named(decoder_name, named_decoders)) |
| 126 out.line() | 248 out.line() |
| 127 out.comment('Parses the given instruction, returning the decoder to use.') | 249 out.block_comment( |
| 128 out.line('virtual const class ClassDecoder ' | 250 'Parses the given instruction, returning the decoder to use.') |
| 129 '&decode(const Instruction) const;') | 251 if named_decoders: |
| 130 out.line() | 252 out.line('const NamedClassDecoder &decode_named(' |
| 131 out.comment('Define the decoders to use in this decoder state') | 253 ' const nacl_arm_dec::Instruction) const;') |
| 132 for t in _table_terminals(tables): | 254 out.line('virtual const class nacl_arm_dec::ClassDecoder') |
| 133 out.line('%s%s %s_instance_;' % (named_prefix, t, t)) | 255 out.line(' &decode(const nacl_arm_dec::Instruction) const;') |
| 134 out.line() | 256 if not named_decoders: |
| 135 out.visibility('private') | 257 out.line() |
| 136 out.comment("Don't allow the following!") | 258 out.visibility('private') |
| 137 out.line('explicit %s(const %s&);' % (cls_name, cls_name)) | 259 _generate_fields(tables, named_decoders, out) |
| 138 out.line('void operator=(const %s&);' % cls_name) | 260 if named_decoders: |
| 261 out.line() | |
| 262 out.visibility('private') | |
| 263 _generate_prototypes(tables, named_decoders, out) | |
| 139 out.exit_block(';') | 264 out.exit_block(';') |
| 140 out.line() | 265 out.line() |
| 141 | 266 |
| 142 def _generate_prototypes(tables, decoder_name, named_prefix, out): | 267 def _generate_fields(tables, named_decoders, out): |
| 268 """ Generates an instance field for each class decoder used by | |
| 269 the decoder state, so that only one instance exists. | |
| 270 """ | |
| 271 out.block_comment('Define the class decoders used by this decoder state.') | |
| 272 for t in _named_terminals(tables, named_decoders): | |
| 273 out.line('const %s %s_instance_;' % (_named(t, named_decoders), t)) | |
| 274 out.line() | |
| 275 | |
| 276 def _generate_prototypes(tables, named_decoders, out): | |
| 277 """ Generate parsing method prototypes for the decoder state. """ | |
| 143 out.block_comment('Prototypes for static table-matching functions.') | 278 out.block_comment('Prototypes for static table-matching functions.') |
| 144 for t in tables: | 279 for t in tables: |
| 145 | 280 out.line('inline const %s &decode_%s(' |
| 146 out.line('static inline const ClassDecoder &decode_%s(' % t.name) | 281 ' const nacl_arm_dec::Instruction insn) const;' |
| 147 out.line(' const Instruction insn, const %s%s *state);' % | 282 % (_named('ClassDecoder', named_decoders), t.name)) |
| 148 (named_prefix, decoder_name)) | |
| 149 out.line() | 283 out.line() |
| 150 | 284 |
| 151 def _generate_implementations(tables, decoder_name, named_prefix, out): | 285 def _generate_implementations(tables, decoder_name, named_decoders, out): |
| 286 """ Generate bodies for each parsing method defined for the | |
| 287 decoder state. | |
| 288 """ | |
| 152 out.block_comment('Table-matching function implementations.') | 289 out.block_comment('Table-matching function implementations.') |
| 153 for t in tables: | 290 for t in tables: |
| 154 out.line() | 291 out.line() |
| 155 _generate_table(t, decoder_name, named_prefix, out) | 292 _generate_table(t, decoder_name, named_decoders, out) |
| 156 out.line() | |
| 157 | 293 |
| 158 def _generate_constructors(tables, decoder_name, named_prefix, out): | 294 def _generate_constructors(tables, decoder_name, named_decoders, out): |
| 159 out.enter_constructor_header('%s%s::%s%s()' % (named_prefix, decoder_name, | 295 """ Generate the constructor/destructor for the decoder state.""" |
| 160 named_prefix, decoder_name)) | 296 out.enter_constructor_header('%s::%s()' % |
| 297 (_named(decoder_name, named_decoders), | |
| 298 _named(decoder_name, named_decoders))) | |
| 161 out.line('DecoderState()') | 299 out.line('DecoderState()') |
| 162 for t in _table_terminals(tables): | 300 for t in _named_terminals(tables, named_decoders): |
| 163 out.line(', %s_instance_()' % t) | 301 out.line(', %s_instance_()' % t) |
| 164 out.exit_constructor_header() | 302 out.exit_constructor_header() |
| 165 out.enter_block() | 303 out.enter_block() |
| 166 out.exit_block() | 304 out.exit_block() |
| 167 out.line() | 305 out.line() |
| 168 out.enter_block('%s%s::~%s%s()' % (named_prefix, decoder_name, | 306 out.enter_block('%s::~%s()' % (_named(decoder_name, named_decoders), |
| 169 named_prefix, decoder_name)) | 307 _named(decoder_name, named_decoders))) |
| 170 out.exit_block() | 308 out.exit_block() |
| 171 out.line() | 309 out.line() |
| 172 | 310 |
| 173 def _generate_entry_point(decoder_name, named_prefix, initial_table_name, out): | 311 def _generate_entry_point(decoder_name, named_decoders, |
| 312 initial_table_name, out): | |
| 313 """ Generate method bodies for the top-level parsing method(s) of | |
| 314 the decoder state. | |
| 315 """ | |
| 174 out.enter_block( | 316 out.enter_block( |
| 175 'const ClassDecoder &%s%s::decode(const Instruction insn) const' % | 317 'const ClassDecoder &%s::decode(const Instruction insn) const' % |
| 176 (named_prefix, decoder_name)) | 318 _named(decoder_name, named_decoders)) |
| 177 out.line('return decode_%s(insn, this);' | 319 if named_decoders: |
| 178 % initial_table_name) | 320 out.line('return decode_named(insn).named_decoder();') |
| 321 else: | |
| 322 out.line('return decode_%s(insn);' % initial_table_name) | |
| 179 out.exit_block() | 323 out.exit_block() |
| 180 out.line() | 324 out.line() |
| 325 if named_decoders: | |
| 326 out.line('const NamedClassDecoder &%s::decode_named(' % | |
| 327 _named(decoder_name, True)) | |
| 328 out.enter_block(' const Instruction insn) const') | |
| 329 out.line('return decode_%s(insn);' % initial_table_name) | |
| 330 out.exit_block() | |
| 331 out.line() | |
| 181 | 332 |
| 182 | 333 def _generate_table(table, decoder_name, named_decoders, out): |
| 183 def _generate_table(table, decoder_name, named_prefix, out): | 334 """Generates the implementation of a single parsing table.""" |
| 184 """Generates the implementation of a single table.""" | |
| 185 out.block_comment( | 335 out.block_comment( |
| 186 'Implementation of table %s.' % table.name, | 336 'Implementation of table %s.' % table.name, |
| 187 'Specified by: %s.' % table.citation | 337 'Specified by: %s.' % table.citation |
| 188 ) | 338 ) |
| 189 out.line('static inline const ClassDecoder &decode_%s(' %table.name) | 339 out.enter_block('const %s &%s::decode_%s(const Instruction insn) const' % |
| 190 out.enter_block(' const Instruction insn, const %s%s *state)' % | 340 (_named('ClassDecoder', named_decoders), |
| 191 (named_prefix, decoder_name)) | 341 _named(decoder_name, named_decoders), |
| 342 table.name)) | |
| 192 | 343 |
| 193 optimized = dgen_opt.optimize_rows(table.rows) | 344 # If not named decoder classes, optimize as much as possible. That |
| 345 # is, only consider the decoder class name when merging. If generating | |
| 346 # named decoder classes, separate base on rule name as well. | |
| 347 num_action_cols = 2 if named_decoders else 1 | |
| 348 optimized = dgen_opt.optimize_rows(table.rows_filtered(num_action_cols)) | |
| 194 print ("Table %s: %d rows minimized to %d" | 349 print ("Table %s: %d rows minimized to %d" |
| 195 % (table.name, len(table.rows), len(optimized))) | 350 % (table.name, len(table.rows), len(optimized))) |
| 196 for row in sorted(optimized): | 351 for row in sorted(optimized): |
| 197 exprs = ["(%s)" % p.to_c_expr('insn') for p in row.patterns] | 352 exprs = ["(%s)" % p.to_c_expr('insn') for p in row.patterns] |
| 198 out.enter_block('if (%s)' % ' && '.join(exprs)) | 353 out.enter_block('if (%s)' % ' && '.join(exprs)) |
| 199 | 354 |
| 200 if row.action.startswith('='): | 355 if row.action.startswith('='): |
| 201 _generate_terminal(row.action[1:], out) | 356 _generate_terminal(_terminal_name(row.action[1:], |
| 357 named_decoders), | |
| 358 out) | |
| 202 elif row.action.startswith('->'): | 359 elif row.action.startswith('->'): |
| 203 _generate_table_change(row.action[2:], out) | 360 _generate_table_change(row.action[2:], out) |
| 204 else: | 361 else: |
| 205 raise Exception('Bad table action: %s' % row.action) | 362 raise Exception('Bad table action: %s' % row.action) |
| 206 | 363 |
| 207 out.exit_block() | 364 out.exit_block() |
| 208 out.line() | 365 out.line() |
| 209 | 366 |
| 210 _generate_safety_net(table, out) | 367 _generate_safety_net(table, out) |
| 211 out.exit_block() | 368 out.exit_block() |
| 369 out.line() | |
| 212 | 370 |
| 213 def _generate_terminal(name, out): | 371 def _generate_terminal(name, out): |
| 214 out.line('return state->%s_instance_;' % name) | 372 out.line('return %s_instance_;' % name) |
| 215 | 373 |
| 216 def _generate_table_change(name, out): | 374 def _generate_table_change(name, out): |
| 217 out.line('return decode_%s(insn, state);' % name) | 375 out.line('return decode_%s(insn);' % name) |
| 218 | 376 |
| 219 def _generate_safety_net(table, out): | 377 def _generate_safety_net(table, out): |
| 220 out.line('// Catch any attempt to fall through...') | 378 out.line('// Catch any attempt to fall through...') |
| 221 out.line('fprintf(stderr, "TABLE IS INCOMPLETE: %s could not parse %%08X",' | 379 out.line('fprintf(stderr, "TABLE IS INCOMPLETE: %s could not parse %%08X",' |
| 222 'insn.bits(31,0));' % table.name) | 380 'insn.bits(31,0));' % table.name) |
| 223 _generate_terminal('Forbidden', out) | 381 _generate_terminal('Forbidden', out) |
| 224 | 382 |
| 383 def _rule_tester(rule): | |
| 384 return '%s_Tester' % rule | |
| 385 | |
| 386 def _rule_base_tester(cls, constraints): | |
| 387 return '%sTester%s' % (cls, (constraints if constraints else '')) | |
| 388 | |
| 389 def _generate_rule_tester(term, out): | |
| 390 components = _terminal_components(term) | |
| 391 cls = components[0] | |
| 392 rule = components[1] | |
| 393 pattern = components[2] | |
| 394 constraints = components[3] | |
| 395 if cls and rule and pattern: | |
| 396 rule_tester = _rule_tester(rule) | |
| 397 rule_base_tester = _rule_base_tester(cls, constraints) | |
| 398 out.line('class %s ' % rule_tester) | |
| 399 out.enter_block(' : public %s' % rule_base_tester) | |
| 400 out.visibility('public') | |
| 401 out.line('%s()' % rule_tester) | |
| 402 out.line(' : %s(' % rule_base_tester) | |
| 403 out.line(' state_.%s_instance_)' % _terminal_name(term, True)) | |
| 404 out.enter_block() | |
| 405 out.exit_block() | |
| 406 out.exit_block(';') | |
| 407 out.line() | |
| 408 | |
| 409 def _generate_rule_testers(tables, out): | |
| 410 out.block_comment('Tester classes for decoder rules') | |
| 411 out.line() | |
| 412 for t in _table_terminals(tables): | |
| 413 _generate_rule_tester(t, out) | |
| 414 | |
| 415 def _generate_tester(out): | |
| 416 out.block_comment('Defines a gtest testing harness for testing', | |
| 417 'Arm32 instructions.') | |
| 418 out.enter_block('class Arm32InstructionTests : public ::testing::Test') | |
| 419 out.visibility('protected') | |
| 420 out.line('Arm32InstructionTests() {}') | |
| 421 out.exit_block(';') | |
| 422 out.line() | |
| 423 | |
| 424 def _generate_test_pattern(term, out): | |
| 425 components = _terminal_components(term) | |
| 426 cls = components[0] | |
| 427 rule = components[1] | |
| 428 pattern = components[2] | |
| 429 if cls and rule and pattern: | |
| 430 rule_tester = _rule_tester(rule) | |
| 431 out.enter_block('TEST_F(Arm32InstructionTests, %s_Test)' % rule_tester) | |
| 432 out.line('%s tester;' % rule_tester) | |
| 433 out.line('tester.Test("%s");' % pattern) | |
| 434 out.exit_block() | |
| 435 out.line() | |
| 436 | |
| 437 def _generate_test_patterns(tables, out): | |
| 438 out.block_comment('Test coverage of rule patterns') | |
| 439 out.line() | |
| 440 for t in _table_terminals(tables): | |
| 441 _generate_test_pattern(t, out) | |
| 442 | |
| 443 def _generate_test_main(out): | |
| 444 out.block_comment('Test driver function.') | |
| 445 out.enter_block('int main(int argc, char *argv[])') | |
| 446 out.line('testing::InitGoogleTest(&argc, argv);') | |
| 447 out.line('return RUN_ALL_TESTS();') | |
| 448 out.exit_block() | |
| 449 | |
| 225 | 450 |
| 226 class COutput(object): | 451 class COutput(object): |
| 227 """Provides nicely-formatted C++ output.""" | 452 """Provides nicely-formatted C++ output.""" |
| 228 | 453 |
| 229 def __init__(self, out): | 454 def __init__(self, out): |
| 230 self._out = out | 455 self._out = out |
| 231 self._indent = 0 | 456 self._indent = 0 |
| 232 | 457 |
| 233 def line(self, str = ''): | 458 def line(self, str = ''): |
| 234 self._out.write(self._tabs()) | 459 self._out.write(self._tabs()) |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 265 | 490 |
| 266 def _tabs(self): | 491 def _tabs(self): |
| 267 return ' ' * self._indent | 492 return ' ' * self._indent |
| 268 | 493 |
| 269 | 494 |
| 270 def each_index_pair(sequence): | 495 def each_index_pair(sequence): |
| 271 """Utility method: Generates each unique index pair in sequence.""" | 496 """Utility method: Generates each unique index pair in sequence.""" |
| 272 for i in range(0, len(sequence)): | 497 for i in range(0, len(sequence)): |
| 273 for j in range(i + 1, len(sequence)): | 498 for j in range(i + 1, len(sequence)): |
| 274 yield (i, j) | 499 yield (i, j) |
| OLD | NEW |