OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import itertools | 6 import itertools |
7 import re | 7 import re |
8 import StringIO | 8 import StringIO |
9 | 9 |
10 | 10 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 'att-show-name-suffix-q', | 107 'att-show-name-suffix-q', |
108 'att-show-name-suffix-x', | 108 'att-show-name-suffix-x', |
109 'att-show-name-suffix-y', | 109 'att-show-name-suffix-y', |
110 'att-show-name-suffix-w', | 110 'att-show-name-suffix-w', |
111 | 111 |
112 # Spurious REX.W bits (instructions 'in', 'out', 'nop', etc). | 112 # Spurious REX.W bits (instructions 'in', 'out', 'nop', etc). |
113 'spurious-rex.w' | 113 'spurious-rex.w' |
114 ] | 114 ] |
115 | 115 |
116 | 116 |
| 117 def Attribute(name): |
| 118 assert name in SUPPORTED_ATTRIBUTES |
| 119 return name |
| 120 |
| 121 |
117 class Operand(object): | 122 class Operand(object): |
118 | 123 |
119 __slots__ = [ | 124 __slots__ = [ |
120 'read_write_attr', | 125 'read_write_attr', |
121 'arg_type', | 126 'arg_type', |
122 'size', | 127 'size', |
123 'implicit', | 128 'implicit', |
124 'index'] | 129 'index'] |
125 | 130 |
126 # Operand read/write modes. | 131 # Operand read/write modes. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 | 185 |
181 TODO(shcherbina): it is possible that format will also be needed by | 186 TODO(shcherbina): it is possible that format will also be needed by |
182 validator64 in order to identify zero-extending instruction, but I'm not | 187 validator64 in order to identify zero-extending instruction, but I'm not |
183 sure how it will be done. | 188 sure how it will be done. |
184 | 189 |
185 Returns: | 190 Returns: |
186 String like '8bit', '32bit', 'xmm', 'mmx', etc. | 191 String like '8bit', '32bit', 'xmm', 'mmx', etc. |
187 """ | 192 """ |
188 if self.size == 'b': | 193 if self.size == 'b': |
189 return '8bit' | 194 return '8bit' |
| 195 if self.size == 'w': |
| 196 return '16bit' |
| 197 if self.size == 'd': |
| 198 return '32bit' |
| 199 if self.size == 'q': |
| 200 return '64bit' |
190 # TODO(shcherbina): support other formats. | 201 # TODO(shcherbina): support other formats. |
191 raise NotImplementedError() | 202 raise NotImplementedError() |
192 | 203 |
193 def __str__(self): | 204 def __str__(self): |
194 return '%s%s%s%s' % ( | 205 return '%s%s%s%s' % ( |
195 self.read_write_attr, | 206 self.read_write_attr, |
196 self.arg_type, | 207 self.arg_type, |
197 self.size, | 208 self.size, |
198 '*' if self.implicit else '') | 209 '*' if self.implicit else '') |
199 | 210 |
200 | 211 |
201 class Instruction(object): | 212 class Instruction(object): |
202 | 213 |
203 __slots__ = [ | 214 __slots__ = [ |
204 'name', | 215 'name', |
205 'operands', | 216 'operands', |
206 'opcodes', | 217 'opcodes', |
207 'attributes'] | 218 'attributes', |
| 219 'rex'] |
| 220 |
| 221 class RexStatus(object): |
| 222 __slots__ = [ |
| 223 'b_matters', |
| 224 'x_matters', |
| 225 'r_matters', |
| 226 'w_matters', |
| 227 'w_set'] |
| 228 |
| 229 def __init__(self): |
| 230 self.rex = self.RexStatus() |
| 231 self.rex.b_matters = False |
| 232 self.rex.x_matters = False |
| 233 self.rex.r_matters = False |
| 234 self.rex.w_matters = True |
| 235 self.rex.w_set = False |
208 | 236 |
209 @staticmethod | 237 @staticmethod |
210 def Parse(line): | 238 def Parse(line): |
211 """Parse one line of def file and return initialized Instruction object. | 239 """Parse one line of def file and return initialized Instruction object. |
212 | 240 |
213 Args: | 241 Args: |
214 line: One line of def file (two or three columns separated by | 242 line: One line of def file (two or three columns separated by |
215 COLUMN_SEPARATOR). First column defines instruction name and operands, | 243 COLUMN_SEPARATOR). First column defines instruction name and operands, |
216 second one - opcodes and encoding details, third (optional) | 244 second one - opcodes and encoding details, third (optional) |
217 one - instruction attributes. | 245 one - instruction attributes. |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 """Return name in a form suitable to use as part of C identifier. | 350 """Return name in a form suitable to use as part of C identifier. |
323 | 351 |
324 In principle, collisions are possible, but will result in compilation, | 352 In principle, collisions are possible, but will result in compilation, |
325 failure, so we are not checking for them here for simplicity. | 353 failure, so we are not checking for them here for simplicity. |
326 | 354 |
327 Returns: | 355 Returns: |
328 Instruction name with all non-alphanumeric characters replaced with '_'. | 356 Instruction name with all non-alphanumeric characters replaced with '_'. |
329 """ | 357 """ |
330 return re.sub(r'\W', '_', self.name) | 358 return re.sub(r'\W', '_', self.name) |
331 | 359 |
| 360 def IsVexOrXop(self): |
| 361 return (self.opcodes[0] == '0xc4' and self.name != 'les' or |
| 362 self.opcodes[0] == '0x8f' and self.name != 'pop') |
| 363 |
332 def __str__(self): | 364 def __str__(self): |
333 return ' '.join([self.name] + map(str, self.operands)) | 365 return ' '.join([self.name] + map(str, self.operands)) |
334 | 366 |
335 | 367 |
336 DECODER = object() | 368 DECODER = object() |
337 VALIDATOR = object() | 369 VALIDATOR = object() |
338 | 370 |
339 | 371 |
340 class InstructionPrinter(object): | 372 class InstructionPrinter(object): |
341 | 373 |
342 def __init__(self, mode, bitness): | 374 def __init__(self, mode, bitness): |
343 assert mode in [DECODER, VALIDATOR] | 375 assert mode in [DECODER, VALIDATOR] |
344 assert bitness in [32, 64] | 376 assert bitness in [32, 64] |
345 self._mode = mode | 377 self._mode = mode |
346 self._bitness = bitness | 378 self._bitness = bitness |
347 self._out = StringIO.StringIO() | 379 self._out = StringIO.StringIO() |
348 | 380 |
349 def GetContent(self): | 381 def GetContent(self): |
350 return self._out.getvalue() | 382 return self._out.getvalue() |
351 | 383 |
| 384 def _PrintRexPrefix(self, instruction): |
| 385 """Print machine for REX prefix.""" |
| 386 if self._bitness != 64: |
| 387 return |
| 388 if instruction.IsVexOrXop(): |
| 389 return |
| 390 if Attribute('norex') in instruction.attributes: |
| 391 return |
| 392 |
| 393 if instruction.rex.w_set: |
| 394 self._out.write('REXW_RXB\n') |
| 395 else: |
| 396 self._out.write('REX_RXB?\n') |
| 397 |
352 def _PrintOpcode(self, instruction): | 398 def _PrintOpcode(self, instruction): |
| 399 """Print machine for opcode.""" |
353 main_opcode_part = instruction.GetMainOpcodePart() | 400 main_opcode_part = instruction.GetMainOpcodePart() |
354 if instruction.HasRegisterInOpcode(): | 401 if instruction.HasRegisterInOpcode(): |
355 assert not instruction.HasModRM() | 402 assert not instruction.HasModRM() |
356 assert not instruction.HasOpcodeInsteadOfImmediate() | 403 assert not instruction.HasOpcodeInsteadOfImmediate() |
357 | 404 |
358 self._out.write(' '.join(main_opcode_part[:-1])) | 405 self._out.write(' '.join(main_opcode_part[:-1])) |
359 | 406 |
360 # Register is encoded in three least significant bits of the last byte | 407 # Register is encoded in three least significant bits of the last byte |
361 # of the opcode (in 64-bit case REX.B bit also will be involved, but it | 408 # of the opcode (in 64-bit case REX.B bit also will be involved, but it |
362 # will be handled elsewhere). | 409 # will be handled elsewhere). |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 self._out.write('@operand%d_%s\n' % (i, operand.GetFormat())) | 443 self._out.write('@operand%d_%s\n' % (i, operand.GetFormat())) |
397 | 444 |
398 # TODO(shcherbina): print operand sources and extract implicit operands. | 445 # TODO(shcherbina): print operand sources and extract implicit operands. |
399 | 446 |
400 # TODO(shcherbina): print '@last_byte_is_not_immediate' when approptiate. | 447 # TODO(shcherbina): print '@last_byte_is_not_immediate' when approptiate. |
401 # TODO(shcherbina): print '@modifiable_instruction' in validator64 if | 448 # TODO(shcherbina): print '@modifiable_instruction' in validator64 if |
402 # attribute 'nacl-amd64-modifiable' is present. | 449 # attribute 'nacl-amd64-modifiable' is present. |
403 # TODO(shcherbina): print info about CPU features. | 450 # TODO(shcherbina): print info about CPU features. |
404 # TODO(shcherbina): att_show_name_suffix. | 451 # TODO(shcherbina): att_show_name_suffix. |
405 | 452 |
406 # TODO(shcherbina): print spurious REX stuff (probably not in this | 453 if (self._mode == DECODER and |
407 # function). | 454 self._bitness == 64 and |
| 455 not instruction.IsVexOrXop()): |
| 456 # Note that even if 'norex' attribute is present, we print |
| 457 # @spurious_rex_... actions because NOP needs them (and it has REX |
| 458 # prefix specified as part of the opcode). |
| 459 # TODO(shcherbina): fix that? |
| 460 if not instruction.rex.b_matters: |
| 461 self._out.write('@set_spurious_rex_b\n') |
| 462 if not instruction.rex.x_matters: |
| 463 self._out.write('@set_spurious_rex_x\n') |
| 464 if not instruction.rex.r_matters: |
| 465 self._out.write('@set_spurious_rex_r\n') |
| 466 if not instruction.rex.w_matters: |
| 467 self._out.write('@set_spurious_rex_w\n') |
408 | 468 |
409 def _PrintOperandSource(self, operand, source): | 469 def _PrintOperandSource(self, operand, source): |
| 470 """Print action specifying operand source.""" |
410 # TODO(shcherbina): add mechanism to check that all operand sources are | 471 # TODO(shcherbina): add mechanism to check that all operand sources are |
411 # printed. | 472 # printed. |
412 self._out.write('@operand%d_%s\n' % (operand.index, source)) | 473 self._out.write('@operand%d_%s\n' % (operand.index, source)) |
413 | 474 |
414 def _PrintImplicitOperandSources(self, instruction): | 475 def _PrintImplicitOperandSources(self, instruction): |
415 """Print actions specifying sources of implicit operands. | 476 """Print actions specifying sources of implicit operands. |
416 | 477 |
417 Args: | 478 Args: |
418 instruction: instruction. | 479 instruction: instruction. |
419 | 480 |
420 Returns: | 481 Returns: |
421 None. | 482 None. |
422 """ | 483 """ |
423 operand = instruction.FindOperand('a') | 484 operand = instruction.FindOperand('a') |
424 if operand is not None: | 485 if operand is not None: |
425 self._PrintOperandSource(operand, 'rax') | 486 self._PrintOperandSource(operand, 'rax') |
426 # TODO(shcherbina): handle other implicit operands. | 487 # TODO(shcherbina): handle other implicit operands. |
427 | 488 |
428 def PrintInstructionWithoutModRM(self, instruction): | 489 def PrintInstructionWithoutModRM(self, instruction): |
429 # TODO(shcherbina): print legacy prefixes. | 490 # TODO(shcherbina): print legacy prefixes. |
430 # TODO(shcherbina): print REX prefix. | |
431 | 491 |
| 492 assert not instruction.IsVexOrXop(), 'not supported yet' |
432 assert not instruction.HasModRM() | 493 assert not instruction.HasModRM() |
| 494 |
| 495 self._PrintRexPrefix(instruction) |
| 496 |
433 assert not instruction.HasOpcodeInsteadOfImmediate(), 'not supported yet' | 497 assert not instruction.HasOpcodeInsteadOfImmediate(), 'not supported yet' |
434 | 498 |
435 self._PrintOpcode(instruction) | 499 self._PrintOpcode(instruction) |
436 self._out.write('\n') | 500 self._out.write('\n') |
437 | 501 |
438 self._PrintSignature(instruction) | 502 self._PrintSignature(instruction) |
439 self._PrintImplicitOperandSources(instruction) | 503 self._PrintImplicitOperandSources(instruction) |
440 | 504 |
441 # TODO(shcherbina): print immediate args. | 505 # TODO(shcherbina): print immediate args. |
442 | 506 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 | 594 |
531 return result | 595 return result |
532 | 596 |
533 | 597 |
534 def main(): | 598 def main(): |
535 pass | 599 pass |
536 | 600 |
537 | 601 |
538 if __name__ == '__main__': | 602 if __name__ == '__main__': |
539 main() | 603 main() |
OLD | NEW |