| 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 |
| 33 # applied. Note: It may be worth reading dgen_test_output.py preamble |
| 34 # to get a better understanding of decoder actions, and why we need |
| 35 # the "action_filter" methods. |
| 36 |
| 37 # Defines the header for decoder.h |
| 38 H_HEADER=""" |
| 39 %(FILE_HEADER)s |
| 40 |
| 41 #ifndef %(IFDEF_NAME)s |
| 42 #define %(IFDEF_NAME)s |
| 43 |
| 44 #include "native_client/src/trusted/validator_arm/decode.h" |
| 45 #include "native_client/src/trusted/validator_arm/inst_classes.h" |
| 46 |
| 47 namespace nacl_arm_dec { |
| 48 """ |
| 49 |
| 50 DECODER_DECLARE_HEADER=""" |
| 51 // Defines a decoder class selector for instructions. |
| 52 class %(decoder_name)s : DecoderState { |
| 53 public: |
| 54 explicit %(decoder_name)s(); |
| 55 virtual ~%(decoder_name)s(); |
| 56 |
| 57 // Parses the given instruction, returning the decoder to use. |
| 58 virtual const ClassDecoder& decode(const Instruction) const; |
| 59 |
| 60 private: |
| 61 """ |
| 62 |
| 63 DECODER_DECLARE_METHOD_COMMENTS=""" |
| 64 // The following list of methods correspond to each decoder table, |
| 65 // and implements the pattern matching of the corresponding bit |
| 66 // patterns. After matching the corresponding bit patterns, they |
| 67 // either call other methods in this list (corresponding to another |
| 68 // decoder table), or they return the instance field that implements |
| 69 // the class decoder that should be used to decode the particular |
| 70 // instruction. |
| 71 """ |
| 72 |
| 73 DECODER_DECLARE_METHOD=""" |
| 74 inline const ClassDecoder& decode_%(table_name)s( |
| 75 const Instruction insn) const; |
| 76 """ |
| 77 |
| 78 DECODER_DECLARE_FIELD_COMMENTS=""" |
| 79 // The following fields define the set of class decoders |
| 80 // that can be returned by the API function "decode". They |
| 81 // are created once as instance fields, and then returned |
| 82 // by the table methods above. This speeds up the code since |
| 83 // the class decoders need to only be built once (and reused |
| 84 // for each call to "decode"). |
| 85 """ |
| 86 |
| 87 DECODER_DECLARE_FIELD=""" |
| 88 const %(decoder)s %(decoder)s_instance_; |
| 89 """ |
| 90 |
| 91 DECODER_DECLARE_FOOTER=""" |
| 92 }; |
| 93 """ |
| 94 |
| 95 H_FOOTER=""" |
| 96 } // namespace nacl_arm_dec |
| 97 #endif // %(IFDEF_NAME)s |
| 98 """ |
| 99 |
| 100 def generate_h(decoder, decoder_name, filename, out): |
| 101 """Entry point to the decoder for .h file. |
| 102 |
| 103 Args: |
| 104 decoder: The decoder defined by the list of Table objects to process. |
| 105 decoder_name: The name of the decoder state to build. |
| 106 filename: The (localized) name for the .h file. |
| 107 named_decoders: If true, generate a decoder state with named instances. |
| 108 out: a COutput object to write to. |
| 109 """ |
| 110 if not decoder.primary: raise Exception('No tables provided.') |
| 111 |
| 112 # Before starting, remove all testing information from the parsed tables. |
| 113 decoder = decoder.action_filter(['name']) |
| 114 |
| 115 values = { |
| 116 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 117 'IFDEF_NAME': dgen_output.ifdef_name(filename), |
| 118 'decoder_name': decoder_name, |
| 119 } |
| 120 out.write(H_HEADER % values) |
| 121 out.write(DECODER_DECLARE_HEADER % values) |
| 122 out.write(DECODER_DECLARE_METHOD_COMMENTS) |
| 123 for table in decoder.tables(): |
| 124 values['table_name'] = table.name |
| 125 out.write(DECODER_DECLARE_METHOD % values) |
| 126 out.write(DECODER_DECLARE_FIELD_COMMENTS) |
| 127 for action in decoder.decoders(): |
| 128 values['decoder'] = action.name; |
| 129 out.write(DECODER_DECLARE_FIELD % values) |
| 130 out.write(DECODER_DECLARE_FOOTER % values) |
| 131 out.write(H_FOOTER % values) |
| 132 |
| 133 # Defines the header for DECODER.h |
| 134 CC_HEADER=""" |
| 135 %(FILE_HEADER)s |
| 136 |
| 137 #include "%(header_filename)s" |
| 138 |
| 139 #include <stdio.h> |
| 140 |
| 141 namespace nacl_arm_dec { |
| 142 |
| 143 """ |
| 144 |
| 145 CONSTRUCTOR_HEADER=""" |
| 146 %(decoder_name)s::%(decoder_name)s() : DecoderState() |
| 147 """ |
| 148 |
| 149 CONSTRUCTOR_FIELD_INIT=""" |
| 150 , %(decoder)s_instance_() |
| 151 """ |
| 152 |
| 153 CONSTRUCTOR_FOOTER=""" |
| 154 {} |
| 155 |
| 156 %(decoder_name)s::~%(decoder_name)s() {} |
| 157 """ |
| 158 |
| 159 METHOD_HEADER=""" |
| 160 // Implementation of table: %(table_name)s. |
| 161 // Specified by: %(citation)s |
| 162 const ClassDecoder& %(decoder_name)s::decode_%(table_name)s( |
| 163 const Instruction insn) const |
| 164 { |
| 165 """ |
| 166 |
| 167 METHOD_DISPATCH=""" |
| 168 if (%(tests)s) |
| 169 """ |
| 170 |
| 171 METHOD_DISPATCH_CLASS_DECODER=""" |
| 172 return %(decoder)s_instance_; |
| 173 """ |
| 174 |
| 175 METHOD_DISPATCH_SUBMETHOD=""" |
| 176 return decode_%(subtable_name)s(insn); |
| 177 """ |
| 178 |
| 179 METHOD_FOOTER=""" |
| 180 // Catch any attempt to fall though ... |
| 181 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", |
| 182 insn.bits(31, 0)); |
| 183 return Forbidden_instance_; |
| 184 } |
| 185 """ |
| 186 |
| 187 DECODER_METHOD=""" |
| 188 const ClassDecoder& %(decoder_name)s::decode(const Instruction insn) const { |
| 189 return decode_%(entry_table_name)s(insn); |
| 190 } |
| 191 """ |
| 192 |
| 193 CC_FOOTER=""" |
| 194 } // namespace nacl_arm_dec |
| 195 """ |
| 196 |
| 197 def generate_cc(decoder, decoder_name, filename, out): |
| 198 """Implementation of the decoder in .cc file |
| 199 |
| 200 Args: |
| 201 decoder: The decoder defined by the list of Table objects to process. |
| 202 decoder_name: The name of the decoder state to build. |
| 203 filename: The (localized) name for the .h file. |
| 204 named_decoders: If true, generate a decoder state with named instances. |
| 205 out: a COutput object to write to. |
| 206 """ |
| 207 if not decoder.primary: raise Exception('No tables provided.') |
| 208 assert filename.endswith('.cc') |
| 209 |
| 210 # Before starting, remove all testing information from the parsed tables. |
| 211 decoder = decoder.action_filter(['name']) |
| 212 values = { |
| 213 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 214 'header_filename': filename[:-2] + 'h', |
| 215 'decoder_name': decoder_name, |
| 216 'entry_table_name': decoder.primary.name, |
| 217 } |
| 218 out.write(CC_HEADER % values) |
| 219 _generate_constructors(decoder, values, out) |
| 220 _generate_methods(decoder, values, out) |
| 221 out.write(DECODER_METHOD % values) |
| 222 out.write(CC_FOOTER % values) |
| 223 |
| 224 def _generate_constructors(decoder, values, out): |
| 225 out.write(CONSTRUCTOR_HEADER % values) |
| 226 for decoder in decoder.decoders(): |
| 227 values['decoder'] = decoder.name |
| 228 out.write(CONSTRUCTOR_FIELD_INIT % values) |
| 229 out.write(CONSTRUCTOR_FOOTER % values) |
| 230 |
| 231 def _generate_methods(decoder, values, out): |
| 232 for table in decoder.tables(): |
| 233 opt_rows = sorted(dgen_opt.optimize_rows(table.rows)) |
| 234 print ("Table %s: %d rows minimized to %d" |
| 235 % (table.name, len(table.rows), len(opt_rows))) |
| 236 |
| 237 values['table_name'] = table.name |
| 238 values['citation'] = table.citation |
| 239 out.write(METHOD_HEADER % values) |
| 240 |
| 241 # Add message to stop compilation warnings if this table |
| 242 # doesn't require subtables to select a class decoder. |
| 243 if not [r for r in opt_rows |
| 244 if r.action.__class__.__name__ == 'DecoderMethod']: |
| 245 out.write(" UNREFERENCED_PARAMETER(insn);") |
| 246 |
| 247 for row in opt_rows: |
| 248 # Each row consists of a set of bit patterns defining if the row |
| 249 # is applicable. Convert this into a sequence of anded C test |
| 250 # expressions. For example, convert the following pair of bit |
| 251 # patterns: |
| 252 # |
| 253 # xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx |
| 254 # xxxxxxxxxxxxxxxxxxxxxxxxxxxx0101 |
| 255 # |
| 256 # Each instruction is masked to get the the bits, and then |
| 257 # tested against the corresponding expected bits. Hence, the |
| 258 # above example is converted to: |
| 259 # |
| 260 # ((insn & 0x0F000000) != 0x0C000000) && |
| 261 # ((insn & 0x0000000F) != 0x00000005) |
| 262 values['tests'] = ' && '.join(["(%s)" % p.to_c_expr('insn') |
| 263 for p in row.patterns]) |
| 264 out.write(METHOD_DISPATCH % values) |
| 265 if row.action.__class__.__name__ == 'DecoderAction': |
| 266 values['decoder'] = row.action.name |
| 267 out.write(METHOD_DISPATCH_CLASS_DECODER % values) |
| 268 elif row.action.__class__.__name__ == 'DecoderMethod': |
| 269 values['subtable_name'] = row.action.name |
| 270 out.write(METHOD_DISPATCH_SUBMETHOD % values) |
| 271 else: |
| 272 raise Exception('Bad table action: %s' % repr(row.action)) |
| 273 out.write(METHOD_FOOTER % values) |
| OLD | NEW |