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