1 // Copyright 2013, ARM Limited 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 #include "test-utils-a64.h" 28 29 #include <math.h> // Needed for isnan(). 30 31 #include "cctest.h" 32 #include "a64/macro-assembler-a64.h" 33 #include "a64/simulator-a64.h" 34 #include "a64/disasm-a64.h" 35 #include "a64/cpu-a64.h" 36 37 #define __ masm-> 38 39 namespace vixl { 40 41 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result) { 42 if (result != expected) { 43 printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 44 expected, result); 45 } 46 47 return expected == result; 48 } 49 50 51 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result) { 52 if (result != expected) { 53 printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 54 expected, result); 55 } 56 57 return expected == result; 58 } 59 60 61 bool EqualFP32(float expected, const RegisterDump*, float result) { 62 if (float_to_rawbits(expected) == float_to_rawbits(result)) { 63 return true; 64 } else { 65 if (isnan(expected) || (expected == 0.0)) { 66 printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 67 float_to_rawbits(expected), float_to_rawbits(result)); 68 } else { 69 printf("Expected %.9f (0x%08" PRIx32 ")\t " 70 "Found %.9f (0x%08" PRIx32 ")\n", 71 expected, float_to_rawbits(expected), 72 result, float_to_rawbits(result)); 73 } 74 return false; 75 } 76 } 77 78 79 bool EqualFP64(double expected, const RegisterDump*, double result) { 80 if (double_to_rawbits(expected) == double_to_rawbits(result)) { 81 return true; 82 } 83 84 if (isnan(expected) || (expected == 0.0)) { 85 printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 86 double_to_rawbits(expected), double_to_rawbits(result)); 87 } else { 88 printf("Expected %.17f (0x%016" PRIx64 ")\t " 89 "Found %.17f (0x%016" PRIx64 ")\n", 90 expected, double_to_rawbits(expected), 91 result, double_to_rawbits(result)); 92 } 93 return false; 94 } 95 96 97 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) { 98 VIXL_ASSERT(reg.Is32Bits()); 99 // Retrieve the corresponding X register so we can check that the upper part 100 // was properly cleared. 101 int64_t result_x = core->xreg(reg.code()); 102 if ((result_x & 0xffffffff00000000) != 0) { 103 printf("Expected 0x%08" PRIx32 "\t Found 0x%016" PRIx64 "\n", 104 expected, result_x); 105 return false; 106 } 107 uint32_t result_w = core->wreg(reg.code()); 108 return Equal32(expected, core, result_w); 109 } 110 111 112 bool Equal64(uint64_t expected, 113 const RegisterDump* core, 114 const Register& reg) { 115 VIXL_ASSERT(reg.Is64Bits()); 116 uint64_t result = core->xreg(reg.code()); 117 return Equal64(expected, core, result); 118 } 119 120 121 bool EqualFP32(float expected, 122 const RegisterDump* core, 123 const FPRegister& fpreg) { 124 VIXL_ASSERT(fpreg.Is32Bits()); 125 // Retrieve the corresponding D register so we can check that the upper part 126 // was properly cleared. 127 uint64_t result_64 = core->dreg_bits(fpreg.code()); 128 if ((result_64 & 0xffffffff00000000) != 0) { 129 printf("Expected 0x%08" PRIx32 " (%f)\t Found 0x%016" PRIx64 "\n", 130 float_to_rawbits(expected), expected, result_64); 131 return false; 132 } 133 134 return EqualFP32(expected, core, core->sreg(fpreg.code())); 135 } 136 137 138 bool EqualFP64(double expected, 139 const RegisterDump* core, 140 const FPRegister& fpreg) { 141 VIXL_ASSERT(fpreg.Is64Bits()); 142 return EqualFP64(expected, core, core->dreg(fpreg.code())); 143 } 144 145 146 bool Equal64(const Register& reg0, 147 const RegisterDump* core, 148 const Register& reg1) { 149 VIXL_ASSERT(reg0.Is64Bits() && reg1.Is64Bits()); 150 int64_t expected = core->xreg(reg0.code()); 151 int64_t result = core->xreg(reg1.code()); 152 return Equal64(expected, core, result); 153 } 154 155 156 static char FlagN(uint32_t flags) { 157 return (flags & NFlag) ? 'N' : 'n'; 158 } 159 160 161 static char FlagZ(uint32_t flags) { 162 return (flags & ZFlag) ? 'Z' : 'z'; 163 } 164 165 166 static char FlagC(uint32_t flags) { 167 return (flags & CFlag) ? 'C' : 'c'; 168 } 169 170 171 static char FlagV(uint32_t flags) { 172 return (flags & VFlag) ? 'V' : 'v'; 173 } 174 175 176 bool EqualNzcv(uint32_t expected, uint32_t result) { 177 VIXL_ASSERT((expected & ~NZCVFlag) == 0); 178 VIXL_ASSERT((result & ~NZCVFlag) == 0); 179 if (result != expected) { 180 printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n", 181 FlagN(expected), FlagZ(expected), FlagC(expected), FlagV(expected), 182 FlagN(result), FlagZ(result), FlagC(result), FlagV(result)); 183 return false; 184 } 185 186 return true; 187 } 188 189 190 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b) { 191 for (unsigned i = 0; i < kNumberOfRegisters; i++) { 192 if (a->xreg(i) != b->xreg(i)) { 193 printf("x%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 194 i, a->xreg(i), b->xreg(i)); 195 return false; 196 } 197 } 198 199 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { 200 uint64_t a_bits = a->dreg_bits(i); 201 uint64_t b_bits = b->dreg_bits(i); 202 if (a_bits != b_bits) { 203 printf("d%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 204 i, a_bits, b_bits); 205 return false; 206 } 207 } 208 209 return true; 210 } 211 212 213 RegList PopulateRegisterArray(Register* w, Register* x, Register* r, 214 int reg_size, int reg_count, RegList allowed) { 215 RegList list = 0; 216 int i = 0; 217 for (unsigned n = 0; (n < kNumberOfRegisters) && (i < reg_count); n++) { 218 if (((UINT64_C(1) << n) & allowed) != 0) { 219 // Only assign allowed registers. 220 if (r) { 221 r[i] = Register(n, reg_size); 222 } 223 if (x) { 224 x[i] = Register(n, kXRegSize); 225 } 226 if (w) { 227 w[i] = Register(n, kWRegSize); 228 } 229 list |= (UINT64_C(1) << n); 230 i++; 231 } 232 } 233 // Check that we got enough registers. 234 VIXL_ASSERT(CountSetBits(list, kNumberOfRegisters) == reg_count); 235 236 return list; 237 } 238 239 240 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v, 241 int reg_size, int reg_count, RegList allowed) { 242 RegList list = 0; 243 int i = 0; 244 for (unsigned n = 0; (n < kNumberOfFPRegisters) && (i < reg_count); n++) { 245 if (((UINT64_C(1) << n) & allowed) != 0) { 246 // Only assigned allowed registers. 247 if (v) { 248 v[i] = FPRegister(n, reg_size); 249 } 250 if (d) { 251 d[i] = FPRegister(n, kDRegSize); 252 } 253 if (s) { 254 s[i] = FPRegister(n, kSRegSize); 255 } 256 list |= (UINT64_C(1) << n); 257 i++; 258 } 259 } 260 // Check that we got enough registers. 261 VIXL_ASSERT(CountSetBits(list, kNumberOfFPRegisters) == reg_count); 262 263 return list; 264 } 265 266 267 void Clobber(MacroAssembler* masm, RegList reg_list, uint64_t const value) { 268 Register first = NoReg; 269 for (unsigned i = 0; i < kNumberOfRegisters; i++) { 270 if (reg_list & (UINT64_C(1) << i)) { 271 Register xn(i, kXRegSize); 272 // We should never write into sp here. 273 VIXL_ASSERT(!xn.Is(sp)); 274 if (!xn.IsZero()) { 275 if (!first.IsValid()) { 276 // This is the first register we've hit, so construct the literal. 277 __ Mov(xn, value); 278 first = xn; 279 } else { 280 // We've already loaded the literal, so re-use the value already 281 // loaded into the first register we hit. 282 __ Mov(xn, first); 283 } 284 } 285 } 286 } 287 } 288 289 290 void ClobberFP(MacroAssembler* masm, RegList reg_list, double const value) { 291 FPRegister first = NoFPReg; 292 for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { 293 if (reg_list & (UINT64_C(1) << i)) { 294 FPRegister dn(i, kDRegSize); 295 if (!first.IsValid()) { 296 // This is the first register we've hit, so construct the literal. 297 __ Fmov(dn, value); 298 first = dn; 299 } else { 300 // We've already loaded the literal, so re-use the value already loaded 301 // into the first register we hit. 302 __ Fmov(dn, first); 303 } 304 } 305 } 306 } 307 308 309 void Clobber(MacroAssembler* masm, CPURegList reg_list) { 310 if (reg_list.type() == CPURegister::kRegister) { 311 // This will always clobber X registers. 312 Clobber(masm, reg_list.list()); 313 } else if (reg_list.type() == CPURegister::kFPRegister) { 314 // This will always clobber D registers. 315 ClobberFP(masm, reg_list.list()); 316 } else { 317 VIXL_UNREACHABLE(); 318 } 319 } 320 321 322 void RegisterDump::Dump(MacroAssembler* masm) { 323 VIXL_ASSERT(__ StackPointer().Is(sp)); 324 325 // Ensure that we don't unintentionally clobber any registers. 326 UseScratchRegisterScope temps(masm); 327 temps.ExcludeAll(); 328 329 // Preserve some temporary registers. 330 Register dump_base = x0; 331 Register dump = x1; 332 Register tmp = x2; 333 Register dump_base_w = dump_base.W(); 334 Register dump_w = dump.W(); 335 Register tmp_w = tmp.W(); 336 337 // Offsets into the dump_ structure. 338 const int x_offset = offsetof(dump_t, x_); 339 const int w_offset = offsetof(dump_t, w_); 340 const int d_offset = offsetof(dump_t, d_); 341 const int s_offset = offsetof(dump_t, s_); 342 const int sp_offset = offsetof(dump_t, sp_); 343 const int wsp_offset = offsetof(dump_t, wsp_); 344 const int flags_offset = offsetof(dump_t, flags_); 345 346 __ Push(xzr, dump_base, dump, tmp); 347 348 // Load the address where we will dump the state. 349 __ Mov(dump_base, reinterpret_cast<uintptr_t>(&dump_)); 350 351 // Dump the stack pointer (sp and wsp). 352 // The stack pointer cannot be stored directly; it needs to be moved into 353 // another register first. Also, we pushed four X registers, so we need to 354 // compensate here. 355 __ Add(tmp, sp, 4 * kXRegSizeInBytes); 356 __ Str(tmp, MemOperand(dump_base, sp_offset)); 357 __ Add(tmp_w, wsp, 4 * kXRegSizeInBytes); 358 __ Str(tmp_w, MemOperand(dump_base, wsp_offset)); 359 360 // Dump X registers. 361 __ Add(dump, dump_base, x_offset); 362 for (unsigned i = 0; i < kNumberOfRegisters; i += 2) { 363 __ Stp(Register::XRegFromCode(i), Register::XRegFromCode(i + 1), 364 MemOperand(dump, i * kXRegSizeInBytes)); 365 } 366 367 // Dump W registers. 368 __ Add(dump, dump_base, w_offset); 369 for (unsigned i = 0; i < kNumberOfRegisters; i += 2) { 370 __ Stp(Register::WRegFromCode(i), Register::WRegFromCode(i + 1), 371 MemOperand(dump, i * kWRegSizeInBytes)); 372 } 373 374 // Dump D registers. 375 __ Add(dump, dump_base, d_offset); 376 for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) { 377 __ Stp(FPRegister::DRegFromCode(i), FPRegister::DRegFromCode(i + 1), 378 MemOperand(dump, i * kDRegSizeInBytes)); 379 } 380 381 // Dump S registers. 382 __ Add(dump, dump_base, s_offset); 383 for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) { 384 __ Stp(FPRegister::SRegFromCode(i), FPRegister::SRegFromCode(i + 1), 385 MemOperand(dump, i * kSRegSizeInBytes)); 386 } 387 388 // Dump the flags. 389 __ Mrs(tmp, NZCV); 390 __ Str(tmp, MemOperand(dump_base, flags_offset)); 391 392 // To dump the values that were in tmp amd dump, we need a new scratch 393 // register. We can use any of the already dumped registers since we can 394 // easily restore them. 395 Register dump2_base = x10; 396 Register dump2 = x11; 397 VIXL_ASSERT(!AreAliased(dump_base, dump, tmp, dump2_base, dump2)); 398 399 // Don't lose the dump_ address. 400 __ Mov(dump2_base, dump_base); 401 402 __ Pop(tmp, dump, dump_base, xzr); 403 404 __ Add(dump2, dump2_base, w_offset); 405 __ Str(dump_base_w, MemOperand(dump2, dump_base.code() * kWRegSizeInBytes)); 406 __ Str(dump_w, MemOperand(dump2, dump.code() * kWRegSizeInBytes)); 407 __ Str(tmp_w, MemOperand(dump2, tmp.code() * kWRegSizeInBytes)); 408 409 __ Add(dump2, dump2_base, x_offset); 410 __ Str(dump_base, MemOperand(dump2, dump_base.code() * kXRegSizeInBytes)); 411 __ Str(dump, MemOperand(dump2, dump.code() * kXRegSizeInBytes)); 412 __ Str(tmp, MemOperand(dump2, tmp.code() * kXRegSizeInBytes)); 413 414 // Finally, restore dump2_base and dump2. 415 __ Ldr(dump2_base, MemOperand(dump2, dump2_base.code() * kXRegSizeInBytes)); 416 __ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes)); 417 418 completed_ = true; 419 } 420 421 } // namespace vixl 422