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 85ASM_FUNCTION_WASM32_RE = re.compile( 86 r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 87 r'(?P<body>.*?)\n' 88 r'.Lfunc_end[0-9]+:\n', 89 flags=(re.M | re.S)) 90 91 92SCRUB_LOOP_COMMENT_RE = re.compile( 93 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M) 94 95SCRUB_X86_SHUFFLES_RE = ( 96 re.compile( 97 r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', 98 flags=re.M)) 99SCRUB_X86_SPILL_RELOAD_RE = ( 100 re.compile( 101 r'-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$', 102 flags=re.M)) 103SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') 104SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') 105SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') 106SCRUB_X86_RET_RE = re.compile(r'ret[l|q]') 107 108def scrub_asm_x86(asm, args): 109 # Scrub runs of whitespace out of the assembly, but leave the leading 110 # whitespace in place. 111 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 112 # Expand the tabs used for indentation. 113 asm = string.expandtabs(asm, 2) 114 # Detect shuffle asm comments and hide the operands in favor of the comments. 115 asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm) 116 # Detect stack spills and reloads and hide their exact offset and whether 117 # they used the stack pointer or frame pointer. 118 asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r'{{[-0-9]+}}(%\1{{[sb]}}p)\2', asm) 119 # Generically match the stack offset of a memory operand. 120 asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) 121 if getattr(args, 'x86_scrub_rip', False): 122 # Generically match a RIP-relative memory operand. 123 asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) 124 # Generically match a LCP symbol. 125 asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) 126 if getattr(args, 'extra_scrub', False): 127 # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'. 128 asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm) 129 # Strip kill operands inserted into the asm. 130 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 131 # Strip trailing whitespace. 132 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 133 return asm 134 135def scrub_asm_amdgpu(asm, args): 136 # Scrub runs of whitespace out of the assembly, but leave the leading 137 # whitespace in place. 138 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 139 # Expand the tabs used for indentation. 140 asm = string.expandtabs(asm, 2) 141 # Strip trailing whitespace. 142 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 143 return asm 144 145def scrub_asm_arm_eabi(asm, args): 146 # Scrub runs of whitespace out of the assembly, but leave the leading 147 # whitespace in place. 148 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 149 # Expand the tabs used for indentation. 150 asm = string.expandtabs(asm, 2) 151 # Strip kill operands inserted into the asm. 152 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm) 153 # Strip trailing whitespace. 154 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 155 return asm 156 157def scrub_asm_powerpc64(asm, args): 158 # Scrub runs of whitespace out of the assembly, but leave the leading 159 # whitespace in place. 160 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 161 # Expand the tabs used for indentation. 162 asm = string.expandtabs(asm, 2) 163 # Stripe unimportant comments 164 asm = SCRUB_LOOP_COMMENT_RE.sub(r'', asm) 165 # Strip trailing whitespace. 166 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 167 return asm 168 169def scrub_asm_mips(asm, args): 170 # Scrub runs of whitespace out of the assembly, but leave the leading 171 # whitespace in place. 172 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 173 # Expand the tabs used for indentation. 174 asm = string.expandtabs(asm, 2) 175 # Strip trailing whitespace. 176 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 177 return asm 178 179def scrub_asm_riscv(asm, args): 180 # Scrub runs of whitespace out of the assembly, but leave the leading 181 # whitespace in place. 182 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 183 # Expand the tabs used for indentation. 184 asm = string.expandtabs(asm, 2) 185 # Strip trailing whitespace. 186 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 187 return asm 188 189def scrub_asm_sparc(asm, args): 190 # Scrub runs of whitespace out of the assembly, but leave the leading 191 # whitespace in place. 192 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 193 # Expand the tabs used for indentation. 194 asm = string.expandtabs(asm, 2) 195 # Strip trailing whitespace. 196 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 197 return asm 198 199def scrub_asm_systemz(asm, args): 200 # Scrub runs of whitespace out of the assembly, but leave the leading 201 # whitespace in place. 202 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 203 # Expand the tabs used for indentation. 204 asm = string.expandtabs(asm, 2) 205 # Strip trailing whitespace. 206 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 207 return asm 208 209def scrub_asm_wasm32(asm, args): 210 # Scrub runs of whitespace out of the assembly, but leave the leading 211 # whitespace in place. 212 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 213 # Expand the tabs used for indentation. 214 asm = string.expandtabs(asm, 2) 215 # Strip trailing whitespace. 216 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 217 return asm 218 219def get_triple_from_march(march): 220 triples = { 221 'amdgcn': 'amdgcn', 222 } 223 for prefix, triple in triples.items(): 224 if march.startswith(prefix): 225 return triple 226 print("Cannot find a triple. Assume 'x86'", file=sys.stderr) 227 return 'x86' 228 229def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, prefixes, func_dict): 230 target_handlers = { 231 'x86_64': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 232 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 233 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 234 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE), 235 'arm64-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 236 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE), 237 'r600': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 238 'amdgcn': (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE), 239 'arm-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 240 'thumb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 241 'thumbv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 242 'thumbv6-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 243 'thumbv6t2': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 244 'thumbv6t2-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 245 'thumbv6m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 246 'thumbv6m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 247 'thumbv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 248 'thumbv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 249 'thumbv7m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 250 'thumbv7m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 251 'thumbv8-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 252 'thumbv8m.base': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 253 'thumbv8m.main': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 254 'armv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 255 'armv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 256 'armv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 257 'armeb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 258 'armv7eb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 259 'armv7eb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 260 'armv8a': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE), 261 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE), 262 'powerpc64': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 263 'powerpc64le': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 264 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 265 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 266 'sparc': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 267 'sparcv9': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 268 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE), 269 'wasm32': (scrub_asm_wasm32, ASM_FUNCTION_WASM32_RE), 270 } 271 handlers = None 272 for prefix, s in target_handlers.items(): 273 if triple.startswith(prefix): 274 handlers = s 275 break 276 else: 277 raise KeyError('Triple %r is not supported' % (triple)) 278 279 scrubber, function_re = handlers 280 common.build_function_body_dictionary( 281 function_re, scrubber, [args], raw_tool_output, prefixes, 282 func_dict, args.verbose) 283 284##### Generator of assembly CHECK lines 285 286def add_asm_checks(output_lines, comment_marker, prefix_list, func_dict, func_name): 287 # Label format is based on ASM string. 288 check_label_format = '{} %s-LABEL: %s:'.format(comment_marker) 289 common.add_checks(output_lines, comment_marker, prefix_list, func_dict, func_name, check_label_format, True, False) 290