OLD | NEW |
| (Empty) |
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_A64_TEST_UTILS_A64_H_ | |
29 #define V8_A64_TEST_UTILS_A64_H_ | |
30 | |
31 #include "v8.h" | |
32 | |
33 #include "macro-assembler.h" | |
34 #include "a64/macro-assembler-a64.h" | |
35 #include "a64/utils-a64.h" | |
36 #include "cctest.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: | |
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. | |
58 inline int32_t wreg(unsigned code) const { | |
59 if (code == kSPRegInternalCode) { | |
60 return wspreg(); | |
61 } | |
62 ASSERT(RegAliasesMatch(code)); | |
63 return dump_.w_[code]; | |
64 } | |
65 | |
66 inline int64_t xreg(unsigned code) const { | |
67 if (code == kSPRegInternalCode) { | |
68 return spreg(); | |
69 } | |
70 ASSERT(RegAliasesMatch(code)); | |
71 return dump_.x_[code]; | |
72 } | |
73 | |
74 // FPRegister accessors. | |
75 inline uint32_t sreg_bits(unsigned code) const { | |
76 ASSERT(FPRegAliasesMatch(code)); | |
77 return dump_.s_[code]; | |
78 } | |
79 | |
80 inline float sreg(unsigned code) const { | |
81 return rawbits_to_float(sreg_bits(code)); | |
82 } | |
83 | |
84 inline uint64_t dreg_bits(unsigned code) const { | |
85 ASSERT(FPRegAliasesMatch(code)); | |
86 return dump_.d_[code]; | |
87 } | |
88 | |
89 inline double dreg(unsigned code) const { | |
90 return rawbits_to_double(dreg_bits(code)); | |
91 } | |
92 | |
93 // Stack pointer accessors. | |
94 inline int64_t spreg() const { | |
95 ASSERT(SPRegAliasesMatch()); | |
96 return dump_.sp_; | |
97 } | |
98 | |
99 inline int64_t wspreg() const { | |
100 ASSERT(SPRegAliasesMatch()); | |
101 return dump_.wsp_; | |
102 } | |
103 | |
104 // Flags accessors. | |
105 inline uint64_t flags_nzcv() const { | |
106 ASSERT(IsComplete()); | |
107 ASSERT((dump_.flags_ & ~Flags_mask) == 0); | |
108 return dump_.flags_ & Flags_mask; | |
109 } | |
110 | |
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. | |
122 bool RegAliasesMatch(unsigned code) const { | |
123 ASSERT(IsComplete()); | |
124 ASSERT(code < kNumberOfRegisters); | |
125 return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]); | |
126 } | |
127 | |
128 // As RegAliasesMatch, but for the stack pointer. | |
129 bool SPRegAliasesMatch() const { | |
130 ASSERT(IsComplete()); | |
131 return ((dump_.sp_ & kWRegMask) == dump_.wsp_); | |
132 } | |
133 | |
134 // As RegAliasesMatch, but for floating-point registers. | |
135 bool FPRegAliasesMatch(unsigned code) const { | |
136 ASSERT(IsComplete()); | |
137 ASSERT(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_A64_TEST_UTILS_A64_H_ | |
OLD | NEW |