1 // Copyright 2014, 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 #ifndef VIXL_A64_TEST_UTILS_A64_H_ 28 #define VIXL_A64_TEST_UTILS_A64_H_ 29 30 #include "test-runner.h" 31 #include "vixl/a64/macro-assembler-a64.h" 32 #include "vixl/a64/simulator-a64.h" 33 #include "vixl/a64/disasm-a64.h" 34 #include "vixl/a64/cpu-a64.h" 35 36 namespace vixl { 37 38 // Signalling and quiet NaNs in double format, constructed such that the bottom 39 // 32 bits look like a signalling or quiet NaN (as appropriate) when interpreted 40 // as a float. These values are not architecturally significant, but they're 41 // useful in tests for initialising registers. 42 extern const double kFP64SignallingNaN; 43 extern const double kFP64QuietNaN; 44 45 // Signalling and quiet NaNs in float format. 46 extern const float kFP32SignallingNaN; 47 extern const float kFP32QuietNaN; 48 49 // Structure representing Q registers in a RegisterDump. 50 struct vec128_t { 51 uint64_t l; 52 uint64_t h; 53 }; 54 55 // RegisterDump: Object allowing integer, floating point and flags registers 56 // to be saved to itself for future reference. 57 class RegisterDump { 58 public: RegisterDump()59 RegisterDump() : completed_(false) { 60 VIXL_ASSERT(sizeof(dump_.d_[0]) == kDRegSizeInBytes); 61 VIXL_ASSERT(sizeof(dump_.s_[0]) == kSRegSizeInBytes); 62 VIXL_ASSERT(sizeof(dump_.d_[0]) == kXRegSizeInBytes); 63 VIXL_ASSERT(sizeof(dump_.s_[0]) == kWRegSizeInBytes); 64 VIXL_ASSERT(sizeof(dump_.x_[0]) == kXRegSizeInBytes); 65 VIXL_ASSERT(sizeof(dump_.w_[0]) == kWRegSizeInBytes); 66 VIXL_ASSERT(sizeof(dump_.q_[0]) == kQRegSizeInBytes); 67 } 68 69 // The Dump method generates code to store a snapshot of the register values. 70 // It needs to be able to use the stack temporarily, and requires that the 71 // current stack pointer is sp, and is properly aligned. 72 // 73 // The dumping code is generated though the given MacroAssembler. No registers 74 // are corrupted in the process, but the stack is used briefly. The flags will 75 // be corrupted during this call. 76 void Dump(MacroAssembler* assm); 77 78 // Register accessors. wreg(unsigned code)79 inline int32_t wreg(unsigned code) const { 80 if (code == kSPRegInternalCode) { 81 return wspreg(); 82 } 83 VIXL_ASSERT(RegAliasesMatch(code)); 84 return dump_.w_[code]; 85 } 86 xreg(unsigned code)87 inline int64_t xreg(unsigned code) const { 88 if (code == kSPRegInternalCode) { 89 return spreg(); 90 } 91 VIXL_ASSERT(RegAliasesMatch(code)); 92 return dump_.x_[code]; 93 } 94 95 // FPRegister accessors. sreg_bits(unsigned code)96 inline uint32_t sreg_bits(unsigned code) const { 97 VIXL_ASSERT(FPRegAliasesMatch(code)); 98 return dump_.s_[code]; 99 } 100 sreg(unsigned code)101 inline float sreg(unsigned code) const { 102 return rawbits_to_float(sreg_bits(code)); 103 } 104 dreg_bits(unsigned code)105 inline uint64_t dreg_bits(unsigned code) const { 106 VIXL_ASSERT(FPRegAliasesMatch(code)); 107 return dump_.d_[code]; 108 } 109 dreg(unsigned code)110 inline double dreg(unsigned code) const { 111 return rawbits_to_double(dreg_bits(code)); 112 } 113 qreg(unsigned code)114 inline vec128_t qreg(unsigned code) const { 115 return dump_.q_[code]; 116 } 117 118 // Stack pointer accessors. spreg()119 inline int64_t spreg() const { 120 VIXL_ASSERT(SPRegAliasesMatch()); 121 return dump_.sp_; 122 } 123 wspreg()124 inline int64_t wspreg() const { 125 VIXL_ASSERT(SPRegAliasesMatch()); 126 return dump_.wsp_; 127 } 128 129 // Flags accessors. flags_nzcv()130 inline uint64_t flags_nzcv() const { 131 VIXL_ASSERT(IsComplete()); 132 VIXL_ASSERT((dump_.flags_ & ~Flags_mask) == 0); 133 return dump_.flags_ & Flags_mask; 134 } 135 IsComplete()136 inline bool IsComplete() const { 137 return completed_; 138 } 139 140 private: 141 // Indicate whether the dump operation has been completed. 142 bool completed_; 143 144 // Check that the lower 32 bits of x<code> exactly match the 32 bits of 145 // w<code>. A failure of this test most likely represents a failure in the 146 // ::Dump method, or a failure in the simulator. RegAliasesMatch(unsigned code)147 bool RegAliasesMatch(unsigned code) const { 148 VIXL_ASSERT(IsComplete()); 149 VIXL_ASSERT(code < kNumberOfRegisters); 150 return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]); 151 } 152 153 // As RegAliasesMatch, but for the stack pointer. SPRegAliasesMatch()154 bool SPRegAliasesMatch() const { 155 VIXL_ASSERT(IsComplete()); 156 return ((dump_.sp_ & kWRegMask) == dump_.wsp_); 157 } 158 159 // As RegAliasesMatch, but for floating-point registers. FPRegAliasesMatch(unsigned code)160 bool FPRegAliasesMatch(unsigned code) const { 161 VIXL_ASSERT(IsComplete()); 162 VIXL_ASSERT(code < kNumberOfFPRegisters); 163 return (dump_.d_[code] & kSRegMask) == dump_.s_[code]; 164 } 165 166 // Store all the dumped elements in a simple struct so the implementation can 167 // use offsetof to quickly find the correct field. 168 struct dump_t { 169 // Core registers. 170 uint64_t x_[kNumberOfRegisters]; 171 uint32_t w_[kNumberOfRegisters]; 172 173 // Floating-point registers, as raw bits. 174 uint64_t d_[kNumberOfFPRegisters]; 175 uint32_t s_[kNumberOfFPRegisters]; 176 177 // Vector registers. 178 vec128_t q_[kNumberOfVRegisters]; 179 180 // The stack pointer. 181 uint64_t sp_; 182 uint64_t wsp_; 183 184 // NZCV flags, stored in bits 28 to 31. 185 // bit[31] : Negative 186 // bit[30] : Zero 187 // bit[29] : Carry 188 // bit[28] : oVerflow 189 uint64_t flags_; 190 } dump_; 191 }; 192 193 // Some of these methods don't use the RegisterDump argument, but they have to 194 // accept them so that they can overload those that take register arguments. 195 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result); 196 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result); 197 198 bool EqualFP32(float expected, const RegisterDump*, float result); 199 bool EqualFP64(double expected, const RegisterDump*, double result); 200 201 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg); 202 bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg); 203 204 bool EqualFP32(float expected, const RegisterDump* core, 205 const FPRegister& fpreg); 206 bool EqualFP64(double expected, const RegisterDump* core, 207 const FPRegister& fpreg); 208 209 bool Equal64(const Register& reg0, const RegisterDump* core, 210 const Register& reg1); 211 bool Equal128(uint64_t expected_h, uint64_t expected_l, 212 const RegisterDump* core, const VRegister& reg); 213 214 bool EqualNzcv(uint32_t expected, uint32_t result); 215 216 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b); 217 218 // Populate the w, x and r arrays with registers from the 'allowed' mask. The 219 // r array will be populated with <reg_size>-sized registers, 220 // 221 // This allows for tests which use large, parameterized blocks of registers 222 // (such as the push and pop tests), but where certain registers must be 223 // avoided as they are used for other purposes. 224 // 225 // Any of w, x, or r can be NULL if they are not required. 226 // 227 // The return value is a RegList indicating which registers were allocated. 228 RegList PopulateRegisterArray(Register* w, Register* x, Register* r, 229 int reg_size, int reg_count, RegList allowed); 230 231 // As PopulateRegisterArray, but for floating-point registers. 232 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v, 233 int reg_size, int reg_count, RegList allowed); 234 235 // Ovewrite the contents of the specified registers. This enables tests to 236 // check that register contents are written in cases where it's likely that the 237 // correct outcome could already be stored in the register. 238 // 239 // This always overwrites X-sized registers. If tests are operating on W 240 // registers, a subsequent write into an aliased W register should clear the 241 // top word anyway, so clobbering the full X registers should make tests more 242 // rigorous. 243 void Clobber(MacroAssembler* masm, RegList reg_list, 244 uint64_t const value = 0xfedcba9876543210); 245 246 // As Clobber, but for FP registers. 247 void ClobberFP(MacroAssembler* masm, RegList reg_list, 248 double const value = kFP64SignallingNaN); 249 250 // As Clobber, but for a CPURegList with either FP or integer registers. When 251 // using this method, the clobber value is always the default for the basic 252 // Clobber or ClobberFP functions. 253 void Clobber(MacroAssembler* masm, CPURegList reg_list); 254 255 } // namespace vixl 256 257 #endif // VIXL_A64_TEST_UTILS_A64_H_ 258