llvm.org GIT mirror llvm / 6ceb7d8
[utils] De-duplicate utils/update_{llc_,}test_checks.py Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D42654 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@323718 91177308-0d34-0410-b5e6-96231b3b80d8 Fangrui Song 2 years ago
5 changed file(s) with 296 addition(s) and 333 deletion(s). Raw diff Collapse all Expand all
0 import re
1 import string
2
3 from . import common
4
5 # RegEx: this is where the magic happens.
6
7 ASM_FUNCTION_X86_RE = re.compile(
8 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
9 r'(?P^##?[ \t]+[^:]+:.*?)\s*'
10 r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)',
11 flags=(re.M | re.S))
12
13 ASM_FUNCTION_ARM_RE = re.compile(
14 r'^(?P[0-9a-zA-Z_]+):\n' # f: (name of function)
15 r'\s+\.fnstart\n' # .fnstart
16 r'(?P.*?)\n' # (body of the function)
17 r'.Lfunc_end[0-9]+:', # .Lfunc_end0: or # -- End function
18 flags=(re.M | re.S))
19
20 ASM_FUNCTION_AARCH64_RE = re.compile(
21 r'^_?(?P[^:]+):[ \t]*\/\/[ \t]*@(?P=func)\n'
22 r'[ \t]+.cfi_startproc\n'
23 r'(?P.*?)\n'
24 # This list is incomplete
25 r'.Lfunc_end[0-9]+:\n',
26 flags=(re.M | re.S))
27
28 ASM_FUNCTION_MIPS_RE = re.compile(
29 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' # f: (name of func)
30 r'(?:^[ \t]+\.(frame|f?mask|set).*?\n)+' # Mips+LLVM standard asm prologue
31 r'(?P.*?)\n' # (body of the function)
32 r'(?:^[ \t]+\.(set|end).*?\n)+' # Mips+LLVM standard asm epilogue
33 r'(\$|\.L)func_end[0-9]+:\n', # $func_end0: (mips32 - O32) or
34 # .Lfunc_end0: (mips64 - NewABI)
35 flags=(re.M | re.S))
36
37 ASM_FUNCTION_PPC_RE = re.compile(
38 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n'
39 r'\.Lfunc_begin[0-9]+:\n'
40 r'(?:[ \t]+.cfi_startproc\n)?'
41 r'(?:\.Lfunc_[gl]ep[0-9]+:\n(?:[ \t]+.*?\n)*)*'
42 r'(?P.*?)\n'
43 # This list is incomplete
44 r'(?:^[ \t]*(?:\.long[ \t]+[^\n]+|\.quad[ \t]+[^\n]+)\n)*'
45 r'.Lfunc_end[0-9]+:\n',
46 flags=(re.M | re.S))
47
48 ASM_FUNCTION_RISCV_RE = re.compile(
49 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
50 r'(?P^##?[ \t]+[^:]+:.*?)\s*'
51 r'.Lfunc_end[0-9]+:\n',
52 flags=(re.M | re.S))
53
54 ASM_FUNCTION_SYSTEMZ_RE = re.compile(
55 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n'
56 r'[ \t]+.cfi_startproc\n'
57 r'(?P.*?)\n'
58 r'.Lfunc_end[0-9]+:\n',
59 flags=(re.M | re.S))
60
61
62 SCRUB_LOOP_COMMENT_RE = re.compile(
63 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
64
65 SCRUB_X86_SHUFFLES_RE = (
66 re.compile(
67 r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$',
68 flags=re.M))
69 SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
70 SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
71 SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+')
72 SCRUB_X86_RET_RE = re.compile(r'ret[l|q]')
73
74 def scrub_asm_x86(asm, args):
75 # Scrub runs of whitespace out of the assembly, but leave the leading
76 # whitespace in place.
77 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
78 # Expand the tabs used for indentation.
79 asm = string.expandtabs(asm, 2)
80 # Detect shuffle asm comments and hide the operands in favor of the comments.
81 asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm)
82 # Generically match the stack offset of a memory operand.
83 asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm)
84 # Generically match a RIP-relative memory operand.
85 asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm)
86 # Generically match a LCP symbol.
87 asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm)
88 if args.x86_extra_scrub:
89 # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'.
90 asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm)
91 # Strip kill operands inserted into the asm.
92 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm)
93 # Strip trailing whitespace.
94 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
95 return asm
96
97 def scrub_asm_arm_eabi(asm, args):
98 # Scrub runs of whitespace out of the assembly, but leave the leading
99 # whitespace in place.
100 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
101 # Expand the tabs used for indentation.
102 asm = string.expandtabs(asm, 2)
103 # Strip kill operands inserted into the asm.
104 asm = common.SCRUB_KILL_COMMENT_RE.sub('', asm)
105 # Strip trailing whitespace.
106 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
107 return asm
108
109 def scrub_asm_powerpc64(asm, args):
110 # Scrub runs of whitespace out of the assembly, but leave the leading
111 # whitespace in place.
112 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
113 # Expand the tabs used for indentation.
114 asm = string.expandtabs(asm, 2)
115 # Stripe unimportant comments
116 asm = SCRUB_LOOP_COMMENT_RE.sub(r'', asm)
117 # Strip trailing whitespace.
118 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
119 return asm
120
121 def scrub_asm_mips(asm, args):
122 # Scrub runs of whitespace out of the assembly, but leave the leading
123 # whitespace in place.
124 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
125 # Expand the tabs used for indentation.
126 asm = string.expandtabs(asm, 2)
127 # Strip trailing whitespace.
128 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
129 return asm
130
131 def scrub_asm_riscv(asm, args):
132 # Scrub runs of whitespace out of the assembly, but leave the leading
133 # whitespace in place.
134 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
135 # Expand the tabs used for indentation.
136 asm = string.expandtabs(asm, 2)
137 # Strip trailing whitespace.
138 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
139 return asm
140
141 def scrub_asm_systemz(asm, args):
142 # Scrub runs of whitespace out of the assembly, but leave the leading
143 # whitespace in place.
144 asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm)
145 # Expand the tabs used for indentation.
146 asm = string.expandtabs(asm, 2)
147 # Strip trailing whitespace.
148 asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
149 return asm
150
151
152 def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, prefixes, func_dict):
153 target_handlers = {
154 'x86_64': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
155 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
156 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
157 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
158 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
159 'arm-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
160 'thumb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
161 'thumbv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
162 'thumbv6-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
163 'thumbv6t2': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
164 'thumbv6t2-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
165 'thumbv6m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
166 'thumbv6m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
167 'thumbv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
168 'thumbv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
169 'thumbv7m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
170 'thumbv7m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
171 'thumbv8-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
172 'thumbv8m.base': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
173 'thumbv8m.main': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
174 'armv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
175 'armv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
176 'armv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
177 'armeb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
178 'armv7eb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
179 'armv7eb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
180 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE),
181 'powerpc64': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE),
182 'powerpc64le': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE),
183 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
184 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
185 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE),
186 }
187 handlers = None
188 for prefix, s in target_handlers.items():
189 if triple.startswith(prefix):
190 handlers = s
191 break
192 else:
193 raise KeyError('Triple %r is not supported' % (triple))
194
195 scrubber, function_re = handlers
196 common.build_function_body_dictionary(
197 function_re, scrubber, [args], raw_tool_output, prefixes,
198 func_dict, args.verbose)
0 import re
1 import subprocess
2
3 RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$')
4 CHECK_PREFIX_RE = re.compile('--?check-prefix(?:es)?=(\S+)')
5 CHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
6
7 IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(')
8 TRIPLE_IR_RE = re.compile(r'^target\s+triple\s*=\s*"([^"]+)"$')
9 TRIPLE_ARG_RE = re.compile(r'-mtriple=([^ ]+)')
10
11 SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
12 SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
13 SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
14 SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
15 SCRUB_LOOP_COMMENT_RE = re.compile(
16 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
17
18 def should_add_line_to_output(input_line, prefix_set):
19 # Skip any blank comment lines in the IR.
20 if input_line.strip() == ';':
21 return False
22 # Skip any blank lines in the IR.
23 #if input_line.strip() == '':
24 # return False
25 # And skip any CHECK lines. We're building our own.
26 m = CHECK_RE.match(input_line)
27 if m and m.group(1) in prefix_set:
28 return False
29
30 return True
31
32 # Invoke the tool that is being tested.
33 def invoke_tool(exe, cmd_args, ir):
34 with open(ir) as ir_file:
35 stdout = subprocess.check_output(exe + ' ' + cmd_args,
36 shell=True, stdin=ir_file)
37 # Fix line endings to unix CR style.
38 stdout = stdout.replace('\r\n', '\n')
39 return stdout
40
41 # Build up a dictionary of all the function bodies.
42 def build_function_body_dictionary(function_re, scrubber, scrubber_args, raw_tool_output, prefixes, func_dict, verbose):
43 for m in function_re.finditer(raw_tool_output):
44 if not m:
45 continue
46 func = m.group('func')
47 scrubbed_body = scrubber(m.group('body'), *scrubber_args)
48 if func.startswith('stress'):
49 # We only use the last line of the function body for stress tests.
50 scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
51 if verbose:
52 print >>sys.stderr, 'Processing function: ' + func
53 for l in scrubbed_body.splitlines():
54 print >>sys.stderr, ' ' + l
55 for prefix in prefixes:
56 if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body:
57 if prefix == prefixes[-1]:
58 print >>sys.stderr, ('WARNING: Found conflicting asm under the '
59 'same prefix: %r!' % (prefix,))
60 else:
61 func_dict[prefix][func] = None
62 continue
63
64 func_dict[prefix][func] = scrubbed_body
11
22 """A test case update script.
33
4 This script is a utility to update LLVM X86 'llc' based test cases with new
4 This script is a utility to update LLVM 'llc' based test cases with new
55 FileCheck patterns. It can either update all of the tests in the file or
66 a single test function.
77 """
1313 import sys
1414 import re
1515
16 # Invoke the tool that is being tested.
17 def llc(args, cmd_args, ir):
18 with open(ir) as ir_file:
19 stdout = subprocess.check_output(args.llc_binary + ' ' + cmd_args,
20 shell=True, stdin=ir_file)
21 # Fix line endings to unix CR style.
22 stdout = stdout.replace('\r\n', '\n')
23 return stdout
16 from UpdateTestChecks import asm, common
2417
25
26 # RegEx: this is where the magic happens.
27
28 ASM_FUNCTION_X86_RE = re.compile(
29 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
30 r'(?P^##?[ \t]+[^:]+:.*?)\s*'
31 r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section|#+ -- End function)',
32 flags=(re.M | re.S))
33
34 ASM_FUNCTION_ARM_RE = re.compile(
35 r'^(?P[0-9a-zA-Z_]+):\n' # f: (name of function)
36 r'\s+\.fnstart\n' # .fnstart
37 r'(?P.*?)\n' # (body of the function)
38 r'.Lfunc_end[0-9]+:', # .Lfunc_end0: or # -- End function
39 flags=(re.M | re.S))
40
41 ASM_FUNCTION_AARCH64_RE = re.compile(
42 r'^_?(?P[^:]+):[ \t]*\/\/[ \t]*@(?P=func)\n'
43 r'[ \t]+.cfi_startproc\n'
44 r'(?P.*?)\n'
45 # This list is incomplete
46 r'.Lfunc_end[0-9]+:\n',
47 flags=(re.M | re.S))
48
49 ASM_FUNCTION_MIPS_RE = re.compile(
50 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' # f: (name of func)
51 r'(?:^[ \t]+\.(frame|f?mask|set).*?\n)+' # Mips+LLVM standard asm prologue
52 r'(?P.*?)\n' # (body of the function)
53 r'(?:^[ \t]+\.(set|end).*?\n)+' # Mips+LLVM standard asm epilogue
54 r'(\$|\.L)func_end[0-9]+:\n', # $func_end0: (mips32 - O32) or
55 # .Lfunc_end0: (mips64 - NewABI)
56 flags=(re.M | re.S))
57
58 ASM_FUNCTION_PPC_RE = re.compile(
59 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n'
60 r'\.Lfunc_begin[0-9]+:\n'
61 r'(?:[ \t]+.cfi_startproc\n)?'
62 r'(?:\.Lfunc_[gl]ep[0-9]+:\n(?:[ \t]+.*?\n)*)*'
63 r'(?P.*?)\n'
64 # This list is incomplete
65 r'(?:^[ \t]*(?:\.long[ \t]+[^\n]+|\.quad[ \t]+[^\n]+)\n)*'
66 r'.Lfunc_end[0-9]+:\n',
67 flags=(re.M | re.S))
68
69 ASM_FUNCTION_RISCV_RE = re.compile(
70 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
71 r'(?P^##?[ \t]+[^:]+:.*?)\s*'
72 r'.Lfunc_end[0-9]+:\n',
73 flags=(re.M | re.S))
74
75 ASM_FUNCTION_SYSTEMZ_RE = re.compile(
76 r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n'
77 r'[ \t]+.cfi_startproc\n'
78 r'(?P.*?)\n'
79 r'.Lfunc_end[0-9]+:\n',
80 flags=(re.M | re.S))
81
82
83 SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
84 SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
85 SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
86 SCRUB_LOOP_COMMENT_RE = re.compile(
87 r'# =>This Inner Loop Header:.*|# in Loop:.*', flags=re.M)
88
89 SCRUB_X86_SHUFFLES_RE = (
90 re.compile(
91 r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$',
92 flags=re.M))
93 SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
94 SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
95 SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+')
96 SCRUB_X86_RET_RE = re.compile(r'ret[l|q]')
97
98 RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$')
99 TRIPLE_ARG_RE = re.compile(r'-mtriple=([^ ]+)')
100 TRIPLE_IR_RE = re.compile(r'^target\s+triple\s*=\s*"([^"]+)"$')
101 IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(')
102 CHECK_PREFIX_RE = re.compile('--?check-prefix(?:es)?=(\S+)')
103 CHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
104
105 def scrub_asm_x86(asm, args):
106 # Scrub runs of whitespace out of the assembly, but leave the leading
107 # whitespace in place.
108 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
109 # Expand the tabs used for indentation.
110 asm = string.expandtabs(asm, 2)
111 # Detect shuffle asm comments and hide the operands in favor of the comments.
112 asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \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 # Generically match a RIP-relative memory operand.
116 asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm)
117 # Generically match a LCP symbol.
118 asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm)
119 if args.x86_extra_scrub:
120 # Avoid generating different checks for 32- and 64-bit because of 'retl' vs 'retq'.
121 asm = SCRUB_X86_RET_RE.sub(r'ret{{[l|q]}}', asm)
122 # Strip kill operands inserted into the asm.
123 asm = SCRUB_KILL_COMMENT_RE.sub('', asm)
124 # Strip trailing whitespace.
125 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
126 return asm
127
128 def scrub_asm_arm_eabi(asm, args):
129 # Scrub runs of whitespace out of the assembly, but leave the leading
130 # whitespace in place.
131 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
132 # Expand the tabs used for indentation.
133 asm = string.expandtabs(asm, 2)
134 # Strip kill operands inserted into the asm.
135 asm = SCRUB_KILL_COMMENT_RE.sub('', asm)
136 # Strip trailing whitespace.
137 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
138 return asm
139
140 def scrub_asm_powerpc64(asm, args):
141 # Scrub runs of whitespace out of the assembly, but leave the leading
142 # whitespace in place.
143 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
144 # Expand the tabs used for indentation.
145 asm = string.expandtabs(asm, 2)
146 # Stripe unimportant comments
147 asm = SCRUB_LOOP_COMMENT_RE.sub(r'', asm)
148 # Strip trailing whitespace.
149 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
150 return asm
151
152 def scrub_asm_mips(asm, args):
153 # Scrub runs of whitespace out of the assembly, but leave the leading
154 # whitespace in place.
155 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
156 # Expand the tabs used for indentation.
157 asm = string.expandtabs(asm, 2)
158 # Strip trailing whitespace.
159 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
160 return asm
161
162 def scrub_asm_riscv(asm, args):
163 # Scrub runs of whitespace out of the assembly, but leave the leading
164 # whitespace in place.
165 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
166 # Expand the tabs used for indentation.
167 asm = string.expandtabs(asm, 2)
168 # Strip trailing whitespace.
169 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
170 return asm
171
172 def scrub_asm_systemz(asm, args):
173 # Scrub runs of whitespace out of the assembly, but leave the leading
174 # whitespace in place.
175 asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
176 # Expand the tabs used for indentation.
177 asm = string.expandtabs(asm, 2)
178 # Strip trailing whitespace.
179 asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
180 return asm
181
182
183 # Build up a dictionary of all the function bodies.
184 def build_function_body_dictionary(raw_tool_output, triple, prefixes, func_dict,
185 args):
186 target_handlers = {
187 'x86_64': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
188 'i686': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
189 'x86': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
190 'i386': (scrub_asm_x86, ASM_FUNCTION_X86_RE),
191 'aarch64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
192 'arm-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
193 'thumb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
194 'thumbv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
195 'thumbv6-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
196 'thumbv6t2': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
197 'thumbv6t2-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
198 'thumbv6m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
199 'thumbv6m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
200 'thumbv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
201 'thumbv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
202 'thumbv7m': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
203 'thumbv7m-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
204 'thumbv8-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
205 'thumbv8m.base': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
206 'thumbv8m.main': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
207 'armv6': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
208 'armv7': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
209 'armv7-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
210 'armeb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
211 'armv7eb-eabi': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
212 'armv7eb': (scrub_asm_arm_eabi, ASM_FUNCTION_ARM_RE),
213 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE),
214 'powerpc64': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE),
215 'powerpc64le': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE),
216 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
217 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE),
218 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE),
219 }
220 handlers = None
221 for prefix, s in target_handlers.items():
222 if triple.startswith(prefix):
223 handlers = s
224 break
225 else:
226 raise KeyError('Triple %r is not supported' % (triple))
227
228 scrubber, function_re = handlers
229 for m in function_re.finditer(raw_tool_output):
230 if not m:
231 continue
232 func = m.group('func')
233 scrubbed_body = scrubber(m.group('body'), args)
234 if func.startswith('stress'):
235 # We only use the last line of the function body for stress tests.
236 scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
237 if args.verbose:
238 print >>sys.stderr, 'Processing function: ' + func
239 for l in scrubbed_body.splitlines():
240 print >>sys.stderr, ' ' + l
241 for prefix in prefixes:
242 if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body:
243 if prefix == prefixes[-1]:
244 print >>sys.stderr, ('WARNING: Found conflicting asm under the '
245 'same prefix: %r!' % (prefix,))
246 else:
247 func_dict[prefix][func] = None
248 continue
249
250 func_dict[prefix][func] = scrubbed_body
18 ADVERT = '; NOTE: Assertions have been autogenerated by '
25119
25220
25321 def add_checks(output_lines, run_list, func_dict, func_name):
27442 return output_lines
27543
27644
277 def should_add_line_to_output(input_line, prefix_set):
278 # Skip any blank comment lines in the IR.
279 if input_line.strip() == ';':
280 return False
281 # Skip any blank lines in the IR.
282 #if input_line.strip() == '':
283 # return False
284 # And skip any CHECK lines. We're building our own.
285 m = CHECK_RE.match(input_line)
286 if m and m.group(1) in prefix_set:
287 return False
288
289 return True
290
291
29245 def main():
29346 parser = argparse.ArgumentParser(description=__doc__)
29447 parser.add_argument('-v', '--verbose', action='store_true',
30356 parser.add_argument('tests', nargs='+')
30457 args = parser.parse_args()
30558
306 autogenerated_note = ('; NOTE: Assertions have been autogenerated by '
307 'utils/' + os.path.basename(__file__))
59 autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__))
30860
30961 for test in args.tests:
31062 if args.verbose:
31466
31567 triple_in_ir = None
31668 for l in input_lines:
317 m = TRIPLE_IR_RE.match(l)
69 m = common.TRIPLE_IR_RE.match(l)
31870 if m:
31971 triple_in_ir = m.groups()[0]
32072 break
32173
32274 raw_lines = [m.group(1)
323 for m in [RUN_LINE_RE.match(l) for l in input_lines] if m]
75 for m in [common.RUN_LINE_RE.match(l) for l in input_lines] if m]
32476 run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
32577 for l in raw_lines[1:]:
32678 if run_lines[-1].endswith("\\"):
33991 llc_cmd = commands[0]
34092
34193 triple_in_cmd = None
342 m = TRIPLE_ARG_RE.search(llc_cmd)
94 m = common.TRIPLE_ARG_RE.search(llc_cmd)
34395 if m:
34496 triple_in_cmd = m.groups()[0]
34597
357109 llc_cmd_args = llc_cmd[len('llc'):].strip()
358110 llc_cmd_args = llc_cmd_args.replace('< %s', '').replace('%s', '').strip()
359111
360 check_prefixes = [item for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)
112 check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
361113 for item in m.group(1).split(',')]
362114 if not check_prefixes:
363115 check_prefixes = ['CHECK']
376128 print >>sys.stderr, 'Extracted LLC cmd: llc ' + llc_args
377129 print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes)
378130
379 raw_tool_output = llc(args, llc_args, test)
131 raw_tool_output = common.invoke_tool(args.llc_binary, llc_args, test)
380132 if not (triple_in_cmd or triple_in_ir):
381133 print >>sys.stderr, "Cannot find a triple. Assume 'x86'"
382134
383 build_function_body_dictionary(raw_tool_output,
384 triple_in_cmd or triple_in_ir or 'x86', prefixes, func_dict, args)
135 asm.build_function_body_dictionary_for_triple(args, raw_tool_output,
136 triple_in_cmd or triple_in_ir or 'x86', prefixes, func_dict)
385137
386138 is_in_function = False
387139 is_in_function_start = False
397149 if input_line == '':
398150 continue
399151 if input_line.lstrip().startswith(';'):
400 m = CHECK_RE.match(input_line)
152 m = common.CHECK_RE.match(input_line)
401153 if not m or m.group(1) not in prefix_set:
402154 output_lines.append(input_line)
403155 continue
407159 is_in_function_start = False
408160
409161 if is_in_function:
410 if should_add_line_to_output(input_line, prefix_set) == True:
162 if common.should_add_line_to_output(input_line, prefix_set):
411163 # This input line of the function body will go as-is into the output.
412164 output_lines.append(input_line)
413165 else:
416168 is_in_function = False
417169 continue
418170
419 if input_line == autogenerated_note:
171 # Discard any previous script advertising.
172 if input_line.startswith(ADVERT):
420173 continue
421174
422175 # If it's outside a function, it just gets copied to the output.
423176 output_lines.append(input_line)
424177
425 m = IR_FUNCTION_RE.match(input_line)
178 m = common.IR_FUNCTION_RE.match(input_line)
426179 if not m:
427180 continue
428181 func_name = m.group(1)
3737 import tempfile
3838 import re
3939
40 from UpdateTestChecks import common
41
4042 ADVERT = '; NOTE: Assertions have been autogenerated by '
4143
4244 # RegEx: this is where the magic happens.
4345
44 SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
45 SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
46 SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
47 SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
4846 SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*')
4947
50 RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$')
5148 IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@([\w-]+)\s*\(')
5249 OPT_FUNCTION_RE = re.compile(
5350 r'^\s*define\s+(?:internal\s+)?[^@]*@(?P[\w-]+?)\s*\('
5451 r'(\s+)?[^)]*[^{]*\{\n(?P.*?)^\}$',
5552 flags=(re.M | re.S))
56 CHECK_PREFIX_RE = re.compile('--?check-prefix(?:es)?=(\S+)')
57 CHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
5853 # Match things that look at identifiers, but only if they are followed by
5954 # spaces, commas, paren, or end of the string
6055 IR_VALUE_RE = re.compile(r'(\s+)%([\w\.]+?)([,\s\(\)]|\Z)')
6156
6257
63 # Invoke the tool that is being tested.
64 def invoke_tool(args, cmd_args, ir):
65 with open(ir) as ir_file:
66 stdout = subprocess.check_output(args.opt_binary + ' ' + cmd_args,
67 shell=True, stdin=ir_file)
68 # Fix line endings to unix CR style.
69 stdout = stdout.replace('\r\n', '\n')
70 return stdout
71
7258
7359 def scrub_body(body, opt_basename):
7460 # Scrub runs of whitespace out of the assembly, but leave the leading
7561 # whitespace in place.
76 body = SCRUB_WHITESPACE_RE.sub(r' ', body)
62 body = common.SCRUB_WHITESPACE_RE.sub(r' ', body)
7763 # Expand the tabs used for indentation.
7864 body = string.expandtabs(body, 2)
7965 # Strip trailing whitespace.
80 body = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body)
66 body = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body)
8167 return body
8268
83
84 # Build up a dictionary of all the function bodies.
85 def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose, opt_basename):
86 func_regex = OPT_FUNCTION_RE
87 for m in func_regex.finditer(raw_tool_output):
88 if not m:
89 continue
90 func = m.group('func')
91 scrubbed_body = scrub_body(m.group('body'), opt_basename)
92 if func.startswith('stress'):
93 # We only use the last line of the function body for stress tests.
94 scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
95 if verbose:
96 print >>sys.stderr, 'Processing function: ' + func
97 for l in scrubbed_body.splitlines():
98 print >>sys.stderr, ' ' + l
99 for prefix in prefixes:
100 if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body:
101 if prefix == prefixes[-1]:
102 print >>sys.stderr, ('WARNING: Found conflicting asm under the '
103 'same prefix: %r!' % (prefix,))
104 else:
105 func_dict[prefix][func] = None
106 continue
107
108 func_dict[prefix][func] = scrubbed_body
10969
11070
11171 # Create a FileCheck variable name based on an IR name.
212172 return output_lines
213173
214174
215 def should_add_line_to_output(input_line, prefix_set):
216 # Skip any blank comment lines in the IR.
217 if input_line.strip() == ';':
218 return False
219 # Skip any blank lines in the IR.
220 #if input_line.strip() == '':
221 # return False
222 # And skip any CHECK lines. We're building our own.
223 m = CHECK_RE.match(input_line)
224 if m and m.group(1) in prefix_set:
225 return False
226
227 return True
228
229
230175 def main():
231176 from argparse import RawTextHelpFormatter
232177 parser = argparse.ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter)
253198 input_lines = [l.rstrip() for l in f]
254199
255200 raw_lines = [m.group(1)
256 for m in [RUN_LINE_RE.match(l) for l in input_lines] if m]
201 for m in [common.RUN_LINE_RE.match(l) for l in input_lines] if m]
257202 run_lines = [raw_lines[0]] if len(raw_lines) > 0 else []
258203 for l in raw_lines[1:]:
259204 if run_lines[-1].endswith("\\"):
281226 tool_cmd_args = tool_cmd[len(opt_basename):].strip()
282227 tool_cmd_args = tool_cmd_args.replace('< %s', '').replace('%s', '').strip()
283228
284 check_prefixes = [item for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)
229 check_prefixes = [item for m in common.CHECK_PREFIX_RE.finditer(filecheck_cmd)
285230 for item in m.group(1).split(',')]
286231 if not check_prefixes:
287232 check_prefixes = ['CHECK']
299244 print >>sys.stderr, 'Extracted opt cmd: ' + opt_basename + ' ' + opt_args
300245 print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes)
301246
302 raw_tool_output = invoke_tool(args, opt_args, test)
303 build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose, opt_basename)
247 raw_tool_output = common.invoke_tool(args.opt_binary, opt_args, test)
248 common.build_function_body_dictionary(
249 OPT_FUNCTION_RE, scrub_body, [opt_basename], raw_tool_output,
250 prefixes, func_dict, args.verbose)
304251
305252 is_in_function = False
306253 is_in_function_start = False
315262 if input_line == '':
316263 continue
317264 if input_line.lstrip().startswith(';'):
318 m = CHECK_RE.match(input_line)
265 m = common.CHECK_RE.match(input_line)
319266 if not m or m.group(1) not in prefix_set:
320267 output_lines.append(input_line)
321268 continue
322269
323270 # Print out the various check lines here.
324 output_lines = add_checks(output_lines, prefix_list, func_dict, name, opt_basename)
271 output_lines = add_checks(output_lines, prefix_list, func_dict, func_name, opt_basename)
325272 is_in_function_start = False
326273
327274 if is_in_function:
328 if should_add_line_to_output(input_line, prefix_set) == True:
275 if common.should_add_line_to_output(input_line, prefix_set):
329276 # This input line of the function body will go as-is into the output.
330277 # Except make leading whitespace uniform: 2 spaces.
331 input_line = SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line)
278 input_line = common.SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line)
332279 output_lines.append(input_line)
333280 else:
334281 continue
346293 m = IR_FUNCTION_RE.match(input_line)
347294 if not m:
348295 continue
349 name = m.group(1)
350 if args.function is not None and name != args.function:
296 func_name = m.group(1)
297 if args.function is not None and func_name != args.function:
351298 # When filtering on a specific function, skip all others.
352299 continue
353300 is_in_function = is_in_function_start = True
361308
362309 if __name__ == '__main__':
363310 main()
364