| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # | |
| 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 be | |
| 5 # found in the LICENSE file. | |
| 6 # | |
| 7 | |
| 8 """ | |
| 9 Responsible for generating the testing decoders based on | |
| 10 parsed table representations. | |
| 11 """ | |
| 12 | |
| 13 # This file generates testing code for our class decoder. The decoder | |
| 14 # tables are specifically written to minimize the number of decoder | |
| 15 # classes needed to parse valid ARM instructions. For testing, this is | |
| 16 # a problem. We can't (easily) tell if the intended instruction rules | |
| 17 # of ARM are being met, since there is not a one-to-one mapping from | |
| 18 # class decoders to rules. | |
| 19 # | |
| 20 # For example, consider the following two rows (from armv7.table): | |
| 21 # | |
| 22 # | 0011x - = Binary4RegisterShiftedOp | |
| 23 # Rsb_Rule_144_A1_P288 | |
| 24 # cccc0000011snnnnddddssss0tt1mmmm | |
| 25 # RegsNotPc | |
| 26 # | 0100x - = Binary4RegisterShiftedOp | |
| 27 # Add_Rule_7_A1_P26 | |
| 28 # cccc0000100snnnnddddssss0tt1mmmm | |
| 29 # RegsNotPc | |
| 30 # | |
| 31 # Both rows state to return a Binary4RegisterShiftedOp class decoder. | |
| 32 # The sequence of four symbols correspond to (in order presented): | |
| 33 # | |
| 34 # name - The name of the class decoder to use in sel_ldr | |
| 35 # rule - A unique name identifying the rule from the manual that | |
| 36 # defines what the selected class decoder is to decode. | |
| 37 # pattern - The sequence of bits defines by the rule (above) | |
| 38 # constraints - Any additional constraints assumed by the rule. | |
| 39 # | |
| 40 # All but the name is optional. The remaining fields provide | |
| 41 # additional documentation and information for testing (which is | |
| 42 # used by this file). | |
| 43 # | |
| 44 # If these two rows had a mergable bit pattern (which they do not), | |
| 45 # these rows would still not mergable since the actions are | |
| 46 # different. However, for sel_ldr, they both state to use a | |
| 47 # Binary4RegisterShiftedOp. The remaining identifiers are added data | |
| 48 # for testing only. | |
| 49 # | |
| 50 # We fix this by defining a notion of "action_filter" where one can | |
| 51 # choose to keep only those fields that are applicable. For sel_ldr, | |
| 52 # it's only 'name'. For testing, it will include other fields, | |
| 53 # depending on the context. | |
| 54 # | |
| 55 # Note: The current ARM instruction table has both new and old | |
| 56 # actions. Old actions only define the 'InstClass' entry. If the | |
| 57 # remaining fields are omitted, the corresponding testing for those | |
| 58 # entries are omitted. | |
| 59 # | |
| 60 # Note: See dgen_decoder_output.py for more details on how we build a | |
| 61 # decoder for sel_ldr. | |
| 62 # | |
| 63 # For testing, we would like to know the specific instruction rule | |
| 64 # that was being tested. Further, we would like to know what | |
| 65 # instruction rule was chosen for each decoder class selection made by | |
| 66 # the parse tables. To do this, we do two levels of wrapping. | |
| 67 # | |
| 68 # This file generates a set of wrapper classes, each a subclass of | |
| 69 # NamedClassDecoder. One is generated for each InstClass needed by | |
| 70 # sel_ldr (i.e. only the 'name' field). These named classes correspond | |
| 71 # to what sel_ldr will select. | |
| 72 # | |
| 73 # The named version of each named InstClass is: | |
| 74 # | |
| 75 # class NamedInstClass : public NamedClassDecoder { | |
| 76 # public: | |
| 77 # inline NamedInstClass() | |
| 78 # : NamedClassDecoder(decoder_, "InstClass") | |
| 79 # {} | |
| 80 # virtual ~NamedInstClass() {} | |
| 81 # protected: | |
| 82 # explicit inline NamedInstClass(const char* name) | |
| 83 # : NamedClassDecoder(decoder_, name) {} | |
| 84 # private: | |
| 85 # Binary3RegisterShiftedTest decoder_; | |
| 86 #}; | |
| 87 # | |
| 88 # This makes sure that each decoder class can be identified using a | |
| 89 # separate class decoder. The public constructor is for table rows | |
| 90 # that don't have rule names. The protected constructor is for table | |
| 91 # rows that have a rule name, and will be a subclass of this class. | |
| 92 # The class defined for rows with a Rule name is: | |
| 93 # | |
| 94 # class NamedRuleInstClass : public NamedInstClass { | |
| 95 # public: | |
| 96 # inline NamedRuleInstClass() | |
| 97 # : NamedInstClass("RuleInstClass") | |
| 98 # {} | |
| 99 # virtual ~NamedRuleInstClass() {} | |
| 100 #}; | |
| 101 # | |
| 102 # The base class for NamedClassDecoder is specified in | |
| 103 # "named_class_decoder.h". This file defines a class that takes a | |
| 104 # ClassDecoder (reference) C and a print name NAME, and builds a | |
| 105 # corresponding ClassDecoder that acts like C, but will print out | |
| 106 # NAME. The behaviour of C is maintained by dispatching each virtual | |
| 107 # on the NamedClassDecoder to the corresponding virtual on C. | |
| 108 # | |
| 109 # We then define the class decoder Decoder, by defining a derived | |
| 110 # instance of DecoderState as follows: | |
| 111 # | |
| 112 # class NamedDecoder : DecoderState { | |
| 113 # public: | |
| 114 # explicit NamedDecoder(); | |
| 115 # virtual ~NamedDecoder(); | |
| 116 # const NamedClassDecoder& decode_named(const Instruction) const; | |
| 117 # virtual const ClassDecoder& decode(const Instruction) const; | |
| 118 # ... | |
| 119 # }; | |
| 120 # | |
| 121 # The method decode is the expected API for the NamedDecoder, which is | |
| 122 # an instance of DecoderState (defined in decode.h). The method | |
| 123 # decode_named is the same, but returns NamedClassDecoder's so that | |
| 124 # good error messages can be generated by the test harnesses for | |
| 125 # ClassDecoder's (see decoder_tester.h for more details on | |
| 126 # ClassDecoder test harnesses). | |
| 127 # | |
| 128 # To the NamedDecoder, we add a constant field NamedClassDecoder for | |
| 129 # each possible class decoder method decode_named could return, or | |
| 130 # that we could use in automatically generated tests. These fields | |
| 131 # allow us to only create the corresponding decoder classes once | |
| 132 # (during constructor initialization). | |
| 133 # | |
| 134 # Finally, we add a method corresponding to each defined decoder | |
| 135 # table. The forms of these decoders is: | |
| 136 # | |
| 137 # inline const NamedClassDecoder& decode_TABLE( | |
| 138 # const nacl_arm_dec::Instruction insn) const; | |
| 139 # | |
| 140 # Each of these methods are defined as inline methods so that they can | |
| 141 # be optimized away in the corresponding top level methods (i.e. | |
| 142 # decode_named and decode). | |
| 143 # | |
| 144 # For testing, there are three files generated: | |
| 145 # | |
| 146 # decoder_named_classes.h | |
| 147 # decoder_named_decoder.h | |
| 148 # decoder_named.cc | |
| 149 # decoder_tests.cc | |
| 150 # | |
| 151 # File decoder_named_classes.h defines the class declarations for the | |
| 152 # generated Rule classes, and named class decoder classes. File | |
| 153 # decoder_named_decoder.h defines the decoder class NamedDecoder | |
| 154 # (discussed above). decoder_named.cc contains the corresponding | |
| 155 # implementations of the constructors and methods of these classes. | |
| 156 # | |
| 157 # decoder_tests.cc generates an automatic test harness executable, | |
| 158 # that will test each instruction Rule. Each test generates all | |
| 159 # possible matches the the corresponding Pattern of the table rule, | |
| 160 # and calls the corresponding tester associated with the class decoder | |
| 161 # of that row. By default, the tester is presumed to be named. | |
| 162 # | |
| 163 # InstClassTester | |
| 164 # | |
| 165 # If the row defines a Constraints identifier, then the tester | |
| 166 # | |
| 167 # InstClassTesterConstraints | |
| 168 # | |
| 169 # is used instead. | |
| 170 | |
| 171 import dgen_opt | |
| 172 import dgen_output | |
| 173 | |
| 174 # Defines the header for decoder_named_classes.h | |
| 175 NAMED_CLASSES_H_HEADER=""" | |
| 176 %(FILE_HEADER)s | |
| 177 %(NOT_TCB_MESSAGE)s | |
| 178 | |
| 179 #ifndef %(IFDEF_NAME)s | |
| 180 #define %(IFDEF_NAME)s | |
| 181 | |
| 182 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" | |
| 183 | |
| 184 """ | |
| 185 | |
| 186 RULE_CLASSES_HEADER=""" | |
| 187 /* | |
| 188 * Define rule decoder classes. | |
| 189 */ | |
| 190 namespace nacl_arm_dec { | |
| 191 """ | |
| 192 | |
| 193 RULE_CLASS=""" | |
| 194 class %(rule)s%(decoder)s | |
| 195 : public %(decoder)s { | |
| 196 public: | |
| 197 virtual ~%(rule)s%(decoder)s() {} | |
| 198 }; | |
| 199 | |
| 200 """ | |
| 201 | |
| 202 RULE_CLASSES_FOOTER=""" | |
| 203 } // nacl_arm_dec | |
| 204 """ | |
| 205 | |
| 206 NAMED_H_NAMESPACE=""" | |
| 207 namespace nacl_arm_test { | |
| 208 """ | |
| 209 | |
| 210 NAMED_DECODERS_HEADER=""" | |
| 211 /* | |
| 212 * Define named class decoders for each class decoder. | |
| 213 * The main purpose of these classes is to introduce | |
| 214 * instances that are named specifically to the class decoder | |
| 215 * and/or rule that was used to parse them. This makes testing | |
| 216 * much easier in that error messages use these named classes | |
| 217 * to clarify what row in the corresponding table was used | |
| 218 * to select this decoder. Without these names, debugging the | |
| 219 * output of the test code would be nearly impossible | |
| 220 */ | |
| 221 | |
| 222 """ | |
| 223 | |
| 224 NAMED_DECODER_DECLARE=""" | |
| 225 class Named%(decoder)s : public NamedClassDecoder { | |
| 226 public: | |
| 227 inline Named%(decoder)s() | |
| 228 : NamedClassDecoder(decoder_, "%(decoder)s") | |
| 229 {} | |
| 230 virtual ~Named%(decoder)s() {} | |
| 231 protected: | |
| 232 explicit inline Named%(decoder)s(const char* name) | |
| 233 : NamedClassDecoder(decoder_, name) {} | |
| 234 private: | |
| 235 nacl_arm_dec::%(decoder)s decoder_; | |
| 236 }; | |
| 237 | |
| 238 """ | |
| 239 | |
| 240 NAMED_RULE_DECLARE=""" | |
| 241 class Named%(rule)s%(decoder)s | |
| 242 : public Named%(decoder)s { | |
| 243 public: | |
| 244 inline Named%(rule)s%(decoder)s() | |
| 245 : Named%(decoder)s("%(rule)s%(decoder)s") | |
| 246 {} | |
| 247 virtual ~Named%(rule)s%(decoder)s() {} | |
| 248 }; | |
| 249 | |
| 250 """ | |
| 251 | |
| 252 NAMED_CLASSES_H_FOOTER=""" | |
| 253 } // namespace nacl_arm_test | |
| 254 #endif // %(IFDEF_NAME)s | |
| 255 """ | |
| 256 | |
| 257 def generate_named_classes_h(decoder, decoder_name, filename, out): | |
| 258 """Defines named classes needed for decoder testing. | |
| 259 | |
| 260 Args: | |
| 261 tables: list of Table objects to process. | |
| 262 decoder_name: The name of the decoder state to build. | |
| 263 filename: The (localized) name for the .h file. | |
| 264 out: a COutput object to write to. | |
| 265 """ | |
| 266 if not decoder.primary: raise Exception('No tables provided.') | |
| 267 | |
| 268 values = { | |
| 269 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 270 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
| 271 'IFDEF_NAME' : dgen_output.ifdef_name(filename), | |
| 272 'decoder_name': decoder_name, | |
| 273 } | |
| 274 out.write(NAMED_CLASSES_H_HEADER % values) | |
| 275 _generate_rule_classes(decoder, values, out) | |
| 276 out.write(NAMED_H_NAMESPACE) | |
| 277 _generate_named_decoder_classes(decoder, values, out) | |
| 278 out.write(NAMED_CLASSES_H_FOOTER % values) | |
| 279 | |
| 280 def _generate_named_decoder_classes(decoder, values, out): | |
| 281 out.write(NAMED_DECODERS_HEADER) | |
| 282 # Generate one for each type of decoder in the decoder. | |
| 283 for d in decoder.action_filter(['name']).decoders(): | |
| 284 values['decoder'] = d.name | |
| 285 values['rule'] = '' | |
| 286 out.write(NAMED_DECODER_DECLARE % values) | |
| 287 # Now generate one for each decoder that has a rule associated with it. | |
| 288 for d in decoder.action_filter(['name', 'rule']).rules(): | |
| 289 values['decoder'] = d.name | |
| 290 values['rule'] = d.rule | |
| 291 out.write(NAMED_RULE_DECLARE % values) | |
| 292 | |
| 293 def _generate_rule_classes(decoder, values, out): | |
| 294 # Note: we generate these classes in nacl_arm_dec, so that | |
| 295 # all decoder classes generated by the pareser are in the | |
| 296 # same namesapce. | |
| 297 out.write(RULE_CLASSES_HEADER) | |
| 298 for action in decoder.action_filter(['name', 'rule']).rules(): | |
| 299 values['decoder'] = action.name | |
| 300 values['rule'] = action.rule | |
| 301 out.write(RULE_CLASS % values) | |
| 302 out.write(RULE_CLASSES_FOOTER) | |
| 303 | |
| 304 NAMED_DECODER_H_HEADER=""" | |
| 305 %(FILE_HEADER)s | |
| 306 %(NOT_TCB_MESSAGE)s | |
| 307 | |
| 308 #ifndef %(IFDEF_NAME)s | |
| 309 #define %(IFDEF_NAME)s | |
| 310 | |
| 311 #include "native_client/src/trusted/validator_arm/decode.h" | |
| 312 #include "%(FILENAME_BASE)s_classes.h" | |
| 313 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" | |
| 314 | |
| 315 namespace nacl_arm_test { | |
| 316 """ | |
| 317 | |
| 318 DECODER_STATE_HEADER=""" | |
| 319 // Defines a (named) decoder class selector for instructions | |
| 320 class Named%(decoder_name)s : nacl_arm_dec::DecoderState { | |
| 321 public: | |
| 322 explicit Named%(decoder_name)s(); | |
| 323 virtual ~Named%(decoder_name)s(); | |
| 324 | |
| 325 // Parses the given instruction, returning the named class | |
| 326 // decoder to use. | |
| 327 const NamedClassDecoder& decode_named( | |
| 328 const nacl_arm_dec::Instruction) const; | |
| 329 | |
| 330 // Parses the given instruction, returning the class decoder | |
| 331 // to use. | |
| 332 virtual const nacl_arm_dec::ClassDecoder& decode( | |
| 333 const nacl_arm_dec::Instruction) const; | |
| 334 """ | |
| 335 | |
| 336 DECODER_STATE_FIELD_COMMENTS=""" | |
| 337 // The following fields define the set of class decoders | |
| 338 // that can be returned by the API function "decode_named". They | |
| 339 // are created once as instance fields, and then returned | |
| 340 // by the table methods above. This speeds up the code since | |
| 341 // the class decoders need to only be bulit once (and reused | |
| 342 // for each call to "decode_named"). | |
| 343 """ | |
| 344 | |
| 345 DECODER_STATE_FIELD=""" | |
| 346 const Named%(rule)s%(decoder)s %(rule)s%(decoder)s_instance_; | |
| 347 """ | |
| 348 | |
| 349 DECODER_STATE_PRIVATE=""" | |
| 350 private: | |
| 351 """ | |
| 352 | |
| 353 DECODER_STATE_DECODER_COMMENTS=""" | |
| 354 // The following list of methods correspond to each decoder table, | |
| 355 // and implements the pattern matching of the corresponding bit | |
| 356 // patterns. After matching the corresponding bit patterns, they | |
| 357 // either call other methods in this list (corresponding to another | |
| 358 // decoder table), or they return the instance field that implements | |
| 359 // the class decoder that should be used to decode the particular | |
| 360 // instruction. | |
| 361 """ | |
| 362 | |
| 363 DECODER_STATE_DECODER=""" | |
| 364 inline const NamedClassDecoder& decode_%(table)s( | |
| 365 const nacl_arm_dec::Instruction insn) const; | |
| 366 """ | |
| 367 | |
| 368 DECODER_STATE_FOOTER=""" | |
| 369 }; | |
| 370 """ | |
| 371 | |
| 372 NAMED_DECODER_H_FOOTER=""" | |
| 373 } // namespace nacl_arm_test | |
| 374 #endif // %(IFDEF_NAME)s | |
| 375 """ | |
| 376 | |
| 377 def generate_named_decoder_h(decoder, decoder_name, filename, out): | |
| 378 """Generates the named decoder for testing. | |
| 379 | |
| 380 Args: | |
| 381 tables: list of Table objects to process. | |
| 382 decoder_name: The name of the decoder state to build. | |
| 383 filename: The (localized) name for the .h file. | |
| 384 out: a COutput object to write to. | |
| 385 """ | |
| 386 if not decoder.primary: raise Exception('No tables provided.') | |
| 387 assert filename.endswith('_decoder.h') | |
| 388 | |
| 389 values = { | |
| 390 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 391 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
| 392 'IFDEF_NAME' : dgen_output.ifdef_name(filename), | |
| 393 'FILENAME_BASE': filename[:-len('_decoder.h')], | |
| 394 'decoder_name': decoder_name, | |
| 395 } | |
| 396 out.write(NAMED_DECODER_H_HEADER % values) | |
| 397 _generate_decoder_state_class(decoder, values, out) | |
| 398 out.write(NAMED_DECODER_H_FOOTER % values) | |
| 399 | |
| 400 def _generate_decoder_state_class(decoder, values, out): | |
| 401 # Generate a field for each type of decoder in the decoder. | |
| 402 out.write(DECODER_STATE_HEADER % values) | |
| 403 out.write(DECODER_STATE_FIELD_COMMENTS); | |
| 404 for d in decoder.action_filter(['name']).decoders(): | |
| 405 values['decoder'] = d.name | |
| 406 values['rule'] = '' | |
| 407 out.write(DECODER_STATE_FIELD % values) | |
| 408 # Now generate one for each decoder that has a rule associated with it. | |
| 409 for d in decoder.action_filter(['name', 'rule']).rules(): | |
| 410 values['decoder'] = d.name | |
| 411 values['rule'] = d.rule | |
| 412 out.write(DECODER_STATE_FIELD % values) | |
| 413 out.write(DECODER_STATE_PRIVATE); | |
| 414 out.write(DECODER_STATE_DECODER_COMMENTS) | |
| 415 for table in decoder.tables(): | |
| 416 values['table'] = table.name | |
| 417 out.write(DECODER_STATE_DECODER % values) | |
| 418 out.write(DECODER_STATE_FOOTER % values) | |
| 419 | |
| 420 # Defines the source for DECODER_named.cc | |
| 421 NAMED_CC_HEADER=""" | |
| 422 %(FILE_HEADER)s | |
| 423 %(NOT_TCB_MESSAGE)s | |
| 424 #include "%(FILENAME_BASE)s_decoder.h" | |
| 425 | |
| 426 #include <stdio.h> | |
| 427 | |
| 428 using nacl_arm_dec::ClassDecoder; | |
| 429 using nacl_arm_dec::Instruction; | |
| 430 | |
| 431 namespace nacl_arm_test { | |
| 432 """ | |
| 433 | |
| 434 PARSE_CONSTRUCT_HEADER=""" | |
| 435 Named%(decoder_name)s::Named%(decoder_name)s() | |
| 436 : nacl_arm_dec::DecoderState() | |
| 437 """ | |
| 438 | |
| 439 PARSE_CONSTRUCT_FIELDS=""" | |
| 440 , %(rule)s%(decoder)s_instance_() | |
| 441 """ | |
| 442 | |
| 443 PARSE_CONSTRUCT_FOOTER=""" | |
| 444 {} | |
| 445 | |
| 446 Named%(decoder_name)s::~Named%(decoder_name)s() {} | |
| 447 """ | |
| 448 | |
| 449 PARSE_TABLE_METHOD_HEADER=""" | |
| 450 /* | |
| 451 * Implementation of table %(table_name)s. | |
| 452 * Specified by: %(citation)s | |
| 453 */ | |
| 454 const NamedClassDecoder& Named%(decoder_name)s::decode_%(table_name)s( | |
| 455 const nacl_arm_dec::Instruction insn) const { | |
| 456 """ | |
| 457 | |
| 458 PARSE_TABLE_METHOD_ROW=""" | |
| 459 if (%(tests)s) { | |
| 460 return %(action)s; | |
| 461 } | |
| 462 """ | |
| 463 | |
| 464 PARSE_TABLE_METHOD_FOOTER=""" | |
| 465 // Catch any attempt to fall through... | |
| 466 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", | |
| 467 insn.bits(31,0)); | |
| 468 return Forbidden_instance_; | |
| 469 } | |
| 470 | |
| 471 """ | |
| 472 | |
| 473 NAMED_CC_FOOTER=""" | |
| 474 const NamedClassDecoder& Named%(decoder_name)s:: | |
| 475 decode_named(const nacl_arm_dec::Instruction insn) const { | |
| 476 return decode_%(entry_table_name)s(insn); | |
| 477 } | |
| 478 | |
| 479 const nacl_arm_dec::ClassDecoder& Named%(decoder_name)s:: | |
| 480 decode(const nacl_arm_dec::Instruction insn) const { | |
| 481 return decode_named(insn).named_decoder(); | |
| 482 } | |
| 483 | |
| 484 } // namespace nacl_arm_test | |
| 485 """ | |
| 486 | |
| 487 def generate_named_cc(decoder, decoder_name, filename, out): | |
| 488 """Implementation of the test decoder in .cc file | |
| 489 | |
| 490 Args: | |
| 491 tables: list of Table objects to process. | |
| 492 decoder_name: The name of the decoder state to build. | |
| 493 filename: The (localized) name for the .h file. | |
| 494 out: a COutput object to write to. | |
| 495 """ | |
| 496 if not decoder.primary: raise Exception('No tables provided.') | |
| 497 assert filename.endswith('.cc') | |
| 498 | |
| 499 values = { | |
| 500 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 501 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
| 502 'FILENAME_BASE' : filename[:-len('.cc')], | |
| 503 'decoder_name': decoder_name, | |
| 504 'entry_table_name': decoder.primary.name, | |
| 505 } | |
| 506 out.write(NAMED_CC_HEADER % values) | |
| 507 _generate_decoder_constructors(decoder, values, out) | |
| 508 _generate_decoder_method_bodies(decoder, values, out) | |
| 509 out.write(NAMED_CC_FOOTER % values) | |
| 510 | |
| 511 def _generate_decoder_constructors(decoder, values, out): | |
| 512 out.write(PARSE_CONSTRUCT_HEADER % values) | |
| 513 # Initialize each type of decoder in the decoder. | |
| 514 for d in decoder.action_filter(['name']).decoders(): | |
| 515 values['decoder'] = d.name | |
| 516 values['rule'] = '' | |
| 517 out.write(PARSE_CONSTRUCT_FIELDS % values) | |
| 518 # Now initialize fields for each decoder with a rule. | |
| 519 for d in decoder.action_filter(['name', 'rule']).rules(): | |
| 520 values['decoder'] = d.name | |
| 521 values['rule'] = d.rule | |
| 522 out.write(PARSE_CONSTRUCT_FIELDS % values) | |
| 523 out.write(PARSE_CONSTRUCT_FOOTER % values) | |
| 524 | |
| 525 def _generate_decoder_method_bodies(decoder, values, out): | |
| 526 for table in decoder.tables(): | |
| 527 opt_rows = dgen_opt.optimize_rows( | |
| 528 table.action_filter(['name', 'rule']).rows) | |
| 529 print ("Table %s: %d rows minimized to %d" | |
| 530 % (table.name, len(table.rows), len(opt_rows))) | |
| 531 | |
| 532 values['table_name'] = table.name | |
| 533 values['citation'] = table.citation, | |
| 534 out.write(PARSE_TABLE_METHOD_HEADER % values) | |
| 535 | |
| 536 # Add message to stop compilation warnings if this table | |
| 537 # doesn't require subtables to select a class decoder. | |
| 538 if not [r for r in opt_rows | |
| 539 if r.action.__class__.__name__ == 'DecoderMethod']: | |
| 540 out.write(" UNREFERENCED_PARAMETER(insn);") | |
| 541 | |
| 542 for row in opt_rows: | |
| 543 if row.action.__class__.__name__ == 'DecoderAction': | |
| 544 values['decoder'] = row.action.name | |
| 545 values['rule'] = row.action.rule if row.action.rule else '' | |
| 546 action = '%(rule)s%(decoder)s_instance_' % values | |
| 547 elif row.action.__class__.__name__ == 'DecoderMethod': | |
| 548 action = 'decode_%s(insn)' % row.action.name | |
| 549 else: | |
| 550 raise Exception('Bad table action: %s' % row.action) | |
| 551 # Each row consists of a set of bit patterns defining if the row | |
| 552 # is applicable. Convert this into a sequence of anded C test | |
| 553 # expressions. For example, convert the following pair of bit | |
| 554 # patterns: | |
| 555 # | |
| 556 # xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx | |
| 557 # xxxxxxxxxxxxxxxxxxxxxxxxxxxx0101 | |
| 558 # | |
| 559 # Each instruction is masked to get the the bits, and then | |
| 560 # tested against the corresponding expected bits. Hence, the | |
| 561 # above example is converted to: | |
| 562 # | |
| 563 # ((insn & 0x0F000000) != 0x0C000000) && | |
| 564 # ((insn & 0x0000000F) != 0x00000005) | |
| 565 values['tests'] = ' && '.join(['(%s)' % p.to_c_expr('insn') | |
| 566 for p in row.patterns]) | |
| 567 values['action'] = action | |
| 568 out.write(PARSE_TABLE_METHOD_ROW % values) | |
| 569 out.write(PARSE_TABLE_METHOD_FOOTER % values) | |
| 570 | |
| 571 # Define the source for DECODER_tests.cc | |
| 572 TEST_CC_HEADER=""" | |
| 573 %(FILE_HEADER)s | |
| 574 %(NOT_TCB_MESSAGE)s | |
| 575 | |
| 576 #include "gtest/gtest.h" | |
| 577 #include "native_client/src/trusted/validator_arm/inst_classes_testers.h" | |
| 578 | |
| 579 namespace nacl_arm_test { | |
| 580 | |
| 581 """ | |
| 582 | |
| 583 TESTER_CLASS=""" | |
| 584 class %(rule)s%(decoder)sTester%(constraints)s | |
| 585 : public %(decoder)sTester%(constraints)s { | |
| 586 public: | |
| 587 %(rule)s%(decoder)sTester%(constraints)s() | |
| 588 : %(decoder)sTester%(constraints)s( | |
| 589 state_.%(rule)s%(decoder)s_instance_) | |
| 590 {} | |
| 591 }; | |
| 592 """ | |
| 593 | |
| 594 TEST_HARNESS=""" | |
| 595 // Defines a gtest testing harness for tests. | |
| 596 class %(decoder_name)sTests : public ::testing::Test { | |
| 597 protected: | |
| 598 %(decoder_name)sTests() {} | |
| 599 }; | |
| 600 """ | |
| 601 | |
| 602 TEST_FUNCTION=""" | |
| 603 TEST_F(%(decoder_name)sTests, | |
| 604 %(rule)s%(decoder)s%(constraints)s_%(pattern)s_Test) { | |
| 605 %(rule)s%(decoder)sTester%(constraints)s tester; | |
| 606 tester.Test("%(pattern)s"); | |
| 607 } | |
| 608 """ | |
| 609 | |
| 610 | |
| 611 TEST_CC_FOOTER=""" | |
| 612 } // namespace nacl_arm_test | |
| 613 | |
| 614 int main(int argc, char* argv[]) { | |
| 615 testing::InitGoogleTest(&argc, argv); | |
| 616 return RUN_ALL_TESTS(); | |
| 617 } | |
| 618 """ | |
| 619 | |
| 620 def generate_tests_cc(decoder, decoder_name, out): | |
| 621 if not decoder.primary: raise Exception('No tables provided.') | |
| 622 values = { | |
| 623 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 624 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, | |
| 625 'decoder_name': decoder_name, | |
| 626 } | |
| 627 out.write(TEST_CC_HEADER % values) | |
| 628 _generate_rule_testers(decoder, values, out) | |
| 629 out.write(TEST_HARNESS % values) | |
| 630 _generate_test_patterns(decoder, values, out) | |
| 631 out.write(TEST_CC_FOOTER % values) | |
| 632 | |
| 633 def _generate_rule_testers(decoder, values, out): | |
| 634 for d in decoder.action_filter(['name', 'rule', 'constraints']).rules(): | |
| 635 values['decoder'] = d.name | |
| 636 values['rule'] = d.rule | |
| 637 values['constraints'] = d.constraints if d.constraints else '' | |
| 638 out.write(TESTER_CLASS % values) | |
| 639 | |
| 640 def _generate_test_patterns(decoder, values, out): | |
| 641 for d in decoder.decoders(): | |
| 642 if d.pattern: | |
| 643 values['decoder'] = d.name | |
| 644 values['rule'] = d.rule if d.rule else '' | |
| 645 values['constraints'] = d.constraints if d.constraints else '' | |
| 646 values['pattern'] = d.pattern | |
| 647 out.write(TEST_FUNCTION % values) | |
| OLD | NEW |