• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
42#define BUF_SIZE (4096)
43
44namespace vixl {
45namespace aarch32 {
46
47// List of instruction mnemonics.
48#define FOREACH_INSTRUCTION(M) \
49  ${instruction_list_declaration}
50
51// The following definitions are defined again in each generated test, therefore
52// we need to place them in an anomymous namespace. It expresses that they are
53// local to this file only, and the compiler is not allowed to share these types
54// across test files during template instantiation. Specifically, `Operands` has
55// various layouts across generated tests so it absolutely cannot be shared.
56
57#ifdef ${isa_guard}
58namespace {
59
60// Values to be passed to the assembler to produce the instruction under test.
61struct Operands {
62  ${operand_list_declaration}
63};
64
65// This structure contains all data needed to test one specific
66// instruction.
67struct TestData {
68  // The `operands` field represents what to pass to the assembler to
69  // produce the instruction.
70  Operands operands;
71  // True if we need to generate an IT instruction for this test to be valid.
72  bool in_it_block;
73  // The condition to give the IT instruction, this will be set to "al" by
74  // default.
75  Condition it_condition;
76  // Description of the operands, used for error reporting.
77  const char* operands_description;
78  // Unique identifier, used for generating traces.
79  const char* identifier;
80};
81
82struct TestResult {
83  size_t size;
84  const byte* encoding;
85};
86
87// Each element of this array produce one instruction encoding.
88const TestData kTests[] = {${test_case_definitions}};
89
90// These headers each contain an array of `TestResult` with the reference output
91// values. The reference arrays are names `kReference{mnemonic}`.
92${include_trace_files}
93
94// The maximum number of errors to report in detail for each test.
95const unsigned kErrorReportLimit = 8;
96
97typedef void (MacroAssembler::*Fn)(${macroassembler_method_args});
98
99void TestHelper(Fn instruction, const char* mnemonic,
100                const TestResult reference[]) {
101  unsigned total_error_count = 0;
102  MacroAssembler masm(BUF_SIZE);
103
104  ${macroassembler_set_isa}
105
106  for (unsigned i = 0; i < ARRAY_SIZE(kTests); i++) {
107    // Values to pass to the macro-assembler.
108    ${code_instantiate_operands}
109
110    int32_t start = masm.GetCursorOffset();
111    {
112      // We never generate more that 4 bytes, as IT instructions are only
113      // allowed for narrow encodings.
114      ExactAssemblyScope scope(&masm, 4, ExactAssemblyScope::kMaximumSize);
115      if (kTests[i].in_it_block) {
116        masm.it(kTests[i].it_condition);
117      }
118      (masm.*instruction)(${code_parameter_list});
119    }
120    int32_t end = masm.GetCursorOffset();
121
122    const byte* result_ptr =
123        masm.GetBuffer()->GetOffsetAddress<const byte*>(start);
124    VIXL_ASSERT(start < end);
125    uint32_t result_size = end - start;
126
127    if (Test::generate_test_trace()) {
128      // Print the result bytes.
129      printf("const byte kInstruction_%s_%s[] = {\n", mnemonic,
130             kTests[i].identifier);
131      for (uint32_t j = 0; j < result_size; j++) {
132        if (j == 0) {
133          printf("  0x%02" PRIx8, result_ptr[j]);
134        } else {
135          printf(", 0x%02" PRIx8, result_ptr[j]);
136        }
137      }
138      // This comment is meant to be used by external tools to validate
139      // the encoding. We can parse the comment to figure out what
140      // instruction this corresponds to.
141      if (kTests[i].in_it_block) {
142        printf(" // It %s; %s %s\n};\n", kTests[i].it_condition.GetName(),
143               mnemonic, kTests[i].operands_description);
144      } else {
145        printf(" // %s %s\n};\n", mnemonic, kTests[i].operands_description);
146      }
147    } else {
148      // Check we've emitted the exact same encoding as present in the
149      // trace file. Only print up to `kErrorReportLimit` errors.
150      if (((result_size != reference[i].size) ||
151           (memcmp(result_ptr,
152                   reference[i].encoding,
153                   reference[i].size) != 0)) &&
154          (++total_error_count <= kErrorReportLimit)) {
155        printf("Error when testing \"%s\" with operands \"%s\":\n", mnemonic,
156               kTests[i].operands_description);
157        printf("  Expected: ");
158        for (uint32_t j = 0; j < reference[i].size; j++) {
159          if (j == 0) {
160            printf("0x%02" PRIx8, reference[i].encoding[j]);
161          } else {
162            printf(", 0x%02" PRIx8, reference[i].encoding[j]);
163          }
164        }
165        printf("\n");
166        printf("  Found:    ");
167        for (uint32_t j = 0; j < result_size; j++) {
168          if (j == 0) {
169            printf("0x%02" PRIx8, result_ptr[j]);
170          } else {
171            printf(", 0x%02" PRIx8, result_ptr[j]);
172          }
173        }
174        printf("\n");
175      }
176    }
177  }
178
179  masm.FinalizeCode();
180
181  if (Test::generate_test_trace()) {
182    // Finalize the trace file by writing the final `TestResult` array
183    // which links all generated instruction encodings.
184    printf("const TestResult kReference%s[] = {\n", mnemonic);
185    for (unsigned i = 0; i < ARRAY_SIZE(kTests); i++) {
186      printf("  {\n");
187      printf("    ARRAY_SIZE(kInstruction_%s_%s),\n", mnemonic,
188             kTests[i].identifier);
189      printf("    kInstruction_%s_%s,\n", mnemonic, kTests[i].identifier);
190      printf("  },\n");
191    }
192    printf("};\n");
193  } else {
194    if (total_error_count > kErrorReportLimit) {
195      printf("%u other errors follow.\n",
196             total_error_count - kErrorReportLimit);
197    }
198    // Crash if the test failed.
199    VIXL_CHECK(total_error_count == 0);
200  }
201}
202
203// Instantiate tests for each instruction in the list.
204#define TEST(mnemonic)                                                      \
205  void Test_##mnemonic() {                                                  \
206    TestHelper(&MacroAssembler::mnemonic, #mnemonic, kReference##mnemonic); \
207  }                                                                         \
208  Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic "_${test_isa}",    \
209                       &Test_##mnemonic);
210FOREACH_INSTRUCTION(TEST)
211#undef TEST
212
213}  // namespace
214#endif
215
216}  // namespace aarch32
217}  // namespace vixl
218