blob: a6cb2b7a47ec6a8dc445573b0bc1e1ad05d39b4e [file] [log] [blame]
Pierre Langlois88c46b82016-06-02 18:15:32 +01001#!/usr/bin/env python3
2
Alexandre Ramesb78f1392016-07-01 14:22:22 +01003# Copyright 2016, VIXL authors
Pierre Langlois88c46b82016-06-02 18:15:32 +01004# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# * Redistributions of source code must retain the above copyright notice,
10# this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright notice,
12# this list of conditions and the following disclaimer in the documentation
13# and/or other materials provided with the distribution.
14# * Neither the name of ARM Limited nor the names of its contributors may be
15# used to endorse or promote products derived from this software without
16# specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29"""
30Generating tests
31================
32
33From the VIXL toplevel directory run:
34
35 $ ./tools/generate_tests.py
36
37The script assumes that `clang-format-3.6` is in the current path. If it isn't,
38you can provide your own:
39
40 $ ./tools/generate_tests.py --clang-format /patch/to/clang-format
41
42Once the script has finished, it will have generated test files, as many as
43present in the `default_config_files` list. For example:
44
Alexandre Ramesd3832962016-07-04 15:03:43 +010045- test/aarch32/test-assembler-cond-rd-rn-immediate-a32.cc
46- test/aarch32/test-assembler-cond-rd-rn-rm-a32.cc
47- test/aarch32/test-assembler-cond-rd-rn-rm-q-a32.cc
48- test/aarch32/test-assembler-cond-rd-rn-rm-ge-a32.cc
Pierre Langlois88c46b82016-06-02 18:15:32 +010049
50Because these test cases need traces in order to build, the script will have
Alexandre Ramesd3832962016-07-04 15:03:43 +010051generated dummy trace files in `test/aarch32/traces/`. If you look at them
52you'll see they are basically empty:
Pierre Langlois88c46b82016-06-02 18:15:32 +010053
Alexandre Ramesd3832962016-07-04 15:03:43 +010054 $ cat test/aarch32/traces/sim-cond-rd-rn-immediate-adc-a32.h
Pierre Langlois88c46b82016-06-02 18:15:32 +010055 static const TestResult *kReferenceAdc = NULL;
56
57So of course, we can now build the test cases but running them will crash. We
58need to re-generate traces with real hardware; the test cases do not support
59running in the simulator just yet.
60
61Generating traces
62=================
63
64You need to have either compiled natively for ARM, or cross-compiled
65`test-runner`. The traces can then be generated in the same way as with VIXL64.
66Note that it takes a few minutes to generate everything.
67
68 ./tools/generate_simulator_traces.py --runner /path/to/test-runner \
69 --aarch32-only
70
71You can now rebuild everything. If it all goes well, running the new tests
72should pass.
73
74Test configuration format
75=========================
76
77TODO: Write a simple and well documented complete example configuration file and
78 mention it here.
79
80The underlying `test_generator` framework reads JSON description files and
Alexandre Ramesd3832962016-07-04 15:03:43 +010081generates tests according to them. These files live in `test/aarch32/config` by
Pierre Langlois88c46b82016-06-02 18:15:32 +010082default, but you may provide your own files with the `--config-files FILE ...`
83flag. The JSON format was extended to support C++ like one-line comments.
84
85Each configuration file will serve to generate one or more test files,
86we even use its file name to choose the name of the test:
87
Alexandre Ramesd3832962016-07-04 15:03:43 +010088 test/aarch32/config/cond-rd-rn-immediate-a32.json
89 `-> test/aarch32/test-simulator-cond-rd-rn-immediate-a32.cc
90 `-> test/aarch32/test-assembler-cond-rd-rn-immediate-a32.cc
Pierre Langlois88c46b82016-06-02 18:15:32 +010091
92In addition to these test configuration files, we also provide a JSON
93description with shared information. This information represents data types that
Alexandre Ramesd3832962016-07-04 15:03:43 +010094instructions use and lives in `test/aarch32/config/data-types.json`.
Pierre Langlois88c46b82016-06-02 18:15:32 +010095
96Data types description
97----------------------
98
99We refer to two kinds of data types: `operand` and `input`.
100
101An `operand` represents an argument passed to the macro-assembler to generate an
102instruction. For example, a register or an immediate are operands. We can think
103of it as "assemble-time" data.
104
105As opposed to `operands`, an `input` represents data passed to an instruction at
106runtime. For example, it will be the value you write to a register before
107executing the instruction under test.
108
109The `data-types.json` file has the following structure:
110
111~~~
112{
113 "operands": [
114 // List of operand types.
115 ],
116 "inputs": [
117 // List of input types.
118 ]
119}
120~~~
121
122Each operand is described with the following structure:
123
124~~~
125{
126 // Unique name for this operand type.
127 "name": "AllRegistersButPC",
128 // C++ type used by VIXL to represent this operand.
129 "type": "Register",
130 // List of possible variants.
131 "variants": [
132 "r0",
133 "r1",
134 "r2",
135 "r3",
136 "r4",
137 "r5",
138 "r6",
139 "r7",
140 "r8",
141 "r9",
142 "r10",
143 "r11",
144 "r12",
145 "r13",
146 "r14"
147 ],
148 // Default variant to use.
149 "default": "r0"
150}
151~~~
152
153The "name" field of the operand will be used by test configuration files in
154order to specify what kind of operands an instruction takes. The "type" field
155simply tells the generator what C++ type should be generated, e.g. "Condition",
156"Register", "uint32_t", "ShiftType", ...etc.
157
158Inputs are described in a very similar way:
159
160~~~
161{
162 // Unique name for this input type.
163 "name": "Register",
164 // Python type from `test_generator.data_types` to use to generate C++ code
165 // for this input.
166 "type": "Register",
167 // List of possible values.
168 "values": [
169 "0x00000000",
170 "0xffffffff",
171 "0xabababab",
172 "0x5a5a5a5a"
173 ],
174 // Default value.
175 "default": "0xabababab"
176}
177~~~
178
179The "name" field has the same purpose as for operands. The "type" field however,
180is the name of a Python class in `test_generator.data_types`. The type will
181specify what C++ code to generate in order to load and record the input value,
182e.g. how to load a value into a register, how to read and record it.
183
184When adding more tests, one may have to create new data types in this file. For
185example, when we want to test an instruction with a different set of registers.
186If adding new input types which need different C++ code to load and record them,
187one will have to add it to `test_generator.data_types` and override the
188`Epilogue` and `Prologue` methods.
189
190Test configuration
191------------------
192
193Once we have all the data types we need described, we need test configuration
194files to describe what instructions to test and with what `inputs` and
195`operands` they take.
196
197These files have the following structure:
198
199~~~
200{
201 "mnemonics": [
202 // List of instruction mnemonics to use. These must correspond to
203 // `MacroAssembler` methods.
204 ],
205 "description": {
206 "operands": [
207 // List of operands the instruction takes.
208 ],
209 "inputs: [
210 // List of inputs the instruction can be affected by.
211 ]
212 },
213 // List of files to generate.
214 "test-files": [
215 {
216 "type": "assembler",
217 "mnemonics": [
218 // Optional list of instruction mnemonics to use, overriding the
219 // top-level list.
220 ],
221 "test-cases": [
222 // List of test cases for "assembler" tests, see below for
223 // details.
224 ]
225 },
226 {
227 "type": "simulator",
228 "test-cases": [
229 // List of test cases for "simulator" tests, see below for
230 // details.
231 ]
232 }
233 ]
234}
235~~~
236
237- List of operands:
238
239The operand list describes the actual argument to the `MacroAssembler` method.
240For example, if we take instruction in the form
241"XXX.cond rd rn rm shift #amount":
242
243We want to generate C++ code as such:
244
245~~~
246Condition cond = ...;
247Register rd = ...;
248Register rn = ...;
249Register rm = ...;
250ShiftType type = ...;
251uint32_t amount = ...;
252Operand op(rm, type, amount);
253
254__ Xxx(cond, rd, rn, op);
255~~~
256
257We will have the following operand list:
258
259~~~
260"operands": [
261 {
262 "name": "cond",
263 "type": "Condition"
264 },
265 {
266 "name": "rd",
267 "type": "AllRegistersButPC"
268 },
269 {
270 "name": "rn",
271 "type": "AllRegistersButPC"
272 },
273 {
274 "name": "op",
275 "wrapper": "Operand",
276 "operands": [
277 {
278 "name": "rm",
279 "operand": "AllRegistersButPC"
280 },
281 {
282 "name": "type",
283 "operand": "Shift"
284 },
285 {
286 "name": "amount",
287 "operand": "ImmediateShiftAmount"
288 }
289 ]
290 }
291]
292~~~
293
294The "name" field represents the identifier of the operand and will be used as a
295variable name in the generated code. The "type" field corresponds to an operand
296type described in the `data-types.json` file as described above.
297
298We can see that we've wrapped the last three operands into an "op"
299wrapper object. This allows us to tell the generator to wrap these
300operands into a `Operand` C++ object.
301
302- List of inputs:
303
304This structure is similar to the operand list, but this time it describes what
305input data the instructions may be affected by at runtime. If we take the same
306example as above, we will have the following list:
307
308~~~
309"inputs": [
310 {
311 "name": "apsr",
312 "type": "NZCV"
313 },
314 {
315 "name": "rd",
316 "type": "Register"
317 },
318 {
319 "name": "rn",
320 "type": "Register"
321 },
322 {
323 "name": "rm",
324 "type": "Register"
325 }
326]
327~~~
328
329This will specify what C++ code to generate before and after emitting the
330instruction under test. The C++ code will set and record register values for
331example. See `test_generator.data_types` for more details.
332
333- Test files and test cases:
334
335Up until now, we've only just described the environment in which instructions
336can operate. We need to express what files we want generating, what instructions
337we want to test and what we want them to do.
338
339As previously mentioned, a configuration file can control the generation of
340several test files. We will generate one file per element in the "test-files"
341array:
342
343~~~
344"test-files": [
345 {
346 "type": "assembler",
347 "test-cases": [
348 // List of test cases for "assembler" tests, see below for
349 // details.
350 ]
351 },
352 {
353 "type": "assembler",
354 "name": "special-case",
355 "mnemonics": [
356 // Override the top-level list with a subset of instructions concerned
357 // with this special case.
358 ],
359 "test-cases": [
360 // List of test cases for "assembler" tests, see below for
361 // details.
362 ]
363 },
364 {
365 "type": "simulator",
366 "test-cases": [
367 // List of test cases for "simulator" tests, see below for
368 // details.
369 ]
370 }
371]
372~~~
373
374Above, we've decided to generate three tests: a "simulator" test and two
375"assembler" tests. The resulting files will have names with the following
376pattern.
377
Alexandre Ramesd3832962016-07-04 15:03:43 +0100378 - "test/aarch32/test-assembler-{configuration name}-a32.cc"
379 - "test/aarch32/test-assembler-{configuration name}-special-case-a32.cc"
380 - "test/aarch32/test-simulator-{configuration name}-a32.cc"
Pierre Langlois88c46b82016-06-02 18:15:32 +0100381
382The "type" field describes the kind of testing we want to do, these types are
Jacob Bramley35f27332016-11-14 17:51:34 +0000383recognized by the generator and, at the moment, can be one of "simulator",
384"assembler" and "macro-assembler". Simulator tests will run each instruction and
385record the changes while assembler tests will only record the code buffer and
386never execute anything. MacroAssembler tests currently only generate code to
387check that the MacroAssembler does not crash; the output itself is not yet
388tested. Because you may want to generate more than one test of the same type, as
389we are doing in the example, we need a way to differentiate them. You may use
Pierre Langlois88c46b82016-06-02 18:15:32 +0100390the optional "name" field for this.
391
392Finally, we describe how to test the instruction by declaring a list of test
393cases with the "test-cases" field.
394
395Here is an example of what we can express:
396~~~
397[
398 // Generate all combinations of instructions where "rd" an "rn" are the same
399 // register and "cond" and "rm" are just the default.
400 // For example:
401 // __ Xxx(al, r0, r0, r0);
402 // __ Xxx(al, r1, r1, r0);
403 // __ Xxx(al, r2, r2, r0);
404 // ...
405 // __ Xxx(al, r12, r12, r0);
406 // __ Xxx(al, r13, r13, r0);
407 // __ Xxx(al, r14, r14, r0);
408 //
409 // For each of the instructions above, run them with a different value in "rd"
410 // and "rn".
411 {
412 "name": "RdIsRn",
413 "operands": [
414 "rd", "rn"
415 ],
416 "operand-filter": "rd == rn",
417 "inputs": [
418 "rd", "rn"
419 ],
420 "input-filter": "rd == rn"
421 },
422 // Generate all combinations of instructions with different condition codes.
423 // For example:
424 // __ Xxx(eq, r0, r0, r0);
425 // __ Xxx(ne, r0, r0, r0);
426 // __ Xxx(cs, r0, r0, r0);
427 // ...
428 // __ Xxx(gt, r0, r0, r0);
429 // __ Xxx(le, r0, r0, r0);
430 // __ Xxx(al, r0, r0, r0);
431 //
432 // For each of the instructions above, run them against all combinations of
433 // NZCV bits.
434 {
435 "name": "ConditionVersusNZCV",
436 "operands": [
437 "cond"
438 ],
439 "inputs": [
440 "apsr"
441 ]
442 },
443 // We are interested in testing that the Q bit gets set and cleared, so we've
444 // limited the instruction generation to a single instruction and instead have
445 // stressed the values put in "rn" and "rm".
446 //
447 // So for this instruction, we choose to run it will all combinations of
448 // values in "rn" and "rm". Additionally, we include "qbit" in the inputs,
449 // which will make the test set or clear it before executing the instruction.
450 // Note that "qbit" needs to be declared as an input in the instruction
451 // description (see "List of inputs" section).
452 {
453 "name": "Qbit",
454 "operands": [
455 "rn", "rm"
456 ],
457 "inputs": [
458 "qbit", "rn", "rm"
459 ],
460 "operand-filter": "rn != rm'",
461 "operand-limit": 1
462 },
463 // Generate 10 random instructions with all different registers but use the
464 // default condition.
465 // For example:
466 // __ Xxx(al, r5, r1, r0);
467 // __ Xxx(al, r8, r9, r7);
468 // __ Xxx(al, r9, r1, r2);
469 // __ Xxx(al, r0, r6, r2);
470 // __ Xxx(al, r11, r9, r11);
471 // __ Xxx(al, r14, r2, r11);
472 // __ Xxx(al, r8, r2, r5);
473 // __ Xxx(al, r10, r0, r1);
474 // __ Xxx(al, r11, r2, r7);
475 // __ Xxx(al, r2, r6, r1);
476 //
477 // For each instruction, feed it 200 different combination of values in the
478 // three registers.
479 {
480 "name": "RegisterSimulatorTest",
481 "operands": [
482 "rd", "rn", "rm"
483 ],
484 "inputs": [
485 "rd", "rn", "rm"
486 ],
487 "operand-limit": 10,
488 "input-limit": 200
489 }
490]
491~~~
492
493Assembler test cases are much simpler, here are some examples:
494~~~
495// Generate 2000 random instructions out of all possible operand combinations.
496{
497 "name": "LotsOfRandomInstructions",
498 "operands": [
499 "cond", "rd", "rn", "rm"
500 ],
501 "operand-limit": 2000
502},
503// Same as above but limit the test to 200 instructions where rd == rn.
504{
505 "name": "RdIsRn",
506 "operands": [
507 "cond", "rd", "rn", "rm"
508 ],
509 "operand-filter": "rd == rn",
510 "operand-limit": 200
511}
512~~~
513
514As can be expected, assembler test do not have the notion of "inputs".
515
516Here are details about each field. Note that all of them except for "name" are
517optional.
518
519 * "name":
520
521 A unique name should be given to the test case, it will be used to give the
522 generated C++ `const Input[]` array a name.
523
524 * "operands":
525
526 List of operand names that we are interested in testing. The generator will
527 lookup the list of variants for each operand and build the product of all of
528 them. It will then choose the default variant for the operands not specified
529 here.
530
531 * "operand-filter":
532
533 As you would expect, the product of all operand variants may be huge. To
534 prevent this, you may specify a Python expression to filter the list.
535
536 * "operand-limit":
537
538 We can potentially obtain a *massive* set of variants of instructions, as we
539 are computing a product of operand variants in "operands". This field allows
540 us to limit this by choosing a random sample from the computed variants.
541 Note that this is a seeded pseudo-random sample, and the seed corresponds to
542 the test case description. The same test case description will always
543 generate the same code.
544
545 * "inputs":
546
547 This is exactly the same as "operands" but for inputs.
548
549 * "input-filter":
550
551 Ditto.
552
553 * "input-limit":
554
555 Ditto.
556
557Here is an example of the C++ code that will be generated for a given test case.
558For simplicity, let's generate tests for an instruction with only `NZCV` and two
559registers as inputs.
560
561For the following test case, which will target encodings where `rd` and `rn` are
562the same registers:
563
564~~~
565{
566 "name": "RdIsRn",
567 "operands": [
568 "rd", "rn"
569 ],
570 "operand-filter": "rd == rn",
571 "inputs": [
572 "rd", "rn"
573 ],
574 "input-filter": "rd == rn"
575},
576~~~
577
578It will generate the following input array.
579
580~~~
581// apsr, rd, rn
582static const Inputs kRdIsRn[] = {{NoFlag, 0x00000000, 0x00000000},
583 {NoFlag, 0xffffffff, 0xffffffff},
584 {NoFlag, 0xabababab, 0xabababab},
585 {NoFlag, 0x5a5a5a5a, 0x5a5a5a5a}};
586~~~
587
588We can see that the default apsr value was chosen (NoFlag), as apsr is not in
589the list of "inputs".
590
591It will also generate a list of instructions to test:
592
593~~~
594static const TestLoopData kTests[] = {
595 {{al, r1, r1, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"},
596 {{al, r2, r2, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"},
597 {{al, r8, r8, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"},
598 {{al, r9, r9, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"},
599};
600~~~
601
602As a result, the new test we will assemble each instructions in "mnemonics" with
603all of the operands described in `kTests` above. And each instruction will be
604executed and passed all inputs in `kRdIsRn`.
605"""
606
607import subprocess
608import argparse
609import string
610import re
611import multiprocessing
612import functools
613
614import test_generator.parser
615
616
617default_config_files = [
Pierre Langloisd1bf2782016-09-27 15:05:07 +0100618 # A32 and T32 tests
619 'test/aarch32/config/rd-rn-rm.json',
620
621 # A32 specific tests
Alexandre Ramesd3832962016-07-04 15:03:43 +0100622 'test/aarch32/config/cond-rd-rn-operand-const-a32.json',
623 'test/aarch32/config/cond-rd-rn-operand-rm-a32.json',
624 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to31-a32.json',
625 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to32-a32.json',
626 'test/aarch32/config/cond-rd-rn-operand-rm-shift-rs-a32.json',
627 'test/aarch32/config/cond-rd-rn-operand-rm-ror-amount-a32.json',
628 'test/aarch32/config/cond-rd-rn-a32.json',
Jacob Bramley35f27332016-11-14 17:51:34 +0000629 'test/aarch32/config/cond-rd-rn-pc-a32.json',
Alexandre Ramesd3832962016-07-04 15:03:43 +0100630 'test/aarch32/config/cond-rd-rn-rm-a32.json',
631 'test/aarch32/config/cond-rd-operand-const-a32.json',
632 'test/aarch32/config/cond-rd-operand-rn-a32.json',
633 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to31-a32.json',
634 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to32-a32.json',
635 'test/aarch32/config/cond-rd-operand-rn-shift-rs-a32.json',
636 'test/aarch32/config/cond-rd-operand-rn-ror-amount-a32.json',
637 'test/aarch32/config/cond-rd-memop-immediate-512-a32.json',
638 'test/aarch32/config/cond-rd-memop-immediate-8192-a32.json',
639 'test/aarch32/config/cond-rd-memop-rs-a32.json',
640 'test/aarch32/config/cond-rd-memop-rs-shift-amount-1to31-a32.json',
641 'test/aarch32/config/cond-rd-memop-rs-shift-amount-1to32-a32.json',
Pierre Langlois88c46b82016-06-02 18:15:32 +0100642
Pierre Langloisd1bf2782016-09-27 15:05:07 +0100643 # T32 specific tests
Alexandre Ramesd3832962016-07-04 15:03:43 +0100644 'test/aarch32/config/cond-rd-rn-t32.json',
645 'test/aarch32/config/cond-rd-rn-rm-t32.json',
646 'test/aarch32/config/cond-rdlow-rnlow-rmlow-t32.json',
647 'test/aarch32/config/cond-rd-rn-operand-const-t32.json',
648 'test/aarch32/config/cond-rd-pc-operand-imm12-t32.json',
649 'test/aarch32/config/cond-rd-rn-operand-imm12-t32.json',
650 'test/aarch32/config/cond-rd-pc-operand-imm8-t32.json',
651 'test/aarch32/config/cond-rd-sp-operand-imm8-t32.json',
652 'test/aarch32/config/cond-rdlow-rnlow-operand-immediate-t32.json',
653 'test/aarch32/config/cond-sp-sp-operand-imm7-t32.json',
654 'test/aarch32/config/cond-rd-rn-operand-rm-t32.json',
655 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to31-t32.json',
656 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to32-t32.json',
657 'test/aarch32/config/cond-rd-rn-operand-rm-ror-amount-t32.json',
658 'test/aarch32/config/cond-rd-operand-const-t32.json',
659 'test/aarch32/config/cond-rd-operand-imm16-t32.json',
660 'test/aarch32/config/cond-rdlow-operand-imm8-t32.json',
661 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to31-t32.json',
662 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to32-t32.json',
663 'test/aarch32/config/cond-rd-operand-rn-shift-rs-t32.json',
664 'test/aarch32/config/cond-rd-operand-rn-ror-amount-t32.json',
665 'test/aarch32/config/cond-rd-operand-rn-t32.json',
Pierre Langlois88c46b82016-06-02 18:15:32 +0100666]
667
668
669# Link a test type with a template file.
670template_files = {
Alexandre Ramesd3832962016-07-04 15:03:43 +0100671 'simulator': "test/aarch32/config/template-simulator-aarch32.cc.in",
672 'assembler': "test/aarch32/config/template-assembler-aarch32.cc.in",
Jacob Bramley35f27332016-11-14 17:51:34 +0000673 'macro-assembler': "test/aarch32/config/template-macro-assembler-aarch32.cc.in",
Pierre Langlois88c46b82016-06-02 18:15:32 +0100674}
675
676
677def BuildOptions():
678 result = argparse.ArgumentParser(
679 description = 'Test generator for AArch32.',
680 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
681 result.add_argument('--config-files', nargs='+',
682 default=default_config_files,
683 metavar='FILE',
684 help='Configuration files, each will generate a test file.')
685 result.add_argument('--clang-format',
686 default='clang-format-3.6', help='Path to clang-format.')
687 result.add_argument('--jobs', '-j', type=int, metavar='N',
688 default=multiprocessing.cpu_count(),
689 help='Allow N jobs at once')
Georgia Kouveli2f885bb2016-12-15 18:43:42 +0000690 result.add_argument('--skip-traces', action='store_true',
691 help='Skip generation of dummy traces.')
Pierre Langlois88c46b82016-06-02 18:15:32 +0100692 return result.parse_args()
693
694
695def DoNotEditComment(template_file):
696 # We rely on `clang-format` to wrap this comment to 80 characters.
697 return """
698// -----------------------------------------------------------------------------
699// This file is auto generated from the {} template file using tools/generate_tests.py.
700//
701// PLEASE DO NOT EDIT.
702// -----------------------------------------------------------------------------
703 """.format(template_file)
704
Georgia Kouveli2f885bb2016-12-15 18:43:42 +0000705def GenerateTest(generator, clang_format, skip_traces):
Pierre Langlois88c46b82016-06-02 18:15:32 +0100706 template_file = template_files[generator.test_type]
707 generated_file = ""
708 with open(template_file, "r") as f:
709 # Strip out comments starting with three forward slashes before creating the
710 # string.Template object.
711 template = string.Template(re.sub("\/\/\/.*", "", f.read()))
712
713 # The `generator` object has methods generating strings to fill the template.
714 generated_file = template.substitute({
715 # Add a top comment stating this file is auto-generated.
716 'do_not_edit_comment': DoNotEditComment(template_file),
717
718 # List of mnemonics.
719 'instruction_list_declaration': generator.InstructionListDeclaration(),
720
721 # Declarations.
722 'operand_list_declaration': generator.OperandDeclarations(),
723 'input_declarations': generator.InputDeclarations(),
724
725 # Definitions.
726 'input_definitions': generator.InputDefinitions(),
727 'test_case_definitions': generator.TestCaseDefinitions(),
728
729 # Include traces.
730 'include_trace_files': generator.IncludeTraceFiles(),
731
732 # Define a typedef for the MacroAssembler method.
733 'macroassembler_method_args': generator.MacroAssemblerMethodArgs(),
734
735 # Generate code to switch instruction set.
736 'macroassembler_set_isa': generator.MacroAssemblerSetISA(),
737
738 # Generate code to emit instructions.
739 'code_instantiate_operands': generator.CodeInstantiateOperands(),
740 'code_prologue': generator.CodePrologue(),
741 'code_epilogue': generator.CodeEpilogue(),
742 'code_parameter_list': generator.CodeParameterList(),
743
744 # Generate code to trace the execution and print C++.
745 'trace_print_outputs': generator.TracePrintOutputs(),
746
747 # Generate code to compare the results against a trace.
748 'check_instantiate_results': generator.CheckInstantiateResults(),
749 'check_instantiate_inputs': generator.CheckInstantiateInputs(),
750 'check_instantiate_references': generator.CheckInstantiateReferences(),
751 'check_results_against_references':
752 generator.CheckResultsAgainstReferences(),
753 'check_print_input': generator.CheckPrintInput(),
754 'check_print_expected': generator.CheckPrintExpected(),
755 'check_print_found': generator.CheckPrintFound(),
756
Pierre Langloisd1bf2782016-09-27 15:05:07 +0100757 'test_isa': generator.TestISA(),
Rodolph Perfetta9a9331f2016-12-09 22:05:48 +0000758 'test_name': generator.TestName(),
759 'isa_guard': generator.GetIsaGuard()
Pierre Langlois88c46b82016-06-02 18:15:32 +0100760 })
761 # Create the test case and pipe it through `clang-format` before writing it.
762 with open(
Pierre Langloisd1bf2782016-09-27 15:05:07 +0100763 "test/aarch32/test-{}-{}-{}.cc".format(generator.test_type,
764 generator.test_name,
765 generator.test_isa),
Pierre Langlois88c46b82016-06-02 18:15:32 +0100766 "w") as f:
Pierre Langlois19c05352016-08-10 18:17:55 +0100767 proc = subprocess.Popen([clang_format], stdin=subprocess.PIPE,
768 stdout=subprocess.PIPE)
Pierre Langlois88c46b82016-06-02 18:15:32 +0100769 out, _ = proc.communicate(generated_file.encode())
770 f.write(out.decode())
Georgia Kouveli2f885bb2016-12-15 18:43:42 +0000771 if not skip_traces:
772 # Write dummy trace files into 'test/aarch32/traces/'.
773 generator.WriteEmptyTraces("test/aarch32/traces/")
Pierre Langloisd1bf2782016-09-27 15:05:07 +0100774 print("Generated {} {} test for \"{}\".".format(generator.test_isa.upper(),
775 generator.test_type,
776 generator.test_name))
Pierre Langlois88c46b82016-06-02 18:15:32 +0100777
778if __name__ == '__main__':
779 args = BuildOptions()
780
781 # Each file in `args.config_files` populates a `Generator` object.
Alexandre Ramesd3832962016-07-04 15:03:43 +0100782 generators = test_generator.parser.Parse('test/aarch32/config/data-types.json',
Pierre Langlois88c46b82016-06-02 18:15:32 +0100783 args.config_files)
784
785 # Call the `GenerateTest` function for each generator object in parallel. This
786 # will use as many processes as defined by `-jN`, which defaults to 1.
787 with multiprocessing.Pool(processes=args.jobs) as pool:
Georgia Kouveli2f885bb2016-12-15 18:43:42 +0000788 pool.map(functools.partial(GenerateTest, clang_format=args.clang_format,
789 skip_traces=args.skip_traces),
Pierre Langlois88c46b82016-06-02 18:15:32 +0100790 generators)