1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_ARM64_TEST_UTILS_ARM64_H_ 29 #define V8_ARM64_TEST_UTILS_ARM64_H_ 30 31 #include "src/v8.h" 32 #include "test/cctest/cctest.h" 33 34 #include "src/arm64/macro-assembler-arm64.h" 35 #include "src/arm64/utils-arm64.h" 36 #include "src/macro-assembler.h" 37 38 39 using namespace v8::internal; 40 41 42 // RegisterDump: Object allowing integer, floating point and flags registers 43 // to be saved to itself for future reference. 44 class RegisterDump { 45 public: RegisterDump()46 RegisterDump() : completed_(false) {} 47 48 // The Dump method generates code to store a snapshot of the register values. 49 // It needs to be able to use the stack temporarily, and requires that the 50 // current stack pointer is csp, and is properly aligned. 51 // 52 // The dumping code is generated though the given MacroAssembler. No registers 53 // are corrupted in the process, but the stack is used briefly. The flags will 54 // be corrupted during this call. 55 void Dump(MacroAssembler* assm); 56 57 // Register accessors. wreg(unsigned code)58 inline int32_t wreg(unsigned code) const { 59 if (code == kSPRegInternalCode) { 60 return wspreg(); 61 } 62 DCHECK(RegAliasesMatch(code)); 63 return dump_.w_[code]; 64 } 65 xreg(unsigned code)66 inline int64_t xreg(unsigned code) const { 67 if (code == kSPRegInternalCode) { 68 return spreg(); 69 } 70 DCHECK(RegAliasesMatch(code)); 71 return dump_.x_[code]; 72 } 73 74 // FPRegister accessors. sreg_bits(unsigned code)75 inline uint32_t sreg_bits(unsigned code) const { 76 DCHECK(FPRegAliasesMatch(code)); 77 return dump_.s_[code]; 78 } 79 sreg(unsigned code)80 inline float sreg(unsigned code) const { 81 return rawbits_to_float(sreg_bits(code)); 82 } 83 dreg_bits(unsigned code)84 inline uint64_t dreg_bits(unsigned code) const { 85 DCHECK(FPRegAliasesMatch(code)); 86 return dump_.d_[code]; 87 } 88 dreg(unsigned code)89 inline double dreg(unsigned code) const { 90 return rawbits_to_double(dreg_bits(code)); 91 } 92 93 // Stack pointer accessors. spreg()94 inline int64_t spreg() const { 95 DCHECK(SPRegAliasesMatch()); 96 return dump_.sp_; 97 } 98 wspreg()99 inline int64_t wspreg() const { 100 DCHECK(SPRegAliasesMatch()); 101 return dump_.wsp_; 102 } 103 104 // Flags accessors. flags_nzcv()105 inline uint64_t flags_nzcv() const { 106 DCHECK(IsComplete()); 107 DCHECK((dump_.flags_ & ~Flags_mask) == 0); 108 return dump_.flags_ & Flags_mask; 109 } 110 IsComplete()111 inline bool IsComplete() const { 112 return completed_; 113 } 114 115 private: 116 // Indicate whether the dump operation has been completed. 117 bool completed_; 118 119 // Check that the lower 32 bits of x<code> exactly match the 32 bits of 120 // w<code>. A failure of this test most likely represents a failure in the 121 // ::Dump method, or a failure in the simulator. RegAliasesMatch(unsigned code)122 bool RegAliasesMatch(unsigned code) const { 123 DCHECK(IsComplete()); 124 DCHECK(code < kNumberOfRegisters); 125 return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]); 126 } 127 128 // As RegAliasesMatch, but for the stack pointer. SPRegAliasesMatch()129 bool SPRegAliasesMatch() const { 130 DCHECK(IsComplete()); 131 return ((dump_.sp_ & kWRegMask) == dump_.wsp_); 132 } 133 134 // As RegAliasesMatch, but for floating-point registers. FPRegAliasesMatch(unsigned code)135 bool FPRegAliasesMatch(unsigned code) const { 136 DCHECK(IsComplete()); 137 DCHECK(code < kNumberOfFPRegisters); 138 return (dump_.d_[code] & kSRegMask) == dump_.s_[code]; 139 } 140 141 // Store all the dumped elements in a simple struct so the implementation can 142 // use offsetof to quickly find the correct field. 143 struct dump_t { 144 // Core registers. 145 uint64_t x_[kNumberOfRegisters]; 146 uint32_t w_[kNumberOfRegisters]; 147 148 // Floating-point registers, as raw bits. 149 uint64_t d_[kNumberOfFPRegisters]; 150 uint32_t s_[kNumberOfFPRegisters]; 151 152 // The stack pointer. 153 uint64_t sp_; 154 uint64_t wsp_; 155 156 // NZCV flags, stored in bits 28 to 31. 157 // bit[31] : Negative 158 // bit[30] : Zero 159 // bit[29] : Carry 160 // bit[28] : oVerflow 161 uint64_t flags_; 162 } dump_; 163 164 static dump_t for_sizeof(); 165 STATIC_ASSERT(sizeof(for_sizeof().d_[0]) == kDRegSize); 166 STATIC_ASSERT(sizeof(for_sizeof().s_[0]) == kSRegSize); 167 STATIC_ASSERT(sizeof(for_sizeof().d_[0]) == kXRegSize); 168 STATIC_ASSERT(sizeof(for_sizeof().s_[0]) == kWRegSize); 169 STATIC_ASSERT(sizeof(for_sizeof().x_[0]) == kXRegSize); 170 STATIC_ASSERT(sizeof(for_sizeof().w_[0]) == kWRegSize); 171 }; 172 173 // Some of these methods don't use the RegisterDump argument, but they have to 174 // accept them so that they can overload those that take register arguments. 175 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result); 176 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result); 177 178 bool EqualFP32(float expected, const RegisterDump*, float result); 179 bool EqualFP64(double expected, const RegisterDump*, double result); 180 181 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg); 182 bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg); 183 184 bool EqualFP32(float expected, const RegisterDump* core, 185 const FPRegister& fpreg); 186 bool EqualFP64(double expected, const RegisterDump* core, 187 const FPRegister& fpreg); 188 189 bool Equal64(const Register& reg0, const RegisterDump* core, 190 const Register& reg1); 191 192 bool EqualNzcv(uint32_t expected, uint32_t result); 193 194 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b); 195 196 // Populate the w, x and r arrays with registers from the 'allowed' mask. The 197 // r array will be populated with <reg_size>-sized registers, 198 // 199 // This allows for tests which use large, parameterized blocks of registers 200 // (such as the push and pop tests), but where certain registers must be 201 // avoided as they are used for other purposes. 202 // 203 // Any of w, x, or r can be NULL if they are not required. 204 // 205 // The return value is a RegList indicating which registers were allocated. 206 RegList PopulateRegisterArray(Register* w, Register* x, Register* r, 207 int reg_size, int reg_count, RegList allowed); 208 209 // As PopulateRegisterArray, but for floating-point registers. 210 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v, 211 int reg_size, int reg_count, RegList allowed); 212 213 // Ovewrite the contents of the specified registers. This enables tests to 214 // check that register contents are written in cases where it's likely that the 215 // correct outcome could already be stored in the register. 216 // 217 // This always overwrites X-sized registers. If tests are operating on W 218 // registers, a subsequent write into an aliased W register should clear the 219 // top word anyway, so clobbering the full X registers should make tests more 220 // rigorous. 221 void Clobber(MacroAssembler* masm, RegList reg_list, 222 uint64_t const value = 0xfedcba9876543210UL); 223 224 // As Clobber, but for FP registers. 225 void ClobberFP(MacroAssembler* masm, RegList reg_list, 226 double const value = kFP64SignallingNaN); 227 228 // As Clobber, but for a CPURegList with either FP or integer registers. When 229 // using this method, the clobber value is always the default for the basic 230 // Clobber or ClobberFP functions. 231 void Clobber(MacroAssembler* masm, CPURegList reg_list); 232 233 #endif // V8_ARM64_TEST_UTILS_ARM64_H_ 234