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