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