xref: /llvm-project/llvm/utils/UpdateTestChecks/asm.py (revision b3363104d3af75f7f0151f28fc9e577cea6dea6b)
1from __future__ import print_function
2import re
3import sys
4
5from . import common
6
7if sys.version_info[0] > 2:
8
9    class string:
10        expandtabs = str.expandtabs
11
12else:
13    import string
14
15# RegEx: this is where the magic happens.
16
17##### Assembly parser
18#
19# The set of per-arch regular expressions define several groups.
20# The required groups are "func" (function name) and "body" (body of the function).
21# Although some backends require some additional groups like: "directives"
22# and "func_name_separator"
23
24ASM_FUNCTION_X86_RE = re.compile(
25    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*(@"?(?P=func)"?| -- Begin function (?P=func))\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?'
26    r"(?:\.L(?P=func)\$local:\n)?"  # drop .L<func>$local:
27    r"(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?"  # drop .type .L<func>$local
28    r"(?:[ \t]*(?:\.cfi_startproc|\.cfi_personality|\.cfi_lsda|\.seh_proc|\.seh_handler)\b[^\n]*\n)*"  # drop optional cfi
29    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
30    r"^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)",
31    flags=(re.M | re.S),
32)
33
34ASM_FUNCTION_ARM_RE = re.compile(
35    r"^(?P<func>[0-9a-zA-Z_$]+):\n"  # f: (name of function)
36    r"(?:\.L(?P=func)\$local:\n)?"  # drop .L<func>$local:
37    r"(?:\s*\.type\s+\.L(?P=func)\$local,@function\n)?"  # drop .type .L<func>$local
38    r"\s+\.fnstart\n"  # .fnstart
39    r"(?P<body>.*?)"  # (body of the function)
40    r"^.Lfunc_end[0-9]+:",  # .Lfunc_end0: or # -- End function
41    flags=(re.M | re.S),
42)
43
44ASM_FUNCTION_AARCH64_RE = re.compile(
45    r'^_?(?P<func>[^:]+):[ \t]*\/\/[ \t]*@"?(?P=func)"?( (Function|Tail Call))?\n'
46    r"(?:[ \t]+.cfi_startproc\n)?"  # drop optional cfi noise
47    r"(?P<body>.*?)\n"
48    # This list is incomplete
49    r"^\s*(\.Lfunc_end[0-9]+|// -- End function)",
50    flags=(re.M | re.S),
51)
52
53ASM_FUNCTION_AMDGPU_RE = re.compile(
54    r"\.type\s+_?(?P<func>[^,\n]+),@function\n"
55    r"(^\s*\.amdgpu_hsa_kernel (?P=func)\n)?"
56    r'^_?(?P=func):(?:[ \t]*;+[ \t]*@"?(?P=func)"?)?\n'
57    r"(?P<body>.*?)\n"  # (body of the function)
58    # This list is incomplete
59    r"^\s*(\.Lfunc_end[0-9]+:\n|\.section)",
60    flags=(re.M | re.S),
61)
62
63ASM_FUNCTION_BPF_RE = re.compile(
64    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
65    r"(?:[ \t]+.cfi_startproc\n|.seh_proc[^\n]+\n)?"  # drop optional cfi
66    r"(?P<body>.*?)\s*"
67    r".Lfunc_end[0-9]+:\n",
68    flags=(re.M | re.S),
69)
70
71ASM_FUNCTION_HEXAGON_RE = re.compile(
72    r'^_?(?P<func>[^:]+):[ \t]*//[ \t]*@"?(?P=func)"?\n[^:]*?'
73    r"(?P<body>.*?)\n"  # (body of the function)
74    # This list is incomplete
75    r".Lfunc_end[0-9]+:\n",
76    flags=(re.M | re.S),
77)
78
79ASM_FUNCTION_M68K_RE = re.compile(
80    r'^_?(?P<func>[^:]+):[ \t]*;[ \t]*@"?(?P=func)"?\n'
81    r'(?:\.L(?P=func)\$local:\n)?'  # drop .L<func>$local:
82    r'(?:[ \t]+\.type[ \t]+\.L(?P=func)\$local,@function\n)?' # drop .type .L<func>$local,@function
83    r'(?P<body>.*?)\s*' # (body of the function)
84    r'.Lfunc_end[0-9]+:\n',
85    flags=(re.M | re.S))
86
87ASM_FUNCTION_MIPS_RE = re.compile(
88    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n[^:]*?'  # f: (name of func)
89    r"(?:\s*\.?Ltmp[^:\n]*:\n)?[^:]*?"  # optional .Ltmp<N> for EH
90    r"(?:^[ \t]+\.(frame|f?mask|set).*?\n)+"  # Mips+LLVM standard asm prologue
91    r"(?P<body>.*?)\n"  # (body of the function)
92    # Mips+LLVM standard asm epilogue
93    r"(?:(^[ \t]+\.set[^\n]*?\n)*^[ \t]+\.end.*?\n)"
94    r"(\$|\.L)func_end[0-9]+:\n",  # $func_end0: (mips32 - O32) or
95    # .Lfunc_end0: (mips64 - NewABI)
96    flags=(re.M | re.S),
97)
98
99ASM_FUNCTION_MSP430_RE = re.compile(
100    r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@"?(?P=func)"?\n[^:]*?'
101    r"(?P<body>.*?)\n"
102    r"(\$|\.L)func_end[0-9]+:\n",  # $func_end0:
103    flags=(re.M | re.S),
104)
105
106ASM_FUNCTION_AVR_RE = re.compile(
107    r'^_?(?P<func>[^:]+):[ \t]*;+[ \t]*@"?(?P=func)"?\n[^:]*?'
108    r"(?P<body>.*?)\n"
109    r".Lfunc_end[0-9]+:\n",
110    flags=(re.M | re.S),
111)
112
113ASM_FUNCTION_PPC_RE = re.compile(
114    r"#[ \-\t]*Begin function (?P<func>[^.:]+)\n"
115    r".*?"
116    r'^[_.]?(?P=func):(?:[ \t]*#+[ \t]*@"?(?P=func)"?)?\n'
117    r"(?:^[^#]*\n)*"
118    r"(?P<body>.*?)\n"
119    # This list is incomplete
120    r"(?:^[ \t]*(?:\.(?:long|quad|v?byte)[ \t]+[^\n]+)\n)*"
121    r"(?:\.Lfunc_end|L\.\.(?P=func))[0-9]+:\n",
122    flags=(re.M | re.S),
123)
124
125ASM_FUNCTION_RISCV_RE = re.compile(
126    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
127    r"(?:\s*\.?L(?P=func)\$local:\n)?"  # optional .L<func>$local: due to -fno-semantic-interposition
128    r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?"  # optional .type .L<func>$local
129    r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
130    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
131    r".Lfunc_end[0-9]+:\n",
132    flags=(re.M | re.S),
133)
134
135ASM_FUNCTION_LANAI_RE = re.compile(
136    r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@"?(?P=func)"?\n'
137    r"(?:[ \t]+.cfi_startproc\n)?"  # drop optional cfi noise
138    r"(?P<body>.*?)\s*"
139    r".Lfunc_end[0-9]+:\n",
140    flags=(re.M | re.S),
141)
142
143ASM_FUNCTION_SPARC_RE = re.compile(
144    r'^_?(?P<func>[^:]+):[ \t]*!+[ \t]*@"?(?P=func)"?\n'
145    r"(?P<body>.*?)\s*"
146    r".Lfunc_end[0-9]+:\n",
147    flags=(re.M | re.S),
148)
149
150ASM_FUNCTION_SYSTEMZ_RE = re.compile(
151    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
152    r"(?:[ \t]+.cfi_startproc\n)?"
153    r"(?P<body>.*?)\n"
154    r".Lfunc_end[0-9]+:\n",
155    flags=(re.M | re.S),
156)
157
158ASM_FUNCTION_AARCH64_DARWIN_RE = re.compile(
159    r'^_(?P<func>[^:]+):[ \t]*;[ \t]@"?(?P=func)"?\n'
160    r"([ \t]*.cfi_startproc\n[\s]*)?"
161    r"(?P<body>.*?)"
162    r"([ \t]*.cfi_endproc\n[\s]*)?"
163    r"^[ \t]*;[ \t]--[ \t]End[ \t]function",
164    flags=(re.M | re.S),
165)
166
167ASM_FUNCTION_ARM_DARWIN_RE = re.compile(
168    r"@[ \t]--[ \t]Begin[ \t]function[ \t](?P<func>[^ \t]+?)\n"
169    r"^[ \t]*\.globl[ \t]*_(?P=func)[ \t]*"
170    r"(?P<directives>.*?)"
171    r"^_(?P=func):\n[ \t]*"
172    r"(?P<body>.*?)"
173    r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
174    flags=(re.M | re.S),
175)
176
177ASM_FUNCTION_ARM_MACHO_RE = re.compile(
178    r"^_(?P<func>[^:]+):[ \t]*\n"
179    r"([ \t]*.cfi_startproc\n[ \t]*)?"
180    r"(?P<body>.*?)\n"
181    r"[ \t]*\.cfi_endproc\n",
182    flags=(re.M | re.S),
183)
184
185ASM_FUNCTION_THUMBS_DARWIN_RE = re.compile(
186    r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)\n" r"[ \t]*\.data_region\n",
187    flags=(re.M | re.S),
188)
189
190ASM_FUNCTION_THUMB_DARWIN_RE = re.compile(
191    r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)\n" r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
192    flags=(re.M | re.S),
193)
194
195ASM_FUNCTION_ARM_IOS_RE = re.compile(
196    r"^_(?P<func>[^:]+):\n" r"(?P<body>.*?)" r"^[ \t]*@[ \t]--[ \t]End[ \t]function",
197    flags=(re.M | re.S),
198)
199
200ASM_FUNCTION_WASM_RE = re.compile(
201    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
202    r"(?P<body>.*?)\n"
203    r"^\s*(\.Lfunc_end[0-9]+:\n|end_function)",
204    flags=(re.M | re.S),
205)
206
207# We parse the function name from OpName, and grab the variable name 'var'
208# for this function. Then we match that when the variable is assigned with
209# OpFunction and match its body.
210ASM_FUNCTION_SPIRV_RE = re.compile(
211    r'OpName (?P<var>%[0-9]+) "(?P<func>[^"]+)(?P<func_name_separator>)".*(?P<body>(?P=var) = OpFunction.+?OpFunctionEnd)',
212    flags=(re.M | re.S),
213)
214
215ASM_FUNCTION_VE_RE = re.compile(
216    r"^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n"
217    r"(?:\s*\.?L(?P=func)\$local:\n)?"  # optional .L<func>$local: due to -fno-semantic-interposition
218    r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?"  # optional .type .L<func>$local
219    r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
220    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
221    r".Lfunc_end[0-9]+:\n",
222    flags=(re.M | re.S),
223)
224
225ASM_FUNCTION_XTENSA_RE = re.compile(
226    r"^(?P<func>[^:]+): +# @(?P=func)\n(?P<body>.*?)\n\.Lfunc_end\d+:\n",
227    flags=(re.M | re.S),
228)
229
230ASM_FUNCTION_CSKY_RE = re.compile(
231    r"^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
232    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
233    r".Lfunc_end[0-9]+:\n",
234    flags=(re.M | re.S),
235)
236
237ASM_FUNCTION_NVPTX_RE = re.compile(
238    # function attributes and retval
239    # .visible .func (.param .align 16 .b8 func_retval0[32])
240    # r'^(\.visible\s+)?\.func\s+(\([^\)]*\)\s*)?'
241    r"^(\.(func|visible|weak|entry|noreturn|extern)\s+)+(\([^\)]*\)\s*)?"
242    # function name
243    r"(?P<func>[^\(\n]+)"
244    # function name separator (opening brace)
245    r"(?P<func_name_separator>\()"
246    # function parameters
247    # (
248    #   .param .align 16 .b8 callee_St8x4_param_0[32]
249    # ) // -- Begin function callee_St8x4
250    r"[^\)]*\)(\s*//[^\n]*)?\n"
251    # function body
252    r"(?P<body>.*?)\n"
253    # function body end marker
254    r"\s*// -- End function",
255    flags=(re.M | re.S),
256)
257
258ASM_FUNCTION_LOONGARCH_RE = re.compile(
259    r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n'
260    r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"
261    r"(?P<body>^##?[ \t]+[^:]+:.*?)\s*"
262    r".Lfunc_end[0-9]+:\n",
263    flags=(re.M | re.S),
264)
265
266SCRUB_X86_SHUFFLES_RE = re.compile(
267    r"^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$", flags=re.M
268)
269
270SCRUB_X86_SHUFFLES_NO_MEM_RE = re.compile(
271    r"^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = (?!.*(?:mem)).*)$",
272    flags=re.M,
273)
274
275SCRUB_X86_SPILL_RELOAD_RE = re.compile(
276    r"-?\d+\(%([er])[sb]p\)(.*(?:Spill|Reload))$", flags=re.M
277)
278SCRUB_X86_SP_RE = re.compile(r"\d+\(%(esp|rsp)\)")
279SCRUB_X86_RIP_RE = re.compile(r"[.\w]+\(%rip\)")
280SCRUB_X86_LCP_RE = re.compile(r"\.?LCPI[0-9]+_[0-9]+")
281SCRUB_X86_RET_RE = re.compile(r"ret[l|q]")
282
283
284def scrub_asm_x86(asm, args):
285    # Scrub runs of whitespace out of the assembly, but leave the leading
286    # whitespace in place.
287    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
288    # Expand the tabs used for indentation.
289    asm = string.expandtabs(asm, 2)
290
291    # Detect shuffle asm comments and hide the operands in favor of the comments.
292    if getattr(args, "no_x86_scrub_mem_shuffle", True):
293        asm = SCRUB_X86_SHUFFLES_NO_MEM_RE.sub(r"\1 {{.*#+}} \2", asm)
294    else:
295        asm = SCRUB_X86_SHUFFLES_RE.sub(r"\1 {{.*#+}} \2", asm)
296
297    # Detect stack spills and reloads and hide their exact offset and whether
298    # they used the stack pointer or frame pointer.
299    asm = SCRUB_X86_SPILL_RELOAD_RE.sub(r"{{[-0-9]+}}(%\1{{[sb]}}p)\2", asm)
300    if getattr(args, "x86_scrub_sp", True):
301        # Generically match the stack offset of a memory operand.
302        asm = SCRUB_X86_SP_RE.sub(r"{{[0-9]+}}(%\1)", asm)
303    if getattr(args, "x86_scrub_rip", False):
304        # Generically match a RIP-relative memory operand.
305        asm = SCRUB_X86_RIP_RE.sub(r"{{.*}}(%rip)", asm)
306    # Generically match a LCP symbol.
307    asm = SCRUB_X86_LCP_RE.sub(r"{{\.?LCPI[0-9]+_[0-9]+}}", asm)
308    if getattr(args, "extra_scrub", False):
309        # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'.
310        asm = SCRUB_X86_RET_RE.sub(r"ret{{[l|q]}}", asm)
311    # Strip kill operands inserted into the asm.
312    asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
313    # Strip trailing whitespace.
314    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
315    return asm
316
317
318def scrub_asm_amdgpu(asm, args):
319    # Scrub runs of whitespace out of the assembly, but leave the leading
320    # whitespace in place.
321    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
322    # Expand the tabs used for indentation.
323    asm = string.expandtabs(asm, 2)
324    # Strip trailing whitespace.
325    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
326    return asm
327
328
329def scrub_asm_arm_eabi(asm, args):
330    # Scrub runs of whitespace out of the assembly, but leave the leading
331    # whitespace in place.
332    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
333    # Expand the tabs used for indentation.
334    asm = string.expandtabs(asm, 2)
335    # Strip kill operands inserted into the asm.
336    asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
337    # Strip trailing whitespace.
338    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
339    return asm
340
341
342def scrub_asm_bpf(asm, args):
343    # Scrub runs of whitespace out of the assembly, but leave the leading
344    # whitespace in place.
345    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
346    # Expand the tabs used for indentation.
347    asm = string.expandtabs(asm, 2)
348    # Strip trailing whitespace.
349    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
350    return asm
351
352
353def scrub_asm_hexagon(asm, args):
354    # Scrub runs of whitespace out of the assembly, but leave the leading
355    # whitespace in place.
356    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
357    # Expand the tabs used for indentation.
358    asm = string.expandtabs(asm, 2)
359    # Strip trailing whitespace.
360    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
361    return asm
362
363
364def scrub_asm_powerpc(asm, args):
365    # Scrub runs of whitespace out of the assembly, but leave the leading
366    # whitespace in place.
367    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
368    # Expand the tabs used for indentation.
369    asm = string.expandtabs(asm, 2)
370    # Strip unimportant comments, but leave the token '#' in place.
371    asm = common.SCRUB_LOOP_COMMENT_RE.sub(r"#", asm)
372    # Strip trailing whitespace.
373    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
374    # Strip the tailing token '#', except the line only has token '#'.
375    asm = common.SCRUB_TAILING_COMMENT_TOKEN_RE.sub(r"", asm)
376    return asm
377
378
379def scrub_asm_m68k(asm, args):
380    # Scrub runs of whitespace out of the assembly, but leave the leading
381    # whitespace in place.
382    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
383    # Expand the tabs used for indentation.
384    asm = string.expandtabs(asm, 2)
385    # Strip trailing whitespace.
386    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
387    return asm
388
389
390def scrub_asm_mips(asm, args):
391    # Scrub runs of whitespace out of the assembly, but leave the leading
392    # whitespace in place.
393    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
394    # Expand the tabs used for indentation.
395    asm = string.expandtabs(asm, 2)
396    # Strip trailing whitespace.
397    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
398    return asm
399
400
401def scrub_asm_msp430(asm, args):
402    # Scrub runs of whitespace out of the assembly, but leave the leading
403    # whitespace in place.
404    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
405    # Expand the tabs used for indentation.
406    asm = string.expandtabs(asm, 2)
407    # Strip trailing whitespace.
408    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
409    return asm
410
411
412def scrub_asm_avr(asm, args):
413    # Scrub runs of whitespace out of the assembly, but leave the leading
414    # whitespace in place.
415    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
416    # Expand the tabs used for indentation.
417    asm = string.expandtabs(asm, 2)
418    # Strip trailing whitespace.
419    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
420    return asm
421
422
423def scrub_asm_riscv(asm, args):
424    # Scrub runs of whitespace out of the assembly, but leave the leading
425    # whitespace in place.
426    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
427    # Expand the tabs used for indentation.
428    asm = string.expandtabs(asm, 2)
429    # Strip trailing whitespace.
430    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
431    return asm
432
433
434def scrub_asm_lanai(asm, args):
435    # Scrub runs of whitespace out of the assembly, but leave the leading
436    # whitespace in place.
437    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
438    # Expand the tabs used for indentation.
439    asm = string.expandtabs(asm, 2)
440    # Strip trailing whitespace.
441    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
442    return asm
443
444
445def scrub_asm_sparc(asm, args):
446    # Scrub runs of whitespace out of the assembly, but leave the leading
447    # whitespace in place.
448    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
449    # Expand the tabs used for indentation.
450    asm = string.expandtabs(asm, 2)
451    # Strip trailing whitespace.
452    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
453    return asm
454
455
456def scrub_asm_spirv(asm, args):
457    # Scrub runs of whitespace out of the assembly, but leave the leading
458    # whitespace in place.
459    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
460    # Expand the tabs used for indentation.
461    asm = string.expandtabs(asm, 2)
462    # Strip trailing whitespace.
463    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
464    return asm
465
466
467def scrub_asm_systemz(asm, args):
468    # Scrub runs of whitespace out of the assembly, but leave the leading
469    # whitespace in place.
470    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
471    # Expand the tabs used for indentation.
472    asm = string.expandtabs(asm, 2)
473    # Strip trailing whitespace.
474    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
475    return asm
476
477
478def scrub_asm_wasm(asm, args):
479    # Scrub runs of whitespace out of the assembly, but leave the leading
480    # whitespace in place.
481    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
482    # Expand the tabs used for indentation.
483    asm = string.expandtabs(asm, 2)
484    # Strip trailing whitespace.
485    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
486    return asm
487
488
489def scrub_asm_ve(asm, args):
490    # Scrub runs of whitespace out of the assembly, but leave the leading
491    # whitespace in place.
492    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
493    # Expand the tabs used for indentation.
494    asm = string.expandtabs(asm, 2)
495    # Strip trailing whitespace.
496    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
497    return asm
498
499
500def scrub_asm_xtensa(asm, args):
501    # Scrub runs of whitespace out of the assembly, but leave the leading
502    # whitespace in place.
503    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
504    # Expand the tabs used for indentation.
505    asm = string.expandtabs(asm, 2)
506    # Strip trailing whitespace.
507    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
508    return asm
509
510
511def scrub_asm_csky(asm, args):
512    # Scrub runs of whitespace out of the assembly, but leave the leading
513    # whitespace in place.
514    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
515    # Expand the tabs used for indentation.
516    asm = string.expandtabs(asm, 2)
517    # Strip kill operands inserted into the asm.
518    asm = common.SCRUB_KILL_COMMENT_RE.sub("", asm)
519    # Strip trailing whitespace.
520    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
521    return asm
522
523
524def scrub_asm_nvptx(asm, args):
525    # Scrub runs of whitespace out of the assembly, but leave the leading
526    # whitespace in place.
527    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
528    # Expand the tabs used for indentation.
529    asm = string.expandtabs(asm, 2)
530    # Strip trailing whitespace.
531    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
532    return asm
533
534
535def scrub_asm_loongarch(asm, args):
536    # Scrub runs of whitespace out of the assembly, but leave the leading
537    # whitespace in place.
538    asm = common.SCRUB_WHITESPACE_RE.sub(r" ", asm)
539    # Expand the tabs used for indentation.
540    asm = string.expandtabs(asm, 2)
541    # Strip trailing whitespace.
542    asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r"", asm)
543    return asm
544
545
546# Returns a tuple of a scrub function and a function regex. Scrub function is
547# used to alter function body in some way, for example, remove trailing spaces.
548# Function regex is used to match function name, body, etc. in raw llc output.
549def get_run_handler(triple):
550    target_handlers = {
551        "i686": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
552        "x86": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
553        "i386": (scrub_asm_x86, ASM_FUNCTION_X86_RE),
554        "arm64_32": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
555        "aarch64": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
556        "aarch64-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
557        "aarch64-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
558        "bpf": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
559        "bpfel": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
560        "bpfeb": (scrub_asm_bpf, ASM_FUNCTION_BPF_RE),
561        "hexagon": (scrub_asm_hexagon, ASM_FUNCTION_HEXAGON_RE),
562        "r600": (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
563        "amdgcn": (scrub_asm_amdgpu, ASM_FUNCTION_AMDGPU_RE),
564        "arm": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
565        "arm64": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
566        "arm64e": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
567        "arm64ec": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
568        "arm64-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
569        "arm64-apple-macosx": (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
570        "armv7-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
571        "armv7-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_DARWIN_RE),
572        "thumb": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
573        "thumb-macho": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
574        "thumbv5-macho": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_MACHO_RE),
575        "thumbv7s-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_THUMBS_DARWIN_RE),
576        "thumbv7-apple-darwin": (scrub_asm_arm_eabi, ASM_FUNCTION_THUMB_DARWIN_RE),
577        "thumbv7-apple-ios": (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_IOS_RE),
578        "m68k": (scrub_asm_m68k, ASM_FUNCTION_M68K_RE),
579        "mips": (scrub_asm_mips, ASM_FUNCTION_MIPS_RE),
580        "msp430": (scrub_asm_msp430, ASM_FUNCTION_MSP430_RE),
581        "avr": (scrub_asm_avr, ASM_FUNCTION_AVR_RE),
582        "ppc32": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
583        "ppc64": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
584        "powerpc": (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE),
585        "riscv32": (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
586        "riscv64": (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
587        "lanai": (scrub_asm_lanai, ASM_FUNCTION_LANAI_RE),
588        "sparc": (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE),
589        "spirv32": (scrub_asm_spirv, ASM_FUNCTION_SPIRV_RE),
590        "spirv64": (scrub_asm_spirv, ASM_FUNCTION_SPIRV_RE),
591        "s390x": (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE),
592        "wasm32": (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
593        "wasm64": (scrub_asm_wasm, ASM_FUNCTION_WASM_RE),
594        "ve": (scrub_asm_ve, ASM_FUNCTION_VE_RE),
595        "xtensa": (scrub_asm_xtensa, ASM_FUNCTION_XTENSA_RE),
596        "csky": (scrub_asm_csky, ASM_FUNCTION_CSKY_RE),
597        "nvptx": (scrub_asm_nvptx, ASM_FUNCTION_NVPTX_RE),
598        "loongarch32": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
599        "loongarch64": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
600    }
601    handler = None
602    best_prefix = ""
603    for prefix, s in target_handlers.items():
604        if triple.startswith(prefix) and len(prefix) > len(best_prefix):
605            handler = s
606            best_prefix = prefix
607
608    if handler is None:
609        raise KeyError("Triple %r is not supported" % (triple))
610
611    return handler
612
613
614##### Generator of assembly CHECK lines
615
616
617def add_checks(
618    output_lines,
619    comment_marker,
620    prefix_list,
621    func_dict,
622    func_name,
623    ginfo: common.GeneralizerInfo,
624    global_vars_seen_dict,
625    is_filtered,
626):
627    # Label format is based on ASM string.
628    check_label_format = "{} %s-LABEL: %s%s%s%s".format(comment_marker)
629    return common.add_checks(
630        output_lines,
631        comment_marker,
632        prefix_list,
633        func_dict,
634        func_name,
635        check_label_format,
636        ginfo,
637        global_vars_seen_dict,
638        is_filtered=is_filtered,
639    )
640