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