1from __future__ import print_function 2import re 3import sys 4 5from . import common 6 7if sys.version_info[0] > 2: 8 class string: 9 expandtabs = str.expandtabs 10else: 11 import string 12 13# RegEx: this is where the magic happens. 14 15##### Assembly parser 16 17ASM_FUNCTION_X86_RE = re.compile( 18 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?' 19 r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*' 20 r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)', 21 flags=(re.M | re.S)) 22 23ASM_FUNCTION_ARM_RE = re.compile( 24 r'^(?P<func>[0-9a-zA-Z_]+):\n' # f: (name of function) 25 r'\s+\.fnstart\n' # .fnstart 26 r'(?P<body>.*?)\n' # (body of the function) 27 r'.Lfunc_end[0-9]+:', # .Lfunc_end0: or # -- End function 28 flags=(re.M | re.S)) 29 30ASM_FUNCTION_AARCH64_RE = re.compile( 31 r'^_?(?P<func>[^:]+):[ \t]*\/\/[ \t]*@(?P=func)\n' 32 r'(?:[ \t]+.cfi_startproc\n)?' # drop optional cfi noise 33 r'(?P<body>.*?)\n' 34 # This list is incomplete 35 r'.Lfunc_end[0-9]+:\n', 36 flags=(re.M | re.S)) 37 38ASM_FUNCTION_AMDGPU_RE = re.compile( 39 r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@(?P=func)\n[^:]*?' 40 r'(?P<body>.*?)\n' # (body of the function) 41 # This list is incomplete 42 r'.Lfunc_end[0-9]+:\n', 43 flags=(re.M | re.S)) 44 45ASM_FUNCTION_MIPS_RE = re.compile( 46 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' # f: (name of func) 47 r'(?:^[ \t]+\.(frame|f?mask|set).*?\n)+' # Mips+LLVM standard asm prologue 48 r'(?P<body>.*?)\n' # (body of the function) 49 r'(?:^[ \t]+\.(set|end).*?\n)+' # Mips+LLVM standard asm epilogue 50 r'(\$|\.L)func_end[0-9]+:\n', # $func_end0: (mips32 - O32) or 51 # .Lfunc_end0: (mips64 - NewABI) 52 flags=(re.M | re.S)) 53 54ASM_FUNCTION_PPC_RE = re.compile( 55 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 56 r'.*?' 57 r'\.Lfunc_begin[0-9]+:\n' 58 r'(?:[ \t]+.cfi_startproc\n)?' 59 r'(?:\.Lfunc_[gl]ep[0-9]+:\n(?:[ \t]+.*?\n)*)*' 60 r'(?P<body>.*?)\n' 61 # This list is incomplete 62 r'(?:^[ \t]*(?:\.long[ \t]+[^\n]+|\.quad[ \t]+[^\n]+)\n)*' 63 r'.Lfunc_end[0-9]+:\n', 64 flags=(re.M | re.S)) 65 66ASM_FUNCTION_RISCV_RE = re.compile( 67 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' 68 r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*' 69 r'.Lfunc_end[0-9]+:\n', 70 flags=(re.M | re.S)) 71 72ASM_FUNCTION_SPARC_RE = re.compile( 73 r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@(?P=func)\n' 74 r'(?P<body>.*?)\s*' 75 r'.Lfunc_end[0-9]+:\n', 76 flags=(re.M | re.S)) 77 78ASM_FUNCTION_SYSTEMZ_RE = re.compile( 79 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 80 r'[ \t]+.cfi_startproc\n' 81 r'(?P<body>.*?)\n' 82 r'.Lfunc_end[0-9]+:\n', 83 flags=(re.M | re.S)) 84 85 86SCRUB_LOOP_COMMENT_RE = re.compile( 87 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M) 88 89SCRUB_X86_SHUFFLES_RE = ( 90 re.compile( 91 r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', 92 flags=re.M)) 93SCRUB_X86_SPILL_RELOAD_RE = ( 94 re.compile( 95 r'-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$', 96 flags=re.M)) 97SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') 98SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') 99SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') 100SCRUB_X86_RET_RE = re.compile(r'ret[l|q]') 101 102def scrub_asm_x86(asm, args): 103 # Scrub runs of whitespace out of the assembly, but leave the leading 104 # whitespace in place. 105 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 106 # Expand the tabs used for indentation. 107 asm = string.expandtabs(asm, 2) 108 # Detect shuffle asm comments and hide the operands in favor of the comments. 109 asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm) 110 # Detect stack spills and reloads and hide their exact offset and whether 111 # they used the stack pointer or frame pointer. 112 asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r'{{[-0-9]+}}(%\1{{[sb]}}p)\2', asm) 113 # Generically match the stack offset of a memory operand. 114 asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) 115 if getattr(args, 'x86_scrub_rip', False): 116 # Generically match a RIP-relative memory operand. 117 asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) 118 # Generically match a LCP symbol. 119 asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) 120 if getattr(args, 'extra_scrub', False): 121 # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'. 122 asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm) 123 # Strip kill operands inserted into the asm. 124 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 125 # Strip trailing whitespace. 126 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 127 return asm 128 129def scrub_asm_amdgpu(asm, args): 130 # Scrub runs of whitespace out of the assembly, but leave the leading 131 # whitespace in place. 132 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 133 # Expand the tabs used for indentation. 134 asm = string.expandtabs(asm, 2) 135 # Strip trailing whitespace. 136 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 137 return asm 138 139def scrub_asm_arm_eabi(asm, args): 140 # Scrub runs of whitespace out of the assembly, but leave the leading 141 # whitespace in place. 142 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 143 # Expand the tabs used for indentation. 144 asm = string.expandtabs(asm, 2) 145 # Strip kill operands inserted into the asm. 146 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 147 # Strip trailing whitespace. 148 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 149 return asm 150 151def scrub_asm_powerpc64(asm, args): 152 # Scrub runs of whitespace out of the assembly, but leave the leading 153 # whitespace in place. 154 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 155 # Expand the tabs used for indentation. 156 asm = string.expandtabs(asm, 2) 157 # Stripe unimportant comments 158 asm = SCRUB_LOOP_COMMENT_RE.sub(r'', asm) 159 # Strip trailing whitespace. 160 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 161 return asm 162 163def scrub_asm_mips(asm, args): 164 # Scrub runs of whitespace out of the assembly, but leave the leading 165 # whitespace in place. 166 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 167 # Expand the tabs used for indentation. 168 asm = string.expandtabs(asm, 2) 169 # Strip trailing whitespace. 170 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 171 return asm 172 173def scrub_asm_riscv(asm, args): 174 # Scrub runs of whitespace out of the assembly, but leave the leading 175 # whitespace in place. 176 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 177 # Expand the tabs used for indentation. 178 asm = string.expandtabs(asm, 2) 179 # Strip trailing whitespace. 180 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 181 return asm 182 183def scrub_asm_sparc(asm, args): 184 # Scrub runs of whitespace out of the assembly, but leave the leading 185 # whitespace in place. 186 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 187 # Expand the tabs used for indentation. 188 asm = string.expandtabs(asm, 2) 189 # Strip trailing whitespace. 190 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 191 return asm 192 193def scrub_asm_systemz(asm, args): 194 # Scrub runs of whitespace out of the assembly, but leave the leading 195 # whitespace in place. 196 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 197 # Expand the tabs used for indentation. 198 asm = string.expandtabs(asm, 2) 199 # Strip trailing whitespace. 200 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 201 return asm 202 203def get_triple_from_march(march): 204 triples = { 205 'amdgcn': 'amdgcn', 206 } 207 for prefix, triple in triples.items(): 208 if march.startswith(prefix): 209 return triple 210 print("Cannot find a triple. Assume 'x86'", file=sys.stderr) 211 return 'x86' 212 213def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, prefixes, func_dict): 214 target_handlers = { 215 'x86_64': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 216 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 217 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 218 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 219 'arm64-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 220 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 221 'r600': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 222 'amdgcn': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 223 'arm-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 224 'thumb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 225 'thumbv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 226 'thumbv6-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 227 'thumbv6t2': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 228 'thumbv6t2-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 229 'thumbv6m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 230 'thumbv6m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 231 'thumbv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 232 'thumbv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 233 'thumbv7m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 234 'thumbv7m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 235 'thumbv8-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 236 'thumbv8m.base': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 237 'thumbv8m.main': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 238 'armv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 239 'armv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 240 'armv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 241 'armeb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 242 'armv7eb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 243 'armv7eb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 244 'armv8a': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 245 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE), 246 'powerpc64': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 247 'powerpc64le': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 248 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 249 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 250 'sparc': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 251 'sparcv9': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 252 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE), 253 } 254 handlers = None 255 for prefix, s in target_handlers.items(): 256 if triple.startswith(prefix): 257 handlers = s 258 break 259 else: 260 raise KeyError('Triple %r is not supported' % (triple)) 261 262 scrubber, function_re = handlers 263 common.build_function_body_dictionary( 264 function_re, scrubber, [args], raw_tool_output, prefixes, 265 func_dict, args.verbose) 266 267##### Generator of assembly CHECK lines 268 269def add_asm_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): 270 # Label format is based on ASM string. 271 check_label_format = '{} %s-LABEL: %s:'.format(comment_marker) 272 common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False) 273