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 |