Chromium Code Reviews| 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 len(self.opcodes) >= 3 and ( | |
| 362 self.opcodes[0] == '0xc4' or | |
| 363 self.opcodes[0] == '0x8f' and self.opcodes[1] != '/0') | |
|
khim
2013/01/29 14:07:01
I don't think you need to check self.opcodes[1] he
Vlad Shcherbina
2013/01/29 14:50:37
Changed to what I think is more straightforward ch
| |
| 364 | |
| 332 def __str__(self): | 365 def __str__(self): |
| 333 return ' '.join([self.name] + map(str, self.operands)) | 366 return ' '.join([self.name] + map(str, self.operands)) |
| 334 | 367 |
| 335 | 368 |
| 336 DECODER = object() | 369 DECODER = object() |
| 337 VALIDATOR = object() | 370 VALIDATOR = object() |
| 338 | 371 |
| 339 | 372 |
| 340 class InstructionPrinter(object): | 373 class InstructionPrinter(object): |
| 341 | 374 |
| 342 def __init__(self, mode, bitness): | 375 def __init__(self, mode, bitness): |
| 343 assert mode in [DECODER, VALIDATOR] | 376 assert mode in [DECODER, VALIDATOR] |
| 344 assert bitness in [32, 64] | 377 assert bitness in [32, 64] |
| 345 self._mode = mode | 378 self._mode = mode |
| 346 self._bitness = bitness | 379 self._bitness = bitness |
| 347 self._out = StringIO.StringIO() | 380 self._out = StringIO.StringIO() |
| 348 | 381 |
| 349 def GetContent(self): | 382 def GetContent(self): |
| 350 return self._out.getvalue() | 383 return self._out.getvalue() |
| 351 | 384 |
| 385 def _PrintRexPrefix(self, instruction): | |
|
halyavin
2013/01/29 15:15:56
"""Print machine for rex prefix."""
| |
| 386 assert self._bitness == 64 | |
| 387 assert not instruction.IsVexOrXop() | |
| 388 | |
| 389 if Attribute('norex') in instruction.attributes: | |
| 390 return | |
| 391 | |
| 392 if instruction.rex.w_set: | |
| 393 self._out.write('REXW_RXB\n') | |
| 394 else: | |
| 395 self._out.write('REX_RXB?\n') | |
| 396 | |
| 352 def _PrintOpcode(self, instruction): | 397 def _PrintOpcode(self, instruction): |
|
halyavin
2013/01/29 15:15:56
"""Print machine for opcode."""
| |
| 353 main_opcode_part = instruction.GetMainOpcodePart() | 398 main_opcode_part = instruction.GetMainOpcodePart() |
| 354 if instruction.HasRegisterInOpcode(): | 399 if instruction.HasRegisterInOpcode(): |
| 355 assert not instruction.HasModRM() | 400 assert not instruction.HasModRM() |
| 356 assert not instruction.HasOpcodeInsteadOfImmediate() | 401 assert not instruction.HasOpcodeInsteadOfImmediate() |
| 357 | 402 |
| 358 self._out.write(' '.join(main_opcode_part[:-1])) | 403 self._out.write(' '.join(main_opcode_part[:-1])) |
| 359 | 404 |
| 360 # Register is encoded in three least significant bits of the last byte | 405 # 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 | 406 # of the opcode (in 64-bit case REX.B bit also will be involved, but it |
| 362 # will be handled elsewhere). | 407 # 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())) | 441 self._out.write('@operand%d_%s\n' % (i, operand.GetFormat())) |
| 397 | 442 |
| 398 # TODO(shcherbina): print operand sources and extract implicit operands. | 443 # TODO(shcherbina): print operand sources and extract implicit operands. |
| 399 | 444 |
| 400 # TODO(shcherbina): print '@last_byte_is_not_immediate' when approptiate. | 445 # TODO(shcherbina): print '@last_byte_is_not_immediate' when approptiate. |
| 401 # TODO(shcherbina): print '@modifiable_instruction' in validator64 if | 446 # TODO(shcherbina): print '@modifiable_instruction' in validator64 if |
| 402 # attribute 'nacl-amd64-modifiable' is present. | 447 # attribute 'nacl-amd64-modifiable' is present. |
| 403 # TODO(shcherbina): print info about CPU features. | 448 # TODO(shcherbina): print info about CPU features. |
| 404 # TODO(shcherbina): att_show_name_suffix. | 449 # TODO(shcherbina): att_show_name_suffix. |
| 405 | 450 |
| 406 # TODO(shcherbina): print spurious REX stuff (probably not in this | 451 if (self._mode == DECODER and |
| 407 # function). | 452 self._bitness == 64 and |
| 453 not instruction.IsVexOrXop()): | |
| 454 # Note that even if 'norex' attribute is present, we print | |
| 455 # @spurious_rex_... actions because NOP needs them (and it has REX | |
| 456 # prefix specified as part of the opcode). | |
| 457 # TODO(shcherbina): fix that? | |
| 458 if not instruction.rex.b_matters: | |
| 459 self._out.write('@set_spurious_rex_b\n') | |
| 460 if not instruction.rex.x_matters: | |
| 461 self._out.write('@set_spurious_rex_x\n') | |
| 462 if not instruction.rex.r_matters: | |
| 463 self._out.write('@set_spurious_rex_r\n') | |
| 464 if not instruction.rex.w_matters: | |
| 465 self._out.write('@set_spurious_rex_w\n') | |
| 408 | 466 |
| 409 def _PrintOperandSource(self, operand, source): | 467 def _PrintOperandSource(self, operand, source): |
| 410 # TODO(shcherbina): add mechanism to check that all operand sources are | 468 # TODO(shcherbina): add mechanism to check that all operand sources are |
| 411 # printed. | 469 # printed. |
| 412 self._out.write('@operand%d_%s\n' % (operand.index, source)) | 470 self._out.write('@operand%d_%s\n' % (operand.index, source)) |
| 413 | 471 |
| 414 def _PrintImplicitOperandSources(self, instruction): | 472 def _PrintImplicitOperandSources(self, instruction): |
| 415 """Print actions specifying sources of implicit operands. | 473 """Print actions specifying sources of implicit operands. |
| 416 | 474 |
| 417 Args: | 475 Args: |
| 418 instruction: instruction. | 476 instruction: instruction. |
| 419 | 477 |
| 420 Returns: | 478 Returns: |
| 421 None. | 479 None. |
| 422 """ | 480 """ |
| 423 operand = instruction.FindOperand('a') | 481 operand = instruction.FindOperand('a') |
| 424 if operand is not None: | 482 if operand is not None: |
| 425 self._PrintOperandSource(operand, 'rax') | 483 self._PrintOperandSource(operand, 'rax') |
| 426 # TODO(shcherbina): handle other implicit operands. | 484 # TODO(shcherbina): handle other implicit operands. |
| 427 | 485 |
| 428 def PrintInstructionWithoutModRM(self, instruction): | 486 def PrintInstructionWithoutModRM(self, instruction): |
| 429 # TODO(shcherbina): print legacy prefixes. | 487 # TODO(shcherbina): print legacy prefixes. |
| 430 # TODO(shcherbina): print REX prefix. | |
| 431 | 488 |
| 489 assert not instruction.IsVexOrXop() | |
|
khim
2013/01/29 14:07:01
Why not? Where and how do you plan to print vzeroa
Vlad Shcherbina
2013/01/29 14:50:37
Right, marked as 'not implemented'.
| |
| 432 assert not instruction.HasModRM() | 490 assert not instruction.HasModRM() |
| 491 | |
| 492 if self._bitness == 64: | |
| 493 self._PrintRexPrefix(instruction) | |
| 494 | |
| 433 assert not instruction.HasOpcodeInsteadOfImmediate(), 'not supported yet' | 495 assert not instruction.HasOpcodeInsteadOfImmediate(), 'not supported yet' |
| 434 | 496 |
| 435 self._PrintOpcode(instruction) | 497 self._PrintOpcode(instruction) |
| 436 self._out.write('\n') | 498 self._out.write('\n') |
| 437 | 499 |
| 438 self._PrintSignature(instruction) | 500 self._PrintSignature(instruction) |
| 439 self._PrintImplicitOperandSources(instruction) | 501 self._PrintImplicitOperandSources(instruction) |
| 440 | 502 |
| 441 # TODO(shcherbina): print immediate args. | 503 # TODO(shcherbina): print immediate args. |
| 442 | 504 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 530 | 592 |
| 531 return result | 593 return result |
| 532 | 594 |
| 533 | 595 |
| 534 def main(): | 596 def main(): |
| 535 pass | 597 pass |
| 536 | 598 |
| 537 | 599 |
| 538 if __name__ == '__main__': | 600 if __name__ == '__main__': |
| 539 main() | 601 main() |
| OLD | NEW |