mc-bundling-x86-gen.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/python
  2. # Auto-generates an exhaustive and repetitive test for correct bundle-locked
  3. # alignment on x86.
  4. # For every possible offset in an aligned bundle, a bundle-locked group of every
  5. # size in the inclusive range [1, bundle_size] is inserted. An appropriate CHECK
  6. # is added to verify that NOP padding occurred (or did not occur) as expected.
  7. # Run with --align-to-end to generate a similar test with align_to_end for each
  8. # .bundle_lock directive.
  9. # This script runs with Python 2.7 and 3.2+
  10. from __future__ import print_function
  11. import argparse
  12. BUNDLE_SIZE_POW2 = 4
  13. BUNDLE_SIZE = 2 ** BUNDLE_SIZE_POW2
  14. PREAMBLE = '''
  15. # RUN: llvm-mc -filetype=obj -triple i386-pc-linux-gnu %s -o - \\
  16. # RUN: | llvm-objdump -triple i386 -disassemble -no-show-raw-insn - | FileCheck %s
  17. # !!! This test is auto-generated from utils/testgen/mc-bundling-x86-gen.py !!!
  18. # It tests that bundle-aligned grouping works correctly in MC. Read the
  19. # source of the script for more details.
  20. .text
  21. .bundle_align_mode {0}
  22. '''.format(BUNDLE_SIZE_POW2).lstrip()
  23. ALIGNTO = ' .align {0}, 0x90'
  24. NOPFILL = ' .fill {0}, 1, 0x90'
  25. def print_bundle_locked_sequence(len, align_to_end=False):
  26. print(' .bundle_lock{0}'.format(' align_to_end' if align_to_end else ''))
  27. print(' .rept {0}'.format(len))
  28. print(' inc %eax')
  29. print(' .endr')
  30. print(' .bundle_unlock')
  31. def generate(align_to_end=False):
  32. print(PREAMBLE)
  33. ntest = 0
  34. for instlen in range(1, BUNDLE_SIZE + 1):
  35. for offset in range(0, BUNDLE_SIZE):
  36. # Spread out all the instructions to not worry about cross-bundle
  37. # interference.
  38. print(ALIGNTO.format(2 * BUNDLE_SIZE))
  39. print('INSTRLEN_{0}_OFFSET_{1}:'.format(instlen, offset))
  40. if offset > 0:
  41. print(NOPFILL.format(offset))
  42. print_bundle_locked_sequence(instlen, align_to_end)
  43. # Now generate an appropriate CHECK line
  44. base_offset = ntest * 2 * BUNDLE_SIZE
  45. inst_orig_offset = base_offset + offset # had it not been padded...
  46. def print_check(adjusted_offset=None, nop_split_offset=None):
  47. if adjusted_offset is not None:
  48. print('# CHECK: {0:x}: nop'.format(inst_orig_offset))
  49. if nop_split_offset is not None:
  50. print('# CHECK: {0:x}: nop'.format(nop_split_offset))
  51. print('# CHECK: {0:x}: incl'.format(adjusted_offset))
  52. else:
  53. print('# CHECK: {0:x}: incl'.format(inst_orig_offset))
  54. if align_to_end:
  55. if offset + instlen == BUNDLE_SIZE:
  56. # No padding needed
  57. print_check()
  58. elif offset + instlen < BUNDLE_SIZE:
  59. # Pad to end at nearest bundle boundary
  60. offset_to_end = base_offset + (BUNDLE_SIZE - instlen)
  61. print_check(offset_to_end)
  62. else: # offset + instlen > BUNDLE_SIZE
  63. # Pad to end at next bundle boundary, splitting the nop sequence
  64. # at the nearest bundle boundary
  65. offset_to_nearest_bundle = base_offset + BUNDLE_SIZE
  66. offset_to_end = base_offset + (BUNDLE_SIZE * 2 - instlen)
  67. if offset_to_nearest_bundle == offset_to_end:
  68. offset_to_nearest_bundle = None
  69. print_check(offset_to_end, offset_to_nearest_bundle)
  70. else:
  71. if offset + instlen > BUNDLE_SIZE:
  72. # Padding needed
  73. aligned_offset = (inst_orig_offset + instlen) & ~(BUNDLE_SIZE - 1)
  74. print_check(aligned_offset)
  75. else:
  76. # No padding needed
  77. print_check()
  78. print()
  79. ntest += 1
  80. if __name__ == '__main__':
  81. argparser = argparse.ArgumentParser()
  82. argparser.add_argument('--align-to-end',
  83. action='store_true',
  84. help='generate .bundle_lock with align_to_end option')
  85. args = argparser.parse_args()
  86. generate(align_to_end=args.align_to_end)