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 111namespace vixl { 112namespace 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} 126namespace { 127 128// Values to be passed to the assembler to produce the instruction under test. 129struct Operands { 130 ${operand_list_declaration} 131}; 132 133// Input data to feed to the instruction. 134struct 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. 140struct 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. 156const 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. 160struct 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. 170const unsigned kErrorReportLimit = 8; 171 172typedef void (MacroAssembler::*Fn)(${macroassembler_method_args}); 173 174void 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 328FOREACH_INSTRUCTION(TEST) 329#undef TEST 330 331} // namespace 332#endif 333 334} // namespace aarch32 335} // namespace vixl 336