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