1// Copyright 2016, VIXL authors
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#include <stdlib.h>
28
29#include "test-runner.h"
30
31#ifdef VIXL_INCLUDE_TARGET_AARCH32
32#include "aarch32/macro-assembler-aarch32.h"
33#endif
34
35#ifdef VIXL_INCLUDE_TARGET_AARCH64
36#include "aarch64/macro-assembler-aarch64.h"
37#endif
38
39#define STRINGIFY(x) #x
40
41#define TEST_AARCH32(Name)                                                \
42  namespace aarch32 {                                                     \
43  void Test_##Name##_AArch32_Impl();                                      \
44  }                                                                       \
45  void Test_##Name##_AArch32() { aarch32::Test_##Name##_AArch32_Impl(); } \
46  Test test_##Name##_AArch32(STRINGIFY(AARCH32_SCRATCH_##Name),           \
47                             &Test_##Name##_AArch32);                     \
48  void aarch32::Test_##Name##_AArch32_Impl()
49
50#define TEST_AARCH64(Name)                                                \
51  namespace aarch64 {                                                     \
52  void Test_##Name##_AArch64_Impl();                                      \
53  }                                                                       \
54  void Test_##Name##_AArch64() { aarch64::Test_##Name##_AArch64_Impl(); } \
55  Test test_##Name##_AArch64(STRINGIFY(AARCH64_SCRATCH_##Name),           \
56                             &Test_##Name##_AArch64);                     \
57  void aarch64::Test_##Name##_AArch64_Impl()
58
59#define SETUP() MacroAssembler masm
60
61#define __ masm.
62
63namespace vixl {
64
65// UseScratchRegisterScopes must be able to nest perfectly. That is, they may
66// nest, but nested scopes must not outlive less-nested scopes.
67template <typename MacroAssembler, typename UseScratchRegisterScope>
68class PerfectNestingTestHelper {
69 public:
70  explicit PerfectNestingTestHelper(MacroAssembler* masm) : masm_(masm) {
71    uint16_t seed[3] = {4, 5, 6};
72    seed48(seed);
73  }
74  void Run() {
75    UseScratchRegisterScope* top_scope =
76        masm_->GetCurrentScratchRegisterScope();
77    int descendents = 0;
78    while (descendents < kMinimumDescendentScopeCount) descendents += Run(0);
79    VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == top_scope);
80  }
81
82 private:
83  int Run(int depth) {
84    // As the depth increases, the probability of recursion decreases.
85    // At depth = kDepthLimit, we never recurse.
86    int max_children = static_cast<int>(std::abs(mrand48()) % kDepthLimit);
87    int children = std::max(0, max_children - depth);
88    int descendents = children;
89    while (children-- > 0) {
90      UseScratchRegisterScope scope(masm_);
91      VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == &scope);
92      descendents += Run(depth + 1);
93      VIXL_CHECK(masm_->GetCurrentScratchRegisterScope() == &scope);
94    }
95    return descendents;
96  }
97
98  MacroAssembler* masm_;
99  static const int kDepthLimit = 12;
100  static const int kMinimumDescendentScopeCount = 10000;
101};
102
103#ifdef VIXL_INCLUDE_TARGET_AARCH32
104TEST_AARCH32(perfect_nesting) {
105  SETUP();
106  PerfectNestingTestHelper<MacroAssembler, UseScratchRegisterScope>(&masm)
107      .Run();
108}
109#endif  // VIXL_INCLUDE_TARGET_AARCH32
110
111#ifdef VIXL_INCLUDE_TARGET_AARCH64
112TEST_AARCH64(perfect_nesting) {
113  SETUP();
114  PerfectNestingTestHelper<MacroAssembler, UseScratchRegisterScope>(&masm)
115      .Run();
116}
117#endif  // VIXL_INCLUDE_TARGET_AARCH64
118
119
120#ifdef VIXL_INCLUDE_TARGET_AARCH32
121TEST_AARCH32(v_registers) {
122  SETUP();
123  {
124    UseScratchRegisterScope temps(&masm);
125    temps.Include(VRegisterList(q0, q1, q2, q3));
126
127    // This test assumes that low-numbered registers are allocated first. The
128    // implementation is allowed to use a different strategy; if it does, the
129    // test will need to be updated.
130    // TODO: Write more flexible (and thorough) tests.
131
132    VIXL_CHECK(q0.Is(temps.AcquireQ()));
133    VIXL_CHECK(!temps.IsAvailable(q0));
134    VIXL_CHECK(!temps.IsAvailable(d0));
135    VIXL_CHECK(!temps.IsAvailable(d1));
136    VIXL_CHECK(!temps.IsAvailable(s0));
137    VIXL_CHECK(!temps.IsAvailable(s1));
138    VIXL_CHECK(!temps.IsAvailable(s2));
139    VIXL_CHECK(!temps.IsAvailable(s3));
140
141    VIXL_CHECK(d2.Is(temps.AcquireV(64)));
142    VIXL_CHECK(!temps.IsAvailable(q1));
143    VIXL_CHECK(!temps.IsAvailable(d2));
144    VIXL_CHECK(temps.IsAvailable(d3));
145    VIXL_CHECK(!temps.IsAvailable(s4));
146    VIXL_CHECK(!temps.IsAvailable(s5));
147    VIXL_CHECK(temps.IsAvailable(s6));
148    VIXL_CHECK(temps.IsAvailable(s7));
149
150    VIXL_CHECK(s6.Is(temps.AcquireS()));
151    VIXL_CHECK(!temps.IsAvailable(d3));
152    VIXL_CHECK(!temps.IsAvailable(s6));
153    VIXL_CHECK(temps.IsAvailable(s7));
154
155    VIXL_CHECK(q2.Is(temps.AcquireV(128)));
156    VIXL_CHECK(!temps.IsAvailable(q2));
157    VIXL_CHECK(!temps.IsAvailable(d4));
158    VIXL_CHECK(!temps.IsAvailable(d5));
159    VIXL_CHECK(!temps.IsAvailable(s8));
160    VIXL_CHECK(!temps.IsAvailable(s9));
161    VIXL_CHECK(!temps.IsAvailable(s10));
162    VIXL_CHECK(!temps.IsAvailable(s11));
163    VIXL_CHECK(temps.IsAvailable(s7));
164
165    VIXL_CHECK(d6.Is(temps.AcquireD()));
166    VIXL_CHECK(!temps.IsAvailable(q3));
167    VIXL_CHECK(!temps.IsAvailable(d6));
168    VIXL_CHECK(temps.IsAvailable(d7));
169    VIXL_CHECK(!temps.IsAvailable(s12));
170    VIXL_CHECK(!temps.IsAvailable(s13));
171    VIXL_CHECK(temps.IsAvailable(s14));
172    VIXL_CHECK(temps.IsAvailable(s15));
173    VIXL_CHECK(temps.IsAvailable(s7));
174
175    VIXL_CHECK(s7.Is(temps.AcquireS()));
176  }
177}
178#endif  // VIXL_INCLUDE_TARGET_AARCH32
179
180
181#ifdef VIXL_INCLUDE_TARGET_AARCH32
182TEST_AARCH32(include_exclude) {
183  SETUP();
184  {
185    UseScratchRegisterScope temps(&masm);
186    temps.Include(r0, r1, r2, r3);
187    temps.Include(s0, s1, d1, q1);
188
189    VIXL_CHECK(temps.IsAvailable(r0));
190    VIXL_CHECK(temps.IsAvailable(r1));
191    VIXL_CHECK(temps.IsAvailable(r2));
192    VIXL_CHECK(temps.IsAvailable(r3));
193
194    VIXL_CHECK(temps.IsAvailable(s0));
195
196    VIXL_CHECK(temps.IsAvailable(s1));
197
198    VIXL_CHECK(temps.IsAvailable(d1));
199    VIXL_CHECK(temps.IsAvailable(s2));
200    VIXL_CHECK(temps.IsAvailable(s3));
201
202    VIXL_CHECK(temps.IsAvailable(q1));
203    VIXL_CHECK(temps.IsAvailable(d2));
204    VIXL_CHECK(temps.IsAvailable(d3));
205    VIXL_CHECK(temps.IsAvailable(s4));
206    VIXL_CHECK(temps.IsAvailable(s5));
207    VIXL_CHECK(temps.IsAvailable(s6));
208    VIXL_CHECK(temps.IsAvailable(s7));
209
210    // Test local exclusion.
211    {
212      UseScratchRegisterScope local_temps(&masm);
213      local_temps.Exclude(r1, r2);
214      local_temps.Exclude(s1, q1);
215
216      VIXL_CHECK(temps.IsAvailable(r0));
217      VIXL_CHECK(!temps.IsAvailable(r1));
218      VIXL_CHECK(!temps.IsAvailable(r2));
219      VIXL_CHECK(temps.IsAvailable(r3));
220
221      VIXL_CHECK(temps.IsAvailable(s0));
222
223      VIXL_CHECK(!temps.IsAvailable(s1));
224
225      VIXL_CHECK(temps.IsAvailable(d1));
226      VIXL_CHECK(temps.IsAvailable(s2));
227      VIXL_CHECK(temps.IsAvailable(s3));
228
229      VIXL_CHECK(!temps.IsAvailable(q1));
230      VIXL_CHECK(!temps.IsAvailable(d2));
231      VIXL_CHECK(!temps.IsAvailable(d3));
232      VIXL_CHECK(!temps.IsAvailable(s4));
233      VIXL_CHECK(!temps.IsAvailable(s5));
234      VIXL_CHECK(!temps.IsAvailable(s6));
235      VIXL_CHECK(!temps.IsAvailable(s7));
236    }
237
238    // This time, exclude part of included registers, making sure the entire
239    // register gets excluded.
240    {
241      UseScratchRegisterScope local_temps(&masm);
242      local_temps.Exclude(s2, d3);
243
244      VIXL_CHECK(temps.IsAvailable(r0));
245      VIXL_CHECK(temps.IsAvailable(r1));
246      VIXL_CHECK(temps.IsAvailable(r2));
247      VIXL_CHECK(temps.IsAvailable(r3));
248
249      VIXL_CHECK(temps.IsAvailable(s0));
250
251      VIXL_CHECK(temps.IsAvailable(s1));
252
253      // Excluding s2 should exclude d1 but not s3.
254      VIXL_CHECK(!temps.IsAvailable(d1));
255      VIXL_CHECK(!temps.IsAvailable(s2));
256      VIXL_CHECK(temps.IsAvailable(s3));
257
258      // Excluding d3 should exclude q1, s7 and s6 but not d2, s5, s4.
259      VIXL_CHECK(!temps.IsAvailable(q1));
260      VIXL_CHECK(temps.IsAvailable(d2));
261      VIXL_CHECK(!temps.IsAvailable(d3));
262      VIXL_CHECK(temps.IsAvailable(s4));
263      VIXL_CHECK(temps.IsAvailable(s5));
264      VIXL_CHECK(!temps.IsAvailable(s6));
265      VIXL_CHECK(!temps.IsAvailable(s7));
266    }
267
268    // Make sure the initial state was restored.
269
270    VIXL_CHECK(temps.IsAvailable(r0));
271    VIXL_CHECK(temps.IsAvailable(r1));
272    VIXL_CHECK(temps.IsAvailable(r2));
273    VIXL_CHECK(temps.IsAvailable(r3));
274
275    VIXL_CHECK(temps.IsAvailable(s0));
276
277    VIXL_CHECK(temps.IsAvailable(s1));
278
279    VIXL_CHECK(temps.IsAvailable(d1));
280    VIXL_CHECK(temps.IsAvailable(s2));
281    VIXL_CHECK(temps.IsAvailable(s3));
282
283    VIXL_CHECK(temps.IsAvailable(q1));
284    VIXL_CHECK(temps.IsAvailable(d2));
285    VIXL_CHECK(temps.IsAvailable(d3));
286    VIXL_CHECK(temps.IsAvailable(s4));
287    VIXL_CHECK(temps.IsAvailable(s5));
288    VIXL_CHECK(temps.IsAvailable(s6));
289    VIXL_CHECK(temps.IsAvailable(s7));
290  }
291}
292#endif  // VIXL_INCLUDE_TARGET_AARCH32
293
294}  // namespace vixl
295