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 #define TEARDOWN() 61 62 #else // ifdef VIXL_INCLUDE_SIMULATOR_AARCH32. 63 64 #define SETUP() \ 65 MacroAssembler masm(BUF_SIZE); \ 66 UseScratchRegisterScope harness_scratch(&masm); \ 67 harness_scratch.ExcludeAll(); 68 69 #define START() \ 70 masm.GetBuffer()->Reset(); \ 71 __ Push(r4); \ 72 __ Push(r5); \ 73 __ Push(r6); \ 74 __ Push(r7); \ 75 __ Push(r8); \ 76 __ Push(r9); \ 77 __ Push(r10); \ 78 __ Push(r11); \ 79 __ Push(lr); \ 80 harness_scratch.Include(ip); 81 82 #define END() \ 83 harness_scratch.Exclude(ip); \ 84 __ Pop(lr); \ 85 __ Pop(r11); \ 86 __ Pop(r10); \ 87 __ Pop(r9); \ 88 __ Pop(r8); \ 89 __ Pop(r7); \ 90 __ Pop(r6); \ 91 __ Pop(r5); \ 92 __ Pop(r4); \ 93 __ Bx(lr); \ 94 __ FinalizeCode(); 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 #define TEARDOWN() \ 107 harness_scratch.Close(); 108 109 #endif // ifdef VIXL_INCLUDE_SIMULATOR_AARCH32 110 111 namespace vixl { 112 namespace aarch32 { 113 114 // List of instruction encodings: 115 #define FOREACH_INSTRUCTION(M) \ 116 ${instruction_list_declaration} 117 118 // The following definitions are defined again in each generated test, therefore 119 // we need to place them in an anomymous namespace. It expresses that they are 120 // local to this file only, and the compiler is not allowed to share these types 121 // across test files during template instantiation. Specifically, `Operands` and 122 // `Inputs` have various layouts across generated tests so they absolutely 123 // cannot be shared. 124 125 #ifdef ${isa_guard} 126 namespace { 127 128 // Values to be passed to the assembler to produce the instruction under test. 129 struct Operands { 130 ${operand_list_declaration} 131 }; 132 133 // Input data to feed to the instruction. 134 struct Inputs { 135 ${input_declarations} 136 }; 137 138 // This structure contains all input data needed to test one specific encoding. 139 // It used to generate a loop over an instruction. 140 struct TestLoopData { 141 // The `operands` fields represents the values to pass to the assembler to 142 // produce the instruction. 143 Operands operands; 144 // Description of the operands, used for error reporting. 145 const char* operands_description; 146 // Unique identifier, used for generating traces. 147 const char* identifier; 148 // Array of values to be fed to the instruction. 149 size_t input_size; 150 const Inputs* inputs; 151 }; 152 153 ${input_definitions} 154 155 // A loop will be generated for each element of this array. 156 const TestLoopData kTests[] = {${test_case_definitions}}; 157 158 // We record all inputs to the instructions as outputs. This way, we also check 159 // that what shouldn't change didn't change. 160 struct TestResult { 161 size_t output_size; 162 const Inputs* outputs; 163 }; 164 165 // These headers each contain an array of `TestResult` with the reference output 166 // values. The reference arrays are names `kReference{mnemonic}`. 167 ${include_trace_files} 168 169 // The maximum number of errors to report in detail for each test. 170 const unsigned kErrorReportLimit = 8; 171 172 typedef void (MacroAssembler::*Fn)(${macroassembler_method_args}); 173 174 void TestHelper(Fn instruction, const char* mnemonic, 175 const TestResult reference[]) { 176 SETUP(); 177 ${macroassembler_set_isa} 178 START(); 179 180 // Data to compare to `reference`. 181 TestResult* results[ARRAY_SIZE(kTests)]; 182 183 // Test cases for memory bound instructions may allocate a buffer and save its 184 // address in this array. 185 byte* scratch_memory_buffers[ARRAY_SIZE(kTests)]; 186 187 // Generate a loop for each element in `kTests`. Each loop tests one specific 188 // instruction. 189 for (unsigned i = 0; i < ARRAY_SIZE(kTests); i++) { 190 // Allocate results on the heap for this test. 191 results[i] = new TestResult; 192 results[i]->outputs = new Inputs[kTests[i].input_size]; 193 results[i]->output_size = kTests[i].input_size; 194 195 size_t input_stride = sizeof(kTests[i].inputs[0]) * kTests[i].input_size; 196 VIXL_ASSERT(IsUint32(input_stride)); 197 198 scratch_memory_buffers[i] = NULL; 199 200 Label loop; 201 UseScratchRegisterScope scratch_registers(&masm); 202 // Include all registers from r0 ro r12. 203 scratch_registers.Include(RegisterList(0x1fff)); 204 205 // Values to pass to the macro-assembler. 206 ${code_instantiate_operands} 207 208 // Allocate reserved registers for our own use. 209 Register input_ptr = scratch_registers.Acquire(); 210 Register input_end = scratch_registers.Acquire(); 211 Register result_ptr = scratch_registers.Acquire(); 212 213 // Initialize `input_ptr` to the first element and `input_end` the address 214 // after the array. 215 __ Mov(input_ptr, Operand::From(kTests[i].inputs)); 216 __ Add(input_end, input_ptr, static_cast<uint32_t>(input_stride)); 217 __ Mov(result_ptr, Operand::From(results[i]->outputs)); 218 __ Bind(&loop); 219 220 ${code_prologue} 221 222 (masm.*instruction)(${code_parameter_list}); 223 224 ${code_epilogue} 225 226 // Advance the result pointer. 227 __ Add(result_ptr, result_ptr, Operand::From(sizeof(kTests[i].inputs[0]))); 228 // Loop back until `input_ptr` is lower than `input_base`. 229 __ Add(input_ptr, input_ptr, Operand::From(sizeof(kTests[i].inputs[0]))); 230 __ Cmp(input_ptr, input_end); 231 __ B(ne, &loop); 232 } 233 234 END(); 235 236 RUN(); 237 238 if (Test::generate_test_trace()) { 239 // Print the results. 240 for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) { 241 printf("const Inputs kOutputs_%s_%s[] = {\n", mnemonic, 242 kTests[i].identifier); 243 for (size_t j = 0; j < results[i]->output_size; j++) { 244 printf(" { "); 245 ${trace_print_outputs} 246 printf(" },\n"); 247 } 248 printf("};\n"); 249 } 250 printf("const TestResult kReference%s[] = {\n", mnemonic); 251 for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) { 252 printf(" {\n"); 253 printf(" ARRAY_SIZE(kOutputs_%s_%s),\n", mnemonic, 254 kTests[i].identifier); 255 printf(" kOutputs_%s_%s,\n", mnemonic, kTests[i].identifier); 256 printf(" },\n"); 257 } 258 printf("};\n"); 259 } else if (kCheckSimulatorTestResults) { 260 // Check the results. 261 unsigned total_error_count = 0; 262 for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) { 263 bool instruction_has_errors = false; 264 for (size_t j = 0; j < kTests[i].input_size; j++) { 265 ${check_instantiate_results} 266 ${check_instantiate_inputs} 267 ${check_instantiate_references} 268 269 if ((${check_results_against_references}) && 270 (++total_error_count <= kErrorReportLimit)) { 271 // Print the instruction once even if it triggered multiple failures. 272 if (!instruction_has_errors) { 273 printf("Error(s) when testing \"%s %s\":\n", mnemonic, 274 kTests[i].operands_description); 275 instruction_has_errors = true; 276 } 277 // Print subsequent errors. 278 printf(" Input: "); 279 ${check_print_input} 280 printf("\n"); 281 printf(" Expected: "); 282 ${check_print_expected} 283 printf("\n"); 284 printf(" Found: "); 285 ${check_print_found} 286 printf("\n\n"); 287 } 288 } 289 } 290 291 if (total_error_count > kErrorReportLimit) { 292 printf("%u other errors follow.\n", 293 total_error_count - kErrorReportLimit); 294 } 295 VIXL_CHECK(total_error_count == 0); 296 } else { 297 VIXL_WARNING("Assembled the code, but did not run anything.\n"); 298 } 299 300 for (size_t i = 0; i < ARRAY_SIZE(kTests); i++) { 301 delete[] results[i]->outputs; 302 delete results[i]; 303 delete[] scratch_memory_buffers[i]; 304 } 305 306 TEARDOWN(); 307 } 308 309 // Instantiate tests for each instruction in the list. 310 // TODO: Remove this limitation by having a sandboxing mechanism. 311 #if defined(VIXL_HOST_POINTER_32) 312 #define TEST(mnemonic) \ 313 void Test_##mnemonic() { \ 314 TestHelper(&MacroAssembler::mnemonic, #mnemonic, kReference##mnemonic); \ 315 } \ 316 Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic, \ 317 &Test_##mnemonic); 318 #else 319 #define TEST(mnemonic) \ 320 void Test_##mnemonic() { \ 321 VIXL_WARNING("This test can only run on a 32-bit host.\n"); \ 322 USE(TestHelper); \ 323 } \ 324 Test test_##mnemonic("AARCH32_${test_name}_" #mnemonic, \ 325 &Test_##mnemonic); 326 #endif 327 328 FOREACH_INSTRUCTION(TEST) 329 #undef TEST 330 331 } // namespace 332 #endif 333 334 } // namespace aarch32 335 } // namespace vixl 336