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