1b8021494Sopenharmony_ci// Copyright 2014, VIXL authors 2b8021494Sopenharmony_ci// All rights reserved. 3b8021494Sopenharmony_ci// 4b8021494Sopenharmony_ci// Redistribution and use in source and binary forms, with or without 5b8021494Sopenharmony_ci// modification, are permitted provided that the following conditions are met: 6b8021494Sopenharmony_ci// 7b8021494Sopenharmony_ci// * Redistributions of source code must retain the above copyright notice, 8b8021494Sopenharmony_ci// this list of conditions and the following disclaimer. 9b8021494Sopenharmony_ci// * Redistributions in binary form must reproduce the above copyright notice, 10b8021494Sopenharmony_ci// this list of conditions and the following disclaimer in the documentation 11b8021494Sopenharmony_ci// and/or other materials provided with the distribution. 12b8021494Sopenharmony_ci// * Neither the name of ARM Limited nor the names of its contributors may be 13b8021494Sopenharmony_ci// used to endorse or promote products derived from this software without 14b8021494Sopenharmony_ci// specific prior written permission. 15b8021494Sopenharmony_ci// 16b8021494Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17b8021494Sopenharmony_ci// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18b8021494Sopenharmony_ci// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19b8021494Sopenharmony_ci// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20b8021494Sopenharmony_ci// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21b8021494Sopenharmony_ci// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22b8021494Sopenharmony_ci// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23b8021494Sopenharmony_ci// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24b8021494Sopenharmony_ci// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25b8021494Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26b8021494Sopenharmony_ci 27b8021494Sopenharmony_ci#include "test-utils-aarch64.h" 28b8021494Sopenharmony_ci 29b8021494Sopenharmony_ci#include <cmath> 30b8021494Sopenharmony_ci#include <queue> 31b8021494Sopenharmony_ci 32b8021494Sopenharmony_ci#include "test-runner.h" 33b8021494Sopenharmony_ci 34b8021494Sopenharmony_ci#include "../test/aarch64/test-simulator-inputs-aarch64.h" 35b8021494Sopenharmony_ci#include "aarch64/cpu-aarch64.h" 36b8021494Sopenharmony_ci#include "aarch64/disasm-aarch64.h" 37b8021494Sopenharmony_ci#include "aarch64/macro-assembler-aarch64.h" 38b8021494Sopenharmony_ci#include "aarch64/simulator-aarch64.h" 39b8021494Sopenharmony_ci 40b8021494Sopenharmony_ci#define __ masm-> 41b8021494Sopenharmony_ci 42b8021494Sopenharmony_cinamespace vixl { 43b8021494Sopenharmony_cinamespace aarch64 { 44b8021494Sopenharmony_ci 45b8021494Sopenharmony_ci 46b8021494Sopenharmony_ci// This value is a signalling NaN as FP64, and also as FP32 or FP16 (taking the 47b8021494Sopenharmony_ci// least-significant bits). 48b8021494Sopenharmony_ciconst double kFP64SignallingNaN = RawbitsToDouble(UINT64_C(0x7ff000007f807c01)); 49b8021494Sopenharmony_ciconst float kFP32SignallingNaN = RawbitsToFloat(0x7f807c01); 50b8021494Sopenharmony_ciconst Float16 kFP16SignallingNaN = RawbitsToFloat16(0x7c01); 51b8021494Sopenharmony_ci 52b8021494Sopenharmony_ci// A similar value, but as a quiet NaN. 53b8021494Sopenharmony_ciconst double kFP64QuietNaN = RawbitsToDouble(UINT64_C(0x7ff800007fc07e01)); 54b8021494Sopenharmony_ciconst float kFP32QuietNaN = RawbitsToFloat(0x7fc07e01); 55b8021494Sopenharmony_ciconst Float16 kFP16QuietNaN = RawbitsToFloat16(0x7e01); 56b8021494Sopenharmony_ci 57b8021494Sopenharmony_ci 58b8021494Sopenharmony_cibool Equal32(uint32_t expected, const RegisterDump*, uint32_t result) { 59b8021494Sopenharmony_ci if (result != expected) { 60b8021494Sopenharmony_ci printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 61b8021494Sopenharmony_ci expected, 62b8021494Sopenharmony_ci result); 63b8021494Sopenharmony_ci } 64b8021494Sopenharmony_ci 65b8021494Sopenharmony_ci return expected == result; 66b8021494Sopenharmony_ci} 67b8021494Sopenharmony_ci 68b8021494Sopenharmony_ci 69b8021494Sopenharmony_cibool Equal64(uint64_t reference, 70b8021494Sopenharmony_ci const RegisterDump*, 71b8021494Sopenharmony_ci uint64_t result, 72b8021494Sopenharmony_ci ExpectedResult option) { 73b8021494Sopenharmony_ci switch (option) { 74b8021494Sopenharmony_ci case kExpectEqual: 75b8021494Sopenharmony_ci if (result != reference) { 76b8021494Sopenharmony_ci printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 77b8021494Sopenharmony_ci reference, 78b8021494Sopenharmony_ci result); 79b8021494Sopenharmony_ci } 80b8021494Sopenharmony_ci break; 81b8021494Sopenharmony_ci case kExpectNotEqual: 82b8021494Sopenharmony_ci if (result == reference) { 83b8021494Sopenharmony_ci printf("Expected a result not equal to 0x%016" PRIx64 "\n", reference); 84b8021494Sopenharmony_ci } 85b8021494Sopenharmony_ci break; 86b8021494Sopenharmony_ci } 87b8021494Sopenharmony_ci 88b8021494Sopenharmony_ci return reference == result; 89b8021494Sopenharmony_ci} 90b8021494Sopenharmony_ci 91b8021494Sopenharmony_ci 92b8021494Sopenharmony_cibool Equal128(QRegisterValue expected, 93b8021494Sopenharmony_ci const RegisterDump*, 94b8021494Sopenharmony_ci QRegisterValue result) { 95b8021494Sopenharmony_ci if (!expected.Equals(result)) { 96b8021494Sopenharmony_ci printf("Expected 0x%016" PRIx64 "%016" PRIx64 97b8021494Sopenharmony_ci "\t " 98b8021494Sopenharmony_ci "Found 0x%016" PRIx64 "%016" PRIx64 "\n", 99b8021494Sopenharmony_ci expected.GetLane<uint64_t>(1), 100b8021494Sopenharmony_ci expected.GetLane<uint64_t>(0), 101b8021494Sopenharmony_ci result.GetLane<uint64_t>(1), 102b8021494Sopenharmony_ci result.GetLane<uint64_t>(0)); 103b8021494Sopenharmony_ci } 104b8021494Sopenharmony_ci 105b8021494Sopenharmony_ci return expected.Equals(result); 106b8021494Sopenharmony_ci} 107b8021494Sopenharmony_ci 108b8021494Sopenharmony_ci 109b8021494Sopenharmony_cibool EqualFP16(Float16 expected, const RegisterDump*, Float16 result) { 110b8021494Sopenharmony_ci uint16_t e_rawbits = Float16ToRawbits(expected); 111b8021494Sopenharmony_ci uint16_t r_rawbits = Float16ToRawbits(result); 112b8021494Sopenharmony_ci if (e_rawbits == r_rawbits) { 113b8021494Sopenharmony_ci return true; 114b8021494Sopenharmony_ci } else { 115b8021494Sopenharmony_ci if (IsNaN(expected) || IsZero(expected)) { 116b8021494Sopenharmony_ci printf("Expected 0x%04" PRIx16 "\t Found 0x%04" PRIx16 "\n", 117b8021494Sopenharmony_ci e_rawbits, 118b8021494Sopenharmony_ci r_rawbits); 119b8021494Sopenharmony_ci } else { 120b8021494Sopenharmony_ci printf("Expected %.6f (16 bit): (0x%04" PRIx16 121b8021494Sopenharmony_ci ")\t " 122b8021494Sopenharmony_ci "Found %.6f (0x%04" PRIx16 ")\n", 123b8021494Sopenharmony_ci FPToFloat(expected, kIgnoreDefaultNaN), 124b8021494Sopenharmony_ci e_rawbits, 125b8021494Sopenharmony_ci FPToFloat(result, kIgnoreDefaultNaN), 126b8021494Sopenharmony_ci r_rawbits); 127b8021494Sopenharmony_ci } 128b8021494Sopenharmony_ci return false; 129b8021494Sopenharmony_ci } 130b8021494Sopenharmony_ci} 131b8021494Sopenharmony_ci 132b8021494Sopenharmony_ci 133b8021494Sopenharmony_cibool EqualFP32(float expected, const RegisterDump*, float result) { 134b8021494Sopenharmony_ci if (FloatToRawbits(expected) == FloatToRawbits(result)) { 135b8021494Sopenharmony_ci return true; 136b8021494Sopenharmony_ci } else { 137b8021494Sopenharmony_ci if (IsNaN(expected) || (expected == 0.0)) { 138b8021494Sopenharmony_ci printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n", 139b8021494Sopenharmony_ci FloatToRawbits(expected), 140b8021494Sopenharmony_ci FloatToRawbits(result)); 141b8021494Sopenharmony_ci } else { 142b8021494Sopenharmony_ci printf("Expected %.9f (0x%08" PRIx32 143b8021494Sopenharmony_ci ")\t " 144b8021494Sopenharmony_ci "Found %.9f (0x%08" PRIx32 ")\n", 145b8021494Sopenharmony_ci expected, 146b8021494Sopenharmony_ci FloatToRawbits(expected), 147b8021494Sopenharmony_ci result, 148b8021494Sopenharmony_ci FloatToRawbits(result)); 149b8021494Sopenharmony_ci } 150b8021494Sopenharmony_ci return false; 151b8021494Sopenharmony_ci } 152b8021494Sopenharmony_ci} 153b8021494Sopenharmony_ci 154b8021494Sopenharmony_ci 155b8021494Sopenharmony_cibool EqualFP64(double expected, const RegisterDump*, double result) { 156b8021494Sopenharmony_ci if (DoubleToRawbits(expected) == DoubleToRawbits(result)) { 157b8021494Sopenharmony_ci return true; 158b8021494Sopenharmony_ci } 159b8021494Sopenharmony_ci 160b8021494Sopenharmony_ci if (IsNaN(expected) || (expected == 0.0)) { 161b8021494Sopenharmony_ci printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 162b8021494Sopenharmony_ci DoubleToRawbits(expected), 163b8021494Sopenharmony_ci DoubleToRawbits(result)); 164b8021494Sopenharmony_ci } else { 165b8021494Sopenharmony_ci printf("Expected %.17f (0x%016" PRIx64 166b8021494Sopenharmony_ci ")\t " 167b8021494Sopenharmony_ci "Found %.17f (0x%016" PRIx64 ")\n", 168b8021494Sopenharmony_ci expected, 169b8021494Sopenharmony_ci DoubleToRawbits(expected), 170b8021494Sopenharmony_ci result, 171b8021494Sopenharmony_ci DoubleToRawbits(result)); 172b8021494Sopenharmony_ci } 173b8021494Sopenharmony_ci return false; 174b8021494Sopenharmony_ci} 175b8021494Sopenharmony_ci 176b8021494Sopenharmony_ci 177b8021494Sopenharmony_cibool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) { 178b8021494Sopenharmony_ci VIXL_ASSERT(reg.Is32Bits()); 179b8021494Sopenharmony_ci // Retrieve the corresponding X register so we can check that the upper part 180b8021494Sopenharmony_ci // was properly cleared. 181b8021494Sopenharmony_ci int64_t result_x = core->xreg(reg.GetCode()); 182b8021494Sopenharmony_ci if ((result_x & 0xffffffff00000000) != 0) { 183b8021494Sopenharmony_ci printf("Expected 0x%08" PRIx32 "\t Found 0x%016" PRIx64 "\n", 184b8021494Sopenharmony_ci expected, 185b8021494Sopenharmony_ci result_x); 186b8021494Sopenharmony_ci return false; 187b8021494Sopenharmony_ci } 188b8021494Sopenharmony_ci uint32_t result_w = core->wreg(reg.GetCode()); 189b8021494Sopenharmony_ci return Equal32(expected, core, result_w); 190b8021494Sopenharmony_ci} 191b8021494Sopenharmony_ci 192b8021494Sopenharmony_ci 193b8021494Sopenharmony_cibool Equal64(uint64_t reference, 194b8021494Sopenharmony_ci const RegisterDump* core, 195b8021494Sopenharmony_ci const Register& reg, 196b8021494Sopenharmony_ci ExpectedResult option) { 197b8021494Sopenharmony_ci VIXL_ASSERT(reg.Is64Bits()); 198b8021494Sopenharmony_ci uint64_t result = core->xreg(reg.GetCode()); 199b8021494Sopenharmony_ci return Equal64(reference, core, result, option); 200b8021494Sopenharmony_ci} 201b8021494Sopenharmony_ci 202b8021494Sopenharmony_ci 203b8021494Sopenharmony_cibool NotEqual64(uint64_t reference, 204b8021494Sopenharmony_ci const RegisterDump* core, 205b8021494Sopenharmony_ci const Register& reg) { 206b8021494Sopenharmony_ci VIXL_ASSERT(reg.Is64Bits()); 207b8021494Sopenharmony_ci uint64_t result = core->xreg(reg.GetCode()); 208b8021494Sopenharmony_ci return NotEqual64(reference, core, result); 209b8021494Sopenharmony_ci} 210b8021494Sopenharmony_ci 211b8021494Sopenharmony_ci 212b8021494Sopenharmony_cibool Equal128(uint64_t expected_h, 213b8021494Sopenharmony_ci uint64_t expected_l, 214b8021494Sopenharmony_ci const RegisterDump* core, 215b8021494Sopenharmony_ci const VRegister& vreg) { 216b8021494Sopenharmony_ci VIXL_ASSERT(vreg.Is128Bits()); 217b8021494Sopenharmony_ci QRegisterValue expected; 218b8021494Sopenharmony_ci expected.SetLane(0, expected_l); 219b8021494Sopenharmony_ci expected.SetLane(1, expected_h); 220b8021494Sopenharmony_ci QRegisterValue result = core->qreg(vreg.GetCode()); 221b8021494Sopenharmony_ci return Equal128(expected, core, result); 222b8021494Sopenharmony_ci} 223b8021494Sopenharmony_ci 224b8021494Sopenharmony_ci 225b8021494Sopenharmony_cibool EqualFP16(Float16 expected, 226b8021494Sopenharmony_ci const RegisterDump* core, 227b8021494Sopenharmony_ci const VRegister& fpreg) { 228b8021494Sopenharmony_ci VIXL_ASSERT(fpreg.Is16Bits()); 229b8021494Sopenharmony_ci // Retrieve the corresponding D register so we can check that the upper part 230b8021494Sopenharmony_ci // was properly cleared. 231b8021494Sopenharmony_ci uint64_t result_64 = core->dreg_bits(fpreg.GetCode()); 232b8021494Sopenharmony_ci if ((result_64 & 0xfffffffffff0000) != 0) { 233b8021494Sopenharmony_ci printf("Expected 0x%04" PRIx16 " (%f)\t Found 0x%016" PRIx64 "\n", 234b8021494Sopenharmony_ci Float16ToRawbits(expected), 235b8021494Sopenharmony_ci FPToFloat(expected, kIgnoreDefaultNaN), 236b8021494Sopenharmony_ci result_64); 237b8021494Sopenharmony_ci return false; 238b8021494Sopenharmony_ci } 239b8021494Sopenharmony_ci return EqualFP16(expected, core, core->hreg(fpreg.GetCode())); 240b8021494Sopenharmony_ci} 241b8021494Sopenharmony_ci 242b8021494Sopenharmony_ci 243b8021494Sopenharmony_cibool EqualFP32(float expected, 244b8021494Sopenharmony_ci const RegisterDump* core, 245b8021494Sopenharmony_ci const VRegister& fpreg) { 246b8021494Sopenharmony_ci VIXL_ASSERT(fpreg.Is32Bits()); 247b8021494Sopenharmony_ci // Retrieve the corresponding D register so we can check that the upper part 248b8021494Sopenharmony_ci // was properly cleared. 249b8021494Sopenharmony_ci uint64_t result_64 = core->dreg_bits(fpreg.GetCode()); 250b8021494Sopenharmony_ci if ((result_64 & 0xffffffff00000000) != 0) { 251b8021494Sopenharmony_ci printf("Expected 0x%08" PRIx32 " (%f)\t Found 0x%016" PRIx64 "\n", 252b8021494Sopenharmony_ci FloatToRawbits(expected), 253b8021494Sopenharmony_ci expected, 254b8021494Sopenharmony_ci result_64); 255b8021494Sopenharmony_ci return false; 256b8021494Sopenharmony_ci } 257b8021494Sopenharmony_ci 258b8021494Sopenharmony_ci return EqualFP32(expected, core, core->sreg(fpreg.GetCode())); 259b8021494Sopenharmony_ci} 260b8021494Sopenharmony_ci 261b8021494Sopenharmony_ci 262b8021494Sopenharmony_cibool EqualFP64(double expected, 263b8021494Sopenharmony_ci const RegisterDump* core, 264b8021494Sopenharmony_ci const VRegister& fpreg) { 265b8021494Sopenharmony_ci VIXL_ASSERT(fpreg.Is64Bits()); 266b8021494Sopenharmony_ci return EqualFP64(expected, core, core->dreg(fpreg.GetCode())); 267b8021494Sopenharmony_ci} 268b8021494Sopenharmony_ci 269b8021494Sopenharmony_ci 270b8021494Sopenharmony_cibool Equal64(const Register& reg0, 271b8021494Sopenharmony_ci const RegisterDump* core, 272b8021494Sopenharmony_ci const Register& reg1, 273b8021494Sopenharmony_ci ExpectedResult option) { 274b8021494Sopenharmony_ci VIXL_ASSERT(reg0.Is64Bits() && reg1.Is64Bits()); 275b8021494Sopenharmony_ci int64_t reference = core->xreg(reg0.GetCode()); 276b8021494Sopenharmony_ci int64_t result = core->xreg(reg1.GetCode()); 277b8021494Sopenharmony_ci return Equal64(reference, core, result, option); 278b8021494Sopenharmony_ci} 279b8021494Sopenharmony_ci 280b8021494Sopenharmony_ci 281b8021494Sopenharmony_cibool NotEqual64(const Register& reg0, 282b8021494Sopenharmony_ci const RegisterDump* core, 283b8021494Sopenharmony_ci const Register& reg1) { 284b8021494Sopenharmony_ci VIXL_ASSERT(reg0.Is64Bits() && reg1.Is64Bits()); 285b8021494Sopenharmony_ci int64_t expected = core->xreg(reg0.GetCode()); 286b8021494Sopenharmony_ci int64_t result = core->xreg(reg1.GetCode()); 287b8021494Sopenharmony_ci return NotEqual64(expected, core, result); 288b8021494Sopenharmony_ci} 289b8021494Sopenharmony_ci 290b8021494Sopenharmony_ci 291b8021494Sopenharmony_cibool Equal64(uint64_t expected, 292b8021494Sopenharmony_ci const RegisterDump* core, 293b8021494Sopenharmony_ci const VRegister& vreg) { 294b8021494Sopenharmony_ci VIXL_ASSERT(vreg.Is64Bits()); 295b8021494Sopenharmony_ci uint64_t result = core->dreg_bits(vreg.GetCode()); 296b8021494Sopenharmony_ci return Equal64(expected, core, result); 297b8021494Sopenharmony_ci} 298b8021494Sopenharmony_ci 299b8021494Sopenharmony_ci 300b8021494Sopenharmony_cistatic char FlagN(uint32_t flags) { return (flags & NFlag) ? 'N' : 'n'; } 301b8021494Sopenharmony_ci 302b8021494Sopenharmony_ci 303b8021494Sopenharmony_cistatic char FlagZ(uint32_t flags) { return (flags & ZFlag) ? 'Z' : 'z'; } 304b8021494Sopenharmony_ci 305b8021494Sopenharmony_ci 306b8021494Sopenharmony_cistatic char FlagC(uint32_t flags) { return (flags & CFlag) ? 'C' : 'c'; } 307b8021494Sopenharmony_ci 308b8021494Sopenharmony_ci 309b8021494Sopenharmony_cistatic char FlagV(uint32_t flags) { return (flags & VFlag) ? 'V' : 'v'; } 310b8021494Sopenharmony_ci 311b8021494Sopenharmony_ci 312b8021494Sopenharmony_cibool EqualNzcv(uint32_t expected, uint32_t result) { 313b8021494Sopenharmony_ci VIXL_ASSERT((expected & ~NZCVFlag) == 0); 314b8021494Sopenharmony_ci VIXL_ASSERT((result & ~NZCVFlag) == 0); 315b8021494Sopenharmony_ci if (result != expected) { 316b8021494Sopenharmony_ci printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n", 317b8021494Sopenharmony_ci FlagN(expected), 318b8021494Sopenharmony_ci FlagZ(expected), 319b8021494Sopenharmony_ci FlagC(expected), 320b8021494Sopenharmony_ci FlagV(expected), 321b8021494Sopenharmony_ci FlagN(result), 322b8021494Sopenharmony_ci FlagZ(result), 323b8021494Sopenharmony_ci FlagC(result), 324b8021494Sopenharmony_ci FlagV(result)); 325b8021494Sopenharmony_ci return false; 326b8021494Sopenharmony_ci } 327b8021494Sopenharmony_ci 328b8021494Sopenharmony_ci return true; 329b8021494Sopenharmony_ci} 330b8021494Sopenharmony_ci 331b8021494Sopenharmony_ci 332b8021494Sopenharmony_cibool EqualRegisters(const RegisterDump* a, const RegisterDump* b) { 333b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfRegisters; i++) { 334b8021494Sopenharmony_ci if (a->xreg(i) != b->xreg(i)) { 335b8021494Sopenharmony_ci printf("x%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 336b8021494Sopenharmony_ci i, 337b8021494Sopenharmony_ci a->xreg(i), 338b8021494Sopenharmony_ci b->xreg(i)); 339b8021494Sopenharmony_ci return false; 340b8021494Sopenharmony_ci } 341b8021494Sopenharmony_ci } 342b8021494Sopenharmony_ci 343b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfVRegisters; i++) { 344b8021494Sopenharmony_ci uint64_t a_bits = a->dreg_bits(i); 345b8021494Sopenharmony_ci uint64_t b_bits = b->dreg_bits(i); 346b8021494Sopenharmony_ci if (a_bits != b_bits) { 347b8021494Sopenharmony_ci printf("d%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n", 348b8021494Sopenharmony_ci i, 349b8021494Sopenharmony_ci a_bits, 350b8021494Sopenharmony_ci b_bits); 351b8021494Sopenharmony_ci return false; 352b8021494Sopenharmony_ci } 353b8021494Sopenharmony_ci } 354b8021494Sopenharmony_ci 355b8021494Sopenharmony_ci return true; 356b8021494Sopenharmony_ci} 357b8021494Sopenharmony_ci 358b8021494Sopenharmony_cibool EqualSVELane(uint64_t expected, 359b8021494Sopenharmony_ci const RegisterDump* core, 360b8021494Sopenharmony_ci const ZRegister& reg, 361b8021494Sopenharmony_ci int lane) { 362b8021494Sopenharmony_ci unsigned lane_size = reg.GetLaneSizeInBits(); 363b8021494Sopenharmony_ci // For convenience in the tests, we allow negative values to be passed into 364b8021494Sopenharmony_ci // `expected`, but truncate them to an appropriately-sized unsigned value for 365b8021494Sopenharmony_ci // the check. For example, in `EqualSVELane(-1, core, z0.VnB())`, the expected 366b8021494Sopenharmony_ci // value is truncated from 0xffffffffffffffff to 0xff before the comparison. 367b8021494Sopenharmony_ci VIXL_ASSERT(IsUintN(lane_size, expected) || 368b8021494Sopenharmony_ci IsIntN(lane_size, RawbitsToInt64(expected))); 369b8021494Sopenharmony_ci expected &= GetUintMask(lane_size); 370b8021494Sopenharmony_ci 371b8021494Sopenharmony_ci uint64_t result = core->zreg_lane(reg.GetCode(), lane_size, lane); 372b8021494Sopenharmony_ci if (expected != result) { 373b8021494Sopenharmony_ci unsigned lane_size_in_hex_chars = lane_size / 4; 374b8021494Sopenharmony_ci std::string reg_name = reg.GetArchitecturalName(); 375b8021494Sopenharmony_ci printf("%s[%d]\t Expected 0x%0*" PRIx64 "\t Found 0x%0*" PRIx64 "\n", 376b8021494Sopenharmony_ci reg_name.c_str(), 377b8021494Sopenharmony_ci lane, 378b8021494Sopenharmony_ci lane_size_in_hex_chars, 379b8021494Sopenharmony_ci expected, 380b8021494Sopenharmony_ci lane_size_in_hex_chars, 381b8021494Sopenharmony_ci result); 382b8021494Sopenharmony_ci return false; 383b8021494Sopenharmony_ci } 384b8021494Sopenharmony_ci return true; 385b8021494Sopenharmony_ci} 386b8021494Sopenharmony_ci 387b8021494Sopenharmony_cibool EqualSVELane(uint64_t expected, 388b8021494Sopenharmony_ci const RegisterDump* core, 389b8021494Sopenharmony_ci const PRegister& reg, 390b8021494Sopenharmony_ci int lane) { 391b8021494Sopenharmony_ci VIXL_ASSERT(reg.HasLaneSize()); 392b8021494Sopenharmony_ci VIXL_ASSERT((reg.GetLaneSizeInBits() % kZRegBitsPerPRegBit) == 0); 393b8021494Sopenharmony_ci unsigned p_bits_per_lane = reg.GetLaneSizeInBits() / kZRegBitsPerPRegBit; 394b8021494Sopenharmony_ci VIXL_ASSERT(IsUintN(p_bits_per_lane, expected)); 395b8021494Sopenharmony_ci expected &= GetUintMask(p_bits_per_lane); 396b8021494Sopenharmony_ci 397b8021494Sopenharmony_ci uint64_t result = core->preg_lane(reg.GetCode(), p_bits_per_lane, lane); 398b8021494Sopenharmony_ci if (expected != result) { 399b8021494Sopenharmony_ci unsigned lane_size_in_hex_chars = (p_bits_per_lane + 3) / 4; 400b8021494Sopenharmony_ci std::string reg_name = reg.GetArchitecturalName(); 401b8021494Sopenharmony_ci printf("%s[%d]\t Expected 0x%0*" PRIx64 "\t Found 0x%0*" PRIx64 "\n", 402b8021494Sopenharmony_ci reg_name.c_str(), 403b8021494Sopenharmony_ci lane, 404b8021494Sopenharmony_ci lane_size_in_hex_chars, 405b8021494Sopenharmony_ci expected, 406b8021494Sopenharmony_ci lane_size_in_hex_chars, 407b8021494Sopenharmony_ci result); 408b8021494Sopenharmony_ci return false; 409b8021494Sopenharmony_ci } 410b8021494Sopenharmony_ci return true; 411b8021494Sopenharmony_ci} 412b8021494Sopenharmony_ci 413b8021494Sopenharmony_cistruct EqualMemoryChunk { 414b8021494Sopenharmony_ci typedef uint64_t RawChunk; 415b8021494Sopenharmony_ci 416b8021494Sopenharmony_ci uintptr_t address; 417b8021494Sopenharmony_ci RawChunk expected; 418b8021494Sopenharmony_ci RawChunk result; 419b8021494Sopenharmony_ci 420b8021494Sopenharmony_ci bool IsEqual() const { return expected == result; } 421b8021494Sopenharmony_ci}; 422b8021494Sopenharmony_ci 423b8021494Sopenharmony_cibool EqualMemory(const void* expected, 424b8021494Sopenharmony_ci const void* result, 425b8021494Sopenharmony_ci size_t size_in_bytes, 426b8021494Sopenharmony_ci size_t zero_offset) { 427b8021494Sopenharmony_ci if (memcmp(expected, result, size_in_bytes) == 0) return true; 428b8021494Sopenharmony_ci 429b8021494Sopenharmony_ci // Read 64-bit chunks, and print them side-by-side if they don't match. 430b8021494Sopenharmony_ci 431b8021494Sopenharmony_ci // Remember the last few chunks, even if they matched, so we can print some 432b8021494Sopenharmony_ci // context. We don't want to print the whole buffer, because it could be huge. 433b8021494Sopenharmony_ci static const size_t kContextLines = 1; 434b8021494Sopenharmony_ci std::queue<EqualMemoryChunk> context; 435b8021494Sopenharmony_ci static const size_t kChunkSize = sizeof(EqualMemoryChunk::RawChunk); 436b8021494Sopenharmony_ci 437b8021494Sopenharmony_ci // This assumption keeps the logic simple, and is acceptable for our tests. 438b8021494Sopenharmony_ci VIXL_ASSERT((size_in_bytes % kChunkSize) == 0); 439b8021494Sopenharmony_ci 440b8021494Sopenharmony_ci const char* expected_it = reinterpret_cast<const char*>(expected); 441b8021494Sopenharmony_ci const char* result_it = reinterpret_cast<const char*>(result); 442b8021494Sopenharmony_ci 443b8021494Sopenharmony_ci // This is the first error, so print a header row. 444b8021494Sopenharmony_ci printf(" Address (of result) Expected Result\n"); 445b8021494Sopenharmony_ci 446b8021494Sopenharmony_ci // Always print some context at the start of the buffer. 447b8021494Sopenharmony_ci uintptr_t print_context_to = 448b8021494Sopenharmony_ci reinterpret_cast<uintptr_t>(result) + (kContextLines + 1) * kChunkSize; 449b8021494Sopenharmony_ci for (size_t i = 0; i < size_in_bytes; i += kChunkSize) { 450b8021494Sopenharmony_ci EqualMemoryChunk chunk; 451b8021494Sopenharmony_ci chunk.address = reinterpret_cast<uintptr_t>(result_it); 452b8021494Sopenharmony_ci memcpy(&chunk.expected, expected_it, kChunkSize); 453b8021494Sopenharmony_ci memcpy(&chunk.result, result_it, kChunkSize); 454b8021494Sopenharmony_ci 455b8021494Sopenharmony_ci while (context.size() > kContextLines) context.pop(); 456b8021494Sopenharmony_ci context.push(chunk); 457b8021494Sopenharmony_ci 458b8021494Sopenharmony_ci // Print context after an error, and at the end of the buffer. 459b8021494Sopenharmony_ci if (!chunk.IsEqual() || ((i + kChunkSize) >= size_in_bytes)) { 460b8021494Sopenharmony_ci if (chunk.address > print_context_to) { 461b8021494Sopenharmony_ci // We aren't currently printing context, so separate this context from 462b8021494Sopenharmony_ci // the previous block. 463b8021494Sopenharmony_ci printf("...\n"); 464b8021494Sopenharmony_ci } 465b8021494Sopenharmony_ci print_context_to = chunk.address + (kContextLines + 1) * kChunkSize; 466b8021494Sopenharmony_ci } 467b8021494Sopenharmony_ci 468b8021494Sopenharmony_ci // Print context (including the current line). 469b8021494Sopenharmony_ci while (!context.empty() && (context.front().address < print_context_to)) { 470b8021494Sopenharmony_ci uintptr_t address = context.front().address; 471b8021494Sopenharmony_ci uint64_t offset = address - reinterpret_cast<uintptr_t>(result); 472b8021494Sopenharmony_ci bool is_negative = (offset < zero_offset); 473b8021494Sopenharmony_ci printf("0x%016" PRIxPTR " (result %c %5" PRIu64 "): 0x%016" PRIx64 474b8021494Sopenharmony_ci " 0x%016" PRIx64 "\n", 475b8021494Sopenharmony_ci address, 476b8021494Sopenharmony_ci (is_negative ? '-' : '+'), 477b8021494Sopenharmony_ci (is_negative ? (zero_offset - offset) : (offset - zero_offset)), 478b8021494Sopenharmony_ci context.front().expected, 479b8021494Sopenharmony_ci context.front().result); 480b8021494Sopenharmony_ci context.pop(); 481b8021494Sopenharmony_ci } 482b8021494Sopenharmony_ci 483b8021494Sopenharmony_ci expected_it += kChunkSize; 484b8021494Sopenharmony_ci result_it += kChunkSize; 485b8021494Sopenharmony_ci } 486b8021494Sopenharmony_ci 487b8021494Sopenharmony_ci return false; 488b8021494Sopenharmony_ci} 489b8021494Sopenharmony_ciRegList PopulateRegisterArray(Register* w, 490b8021494Sopenharmony_ci Register* x, 491b8021494Sopenharmony_ci Register* r, 492b8021494Sopenharmony_ci int reg_size, 493b8021494Sopenharmony_ci int reg_count, 494b8021494Sopenharmony_ci RegList allowed) { 495b8021494Sopenharmony_ci RegList list = 0; 496b8021494Sopenharmony_ci int i = 0; 497b8021494Sopenharmony_ci for (unsigned n = 0; (n < kNumberOfRegisters) && (i < reg_count); n++) { 498b8021494Sopenharmony_ci if (((UINT64_C(1) << n) & allowed) != 0) { 499b8021494Sopenharmony_ci // Only assign allowed registers. 500b8021494Sopenharmony_ci if (r) { 501b8021494Sopenharmony_ci r[i] = Register(n, reg_size); 502b8021494Sopenharmony_ci } 503b8021494Sopenharmony_ci if (x) { 504b8021494Sopenharmony_ci x[i] = Register(n, kXRegSize); 505b8021494Sopenharmony_ci } 506b8021494Sopenharmony_ci if (w) { 507b8021494Sopenharmony_ci w[i] = Register(n, kWRegSize); 508b8021494Sopenharmony_ci } 509b8021494Sopenharmony_ci list |= (UINT64_C(1) << n); 510b8021494Sopenharmony_ci i++; 511b8021494Sopenharmony_ci } 512b8021494Sopenharmony_ci } 513b8021494Sopenharmony_ci // Check that we got enough registers. 514b8021494Sopenharmony_ci VIXL_ASSERT(CountSetBits(list, kNumberOfRegisters) == reg_count); 515b8021494Sopenharmony_ci 516b8021494Sopenharmony_ci return list; 517b8021494Sopenharmony_ci} 518b8021494Sopenharmony_ci 519b8021494Sopenharmony_ci 520b8021494Sopenharmony_ciRegList PopulateVRegisterArray(VRegister* s, 521b8021494Sopenharmony_ci VRegister* d, 522b8021494Sopenharmony_ci VRegister* v, 523b8021494Sopenharmony_ci int reg_size, 524b8021494Sopenharmony_ci int reg_count, 525b8021494Sopenharmony_ci RegList allowed) { 526b8021494Sopenharmony_ci RegList list = 0; 527b8021494Sopenharmony_ci int i = 0; 528b8021494Sopenharmony_ci for (unsigned n = 0; (n < kNumberOfVRegisters) && (i < reg_count); n++) { 529b8021494Sopenharmony_ci if (((UINT64_C(1) << n) & allowed) != 0) { 530b8021494Sopenharmony_ci // Only assigned allowed registers. 531b8021494Sopenharmony_ci if (v) { 532b8021494Sopenharmony_ci v[i] = VRegister(n, reg_size); 533b8021494Sopenharmony_ci } 534b8021494Sopenharmony_ci if (d) { 535b8021494Sopenharmony_ci d[i] = VRegister(n, kDRegSize); 536b8021494Sopenharmony_ci } 537b8021494Sopenharmony_ci if (s) { 538b8021494Sopenharmony_ci s[i] = VRegister(n, kSRegSize); 539b8021494Sopenharmony_ci } 540b8021494Sopenharmony_ci list |= (UINT64_C(1) << n); 541b8021494Sopenharmony_ci i++; 542b8021494Sopenharmony_ci } 543b8021494Sopenharmony_ci } 544b8021494Sopenharmony_ci // Check that we got enough registers. 545b8021494Sopenharmony_ci VIXL_ASSERT(CountSetBits(list, kNumberOfVRegisters) == reg_count); 546b8021494Sopenharmony_ci 547b8021494Sopenharmony_ci return list; 548b8021494Sopenharmony_ci} 549b8021494Sopenharmony_ci 550b8021494Sopenharmony_ci 551b8021494Sopenharmony_civoid Clobber(MacroAssembler* masm, RegList reg_list, uint64_t const value) { 552b8021494Sopenharmony_ci Register first = NoReg; 553b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfRegisters; i++) { 554b8021494Sopenharmony_ci if (reg_list & (UINT64_C(1) << i)) { 555b8021494Sopenharmony_ci Register xn(i, kXRegSize); 556b8021494Sopenharmony_ci // We should never write into sp here. 557b8021494Sopenharmony_ci VIXL_ASSERT(!xn.Is(sp)); 558b8021494Sopenharmony_ci if (!xn.IsZero()) { 559b8021494Sopenharmony_ci if (!first.IsValid()) { 560b8021494Sopenharmony_ci // This is the first register we've hit, so construct the literal. 561b8021494Sopenharmony_ci __ Mov(xn, value); 562b8021494Sopenharmony_ci first = xn; 563b8021494Sopenharmony_ci } else { 564b8021494Sopenharmony_ci // We've already loaded the literal, so re-use the value already 565b8021494Sopenharmony_ci // loaded into the first register we hit. 566b8021494Sopenharmony_ci __ Mov(xn, first); 567b8021494Sopenharmony_ci } 568b8021494Sopenharmony_ci } 569b8021494Sopenharmony_ci } 570b8021494Sopenharmony_ci } 571b8021494Sopenharmony_ci} 572b8021494Sopenharmony_ci 573b8021494Sopenharmony_ci 574b8021494Sopenharmony_civoid ClobberFP(MacroAssembler* masm, RegList reg_list, double const value) { 575b8021494Sopenharmony_ci VRegister first = NoVReg; 576b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfVRegisters; i++) { 577b8021494Sopenharmony_ci if (reg_list & (UINT64_C(1) << i)) { 578b8021494Sopenharmony_ci VRegister dn(i, kDRegSize); 579b8021494Sopenharmony_ci if (!first.IsValid()) { 580b8021494Sopenharmony_ci // This is the first register we've hit, so construct the literal. 581b8021494Sopenharmony_ci __ Fmov(dn, value); 582b8021494Sopenharmony_ci first = dn; 583b8021494Sopenharmony_ci } else { 584b8021494Sopenharmony_ci // We've already loaded the literal, so re-use the value already loaded 585b8021494Sopenharmony_ci // into the first register we hit. 586b8021494Sopenharmony_ci __ Fmov(dn, first); 587b8021494Sopenharmony_ci } 588b8021494Sopenharmony_ci } 589b8021494Sopenharmony_ci } 590b8021494Sopenharmony_ci} 591b8021494Sopenharmony_ci 592b8021494Sopenharmony_ci 593b8021494Sopenharmony_civoid Clobber(MacroAssembler* masm, CPURegList reg_list) { 594b8021494Sopenharmony_ci if (reg_list.GetType() == CPURegister::kRegister) { 595b8021494Sopenharmony_ci // This will always clobber X registers. 596b8021494Sopenharmony_ci Clobber(masm, reg_list.GetList()); 597b8021494Sopenharmony_ci } else if (reg_list.GetType() == CPURegister::kVRegister) { 598b8021494Sopenharmony_ci // This will always clobber D registers. 599b8021494Sopenharmony_ci ClobberFP(masm, reg_list.GetList()); 600b8021494Sopenharmony_ci } else { 601b8021494Sopenharmony_ci VIXL_UNIMPLEMENTED(); 602b8021494Sopenharmony_ci } 603b8021494Sopenharmony_ci} 604b8021494Sopenharmony_ci 605b8021494Sopenharmony_ci// TODO: Once registers have sufficiently compatible interfaces, merge the two 606b8021494Sopenharmony_ci// DumpRegisters templates. 607b8021494Sopenharmony_citemplate <typename T> 608b8021494Sopenharmony_cistatic void DumpRegisters(MacroAssembler* masm, 609b8021494Sopenharmony_ci Register dump_base, 610b8021494Sopenharmony_ci int offset) { 611b8021494Sopenharmony_ci UseScratchRegisterScope temps(masm); 612b8021494Sopenharmony_ci Register dump = temps.AcquireX(); 613b8021494Sopenharmony_ci __ Add(dump, dump_base, offset); 614b8021494Sopenharmony_ci for (unsigned i = 0; i <= T::GetMaxCode(); i++) { 615b8021494Sopenharmony_ci T reg(i); 616b8021494Sopenharmony_ci __ Str(reg, SVEMemOperand(dump)); 617b8021494Sopenharmony_ci __ Add(dump, dump, reg.GetMaxSizeInBytes()); 618b8021494Sopenharmony_ci } 619b8021494Sopenharmony_ci} 620b8021494Sopenharmony_ci 621b8021494Sopenharmony_citemplate <typename T> 622b8021494Sopenharmony_cistatic void DumpRegisters(MacroAssembler* masm, 623b8021494Sopenharmony_ci Register dump_base, 624b8021494Sopenharmony_ci int offset, 625b8021494Sopenharmony_ci int reg_size_in_bytes) { 626b8021494Sopenharmony_ci UseScratchRegisterScope temps(masm); 627b8021494Sopenharmony_ci Register dump = temps.AcquireX(); 628b8021494Sopenharmony_ci __ Add(dump, dump_base, offset); 629b8021494Sopenharmony_ci for (unsigned i = 0; i <= T::GetMaxCode(); i++) { 630b8021494Sopenharmony_ci T reg(i, reg_size_in_bytes * kBitsPerByte); 631b8021494Sopenharmony_ci __ Str(reg, MemOperand(dump)); 632b8021494Sopenharmony_ci __ Add(dump, dump, reg_size_in_bytes); 633b8021494Sopenharmony_ci } 634b8021494Sopenharmony_ci} 635b8021494Sopenharmony_ci 636b8021494Sopenharmony_civoid RegisterDump::Dump(MacroAssembler* masm) { 637b8021494Sopenharmony_ci VIXL_ASSERT(__ StackPointer().Is(sp)); 638b8021494Sopenharmony_ci 639b8021494Sopenharmony_ci dump_cpu_features_ = *masm->GetCPUFeatures(); 640b8021494Sopenharmony_ci 641b8021494Sopenharmony_ci // We need some scratch registers, but we also need to dump them, so we have 642b8021494Sopenharmony_ci // to control exactly which registers are used, and dump them separately. 643b8021494Sopenharmony_ci CPURegList scratch_registers(x0, x1, x2, x3); 644b8021494Sopenharmony_ci 645b8021494Sopenharmony_ci UseScratchRegisterScope temps(masm); 646b8021494Sopenharmony_ci temps.ExcludeAll(); 647b8021494Sopenharmony_ci __ PushCPURegList(scratch_registers); 648b8021494Sopenharmony_ci temps.Include(scratch_registers); 649b8021494Sopenharmony_ci 650b8021494Sopenharmony_ci Register dump_base = temps.AcquireX(); 651b8021494Sopenharmony_ci Register tmp = temps.AcquireX(); 652b8021494Sopenharmony_ci 653b8021494Sopenharmony_ci // Offsets into the dump_ structure. 654b8021494Sopenharmony_ci const int x_offset = offsetof(dump_t, x_); 655b8021494Sopenharmony_ci const int w_offset = offsetof(dump_t, w_); 656b8021494Sopenharmony_ci const int d_offset = offsetof(dump_t, d_); 657b8021494Sopenharmony_ci const int s_offset = offsetof(dump_t, s_); 658b8021494Sopenharmony_ci const int h_offset = offsetof(dump_t, h_); 659b8021494Sopenharmony_ci const int q_offset = offsetof(dump_t, q_); 660b8021494Sopenharmony_ci const int z_offset = offsetof(dump_t, z_); 661b8021494Sopenharmony_ci const int p_offset = offsetof(dump_t, p_); 662b8021494Sopenharmony_ci const int sp_offset = offsetof(dump_t, sp_); 663b8021494Sopenharmony_ci const int wsp_offset = offsetof(dump_t, wsp_); 664b8021494Sopenharmony_ci const int flags_offset = offsetof(dump_t, flags_); 665b8021494Sopenharmony_ci const int vl_offset = offsetof(dump_t, vl_); 666b8021494Sopenharmony_ci 667b8021494Sopenharmony_ci // Load the address where we will dump the state. 668b8021494Sopenharmony_ci __ Mov(dump_base, reinterpret_cast<uintptr_t>(&dump_)); 669b8021494Sopenharmony_ci 670b8021494Sopenharmony_ci // Dump the stack pointer (sp and wsp). 671b8021494Sopenharmony_ci // The stack pointer cannot be stored directly; it needs to be moved into 672b8021494Sopenharmony_ci // another register first. Also, we pushed four X registers, so we need to 673b8021494Sopenharmony_ci // compensate here. 674b8021494Sopenharmony_ci __ Add(tmp, sp, 4 * kXRegSizeInBytes); 675b8021494Sopenharmony_ci __ Str(tmp, MemOperand(dump_base, sp_offset)); 676b8021494Sopenharmony_ci __ Add(tmp.W(), wsp, 4 * kXRegSizeInBytes); 677b8021494Sopenharmony_ci __ Str(tmp.W(), MemOperand(dump_base, wsp_offset)); 678b8021494Sopenharmony_ci 679b8021494Sopenharmony_ci // Dump core registers. 680b8021494Sopenharmony_ci DumpRegisters<Register>(masm, dump_base, x_offset, kXRegSizeInBytes); 681b8021494Sopenharmony_ci DumpRegisters<Register>(masm, dump_base, w_offset, kWRegSizeInBytes); 682b8021494Sopenharmony_ci 683b8021494Sopenharmony_ci // Dump NEON and FP registers. 684b8021494Sopenharmony_ci DumpRegisters<VRegister>(masm, dump_base, q_offset, kQRegSizeInBytes); 685b8021494Sopenharmony_ci DumpRegisters<VRegister>(masm, dump_base, d_offset, kDRegSizeInBytes); 686b8021494Sopenharmony_ci DumpRegisters<VRegister>(masm, dump_base, s_offset, kSRegSizeInBytes); 687b8021494Sopenharmony_ci DumpRegisters<VRegister>(masm, dump_base, h_offset, kHRegSizeInBytes); 688b8021494Sopenharmony_ci 689b8021494Sopenharmony_ci // Dump SVE registers. 690b8021494Sopenharmony_ci if (CPUHas(CPUFeatures::kSVE)) { 691b8021494Sopenharmony_ci DumpRegisters<ZRegister>(masm, dump_base, z_offset); 692b8021494Sopenharmony_ci DumpRegisters<PRegister>(masm, dump_base, p_offset); 693b8021494Sopenharmony_ci 694b8021494Sopenharmony_ci // Record the vector length. 695b8021494Sopenharmony_ci __ Rdvl(tmp, kBitsPerByte); 696b8021494Sopenharmony_ci __ Str(tmp, MemOperand(dump_base, vl_offset)); 697b8021494Sopenharmony_ci } 698b8021494Sopenharmony_ci 699b8021494Sopenharmony_ci // Dump the flags. 700b8021494Sopenharmony_ci __ Mrs(tmp, NZCV); 701b8021494Sopenharmony_ci __ Str(tmp, MemOperand(dump_base, flags_offset)); 702b8021494Sopenharmony_ci 703b8021494Sopenharmony_ci // To dump the values we used as scratch registers, we need a new scratch 704b8021494Sopenharmony_ci // register. We can use any of the already dumped registers since we can 705b8021494Sopenharmony_ci // easily restore them. 706b8021494Sopenharmony_ci Register dump2_base = x10; 707b8021494Sopenharmony_ci VIXL_ASSERT(!scratch_registers.IncludesAliasOf(dump2_base)); 708b8021494Sopenharmony_ci 709b8021494Sopenharmony_ci VIXL_ASSERT(scratch_registers.IncludesAliasOf(dump_base)); 710b8021494Sopenharmony_ci 711b8021494Sopenharmony_ci // Ensure that we don't try to use the scratch registers again. 712b8021494Sopenharmony_ci temps.ExcludeAll(); 713b8021494Sopenharmony_ci 714b8021494Sopenharmony_ci // Don't lose the dump_ address. 715b8021494Sopenharmony_ci __ Mov(dump2_base, dump_base); 716b8021494Sopenharmony_ci 717b8021494Sopenharmony_ci __ PopCPURegList(scratch_registers); 718b8021494Sopenharmony_ci 719b8021494Sopenharmony_ci while (!scratch_registers.IsEmpty()) { 720b8021494Sopenharmony_ci CPURegister reg = scratch_registers.PopLowestIndex(); 721b8021494Sopenharmony_ci Register x = reg.X(); 722b8021494Sopenharmony_ci Register w = reg.W(); 723b8021494Sopenharmony_ci unsigned code = reg.GetCode(); 724b8021494Sopenharmony_ci __ Str(x, MemOperand(dump2_base, x_offset + (code * kXRegSizeInBytes))); 725b8021494Sopenharmony_ci __ Str(w, MemOperand(dump2_base, w_offset + (code * kWRegSizeInBytes))); 726b8021494Sopenharmony_ci } 727b8021494Sopenharmony_ci 728b8021494Sopenharmony_ci // Finally, restore dump2_base. 729b8021494Sopenharmony_ci __ Ldr(dump2_base, 730b8021494Sopenharmony_ci MemOperand(dump2_base, 731b8021494Sopenharmony_ci x_offset + (dump2_base.GetCode() * kXRegSizeInBytes))); 732b8021494Sopenharmony_ci 733b8021494Sopenharmony_ci completed_ = true; 734b8021494Sopenharmony_ci} 735b8021494Sopenharmony_ci 736b8021494Sopenharmony_ciuint64_t GetSignallingNan(int size_in_bits) { 737b8021494Sopenharmony_ci switch (size_in_bits) { 738b8021494Sopenharmony_ci case kHRegSize: 739b8021494Sopenharmony_ci return Float16ToRawbits(kFP16SignallingNaN); 740b8021494Sopenharmony_ci case kSRegSize: 741b8021494Sopenharmony_ci return FloatToRawbits(kFP32SignallingNaN); 742b8021494Sopenharmony_ci case kDRegSize: 743b8021494Sopenharmony_ci return DoubleToRawbits(kFP64SignallingNaN); 744b8021494Sopenharmony_ci default: 745b8021494Sopenharmony_ci VIXL_UNIMPLEMENTED(); 746b8021494Sopenharmony_ci return 0; 747b8021494Sopenharmony_ci } 748b8021494Sopenharmony_ci} 749b8021494Sopenharmony_ci 750b8021494Sopenharmony_cibool CanRun(const CPUFeatures& required, bool* queried_can_run) { 751b8021494Sopenharmony_ci bool log_if_missing = true; 752b8021494Sopenharmony_ci if (queried_can_run != NULL) { 753b8021494Sopenharmony_ci log_if_missing = !*queried_can_run; 754b8021494Sopenharmony_ci *queried_can_run = true; 755b8021494Sopenharmony_ci } 756b8021494Sopenharmony_ci 757b8021494Sopenharmony_ci#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64 758b8021494Sopenharmony_ci // The Simulator can run any test that VIXL can assemble. 759b8021494Sopenharmony_ci USE(required); 760b8021494Sopenharmony_ci USE(log_if_missing); 761b8021494Sopenharmony_ci return true; 762b8021494Sopenharmony_ci#else 763b8021494Sopenharmony_ci CPUFeatures cpu = CPUFeatures::InferFromOS(); 764b8021494Sopenharmony_ci // If InferFromOS fails, assume that basic features are present. 765b8021494Sopenharmony_ci if (cpu.HasNoFeatures()) cpu = CPUFeatures::AArch64LegacyBaseline(); 766b8021494Sopenharmony_ci VIXL_ASSERT(cpu.Has(kInfrastructureCPUFeatures)); 767b8021494Sopenharmony_ci 768b8021494Sopenharmony_ci if (cpu.Has(required)) return true; 769b8021494Sopenharmony_ci 770b8021494Sopenharmony_ci if (log_if_missing) { 771b8021494Sopenharmony_ci CPUFeatures missing = required.Without(cpu); 772b8021494Sopenharmony_ci // Note: This message needs to match REGEXP_MISSING_FEATURES from 773b8021494Sopenharmony_ci // tools/threaded_test.py. 774b8021494Sopenharmony_ci std::cout << "SKIPPED: Missing features: { " << missing << " }\n"; 775b8021494Sopenharmony_ci std::cout << "This test requires the following features to run its " 776b8021494Sopenharmony_ci "generated code on this CPU: " 777b8021494Sopenharmony_ci << required << "\n"; 778b8021494Sopenharmony_ci } 779b8021494Sopenharmony_ci return false; 780b8021494Sopenharmony_ci#endif 781b8021494Sopenharmony_ci} 782b8021494Sopenharmony_ci 783b8021494Sopenharmony_ci// Note that the function assumes p0, p1, p2 and p3 are set to all true in b-, 784b8021494Sopenharmony_ci// h-, s- and d-lane sizes respectively, and p4, p5 are clobbered as a temp 785b8021494Sopenharmony_ci// predicate. 786b8021494Sopenharmony_citemplate <typename T, size_t N> 787b8021494Sopenharmony_civoid SetFpData(MacroAssembler* masm, 788b8021494Sopenharmony_ci int esize, 789b8021494Sopenharmony_ci const T (&values)[N], 790b8021494Sopenharmony_ci uint64_t lcg_mult) { 791b8021494Sopenharmony_ci uint64_t a = 0; 792b8021494Sopenharmony_ci uint64_t b = lcg_mult; 793b8021494Sopenharmony_ci // Be used to populate the assigned element slots of register based on the 794b8021494Sopenharmony_ci // type of floating point. 795b8021494Sopenharmony_ci __ Pfalse(p5.VnB()); 796b8021494Sopenharmony_ci switch (esize) { 797b8021494Sopenharmony_ci case kHRegSize: 798b8021494Sopenharmony_ci a = Float16ToRawbits(Float16(1.5)); 799b8021494Sopenharmony_ci // Pick a convenient number within largest normal half-precision floating 800b8021494Sopenharmony_ci // point. 801b8021494Sopenharmony_ci b = Float16ToRawbits(Float16(lcg_mult % 1024)); 802b8021494Sopenharmony_ci // Step 1: Set fp16 numbers to the undefined registers. 803b8021494Sopenharmony_ci // p4< 15:0>: 0b0101010101010101 804b8021494Sopenharmony_ci // z{code}<127:0>: 0xHHHHHHHHHHHHHHHH 805b8021494Sopenharmony_ci __ Zip1(p4.VnB(), p0.VnB(), p5.VnB()); 806b8021494Sopenharmony_ci break; 807b8021494Sopenharmony_ci case kSRegSize: 808b8021494Sopenharmony_ci a = FloatToRawbits(1.5); 809b8021494Sopenharmony_ci b = FloatToRawbits(lcg_mult); 810b8021494Sopenharmony_ci // Step 2: Set fp32 numbers to register on top of fp16 initialized. 811b8021494Sopenharmony_ci // p4< 15:0>: 0b0000000100000001 812b8021494Sopenharmony_ci // z{code}<127:0>: 0xHHHHSSSSHHHHSSSS 813b8021494Sopenharmony_ci __ Zip1(p4.VnS(), p2.VnS(), p5.VnS()); 814b8021494Sopenharmony_ci break; 815b8021494Sopenharmony_ci case kDRegSize: 816b8021494Sopenharmony_ci a = DoubleToRawbits(1.5); 817b8021494Sopenharmony_ci b = DoubleToRawbits(lcg_mult); 818b8021494Sopenharmony_ci // Step 3: Set fp64 numbers to register on top of both fp16 and fp 32 819b8021494Sopenharmony_ci // initialized. 820b8021494Sopenharmony_ci // p4< 15:0>: 0b0000000000000001 821b8021494Sopenharmony_ci // z{code}<127:0>: 0xHHHHSSSSDDDDDDDD 822b8021494Sopenharmony_ci __ Zip1(p4.VnD(), p3.VnD(), p5.VnD()); 823b8021494Sopenharmony_ci break; 824b8021494Sopenharmony_ci default: 825b8021494Sopenharmony_ci VIXL_UNIMPLEMENTED(); 826b8021494Sopenharmony_ci break; 827b8021494Sopenharmony_ci } 828b8021494Sopenharmony_ci 829b8021494Sopenharmony_ci __ Dup(z30.WithLaneSize(esize), a); 830b8021494Sopenharmony_ci __ Dup(z31.WithLaneSize(esize), b); 831b8021494Sopenharmony_ci 832b8021494Sopenharmony_ci for (unsigned j = 0; j <= (kZRegMaxSize / (N * esize)); j++) { 833b8021494Sopenharmony_ci // As floating point operations on random values have a tendency to 834b8021494Sopenharmony_ci // converge on special-case numbers like NaNs, adopt normal floating point 835b8021494Sopenharmony_ci // values be the seed instead. 836b8021494Sopenharmony_ci InsrHelper(masm, z0.WithLaneSize(esize), values); 837b8021494Sopenharmony_ci } 838b8021494Sopenharmony_ci 839b8021494Sopenharmony_ci __ Fmla(z0.WithLaneSize(esize), 840b8021494Sopenharmony_ci p4.Merging(), 841b8021494Sopenharmony_ci z30.WithLaneSize(esize), 842b8021494Sopenharmony_ci z0.WithLaneSize(esize), 843b8021494Sopenharmony_ci z31.WithLaneSize(esize), 844b8021494Sopenharmony_ci FastNaNPropagation); 845b8021494Sopenharmony_ci 846b8021494Sopenharmony_ci for (unsigned i = 1; i < kNumberOfZRegisters - 1; i++) { 847b8021494Sopenharmony_ci __ Fmla(ZRegister(i).WithLaneSize(esize), 848b8021494Sopenharmony_ci p4.Merging(), 849b8021494Sopenharmony_ci z30.WithLaneSize(esize), 850b8021494Sopenharmony_ci ZRegister(i - 1).WithLaneSize(esize), 851b8021494Sopenharmony_ci z31.WithLaneSize(esize), 852b8021494Sopenharmony_ci FastNaNPropagation); 853b8021494Sopenharmony_ci } 854b8021494Sopenharmony_ci 855b8021494Sopenharmony_ci __ Fmul(z31.WithLaneSize(esize), 856b8021494Sopenharmony_ci p4.Merging(), 857b8021494Sopenharmony_ci z31.WithLaneSize(esize), 858b8021494Sopenharmony_ci z30.WithLaneSize(esize), 859b8021494Sopenharmony_ci FastNaNPropagation); 860b8021494Sopenharmony_ci __ Fadd(z31.WithLaneSize(esize), p4.Merging(), z31.WithLaneSize(esize), 1); 861b8021494Sopenharmony_ci} 862b8021494Sopenharmony_ci 863b8021494Sopenharmony_ci// Set z0 - z31 to some normal floating point data. 864b8021494Sopenharmony_civoid InitialiseRegisterFp(MacroAssembler* masm, uint64_t lcg_mult) { 865b8021494Sopenharmony_ci // Initialise each Z registers to a mixture of fp16/32/64 values as following 866b8021494Sopenharmony_ci // pattern: 867b8021494Sopenharmony_ci // z0.h[0-1] = fp16, z0.s[1] = fp32, z0.d[1] = fp64 repeatedly throughout the 868b8021494Sopenharmony_ci // register. 869b8021494Sopenharmony_ci // 870b8021494Sopenharmony_ci // For example: 871b8021494Sopenharmony_ci // z{code}<2047:1920>: 0x{< fp64 >< fp32 ><fp16><fp16>} 872b8021494Sopenharmony_ci // ... 873b8021494Sopenharmony_ci // z{code}< 127: 0>: 0x{< fp64 >< fp32 ><fp16><fp16>} 874b8021494Sopenharmony_ci // 875b8021494Sopenharmony_ci // In current manner, in order to make a desired mixture, each part of 876b8021494Sopenharmony_ci // initialization have to be called in the following order. 877b8021494Sopenharmony_ci SetFpData(masm, kHRegSize, kInputFloat16Basic, lcg_mult); 878b8021494Sopenharmony_ci SetFpData(masm, kSRegSize, kInputFloatBasic, lcg_mult); 879b8021494Sopenharmony_ci SetFpData(masm, kDRegSize, kInputDoubleBasic, lcg_mult); 880b8021494Sopenharmony_ci} 881b8021494Sopenharmony_ci 882b8021494Sopenharmony_civoid SetInitialMachineState(MacroAssembler* masm, InputSet input_set) { 883b8021494Sopenharmony_ci USE(input_set); 884b8021494Sopenharmony_ci uint64_t lcg_mult = 6364136223846793005; 885b8021494Sopenharmony_ci 886b8021494Sopenharmony_ci // Set x0 - x30 to pseudo-random data. 887b8021494Sopenharmony_ci __ Mov(x29, 1); // LCG increment. 888b8021494Sopenharmony_ci __ Mov(x30, lcg_mult); 889b8021494Sopenharmony_ci __ Mov(x0, 42); // LCG seed. 890b8021494Sopenharmony_ci 891b8021494Sopenharmony_ci __ Cmn(x0, 0); // Clear NZCV flags for later. 892b8021494Sopenharmony_ci 893b8021494Sopenharmony_ci __ Madd(x0, x0, x30, x29); // First pseudo-random number. 894b8021494Sopenharmony_ci 895b8021494Sopenharmony_ci // Registers 1 - 29. 896b8021494Sopenharmony_ci for (unsigned i = 1; i < 30; i++) { 897b8021494Sopenharmony_ci __ Madd(XRegister(i), XRegister(i - 1), x30, x29); 898b8021494Sopenharmony_ci } 899b8021494Sopenharmony_ci __ Mul(x30, x29, x30); 900b8021494Sopenharmony_ci __ Add(x30, x30, 1); 901b8021494Sopenharmony_ci 902b8021494Sopenharmony_ci 903b8021494Sopenharmony_ci // Set first four predicate registers to true for increasing lane sizes. 904b8021494Sopenharmony_ci __ Ptrue(p0.VnB()); 905b8021494Sopenharmony_ci __ Ptrue(p1.VnH()); 906b8021494Sopenharmony_ci __ Ptrue(p2.VnS()); 907b8021494Sopenharmony_ci __ Ptrue(p3.VnD()); 908b8021494Sopenharmony_ci 909b8021494Sopenharmony_ci // Set z0 - z31 to pseudo-random data. 910b8021494Sopenharmony_ci if (input_set == kIntInputSet) { 911b8021494Sopenharmony_ci __ Dup(z30.VnD(), 1); 912b8021494Sopenharmony_ci __ Dup(z31.VnD(), lcg_mult); 913b8021494Sopenharmony_ci __ Index(z0.VnB(), -16, 13); // LCG seeds. 914b8021494Sopenharmony_ci 915b8021494Sopenharmony_ci __ Mla(z0.VnD(), p0.Merging(), z30.VnD(), z0.VnD(), z31.VnD()); 916b8021494Sopenharmony_ci for (unsigned i = 1; i < kNumberOfZRegisters - 1; i++) { 917b8021494Sopenharmony_ci __ Mla(ZRegister(i).VnD(), 918b8021494Sopenharmony_ci p0.Merging(), 919b8021494Sopenharmony_ci z30.VnD(), 920b8021494Sopenharmony_ci ZRegister(i - 1).VnD(), 921b8021494Sopenharmony_ci z31.VnD()); 922b8021494Sopenharmony_ci } 923b8021494Sopenharmony_ci __ Mul(z31.VnD(), p0.Merging(), z31.VnD(), z30.VnD()); 924b8021494Sopenharmony_ci __ Add(z31.VnD(), z31.VnD(), 1); 925b8021494Sopenharmony_ci 926b8021494Sopenharmony_ci } else { 927b8021494Sopenharmony_ci VIXL_ASSERT(input_set == kFpInputSet); 928b8021494Sopenharmony_ci InitialiseRegisterFp(masm, lcg_mult); 929b8021494Sopenharmony_ci } 930b8021494Sopenharmony_ci 931b8021494Sopenharmony_ci // Set remaining predicate registers based on earlier pseudo-random data. 932b8021494Sopenharmony_ci for (unsigned i = 4; i < kNumberOfPRegisters; i++) { 933b8021494Sopenharmony_ci __ Cmpge(PRegister(i).VnB(), p0.Zeroing(), ZRegister(i).VnB(), 0); 934b8021494Sopenharmony_ci } 935b8021494Sopenharmony_ci for (unsigned i = 4; i < kNumberOfPRegisters; i += 2) { 936b8021494Sopenharmony_ci __ Zip1(p0.VnB(), PRegister(i).VnB(), PRegister(i + 1).VnB()); 937b8021494Sopenharmony_ci __ Zip2(PRegister(i + 1).VnB(), PRegister(i).VnB(), PRegister(i + 1).VnB()); 938b8021494Sopenharmony_ci __ Mov(PRegister(i), p0); 939b8021494Sopenharmony_ci } 940b8021494Sopenharmony_ci __ Ptrue(p0.VnB()); 941b8021494Sopenharmony_ci 942b8021494Sopenharmony_ci // At this point, only sp and a few status registers are undefined. These 943b8021494Sopenharmony_ci // must be ignored when computing the state hash. 944b8021494Sopenharmony_ci} 945b8021494Sopenharmony_ci 946b8021494Sopenharmony_civoid ComputeMachineStateHash(MacroAssembler* masm, uint32_t* dst) { 947b8021494Sopenharmony_ci // Use explicit registers, to avoid hash order varying if 948b8021494Sopenharmony_ci // UseScratchRegisterScope changes. 949b8021494Sopenharmony_ci UseScratchRegisterScope temps(masm); 950b8021494Sopenharmony_ci temps.ExcludeAll(); 951b8021494Sopenharmony_ci Register t0 = w0; 952b8021494Sopenharmony_ci Register t1 = x1; 953b8021494Sopenharmony_ci 954b8021494Sopenharmony_ci // Compute hash of x0 - x30. 955b8021494Sopenharmony_ci __ Push(t0.X(), t1); 956b8021494Sopenharmony_ci __ Crc32x(t0, wzr, t0.X()); 957b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfRegisters; i++) { 958b8021494Sopenharmony_ci if (i == xzr.GetCode()) continue; // Skip sp. 959b8021494Sopenharmony_ci if (t0.Is(WRegister(i))) continue; // Skip t0, as it's already hashed. 960b8021494Sopenharmony_ci __ Crc32x(t0, t0, XRegister(i)); 961b8021494Sopenharmony_ci } 962b8021494Sopenharmony_ci 963b8021494Sopenharmony_ci // Hash the status flags. 964b8021494Sopenharmony_ci __ Mrs(t1, NZCV); 965b8021494Sopenharmony_ci __ Crc32x(t0, t0, t1); 966b8021494Sopenharmony_ci 967b8021494Sopenharmony_ci // Acquire another temp, as integer registers have been hashed already. 968b8021494Sopenharmony_ci __ Push(x30, xzr); 969b8021494Sopenharmony_ci Register t2 = x30; 970b8021494Sopenharmony_ci 971b8021494Sopenharmony_ci // Compute hash of all bits in z0 - z31. This implies different hashes are 972b8021494Sopenharmony_ci // produced for machines of different vector length. 973b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfZRegisters; i++) { 974b8021494Sopenharmony_ci __ Rdvl(t2, 1); 975b8021494Sopenharmony_ci __ Lsr(t2, t2, 4); 976b8021494Sopenharmony_ci Label vl_loop; 977b8021494Sopenharmony_ci __ Bind(&vl_loop); 978b8021494Sopenharmony_ci __ Umov(t1, VRegister(i).V2D(), 0); 979b8021494Sopenharmony_ci __ Crc32x(t0, t0, t1); 980b8021494Sopenharmony_ci __ Umov(t1, VRegister(i).V2D(), 1); 981b8021494Sopenharmony_ci __ Crc32x(t0, t0, t1); 982b8021494Sopenharmony_ci __ Ext(ZRegister(i).VnB(), ZRegister(i).VnB(), ZRegister(i).VnB(), 16); 983b8021494Sopenharmony_ci __ Sub(t2, t2, 1); 984b8021494Sopenharmony_ci __ Cbnz(t2, &vl_loop); 985b8021494Sopenharmony_ci } 986b8021494Sopenharmony_ci 987b8021494Sopenharmony_ci // Hash predicate registers. For simplicity, this writes the predicate 988b8021494Sopenharmony_ci // registers to a zero-initialised area of stack of the maximum size required 989b8021494Sopenharmony_ci // for P registers. It then computes a hash of that entire stack area. 990b8021494Sopenharmony_ci unsigned p_stack_space = kNumberOfPRegisters * kPRegMaxSizeInBytes; 991b8021494Sopenharmony_ci 992b8021494Sopenharmony_ci // Zero claimed stack area. 993b8021494Sopenharmony_ci for (unsigned i = 0; i < p_stack_space; i += kXRegSizeInBytes * 2) { 994b8021494Sopenharmony_ci __ Push(xzr, xzr); 995b8021494Sopenharmony_ci } 996b8021494Sopenharmony_ci 997b8021494Sopenharmony_ci // Store all P registers to the stack. 998b8021494Sopenharmony_ci __ Mov(t1, sp); 999b8021494Sopenharmony_ci for (unsigned i = 0; i < kNumberOfPRegisters; i++) { 1000b8021494Sopenharmony_ci __ Str(PRegister(i), SVEMemOperand(t1)); 1001b8021494Sopenharmony_ci __ Add(t1, t1, kPRegMaxSizeInBytes); 1002b8021494Sopenharmony_ci } 1003b8021494Sopenharmony_ci 1004b8021494Sopenharmony_ci // Hash the entire stack area. 1005b8021494Sopenharmony_ci for (unsigned i = 0; i < p_stack_space; i += kXRegSizeInBytes * 2) { 1006b8021494Sopenharmony_ci __ Pop(t1, t2); 1007b8021494Sopenharmony_ci __ Crc32x(t0, t0, t1); 1008b8021494Sopenharmony_ci __ Crc32x(t0, t0, t2); 1009b8021494Sopenharmony_ci } 1010b8021494Sopenharmony_ci 1011b8021494Sopenharmony_ci __ Mov(t1, reinterpret_cast<uint64_t>(dst)); 1012b8021494Sopenharmony_ci __ Str(t0, MemOperand(t1)); 1013b8021494Sopenharmony_ci 1014b8021494Sopenharmony_ci __ Pop(xzr, x30); 1015b8021494Sopenharmony_ci __ Pop(t1, t0.X()); 1016b8021494Sopenharmony_ci} 1017b8021494Sopenharmony_ci 1018b8021494Sopenharmony_ci} // namespace aarch64 1019b8021494Sopenharmony_ci} // namespace vixl 1020