| 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 minimize 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 |