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