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 <iostream>
     35 #include <map>
     36 
     37 #include "test-runner.h"
     38 
     39 #include "test-utils.h"
     40 #include "test-utils-aarch32.h"
     41 
     42 #include "aarch32/assembler-aarch32.h"
     43 #include "aarch32/disasm-aarch32.h"
     44 #include "aarch32/macro-assembler-aarch32.h"
     45 
     46 #define BUF_SIZE (4096)
     47 
     48 namespace vixl {
     49 namespace aarch32 {
     50 
     51 // List of instruction mnemonics.
     52 #define FOREACH_INSTRUCTION(M) \
     53   ${instruction_list_declaration}
     54 
     55 // The following definitions are defined again in each generated test, therefore
     56 // we need to place them in an anomymous namespace. It expresses that they are
     57 // local to this file only, and the compiler is not allowed to share these types
     58 // across test files during template instantiation. Specifically, `Operands` has
     59 // various layouts across generated tests so it absolutely cannot be shared.
     60 
     61 #ifdef ${isa_guard}
     62 namespace {
     63 
     64 // Values to be passed to the assembler to produce the instruction under test.
     65 struct Operands {
     66   ${operand_list_declaration}
     67 };
     68 
     69 // This structure contains all data needed to test one specific
     70 // instruction.
     71 struct TestData {
     72   // The `operands` field represents what to pass to the assembler to
     73   // produce the instruction.
     74   Operands operands;
     75   // Description of the operands, used for error reporting.
     76   const char* operands_description;
     77   // Unique identifier, used for generating traces.
     78   const char* identifier;
     79 };
     80 
     81 // Each element of this array produce one instruction encoding.
     82 const TestData kTests[] = {${test_case_definitions}};
     83 
     84 typedef void (MacroAssembler::*Fn)(${macroassembler_method_args});
     85 
     86 // Use a customised disassembler to label test cases.
     87 typedef std::map<uint32_t, int> TestCaseSymbolMap;
     88 
     89 class TestDisassembler : public PrintDisassembler {
     90  public:
     91   TestDisassembler(std::ostream& os,  // NOLINT(runtime/references)
     92                    const TestCaseSymbolMap& symbols,
     93                    const char* mnemonic)
     94       : PrintDisassembler(os), symbols_(symbols), mnemonic_(mnemonic) {}
     95 
     96   virtual void PrintCodeAddress(uint32_t pc) VIXL_OVERRIDE {
     97     // Label test cases.
     98     TestCaseSymbolMap::const_iterator symbol = symbols_.find(pc);
     99     if (symbol != symbols_.end()) {
    100       int n = symbol->second;
    101       os().os() << "// " << mnemonic_ << "(" <<
    102           kTests[n].operands_description << ")" << std::endl;
    103     }
    104     // Print the code address as normal.
    105     PrintDisassembler::PrintCodeAddress(pc);
    106   }
    107 
    108  private:
    109   const TestCaseSymbolMap& symbols_;
    110   const char* mnemonic_;
    111 };
    112 
    113 void TestHelper(Fn instruction, const char* mnemonic) {
    114   MacroAssembler masm(BUF_SIZE);
    115 
    116   ${macroassembler_set_isa}
    117 
    118   TestCaseSymbolMap symbols;
    119 
    120   for (unsigned i = 0; i < ARRAY_SIZE(kTests); i++) {
    121     if (Test::disassemble()) {
    122       // TODO: This will fail if the MacroAssembler generates no code. We can
    123       // fix this with multimap but then we must take care to print the labels
    124       // in the correct order. (Insertion order is only preserved for C++11.)
    125       symbols.insert(std::pair<uint32_t, int>(masm.GetCursorOffset(), i));
    126     }
    127 
    128     // Values to pass to the macro-assembler.
    129     UseScratchRegisterScope scratch_registers(&masm);
    130     ${code_instantiate_operands}
    131 
    132     (masm.*instruction)(${code_parameter_list});
    133 
    134     // For now, these test don't currently produce (or check) any trace; we just
    135     // check that the MacroAssembler didn't crash.
    136     // TODO: We could generate disassembly as a trace here, to check for sane
    137     // output, though the trace would need to be manually checked.
    138   }
    139 
    140   masm.FinalizeCode();
    141 
    142   if (Test::disassemble()) {
    143     // Disassemble to stdout if given --disassemble on the command line.
    144     TestDisassembler dis(std::cout, symbols, mnemonic);
    145     if (masm.IsUsingT32()) {
    146       dis.DisassembleT32Buffer(masm.GetBuffer()->GetStartAddress<uint16_t*>(),
    147                                masm.GetCursorOffset());
    148     } else {
    149       dis.DisassembleA32Buffer(masm.GetBuffer()->GetStartAddress<uint32_t*>(),
    150                                masm.GetCursorOffset());
    151     }
    152   }
    153 }
    154 
    155 // Instantiate tests for each instruction in the list.
    156 #define TEST(mnemonic)                                    \
    157   void Test_##mnemonic() {                                \
    158     TestHelper(&MacroAssembler::mnemonic, #mnemonic);     \
    159   }                                                       \
    160   Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic, \
    161                               &Test_##mnemonic);
    162 FOREACH_INSTRUCTION(TEST)
    163 #undef TEST
    164 
    165 }  // namespace
    166 #endif
    167 
    168 }  // namespace aarch32
    169 }  // namespace vixl
    170