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'^\s*(\.Lfunc_end[0-9]+:\n|\.section)', 43 flags=(re.M | re.S)) 44 45ASM_FUNCTION_HEXAGON_RE = re.compile( 46 r'^_?(?P<func>[^:]+):[ \t]*//[ \t]*@(?P=func)\n[^:]*?' 47 r'(?P<body>.*?)\n' # (body of the function) 48 # This list is incomplete 49 r'.Lfunc_end[0-9]+:\n', 50 flags=(re.M | re.S)) 51 52ASM_FUNCTION_MIPS_RE = re.compile( 53 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' # f: (name of func) 54 r'(?:^[ \t]+\.(frame|f?mask|set).*?\n)+' # Mips+LLVM standard asm prologue 55 r'(?P<body>.*?)\n' # (body of the function) 56 r'(?:^[ \t]+\.(set|end).*?\n)+' # Mips+LLVM standard asm epilogue 57 r'(\$|\.L)func_end[0-9]+:\n', # $func_end0: (mips32 - O32) or 58 # .Lfunc_end0: (mips64 - NewABI) 59 flags=(re.M | re.S)) 60 61ASM_FUNCTION_PPC_RE = re.compile( 62 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 63 r'.*?' 64 r'\.Lfunc_begin[0-9]+:\n' 65 r'(?:[ \t]+.cfi_startproc\n)?' 66 r'(?:\.Lfunc_[gl]ep[0-9]+:\n(?:[ \t]+.*?\n)*)*' 67 r'(?P<body>.*?)\n' 68 # This list is incomplete 69 r'(?:^[ \t]*(?:\.long[ \t]+[^\n]+|\.quad[ \t]+[^\n]+)\n)*' 70 r'.Lfunc_end[0-9]+:\n', 71 flags=(re.M | re.S)) 72 73ASM_FUNCTION_RISCV_RE = re.compile( 74 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?' 75 r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*' 76 r'.Lfunc_end[0-9]+:\n', 77 flags=(re.M | re.S)) 78 79ASM_FUNCTION_LANAI_RE = re.compile( 80 r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@(?P=func)\n' 81 r'(?:[ \t]+.cfi_startproc\n)?' # drop optional cfi noise 82 r'(?P<body>.*?)\s*' 83 r'.Lfunc_end[0-9]+:\n', 84 flags=(re.M | re.S)) 85 86ASM_FUNCTION_SPARC_RE = re.compile( 87 r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@(?P=func)\n' 88 r'(?P<body>.*?)\s*' 89 r'.Lfunc_end[0-9]+:\n', 90 flags=(re.M | re.S)) 91 92ASM_FUNCTION_SYSTEMZ_RE = re.compile( 93 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 94 r'[ \t]+.cfi_startproc\n' 95 r'(?P<body>.*?)\n' 96 r'.Lfunc_end[0-9]+:\n', 97 flags=(re.M | re.S)) 98 99ASM_FUNCTION_AARCH64_DARWIN_RE = re.compile( 100 r'^_(?P<func>[^:]+):[ \t]*;[ \t]@(?P=func)\n' 101 r'([ \t]*.cfi_startproc\n[\s]*)?' 102 r'(?P<body>.*?)' 103 r'([ \t]*.cfi_endproc\n[\s]*)?' 104 r'^[ \t]*;[ \t]--[ \t]End[ \t]function', 105 flags=(re.M | re.S)) 106 107ASM_FUNCTION_ARM_DARWIN_RE = re.compile( 108 r'^[ \t]*\.globl[ \t]*_(?P<func>[^ \t])[ \t]*@[ \t]--[ \t]Begin[ \t]function[ \t](?P=func)' 109 r'(?P<directives>.*?)' 110 r'^_(?P=func):\n[ \t]*' 111 r'(?P<body>.*?)' 112 r'^[ \t]*@[ \t]--[ \t]End[ \t]function', 113 flags=(re.M | re.S )) 114 115ASM_FUNCTION_ARM_MACHO_RE = re.compile( 116 r'^_(?P<func>[^:]+):[ \t]*\n' 117 r'([ \t]*.cfi_startproc\n[ \t]*)?' 118 r'(?P<body>.*?)\n' 119 r'[ \t]*\.cfi_endproc\n', 120 flags=(re.M | re.S)) 121 122ASM_FUNCTION_ARM_IOS_RE = re.compile( 123 r'^_(?P<func>[^:]+):[ \t]*\n' 124 r'^Lfunc_begin(?P<id>[0-9][1-9]*):\n' 125 r'(?P<body>.*?)' 126 r'^Lfunc_end(?P=id):\n' 127 r'^[ \t]*@[ \t]--[ \t]End[ \t]function', 128 flags=(re.M | re.S)) 129 130ASM_FUNCTION_WASM32_RE = re.compile( 131 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 132 r'(?P<body>.*?)\n' 133 r'^\s*(\.Lfunc_end[0-9]+:\n|end_function)', 134 flags=(re.M | re.S)) 135 136 137SCRUB_LOOP_COMMENT_RE = re.compile( 138 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M) 139 140SCRUB_X86_SHUFFLES_RE = ( 141 re.compile( 142 r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', 143 flags=re.M)) 144SCRUB_X86_SPILL_RELOAD_RE = ( 145 re.compile( 146 r'-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$', 147 flags=re.M)) 148SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') 149SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') 150SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') 151SCRUB_X86_RET_RE = re.compile(r'ret[l|q]') 152 153def scrub_asm_x86(asm, args): 154 # Scrub runs of whitespace out of the assembly, but leave the leading 155 # whitespace in place. 156 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 157 # Expand the tabs used for indentation. 158 asm = string.expandtabs(asm, 2) 159 # Detect shuffle asm comments and hide the operands in favor of the comments. 160 asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm) 161 # Detect stack spills and reloads and hide their exact offset and whether 162 # they used the stack pointer or frame pointer. 163 asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r'{{[-0-9]+}}(%\1{{[sb]}}p)\2', asm) 164 # Generically match the stack offset of a memory operand. 165 asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) 166 if getattr(args, 'x86_scrub_rip', False): 167 # Generically match a RIP-relative memory operand. 168 asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) 169 # Generically match a LCP symbol. 170 asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) 171 if getattr(args, 'extra_scrub', False): 172 # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'. 173 asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm) 174 # Strip kill operands inserted into the asm. 175 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 176 # Strip trailing whitespace. 177 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 178 return asm 179 180def scrub_asm_amdgpu(asm, args): 181 # Scrub runs of whitespace out of the assembly, but leave the leading 182 # whitespace in place. 183 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 184 # Expand the tabs used for indentation. 185 asm = string.expandtabs(asm, 2) 186 # Strip trailing whitespace. 187 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 188 return asm 189 190def scrub_asm_arm_eabi(asm, args): 191 # Scrub runs of whitespace out of the assembly, but leave the leading 192 # whitespace in place. 193 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 194 # Expand the tabs used for indentation. 195 asm = string.expandtabs(asm, 2) 196 # Strip kill operands inserted into the asm. 197 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 198 # Strip trailing whitespace. 199 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 200 return asm 201 202def scrub_asm_hexagon(asm, args): 203 # Scrub runs of whitespace out of the assembly, but leave the leading 204 # whitespace in place. 205 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 206 # Expand the tabs used for indentation. 207 asm = string.expandtabs(asm, 2) 208 # Strip trailing whitespace. 209 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 210 return asm 211 212def scrub_asm_powerpc(asm, args): 213 # Scrub runs of whitespace out of the assembly, but leave the leading 214 # whitespace in place. 215 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 216 # Expand the tabs used for indentation. 217 asm = string.expandtabs(asm, 2) 218 # Stripe unimportant comments, but leave the token '#' in place. 219 asm = SCRUB_LOOP_COMMENT_RE.sub(r'#', asm) 220 # Strip trailing whitespace. 221 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 222 return asm 223 224def scrub_asm_mips(asm, args): 225 # Scrub runs of whitespace out of the assembly, but leave the leading 226 # whitespace in place. 227 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 228 # Expand the tabs used for indentation. 229 asm = string.expandtabs(asm, 2) 230 # Strip trailing whitespace. 231 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 232 return asm 233 234def scrub_asm_riscv(asm, args): 235 # Scrub runs of whitespace out of the assembly, but leave the leading 236 # whitespace in place. 237 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 238 # Expand the tabs used for indentation. 239 asm = string.expandtabs(asm, 2) 240 # Strip trailing whitespace. 241 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 242 return asm 243 244def scrub_asm_lanai(asm, args): 245 # Scrub runs of whitespace out of the assembly, but leave the leading 246 # whitespace in place. 247 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 248 # Expand the tabs used for indentation. 249 asm = string.expandtabs(asm, 2) 250 # Strip trailing whitespace. 251 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 252 return asm 253 254def scrub_asm_sparc(asm, args): 255 # Scrub runs of whitespace out of the assembly, but leave the leading 256 # whitespace in place. 257 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 258 # Expand the tabs used for indentation. 259 asm = string.expandtabs(asm, 2) 260 # Strip trailing whitespace. 261 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 262 return asm 263 264def scrub_asm_systemz(asm, args): 265 # Scrub runs of whitespace out of the assembly, but leave the leading 266 # whitespace in place. 267 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 268 # Expand the tabs used for indentation. 269 asm = string.expandtabs(asm, 2) 270 # Strip trailing whitespace. 271 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 272 return asm 273 274def scrub_asm_wasm32(asm, args): 275 # Scrub runs of whitespace out of the assembly, but leave the leading 276 # whitespace in place. 277 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 278 # Expand the tabs used for indentation. 279 asm = string.expandtabs(asm, 2) 280 # Strip trailing whitespace. 281 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 282 return asm 283 284def get_triple_from_march(march): 285 triples = { 286 'amdgcn': 'amdgcn', 287 'r600': 'r600', 288 'mips': 'mips', 289 'sparc': 'sparc', 290 'hexagon': 'hexagon', 291 } 292 for prefix, triple in triples.items(): 293 if march.startswith(prefix): 294 return triple 295 print("Cannot find a triple. Assume 'x86'", file=sys.stderr) 296 return 'x86' 297 298def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, prefixes, func_dict): 299 target_handlers = { 300 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 301 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 302 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 303 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 304 'aarch64-apple-darwin': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE), 305 'hexagon': (scrub_asm_hexagon, ASM_FUNCTION_HEXAGON_RE), 306 'r600': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 307 'amdgcn': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 308 'arm': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 309 'arm64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 310 'arm64-apple-ios': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE), 311 'armv7-apple-ios' : (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE), 312 'armv7-apple-darwin': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_DARWIN_RE), 313 'thumb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 314 'thumb-macho': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE), 315 'thumbv5-macho': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE), 316 'thumbv7-apple-ios' : (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE), 317 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE), 318 'ppc32': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE), 319 'powerpc': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE), 320 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 321 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 322 'lanai': (scrub_asm_lanai, ASM_FUNCTION_LANAI_RE), 323 'sparc': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 324 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE), 325 'wasm32': (scrub_asm_wasm32, ASM_FUNCTION_WASM32_RE), 326 } 327 handler = None 328 best_prefix = '' 329 for prefix, s in target_handlers.items(): 330 if triple.startswith(prefix) and len(prefix) > len(best_prefix): 331 handler = s 332 best_prefix = prefix 333 334 if handler is None: 335 raise KeyError('Triple %r is not supported' % (triple)) 336 337 scrubber, function_re = handler 338 common.build_function_body_dictionary( 339 function_re, scrubber, [args], raw_tool_output, prefixes, 340 func_dict, args.verbose) 341 342##### Generator of assembly CHECK lines 343 344def add_asm_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): 345 # Label format is based on ASM string. 346 check_label_format = '{} %s-LABEL: %s:'.format(comment_marker) 347 common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False) 348