Home | History | Annotate | Download | only in config
      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 
     44 namespace vixl {
     45 namespace 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}
     58 namespace {
     59 
     60 // Values to be passed to the assembler to produce the instruction under test.
     61 struct Operands {
     62   ${operand_list_declaration}
     63 };
     64 
     65 // This structure contains all data needed to test one specific
     66 // instruction.
     67 struct 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 
     82 struct TestResult {
     83   size_t size;
     84   const byte* encoding;
     85 };
     86 
     87 // Each element of this array produce one instruction encoding.
     88 const 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.
     95 const unsigned kErrorReportLimit = 8;
     96 
     97 typedef void (MacroAssembler::*Fn)(${macroassembler_method_args});
     98 
     99 void 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,                   \
    209                               &Test_##mnemonic);
    210 FOREACH_INSTRUCTION(TEST)
    211 #undef TEST
    212 
    213 }  // namespace
    214 #endif
    215 
    216 }  // namespace aarch32
    217 }  // namespace vixl
    218