| #!/usr/bin/env python |
| |
| # Auto-generates an exhaustive and repetitive test for correct bundle-locked |
| # alignment on x86. |
| # For every possible offset in an aligned bundle, a bundle-locked group of every |
| # size in the inclusive range [1, bundle_size] is inserted. An appropriate CHECK |
| # is added to verify that NOP padding occurred (or did not occur) as expected. |
| # Run with --align-to-end to generate a similar test with align_to_end for each |
| # .bundle_lock directive. |
| |
| # This script runs with Python 2.7 and 3.2+ |
| |
| from __future__ import print_function |
| import argparse |
| |
| BUNDLE_SIZE_POW2 = 4 |
| BUNDLE_SIZE = 2**BUNDLE_SIZE_POW2 |
| |
| PREAMBLE = """ |
| # RUN: llvm-mc -filetype=obj -triple i386-pc-linux-gnu %s -o - \\ |
| # RUN: | llvm-objdump -triple i386 -disassemble -no-show-raw-insn - | FileCheck %s |
| |
| # !!! This test is auto-generated from utils/testgen/mc-bundling-x86-gen.py !!! |
| # It tests that bundle-aligned grouping works correctly in MC. Read the |
| # source of the script for more details. |
| |
| .text |
| .bundle_align_mode {0} |
| """.format( |
| BUNDLE_SIZE_POW2 |
| ).lstrip() |
| |
| ALIGNTO = " .align {0}, 0x90" |
| NOPFILL = " .fill {0}, 1, 0x90" |
| |
| |
| def print_bundle_locked_sequence(len, align_to_end=False): |
| print(" .bundle_lock{0}".format(" align_to_end" if align_to_end else "")) |
| print(" .rept {0}".format(len)) |
| print(" inc %eax") |
| print(" .endr") |
| print(" .bundle_unlock") |
| |
| |
| def generate(align_to_end=False): |
| print(PREAMBLE) |
| |
| ntest = 0 |
| for instlen in range(1, BUNDLE_SIZE + 1): |
| for offset in range(0, BUNDLE_SIZE): |
| # Spread out all the instructions to not worry about cross-bundle |
| # interference. |
| print(ALIGNTO.format(2 * BUNDLE_SIZE)) |
| print("INSTRLEN_{0}_OFFSET_{1}:".format(instlen, offset)) |
| if offset > 0: |
| print(NOPFILL.format(offset)) |
| print_bundle_locked_sequence(instlen, align_to_end) |
| |
| # Now generate an appropriate CHECK line |
| base_offset = ntest * 2 * BUNDLE_SIZE |
| inst_orig_offset = base_offset + offset # had it not been padded... |
| |
| def print_check(adjusted_offset=None, nop_split_offset=None): |
| if adjusted_offset is not None: |
| print("# CHECK: {0:x}: nop".format(inst_orig_offset)) |
| if nop_split_offset is not None: |
| print("# CHECK: {0:x}: nop".format(nop_split_offset)) |
| print("# CHECK: {0:x}: incl".format(adjusted_offset)) |
| else: |
| print("# CHECK: {0:x}: incl".format(inst_orig_offset)) |
| |
| if align_to_end: |
| if offset + instlen == BUNDLE_SIZE: |
| # No padding needed |
| print_check() |
| elif offset + instlen < BUNDLE_SIZE: |
| # Pad to end at nearest bundle boundary |
| offset_to_end = base_offset + (BUNDLE_SIZE - instlen) |
| print_check(offset_to_end) |
| else: # offset + instlen > BUNDLE_SIZE |
| # Pad to end at next bundle boundary, splitting the nop sequence |
| # at the nearest bundle boundary |
| offset_to_nearest_bundle = base_offset + BUNDLE_SIZE |
| offset_to_end = base_offset + (BUNDLE_SIZE * 2 - instlen) |
| if offset_to_nearest_bundle == offset_to_end: |
| offset_to_nearest_bundle = None |
| print_check(offset_to_end, offset_to_nearest_bundle) |
| else: |
| if offset + instlen > BUNDLE_SIZE: |
| # Padding needed |
| aligned_offset = (inst_orig_offset + instlen) & ~(BUNDLE_SIZE - 1) |
| print_check(aligned_offset) |
| else: |
| # No padding needed |
| print_check() |
| |
| print() |
| ntest += 1 |
| |
| |
| if __name__ == "__main__": |
| argparser = argparse.ArgumentParser() |
| argparser.add_argument( |
| "--align-to-end", |
| action="store_true", |
| help="generate .bundle_lock with align_to_end option", |
| ) |
| args = argparser.parse_args() |
| generate(align_to_end=args.align_to_end) |