Chromium Code Reviews
|
| 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 decoder based on parsed | |
| 10 table representations. | |
| 11 """ | |
| 12 | |
| 13 | |
| 14 import dgen_opt | |
| 15 import dgen_output | |
| 16 | |
| 17 # This file generates the class decoder Decoder as defined by the | |
| 18 # decoder tables. The code is specifically written to minize the | |
| 19 # number of decoder classes needed to parse valid ARM | |
| 20 # instructions. Many rows in the table use the same decoder class. In | |
| 21 # addition, we optimize tables by merging, so long as the same decoder | |
| 22 # class is built. | |
| 23 # | |
| 24 # The following files are generated: | |
| 25 # | |
| 26 # decoder.h | |
| 27 # decoder.cc | |
| 28 # | |
| 29 # decoder.h declares the generated decoder parser class while | |
| 30 # decoder.cc contains the implementation of that decoder class. | |
| 31 # | |
| 32 # For testing purposes (see dgen_test_output.py) different rules are | |
|
robertm
2012/04/17 17:12:19
mention that the other file as a nice description
Karl
2012/04/17 19:28:31
Done.
| |
| 33 # applied. | |
| 34 # | |
| 35 | |
| 36 # Defines the header for decoder.h | |
| 37 H_HEADER=""" | |
| 38 %(FILE_HEADER)s | |
| 39 | |
| 40 #ifndef %(IFDEF_NAME)s | |
| 41 #define %(IFDEF_NAME)s | |
| 42 | |
| 43 #include "native_client/src/trusted/validator_arm/decode.h" | |
| 44 #include "native_client/src/trusted/validator_arm/inst_classes.h" | |
| 45 | |
| 46 namespace nacl_arm_dec { | |
| 47 """ | |
| 48 | |
| 49 DECODER_DECLARE_HEADER=""" | |
| 50 // Defines a stateless decoder class selector for instructions. | |
| 51 class %(decoder_name)s : DecoderState { | |
| 52 public: | |
| 53 explicit %(decoder_name)s(); | |
| 54 virtual ~%(decoder_name)s(); | |
| 55 | |
| 56 // Parses the given instruction, returning the decoder to use. | |
| 57 virtual const ClassDecoder& decode(const Instruction) const; | |
| 58 | |
| 59 private: | |
| 60 """ | |
| 61 | |
| 62 DECODER_DECLARE_METHOD=""" | |
| 63 inline const ClassDecoder& decode_%(table_name)s( | |
| 64 const Instruction insn) const; | |
| 65 """ | |
| 66 | |
| 67 DECODER_DECLARE_FIELD=""" | |
| 68 %(decoder)s %(decoder)s_instance_; | |
| 69 """ | |
| 70 | |
| 71 DECODER_DECLARE_FOOTER=""" | |
| 72 }; | |
| 73 """ | |
| 74 | |
| 75 H_FOOTER=""" | |
| 76 } // namespace nacl_arm_dec | |
| 77 #endif // %(IFDEF_NAME)s | |
| 78 """ | |
| 79 | |
| 80 def generate_h(decoder, decoder_name, filename, out): | |
| 81 """Entry point to the decoder for .h file. | |
| 82 | |
| 83 Args: | |
| 84 decoder: The decoder defined by the list of Table objects to process. | |
| 85 decoder_name: The name of the decoder state to build. | |
| 86 filename: The (localized) name for the .h file. | |
| 87 named_decoders: If true, generate a decoder state with named instances. | |
| 88 out: a COutput object to write to. | |
| 89 """ | |
| 90 if not decoder.primary: raise Exception('No tables provided.') | |
| 91 | |
| 92 # Before starting, remove all testing information from the parsed tables. | |
| 93 decoder = decoder.action_filter(['name']) | |
| 94 | |
| 95 values = { | |
| 96 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 97 'IFDEF_NAME': dgen_output.ifdef_name(filename), | |
| 98 'decoder_name': decoder_name, | |
| 99 } | |
| 100 out.write(H_HEADER % values) | |
| 101 out.write(DECODER_DECLARE_HEADER % values) | |
| 102 for table in decoder.tables(): | |
| 103 values['table_name'] = table.name | |
| 104 out.write(DECODER_DECLARE_METHOD % values) | |
| 105 for action in decoder.decoders(): | |
| 106 values['decoder'] = action.name; | |
| 107 out.write(DECODER_DECLARE_FIELD % values) | |
| 108 out.write(DECODER_DECLARE_FOOTER % values) | |
| 109 out.write(H_FOOTER % values) | |
| 110 | |
| 111 # Defines the header for DECODER.h | |
| 112 CC_HEADER=""" | |
| 113 %(FILE_HEADER)s | |
| 114 | |
| 115 #include "%(header_filename)s" | |
| 116 | |
| 117 #include <stdio.h> | |
| 118 | |
| 119 namespace nacl_arm_dec { | |
| 120 | |
| 121 """ | |
| 122 | |
| 123 CONSTRUCTOR_HEADER=""" | |
| 124 %(decoder_name)s::%(decoder_name)s() : DecoderState() | |
| 125 """ | |
| 126 | |
| 127 CONSTRUCTOR_FIELD_INIT=""" | |
| 128 , %(decoder)s_instance_() | |
| 129 """ | |
| 130 | |
| 131 CONSTRUCTOR_FOOTER=""" | |
| 132 {} | |
| 133 | |
| 134 %(decoder_name)s::~%(decoder_name)s() {} | |
| 135 """ | |
| 136 | |
| 137 METHOD_HEADER=""" | |
| 138 // Implementation of table: %(table_name)s. | |
| 139 // Specified by: %(citation)s | |
| 140 const ClassDecoder& %(decoder_name)s::decode_%(table_name)s( | |
| 141 const Instruction insn) const | |
| 142 { | |
| 143 """ | |
| 144 | |
| 145 METHOD_DISPATCH=""" | |
| 146 if (%(tests)s) | |
| 147 """ | |
| 148 | |
| 149 METHOD_DISPATCH_CLASS_DECODER=""" | |
| 150 return %(decoder)s_instance_; | |
| 151 """ | |
| 152 | |
| 153 METHOD_DISPATCH_SUBMETHOD=""" | |
| 154 return decode_%(subtable_name)s(insn); | |
| 155 """ | |
| 156 | |
| 157 METHOD_FOOTER=""" | |
| 158 // Catch any attempt to fall though ... | |
| 159 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", | |
| 160 insn.bits(31, 0)); | |
| 161 return Forbidden_instance_; | |
| 162 } | |
| 163 """ | |
| 164 | |
| 165 DECODER_METHOD=""" | |
| 166 const ClassDecoder& %(decoder_name)s::decode(const Instruction insn) const { | |
| 167 return decode_%(entry_table_name)s(insn); | |
| 168 } | |
| 169 """ | |
| 170 | |
| 171 CC_FOOTER=""" | |
| 172 } // namespace nacl_arm_dec | |
| 173 """ | |
| 174 | |
| 175 def generate_cc(decoder, decoder_name, filename, out): | |
| 176 """Implementation of the decoder in .cc file | |
| 177 | |
| 178 Args: | |
| 179 decoder: The decoder defined by the list of Table objects to process. | |
| 180 decoder_name: The name of the decoder state to build. | |
| 181 filename: The (localized) name for the .h file. | |
| 182 named_decoders: If true, generate a decoder state with named instances. | |
| 183 out: a COutput object to write to. | |
| 184 """ | |
| 185 if not decoder.primary: raise Exception('No tables provided.') | |
| 186 | |
| 187 # Before starting, remove all testing information from the parsed tables. | |
| 188 decoder = decoder.action_filter(['name']) | |
| 189 values = { | |
| 190 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
| 191 'header_filename': filename[:-2] + 'h', | |
|
robertm
2012/04/17 17:12:19
maybe assert that file name ends with '.cc'
Karl
2012/04/17 19:28:31
Done.
| |
| 192 'decoder_name': decoder_name, | |
| 193 'entry_table_name': decoder.primary.name, | |
| 194 } | |
| 195 out.write(CC_HEADER % values) | |
| 196 _generate_constructors(decoder, values, out) | |
| 197 _generate_methods(decoder, values, out) | |
| 198 out.write(DECODER_METHOD % values) | |
| 199 out.write(CC_FOOTER % values) | |
| 200 | |
| 201 def _generate_constructors(decoder, values, out): | |
| 202 out.write(CONSTRUCTOR_HEADER % values) | |
| 203 for decoder in decoder.decoders(): | |
| 204 values['decoder'] = decoder.name | |
| 205 out.write(CONSTRUCTOR_FIELD_INIT % values) | |
| 206 out.write(CONSTRUCTOR_FOOTER % values) | |
| 207 | |
| 208 def _generate_methods(decoder, values, out): | |
| 209 for table in decoder.tables(): | |
| 210 opt_rows = sorted(dgen_opt.optimize_rows(table.rows)) | |
| 211 print ("Table %s: %d rows minimized to %d" | |
| 212 % (table.name, len(table.rows), len(opt_rows))) | |
| 213 | |
| 214 values['table_name'] = table.name | |
| 215 values['citation'] = table.citation | |
| 216 out.write(METHOD_HEADER % values) | |
| 217 method_calls = filter( | |
|
robertm
2012/04/17 17:12:19
try to replace this with list comprehension
(there
Karl
2012/04/17 19:28:31
Done.
| |
| 218 lambda(r): r.action.__class__.__name__ == 'DecoderMethod', opt_rows) | |
| 219 if not method_calls: | |
| 220 out.write(" UNREFERENCED_PARAMETER(insn);") | |
| 221 | |
| 222 for row in opt_rows: | |
| 223 values['tests'] = ' && '.join(["(%s)" % p.to_c_expr('insn') | |
|
robertm
2012/04/17 17:12:19
add a comment explaining the introspection magic -
Karl
2012/04/17 19:28:31
Done.
| |
| 224 for p in row.patterns]) | |
| 225 out.write(METHOD_DISPATCH % values) | |
| 226 if row.action.__class__.__name__ == 'DecoderAction': | |
| 227 values['decoder'] = row.action.name | |
| 228 out.write(METHOD_DISPATCH_CLASS_DECODER % values) | |
| 229 elif row.action.__class__.__name__ == 'DecoderMethod': | |
| 230 values['subtable_name'] = row.action.name | |
| 231 out.write(METHOD_DISPATCH_SUBMETHOD % values) | |
| 232 else: | |
| 233 raise Exception('Bad table action: %s' % repr(row.action)) | |
| 234 out.write(METHOD_FOOTER % values) | |
| OLD | NEW |