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