1// Copyright 2016, VIXL authors
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7//   * Redistributions of source code must retain the above copyright notice,
8//     this list of conditions and the following disclaimer.
9//   * Redistributions in binary form must reproduce the above copyright notice,
10//     this list of conditions and the following disclaimer in the documentation
11//     and/or other materials provided with the distribution.
12//   * Neither the name of ARM Limited nor the names of its contributors may be
13//     used to endorse or promote products derived from this software without
14//     specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27/// This file is a template read by tools/generate_tests.py, it isn't valid C++
28/// as it is. Variables written as ${substitute_me} are replaced by the script.
29/// Comments starting with three forward slashes such as this one are also
30/// removed.
31
32${do_not_edit_comment}
33
34#include "test-runner.h"
35
36#include "test-utils.h"
37#include "test-utils-aarch32.h"
38
39#include "aarch32/assembler-aarch32.h"
40#include "aarch32/macro-assembler-aarch32.h"
41#include "aarch32/disasm-aarch32.h"
42
43#define __ masm.
44#define BUF_SIZE (4096)
45
46#ifdef VIXL_INCLUDE_SIMULATOR_AARCH32
47// Run tests with the simulator.
48
49#define SETUP() MacroAssembler masm(BUF_SIZE)
50
51#define START() masm.GetBuffer()->Reset()
52
53#define END() \
54  __ Hlt(0);  \
55  __ FinalizeCode();
56
57// TODO: Run the tests in the simulator.
58#define RUN()
59
60#else  // ifdef VIXL_INCLUDE_SIMULATOR_AARCH32.
61
62#define SETUP()                                   \
63  MacroAssembler masm(BUF_SIZE);                  \
64  UseScratchRegisterScope harness_scratch;        \
65
66#define START()                             \
67  harness_scratch.Open(&masm);              \
68  harness_scratch.ExcludeAll();             \
69  masm.GetBuffer()->Reset();                \
70  __ Push(r4);                              \
71  __ Push(r5);                              \
72  __ Push(r6);                              \
73  __ Push(r7);                              \
74  __ Push(r8);                              \
75  __ Push(r9);                              \
76  __ Push(r10);                             \
77  __ Push(r11);                             \
78  __ Push(lr);                              \
79  harness_scratch.Include(ip);
80
81#define END()                               \
82  harness_scratch.Exclude(ip);              \
83  __ Pop(lr);                               \
84  __ Pop(r11);                              \
85  __ Pop(r10);                              \
86  __ Pop(r9);                               \
87  __ Pop(r8);                               \
88  __ Pop(r7);                               \
89  __ Pop(r6);                               \
90  __ Pop(r5);                               \
91  __ Pop(r4);                               \
92  __ Bx(lr);                                \
93  __ FinalizeCode();                        \
94  harness_scratch.Close();
95
96#define RUN()                                                                \
97  {                                                                          \
98    int pcs_offset = masm.IsUsingT32() ? 1 : 0;                              \
99    masm.GetBuffer()->SetExecutable();                                       \
100    ExecuteMemory(masm.GetBuffer()->GetStartAddress<byte*>(),                \
101                  masm.GetSizeOfCodeGenerated(),                             \
102                  pcs_offset);                                               \
103    masm.GetBuffer()->SetWritable();                                         \
104  }
105
106#endif  // ifdef VIXL_INCLUDE_SIMULATOR_AARCH32
107
108namespace vixl {
109namespace aarch32 {
110
111// List of instruction encodings:
112#define FOREACH_INSTRUCTION(M) \
113  ${instruction_list_declaration}
114
115// The following definitions are defined again in each generated test, therefore
116// we need to place them in an anomymous namespace. It expresses that they are
117// local to this file only, and the compiler is not allowed to share these types
118// across test files during template instantiation. Specifically, `Operands` and
119// `Inputs` have various layouts across generated tests so they absolutely
120// cannot be shared.
121
122#ifdef ${isa_guard}
123namespace {
124
125// Values to be passed to the assembler to produce the instruction under test.
126struct Operands {
127  ${operand_list_declaration}
128};
129
130// Input data to feed to the instruction.
131struct Inputs {
132  ${input_declarations}
133};
134
135// This structure contains all input data needed to test one specific encoding.
136// It used to generate a loop over an instruction.
137struct TestLoopData {
138  // The `operands` fields represents the values to pass to the assembler to
139  // produce the instruction.
140  Operands operands;
141  // Description of the operands, used for error reporting.
142  const char* operands_description;
143  // Unique identifier, used for generating traces.
144  const char* identifier;
145  // Array of values to be fed to the instruction.
146  size_t input_size;
147  const Inputs* inputs;
148};
149
150${input_definitions}
151
152// A loop will be generated for each element of this array.
153const TestLoopData kTests[] = {${test_case_definitions}};
154
155// We record all inputs to the instructions as outputs. This way, we also check
156// that what shouldn't change didn't change.
157struct TestResult {
158  size_t output_size;
159  const Inputs* outputs;
160};
161
162// These headers each contain an array of `TestResult` with the reference output
163// values. The reference arrays are names `kReference{mnemonic}`.
164${include_trace_files}
165
166// The maximum number of errors to report in detail for each test.
167const unsigned kErrorReportLimit = 8;
168
169typedef void (MacroAssembler::*Fn)(${macroassembler_method_args});
170
171void TestHelper(Fn instruction, const char* mnemonic,
172                const TestResult reference[]) {
173  SETUP();
174  ${macroassembler_set_isa}
175  START();
176
177  // Data to compare to `reference`.
178  TestResult* results[ARRAY_SIZE(kTests)];
179
180  // Test cases for memory bound instructions may allocate a buffer and save its
181  // address in this array.
182  byte* scratch_memory_buffers[ARRAY_SIZE(kTests)];
183
184  // Generate a loop for each element in `kTests`. Each loop tests one specific
185  // instruction.
186  for (unsigned i = 0; i < ARRAY_SIZE(kTests); i++) {
187    // Allocate results on the heap for this test.
188    results[i] = new TestResult;
189    results[i]->outputs = new Inputs[kTests[i].input_size];
190    results[i]->output_size = kTests[i].input_size;
191
192    size_t input_stride = sizeof(kTests[i].inputs[0]) * kTests[i].input_size;
193    VIXL_ASSERT(IsUint32(input_stride));
194
195    scratch_memory_buffers[i] = NULL;
196
197    Label loop;
198    UseScratchRegisterScope scratch_registers(&masm);
199    // Include all registers from r0 ro r12.
200    scratch_registers.Include(RegisterList(0x1fff));
201
202    // Values to pass to the macro-assembler.
203    ${code_instantiate_operands}
204
205    // Allocate reserved registers for our own use.
206    Register input_ptr = scratch_registers.Acquire();
207    Register input_end = scratch_registers.Acquire();
208    Register result_ptr = scratch_registers.Acquire();
209
210    // Initialize `input_ptr` to the first element and `input_end` the address
211    // after the array.
212    __ Mov(input_ptr, Operand::From(kTests[i].inputs));
213    __ Add(input_end, input_ptr, static_cast<uint32_t>(input_stride));
214    __ Mov(result_ptr, Operand::From(results[i]->outputs));
215    __ Bind(&loop);
216
217    ${code_prologue}
218
219    (masm.*instruction)(${code_parameter_list});
220
221    ${code_epilogue}
222
223    // Advance the result pointer.
224    __ Add(result_ptr, result_ptr, Operand::From(sizeof(kTests[i].inputs[0])));
225    // Loop back until `input_ptr` is lower than `input_base`.
226    __ Add(input_ptr, input_ptr, Operand::From(sizeof(kTests[i].inputs[0])));
227    __ Cmp(input_ptr, input_end);
228    __ B(ne, &loop);
229  }
230
231  END();
232
233  RUN();
234
235  if (Test::generate_test_trace()) {
236    // Print the results.
237    for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) {
238      printf("const Inputs kOutputs_%s_%s[] = {\n", mnemonic,
239             kTests[i].identifier);
240      for (size_t j = 0; j < results[i]->output_size; j++) {
241        printf("  { ");
242        ${trace_print_outputs}
243        printf(" },\n");
244      }
245      printf("};\n");
246    }
247    printf("const TestResult kReference%s[] = {\n", mnemonic);
248    for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) {
249      printf("  {\n");
250      printf("    ARRAY_SIZE(kOutputs_%s_%s),\n", mnemonic,
251             kTests[i].identifier);
252      printf("    kOutputs_%s_%s,\n", mnemonic, kTests[i].identifier);
253      printf("  },\n");
254    }
255    printf("};\n");
256  } else if (kCheckSimulatorTestResults) {
257    // Check the results.
258    unsigned total_error_count = 0;
259    for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) {
260      bool instruction_has_errors = false;
261      for (size_t j = 0; j < kTests[i].input_size; j++) {
262        ${check_instantiate_results}
263        ${check_instantiate_inputs}
264        ${check_instantiate_references}
265
266        if ((${check_results_against_references}) &&
267            (++total_error_count <= kErrorReportLimit)) {
268          // Print the instruction once even if it triggered multiple failures.
269          if (!instruction_has_errors) {
270            printf("Error(s) when testing \"%s %s\":\n", mnemonic,
271                   kTests[i].operands_description);
272            instruction_has_errors = true;
273          }
274          // Print subsequent errors.
275          printf("  Input:    ");
276          ${check_print_input}
277          printf("\n");
278          printf("  Expected: ");
279          ${check_print_expected}
280          printf("\n");
281          printf("  Found:    ");
282          ${check_print_found}
283          printf("\n\n");
284        }
285      }
286    }
287
288    if (total_error_count > kErrorReportLimit) {
289      printf("%u other errors follow.\n",
290             total_error_count - kErrorReportLimit);
291    }
292    VIXL_CHECK(total_error_count == 0);
293  } else {
294    VIXL_WARNING("Assembled the code, but did not run anything.\n");
295  }
296
297  for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) {
298    delete[] results[i]->outputs;
299    delete results[i];
300    delete[] scratch_memory_buffers[i];
301  }
302}
303
304// Instantiate tests for each instruction in the list.
305// TODO: Remove this limitation by having a sandboxing mechanism.
306#if defined(VIXL_HOST_POINTER_32)
307#define TEST(mnemonic)                                                      \
308  void Test_##mnemonic() {                                                  \
309    TestHelper(&MacroAssembler::mnemonic, #mnemonic, kReference##mnemonic); \
310  }                                                                         \
311  Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic "_${test_isa}",    \
312                       &Test_##mnemonic);
313#else
314#define TEST(mnemonic)                                                      \
315  void Test_##mnemonic() {                                                  \
316    VIXL_WARNING("This test can only run on a 32-bit host.\n");             \
317    USE(TestHelper);                                                        \
318  }                                                                         \
319  Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic "_${test_isa}",    \
320                       &Test_##mnemonic);
321#endif
322
323FOREACH_INSTRUCTION(TEST)
324#undef TEST
325
326}  // namespace
327#endif
328
329}  // namespace aarch32
330}  // namespace vixl
331