OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python2 | |
2 | |
3 import argparse | |
4 import os | |
5 import shutil | |
6 import sys | |
7 | |
8 from utils import shellcmd | |
9 from utils import FindBaseNaCl | |
10 | |
11 def Match(desc, includes, excludes, default_match): | |
12 """Determines whether desc is a match against includes and excludes. | |
13 | |
14 'desc' is a set of attributes, and 'includes' and 'excludes' are lists of sets | |
15 of attributes. | |
16 | |
17 If 'desc' matches any element from 'excludes', the result is False. | |
18 Otherwise, if 'desc' matches any element from 'includes', the result is True. | |
19 Otherwise, the 'default_match' value is returned. | |
20 """ | |
21 for exclude in excludes: | |
22 if exclude < desc: | |
23 return False | |
24 for include in includes: | |
25 if include < desc: | |
26 return True | |
27 return default_match | |
28 | |
29 def main(): | |
30 """Framework for cross test generation and execution. | |
31 | |
32 Builds and executes cross tests from the space of all possible attribute | |
33 combinations. The space can be restricted by providing subsets of attributes | |
34 to specifically include or exclude. | |
35 """ | |
36 # Defines the set of tests and each test's inputs. Each test maps to a | |
37 # dictionary containing a single driver file, one or more test source files, | |
38 # and an optional list of crosstest.py flags for special cases. | |
39 tests = { | |
Mircea Trofin
2015/03/08 16:23:30
will this list potentially grow? If so, is the exp
Jim Stichnoth
2015/03/09 18:16:16
Good point that I should try not to hard-code the
| |
40 'simple_loop' : { | |
41 'driver' : 'simple_loop_main.c', | |
42 'test' : [ 'simple_loop.c' ] | |
43 }, | |
44 'mem_intrin' : { | |
45 'driver' : 'mem_intrin_main.cpp', | |
46 'test' : [ 'mem_intrin.cpp' ] | |
47 }, | |
48 'test_arith' : { | |
49 'driver' : 'test_arith_main.cpp', | |
50 'test' : [ 'test_arith.cpp', 'test_arith_frem.ll', 'test_arith_sqrt.ll' ] | |
51 }, | |
52 'test_bitmanip' : { | |
53 'driver' : 'test_bitmanip_main.cpp', | |
54 'test' : [ 'test_bitmanip.cpp', 'test_bitmanip_intrin.ll' ] | |
55 }, | |
56 'test_calling_conv' : { | |
57 'driver' : 'test_calling_conv_main.cpp', | |
58 'test' : [ 'test_calling_conv.cpp' ] | |
59 }, | |
60 'test_cast' : { | |
61 'driver' : 'test_cast_main.cpp', | |
62 'test' : [ 'test_cast.cpp', 'test_cast_to_u1.ll', 'test_cast_vectors.ll' ] | |
63 }, | |
64 'test_fcmp' : { | |
65 'driver' : 'test_fcmp_main.cpp', | |
66 'test' : [ 'test_fcmp.pnacl.ll' ] | |
67 }, | |
68 'test_global' : { | |
69 'driver' : 'test_global_main.cpp', | |
70 'test' : [ 'test_global.cpp' ] | |
71 }, | |
72 'test_icmp' : { | |
73 'driver' : 'test_icmp_main.cpp', | |
74 'test' : [ 'test_icmp.cpp', 'test_icmp_i1vec.ll' ] | |
75 }, | |
76 'test_select' : { | |
77 'driver' : 'test_select_main.cpp', | |
78 'test' : [ 'test_select.ll' ] | |
79 }, | |
80 'test_stacksave' : { | |
81 'driver' : 'test_stacksave_main.c', | |
82 'test' : [ 'test_stacksave.c' ] | |
83 }, | |
84 'test_sync_atomic' : { | |
85 'driver' : 'test_sync_atomic_main.cpp', | |
86 # Compile the non-subzero object files straight from source since the | |
87 # native LLVM backend does not understand how to lower NaCl-specific | |
88 # intrinsics. | |
89 'flags' : [ '--crosstest-bitcode=0' ], | |
90 'test' : [ 'test_sync_atomic.cpp' ] | |
91 }, | |
92 'test_vector_ops' : { | |
93 'driver' : 'test_vector_ops_main.cpp', | |
94 'test' : [ 'test_vector_ops.ll' ] | |
95 }, | |
96 } | |
97 # The rest of the attribute sets. | |
98 targets = [ 'x8632' ] | |
99 sandboxing = [ 'native', 'sandbox' ] | |
100 opt_levels = [ 'Om1', 'O2' ] | |
101 arch_attrs = [ 'sse2', 'sse4.1' ] | |
102 # all_keys is only used in the help text. | |
103 all_keys = '; '.join([' '.join(sorted(tests.keys())), ' '.join(targets), | |
104 ' '.join(sandboxing), ' '.join(opt_levels), | |
105 ' '.join(arch_attrs)]) | |
106 | |
107 root = FindBaseNaCl() | |
108 argparser = argparse.ArgumentParser( | |
109 description=' ' + main.__doc__ + | |
110 'The set of attributes is the following:\n\n' + all_keys, | |
111 formatter_class=argparse.RawTextHelpFormatter) | |
112 argparser.add_argument('--include', '-i', default=[], dest='include', | |
113 action='append', metavar='ATTR_LIST', | |
114 help='Attributes to include (comma-separated). ' + | |
115 'Can be used multiple times.') | |
116 argparser.add_argument('--exclude', '-e', default=[], dest='exclude', | |
117 action='append', metavar='ATTR_LIST', | |
118 help='Attributes to include (comma-separated). ' + | |
119 'Can be used multiple times.') | |
120 argparser.add_argument('--verbose', '-v', default=False, action='store_true', | |
121 help='Use verbose output') | |
122 argparser.add_argument('--defer', default=False, action='store_true', | |
123 help='Defer execution until all executables are built') | |
124 argparser.add_argument('--no-compile', '-n', default=False, | |
125 action='store_true', | |
126 help="Don't build; reuse binaries from the last run") | |
127 argparser.add_argument('--dir', dest='dir', metavar='DIRECTORY', | |
128 default=('{root}/toolchain_build/src/subzero/' + | |
129 'crosstest/Output').format(root=root), | |
130 help='Output directory') | |
131 argparser.add_argument('--lit', default=False, action='store_true', | |
132 help='Generate files for lit testing') | |
133 args = argparser.parse_args() | |
134 # includes and excludes are both lists of sets. | |
135 includes = [ set(item.split(',')) for item in args.include ] | |
136 excludes = [ set(item.split(',')) for item in args.exclude ] | |
137 # If any --include args are provided, the default is to not match. | |
138 default_match = not args.include | |
139 | |
140 # Delete and recreate the output directory, unless --no-compile was specified. | |
141 if not args.no_compile: | |
142 if os.path.exists(args.dir): | |
143 if os.path.isdir(args.dir): | |
144 shutil.rmtree(args.dir) | |
145 else: | |
146 os.remove(args.dir) | |
147 if not os.path.exists(args.dir): | |
148 os.makedirs(args.dir) | |
149 | |
150 # pypath is where to find other Subzero python scripts. | |
151 pypath = os.path.abspath(os.path.dirname(sys.argv[0])) | |
152 # Run from the crosstest directory to make it easy to grab inputs. | |
153 crosstest_dir = '{root}/toolchain_build/src/subzero/crosstest'.format( | |
154 root=root) | |
155 os.chdir(crosstest_dir) | |
156 # If --defer is specified, collect the run commands into deferred_cmds for | |
157 # later execution. | |
158 deferred_cmds = [] | |
159 for test in sorted(tests.keys()): | |
160 for target in targets: | |
161 for sb in sandboxing: | |
162 for opt in opt_levels: | |
163 for attr in arch_attrs: | |
164 desc = [ test, target, sb, opt, attr ] | |
165 if Match(set(desc), includes, excludes, default_match): | |
166 exe = '{test}_{target}_{sb}_{opt}_{attr}'.format( | |
167 test=test, target=target, sb=sb, opt=opt, | |
168 attr=attr) | |
169 extra = tests[test]['flags'] if 'flags' in tests[test] else [] | |
jvoung (off chromium)
2015/03/09 17:34:21
Could probably have done "tests[test].get('flags',
Jim Stichnoth
2015/03/09 18:16:16
Hmm, nice. Unfortunately, I don't think there's a
jvoung (off chromium)
2015/03/09 20:34:59
Hmm I don't see anything like that for ConfigParse
| |
170 # Generate the compile command. | |
171 cmp_cmd = ['{path}/crosstest.py'.format(path=pypath), | |
172 '-{opt}'.format(opt=opt), | |
173 '--mattr={attr}'.format(attr=attr), | |
174 '--prefix=Subzero_', | |
175 '--target={target}'.format(target=target), | |
176 '--sandbox={sb}'.format(sb='1' if sb=='sandbox' | |
177 else '0'), | |
178 '--dir={dir}'.format(dir=args.dir), | |
179 '--output={exe}'.format(exe=exe), | |
180 '--driver={drv}'.format(drv=tests[test]['driver']), | |
181 ] + extra + \ | |
182 [ '--test=' + t for t in tests[test]['test'] ] | |
183 run_cmd_base = os.path.join(args.dir, exe) | |
184 # Generate the run command. | |
185 run_cmd = run_cmd_base | |
186 if sb == 'sandbox': | |
187 run_cmd = '{root}/run.py -q '.format(root=root) + run_cmd | |
188 if args.lit: | |
189 # Create a file to drive the lit test. | |
190 with open(run_cmd_base + '.xtest', 'w') as f: | |
191 f.write('# RUN: sh %s | FileCheck %s\n') | |
192 f.write('cd ' + crosstest_dir + ' && \\\n') | |
193 f.write(' '.join(cmp_cmd) + ' && \\\n') | |
194 f.write(run_cmd + '\n') | |
195 f.write('echo Recreate a failure using ' + __file__ + | |
196 ' --include=' + ','.join(desc) + '\n') | |
197 f.write('# CHECK: Failures=0\n') | |
198 else: | |
199 if not args.no_compile: | |
200 shellcmd(cmp_cmd, | |
201 echo=args.verbose) | |
202 if (args.defer): | |
203 deferred_cmds.append(run_cmd) | |
204 else: | |
205 shellcmd(run_cmd, echo=True) | |
206 for run_cmd in deferred_cmds: | |
207 shellcmd(run_cmd, echo=True) | |
208 | |
209 if __name__ == '__main__': | |
210 main() | |
OLD | NEW |