1// Copyright 2019, 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// Test infrastructure. 27// 28// Tests are functions which accept no parameters and have no return values. 29// The testing code should not perform an explicit return once completed. For 30// example to test the mov immediate instruction a very simple test would be: 31// 32// TEST(mov_x0_one) { 33// SETUP(); 34// 35// START(); 36// __ mov(x0, 1); 37// END(); 38// 39// if (CAN_RUN()) { 40// RUN(); 41// 42// ASSERT_EQUAL_64(1, x0); 43// } 44// } 45// 46// Within a START ... END block all registers but sp can be modified. sp has to 47// be explicitly saved/restored. The END() macro replaces the function return 48// so it may appear multiple times in a test if the test has multiple exit 49// points. 50// 51// Tests requiring specific CPU features should specify exactly what they 52// require using SETUP_WITH_FEATURES(...) instead of SETUP(). 53// 54// Once the test has been run all integer and floating point registers as well 55// as flags are accessible through a RegisterDump instance, see 56// utils-aarch64.cc for more info on RegisterDump. 57// 58// We provide some helper assert to handle common cases: 59// 60// ASSERT_EQUAL_32(int32_t, int_32t) 61// ASSERT_EQUAL_FP32(float, float) 62// ASSERT_EQUAL_32(int32_t, W register) 63// ASSERT_EQUAL_FP32(float, S register) 64// ASSERT_EQUAL_64(int64_t, int_64t) 65// ASSERT_EQUAL_FP64(double, double) 66// ASSERT_EQUAL_64(int64_t, X register) 67// ASSERT_EQUAL_64(X register, X register) 68// ASSERT_EQUAL_FP64(double, D register) 69// 70// e.g. ASSERT_EQUAL_64(0.5, d30); 71// 72// If more advanced computation is required before the assert then access the 73// RegisterDump named core directly: 74// 75// ASSERT_EQUAL_64(0x1234, core->reg_x0() & 0xffff); 76 77namespace vixl { 78namespace aarch64 { 79 80#define __ masm. 81#define TEST(name) TEST_(AARCH64_ASM_##name) 82 83#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64 84// Run tests with the simulator. 85 86#define SETUP() \ 87 MacroAssembler masm; \ 88 SETUP_COMMON(); \ 89 SETUP_COMMON_SIM() 90 91#define SETUP_WITH_FEATURES(...) \ 92 MacroAssembler masm; \ 93 SETUP_COMMON(); \ 94 SETUP_COMMON_SIM(); \ 95 masm.SetCPUFeatures(CPUFeatures(__VA_ARGS__)); \ 96 simulator.SetCPUFeatures(CPUFeatures(__VA_ARGS__)) 97 98#define SETUP_CUSTOM(size, pic) \ 99 MacroAssembler masm(size + CodeBuffer::kDefaultCapacity, pic); \ 100 SETUP_COMMON(); \ 101 SETUP_COMMON_SIM() 102 103#define SETUP_CUSTOM_SIM(...) \ 104 MacroAssembler masm; \ 105 SETUP_COMMON(); \ 106 Simulator simulator(&simulator_decoder, stdout, __VA_ARGS__); \ 107 simulator.SetColouredTrace(Test::coloured_trace()); \ 108 simulator.SetCPUFeatures(CPUFeatures::None()) 109 110#define SETUP_COMMON() \ 111 bool queried_can_run = false; \ 112 bool printed_sve_lane_warning = false; \ 113 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 114 USE(queried_can_run); \ 115 USE(printed_sve_lane_warning); \ 116 masm.SetCPUFeatures(CPUFeatures::None()); \ 117 masm.SetGenerateSimulatorCode(true); \ 118 Decoder simulator_decoder; \ 119 RegisterDump core; \ 120 ptrdiff_t offset_after_infrastructure_start; \ 121 ptrdiff_t offset_before_infrastructure_end 122 123#define SETUP_COMMON_SIM() \ 124 Simulator simulator(&simulator_decoder); \ 125 simulator.SetColouredTrace(Test::coloured_trace()); \ 126 simulator.SetCPUFeatures(CPUFeatures::None()) 127 128#define START() \ 129 masm.Reset(); \ 130 simulator.ResetState(); \ 131 { \ 132 SimulationCPUFeaturesScope cpu(&masm, kInfrastructureCPUFeatures); \ 133 __ PushCalleeSavedRegisters(); \ 134 } \ 135 /* The infrastructure code hasn't been covered at the moment, e.g. */ \ 136 /* prologue/epilogue. Suppress tagging mis-match exception before */ \ 137 /* this point. */ \ 138 if (masm.GetCPUFeatures()->Has(CPUFeatures::kMTE)) { \ 139 __ Hlt(DebugHltOpcode::kMTEActive); \ 140 } \ 141 { \ 142 int trace_parameters = 0; \ 143 if (Test::trace_reg()) trace_parameters |= LOG_STATE; \ 144 if (Test::trace_write()) trace_parameters |= LOG_WRITE; \ 145 if (Test::trace_sim()) trace_parameters |= LOG_DISASM; \ 146 if (Test::trace_branch()) trace_parameters |= LOG_BRANCH; \ 147 if (trace_parameters != 0) { \ 148 __ Trace(static_cast<TraceParameters>(trace_parameters), TRACE_ENABLE); \ 149 } \ 150 } \ 151 offset_after_infrastructure_start = masm.GetCursorOffset(); \ 152 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 153 USE(offset_after_infrastructure_start) 154 155#define END() \ 156 offset_before_infrastructure_end = masm.GetCursorOffset(); \ 157 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 158 USE(offset_before_infrastructure_end); \ 159 __ Trace(LOG_ALL, TRACE_DISABLE); \ 160 if (masm.GetCPUFeatures()->Has(CPUFeatures::kMTE)) { \ 161 __ Hlt(DebugHltOpcode::kMTEInactive); \ 162 } \ 163 { \ 164 SimulationCPUFeaturesScope cpu(&masm, kInfrastructureCPUFeatures); \ 165 core.Dump(&masm); \ 166 __ PopCalleeSavedRegisters(); \ 167 } \ 168 __ Ret(); \ 169 masm.FinalizeCode() 170 171#define RUN() \ 172 RUN_WITHOUT_SEEN_FEATURE_CHECK(); \ 173 { \ 174 /* We expect the test to use all of the features it requested, plus the */ \ 175 /* features that the instruction code requires. */ \ 176 CPUFeatures const& expected_features = \ 177 simulator.GetCPUFeatures()->With(CPUFeatures::kNEON); \ 178 CPUFeatures const& seen = simulator.GetSeenFeatures(); \ 179 /* This gives three broad categories of features that we care about: */ \ 180 /* 1. Things both expected and seen. */ \ 181 /* 2. Things seen, but not expected. The simulator catches these. */ \ 182 /* 3. Things expected, but not seen. We check these here. */ \ 183 /* In a valid, passing test, categories 2 and 3 should be empty. */ \ 184 if (seen != expected_features) { \ 185 /* The Simulator should have caught anything in category 2 already. */ \ 186 VIXL_ASSERT(expected_features.Has(seen)); \ 187 /* Anything left is category 3: things expected, but not seen. This */ \ 188 /* is not necessarily a bug in VIXL itself, but indicates that the */ \ 189 /* test is less strict than it could be. */ \ 190 CPUFeatures missing = expected_features.Without(seen); \ 191 VIXL_ASSERT(missing.Count() > 0); \ 192 std::cout << "Error: expected to see CPUFeatures { " << missing \ 193 << " }\n"; \ 194 VIXL_ABORT(); \ 195 } \ 196 } 197 198#define RUN_WITHOUT_SEEN_FEATURE_CHECK() \ 199 DISASSEMBLE(); \ 200 VIXL_ASSERT(QUERIED_CAN_RUN()); \ 201 VIXL_ASSERT(CAN_RUN()); \ 202 simulator.RunFrom(masm.GetBuffer()->GetStartAddress<Instruction*>()) 203 204#else // ifdef VIXL_INCLUDE_SIMULATOR_AARCH64. 205#define SETUP() \ 206 MacroAssembler masm; \ 207 SETUP_COMMON() 208 209#define SETUP_WITH_FEATURES(...) \ 210 MacroAssembler masm; \ 211 SETUP_COMMON(); \ 212 masm.SetCPUFeatures(CPUFeatures(__VA_ARGS__)) 213 214#define SETUP_CUSTOM(size, pic) \ 215 size_t buffer_size = size + CodeBuffer::kDefaultCapacity; \ 216 MacroAssembler masm(buffer_size, pic); \ 217 SETUP_COMMON() 218 219#define SETUP_COMMON() \ 220 bool queried_can_run = false; \ 221 bool printed_sve_lane_warning = false; \ 222 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 223 USE(queried_can_run); \ 224 USE(printed_sve_lane_warning); \ 225 masm.SetCPUFeatures(CPUFeatures::None()); \ 226 masm.SetGenerateSimulatorCode(false); \ 227 RegisterDump core; \ 228 CPU::SetUp(); \ 229 ptrdiff_t offset_after_infrastructure_start; \ 230 ptrdiff_t offset_before_infrastructure_end 231 232#define START() \ 233 masm.Reset(); \ 234 { \ 235 CPUFeaturesScope cpu(&masm, kInfrastructureCPUFeatures); \ 236 __ PushCalleeSavedRegisters(); \ 237 } \ 238 offset_after_infrastructure_start = masm.GetCursorOffset(); \ 239 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 240 USE(offset_after_infrastructure_start) 241 242#define END() \ 243 offset_before_infrastructure_end = masm.GetCursorOffset(); \ 244 /* Avoid unused-variable warnings in case a test never calls RUN(). */ \ 245 USE(offset_before_infrastructure_end); \ 246 { \ 247 CPUFeaturesScope cpu(&masm, kInfrastructureCPUFeatures); \ 248 core.Dump(&masm); \ 249 __ PopCalleeSavedRegisters(); \ 250 } \ 251 __ Ret(); \ 252 masm.FinalizeCode() 253 254// Execute the generated code from the memory area. 255#define RUN() \ 256 DISASSEMBLE(); \ 257 VIXL_ASSERT(QUERIED_CAN_RUN()); \ 258 VIXL_ASSERT(CAN_RUN()); \ 259 masm.GetBuffer()->SetExecutable(); \ 260 ExecuteMemory(masm.GetBuffer()->GetStartAddress<byte*>(), \ 261 masm.GetSizeOfCodeGenerated()); \ 262 masm.GetBuffer()->SetWritable() 263 264// This just provides compatibility with VIXL_INCLUDE_SIMULATOR_AARCH64 builds. 265// We cannot run seen-feature checks when running natively. 266#define RUN_WITHOUT_SEEN_FEATURE_CHECK() RUN() 267 268#endif // ifdef VIXL_INCLUDE_SIMULATOR_AARCH64. 269 270#define CAN_RUN() CanRun(*masm.GetCPUFeatures(), &queried_can_run) 271#define QUERIED_CAN_RUN() (queried_can_run) 272 273#define DISASSEMBLE() \ 274 if (Test::disassemble()) { \ 275 PrintDisassembler disasm(stdout); \ 276 CodeBuffer* buffer = masm.GetBuffer(); \ 277 Instruction* test_start = buffer->GetOffsetAddress<Instruction*>( \ 278 offset_after_infrastructure_start); \ 279 Instruction* test_end = buffer->GetOffsetAddress<Instruction*>( \ 280 offset_before_infrastructure_end); \ 281 \ 282 if (Test::disassemble_infrastructure()) { \ 283 Instruction* infra_start = buffer->GetStartAddress<Instruction*>(); \ 284 printf("# Infrastructure code (prologue)\n"); \ 285 disasm.DisassembleBuffer(infra_start, test_start); \ 286 printf("# Test code\n"); \ 287 } else { \ 288 printf( \ 289 "# Warning: Omitting infrastructure code. " \ 290 "Use --disassemble to see it.\n"); \ 291 } \ 292 \ 293 disasm.DisassembleBuffer(test_start, test_end); \ 294 \ 295 if (Test::disassemble_infrastructure()) { \ 296 printf("# Infrastructure code (epilogue)\n"); \ 297 Instruction* infra_end = buffer->GetEndAddress<Instruction*>(); \ 298 disasm.DisassembleBuffer(test_end, infra_end); \ 299 } \ 300 } 301 302#define ASSERT_EQUAL_NZCV(expected) \ 303 VIXL_CHECK(EqualNzcv(expected, core.flags_nzcv())) 304 305#define ASSERT_EQUAL_REGISTERS(expected) \ 306 VIXL_CHECK(EqualRegisters(&expected, &core)) 307 308#define ASSERT_EQUAL_FP16(expected, result) \ 309 VIXL_CHECK(EqualFP16(expected, &core, result)) 310 311#define ASSERT_EQUAL_32(expected, result) \ 312 VIXL_CHECK(Equal32(static_cast<uint32_t>(expected), &core, result)) 313 314#define ASSERT_EQUAL_FP32(expected, result) \ 315 VIXL_CHECK(EqualFP32(expected, &core, result)) 316 317#define ASSERT_EQUAL_64(expected, result) \ 318 VIXL_CHECK(Equal64(expected, &core, result)) 319 320#define ASSERT_NOT_EQUAL_64(expected, result) \ 321 VIXL_CHECK(NotEqual64(expected, &core, result)) 322 323#define ASSERT_EQUAL_FP64(expected, result) \ 324 VIXL_CHECK(EqualFP64(expected, &core, result)) 325 326#define ASSERT_EQUAL_128(expected_h, expected_l, result) \ 327 VIXL_CHECK(Equal128(expected_h, expected_l, &core, result)) 328 329#define ASSERT_LITERAL_POOL_SIZE(expected) \ 330 VIXL_CHECK((expected + kInstructionSize) == (masm.GetLiteralPoolSize())) 331 332#define ASSERT_EQUAL_SVE_LANE(expected, result, lane) \ 333 VIXL_CHECK(EqualSVELane(expected, &core, result, lane)); 334 335// If `expected` is scalar, check that every lane of `result` matches it. 336// If `expected` is an array of N expected values, check that the first N 337// lanes on `result` match. The rightmost (highest-indexed) array element maps 338// to the lowest-numbered lane. 339#define ASSERT_EQUAL_SVE(expected, result) \ 340 VIXL_CHECK(EqualSVE(expected, &core, result, &printed_sve_lane_warning)) 341 342#define ASSERT_EQUAL_MEMORY(expected, result, ...) \ 343 VIXL_CHECK(EqualMemory(reinterpret_cast<void*>(expected), \ 344 reinterpret_cast<void*>(result), \ 345 __VA_ARGS__)) 346 347#define MUST_FAIL_WITH_MESSAGE(code, message) \ 348 { \ 349 bool aborted = false; \ 350 try { \ 351 code; \ 352 } catch (const std::runtime_error& e) { \ 353 const char* expected_error = message; \ 354 size_t error_length = strlen(expected_error); \ 355 if (strncmp(expected_error, e.what(), error_length) == 0) { \ 356 aborted = true; \ 357 } else { \ 358 printf("Mismatch in error message.\n"); \ 359 printf("Expected: %s\n", expected_error); \ 360 printf("Found: %s\n", e.what()); \ 361 } \ 362 } \ 363 VIXL_CHECK(aborted); \ 364 } 365 366} // namespace aarch64 367} // namespace vixl 368