blob: 95cca5172b89f2d77dc09ba6017b6d3b26d8834e [file] [log] [blame]
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010018#include "nodes.h"
19#include "parallel_move_resolver.h"
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010020
21#include "gtest/gtest.h"
22
23namespace art {
24
25class TestParallelMoveResolver : public ParallelMoveResolver {
26 public:
27 explicit TestParallelMoveResolver(ArenaAllocator* allocator) : ParallelMoveResolver(allocator) {}
28
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000029 void Dump(Location location) {
30 if (location.IsConstant()) {
31 message_ << "C";
32 } else if (location.IsPair()) {
33 message_ << location.low() << "," << location.high();
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +010034 } else if (location.IsRegister()) {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000035 message_ << location.reg();
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +010036 } else if (location.IsStackSlot()) {
37 message_ << location.GetStackIndex() << "(sp)";
38 } else {
39 message_ << "2x" << location.GetStackIndex() << "(sp)";
40 DCHECK(location.IsDoubleStackSlot()) << location;
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000041 }
42 }
43
Alexandre Rames2ed20af2015-03-06 13:55:35 +000044 void EmitMove(size_t index) OVERRIDE {
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010045 MoveOperands* move = moves_.Get(index);
46 if (!message_.str().empty()) {
47 message_ << " ";
48 }
Nicolas Geoffray48c310c2015-01-14 10:45:05 +000049 message_ << "(";
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000050 Dump(move->GetSource());
51 message_ << " -> ";
52 Dump(move->GetDestination());
53 message_ << ")";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010054 }
55
Alexandre Rames2ed20af2015-03-06 13:55:35 +000056 void EmitSwap(size_t index) OVERRIDE {
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010057 MoveOperands* move = moves_.Get(index);
58 if (!message_.str().empty()) {
59 message_ << " ";
60 }
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000061 message_ << "(";
62 Dump(move->GetSource());
63 message_ << " <-> ";
64 Dump(move->GetDestination());
65 message_ << ")";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010066 }
67
Alexandre Rames2ed20af2015-03-06 13:55:35 +000068 void SpillScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {}
69 void RestoreScratch(int reg ATTRIBUTE_UNUSED) OVERRIDE {}
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010070
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010071 std::string GetMessage() const {
72 return message_.str();
73 }
74
75 private:
76 std::ostringstream message_;
77
78
79 DISALLOW_COPY_AND_ASSIGN(TestParallelMoveResolver);
80};
81
82static HParallelMove* BuildParallelMove(ArenaAllocator* allocator,
83 const size_t operands[][2],
84 size_t number_of_moves) {
85 HParallelMove* moves = new (allocator) HParallelMove(allocator);
86 for (size_t i = 0; i < number_of_moves; ++i) {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000087 moves->AddMove(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +010088 Location::RegisterLocation(operands[i][0]),
89 Location::RegisterLocation(operands[i][1]),
Nicolas Geoffray90218252015-04-15 11:56:51 +010090 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +000091 nullptr);
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +010092 }
93 return moves;
94}
95
96TEST(ParallelMoveTest, Dependency) {
97 ArenaPool pool;
98 ArenaAllocator allocator(&pool);
99
100 {
101 TestParallelMoveResolver resolver(&allocator);
102 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}};
103 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
104 ASSERT_STREQ("(1 -> 2) (0 -> 1)", resolver.GetMessage().c_str());
105 }
106
107 {
108 TestParallelMoveResolver resolver(&allocator);
109 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {1, 4}};
110 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
111 ASSERT_STREQ("(2 -> 3) (1 -> 2) (1 -> 4) (0 -> 1)", resolver.GetMessage().c_str());
112 }
113}
114
115TEST(ParallelMoveTest, Swap) {
116 ArenaPool pool;
117 ArenaAllocator allocator(&pool);
118
119 {
120 TestParallelMoveResolver resolver(&allocator);
121 static constexpr size_t moves[][2] = {{0, 1}, {1, 0}};
122 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
123 ASSERT_STREQ("(1 <-> 0)", resolver.GetMessage().c_str());
124 }
125
126 {
127 TestParallelMoveResolver resolver(&allocator);
128 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {1, 0}};
129 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
130 ASSERT_STREQ("(1 -> 2) (1 <-> 0)", resolver.GetMessage().c_str());
131 }
132
133 {
134 TestParallelMoveResolver resolver(&allocator);
Nicolas Geoffray6450d142015-01-16 09:04:49 +0000135 static constexpr size_t moves[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}};
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100136 resolver.EmitNativeCode(BuildParallelMove(&allocator, moves, arraysize(moves)));
Nicolas Geoffray6450d142015-01-16 09:04:49 +0000137 ASSERT_STREQ("(4 <-> 0) (3 <-> 4) (2 <-> 3) (1 <-> 2)", resolver.GetMessage().c_str());
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100138 }
139}
140
Nicolas Geoffray48c310c2015-01-14 10:45:05 +0000141TEST(ParallelMoveTest, ConstantLast) {
142 ArenaPool pool;
143 ArenaAllocator allocator(&pool);
144 TestParallelMoveResolver resolver(&allocator);
145 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000146 moves->AddMove(
Nicolas Geoffray48c310c2015-01-14 10:45:05 +0000147 Location::ConstantLocation(new (&allocator) HIntConstant(0)),
148 Location::RegisterLocation(0),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100149 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000150 nullptr);
151 moves->AddMove(
Nicolas Geoffray48c310c2015-01-14 10:45:05 +0000152 Location::RegisterLocation(1),
153 Location::RegisterLocation(2),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100154 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000155 nullptr);
Nicolas Geoffray48c310c2015-01-14 10:45:05 +0000156 resolver.EmitNativeCode(moves);
157 ASSERT_STREQ("(1 -> 2) (C -> 0)", resolver.GetMessage().c_str());
158}
159
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000160TEST(ParallelMoveTest, Pairs) {
161 ArenaPool pool;
162 ArenaAllocator allocator(&pool);
163
164 {
165 TestParallelMoveResolver resolver(&allocator);
166 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
167 moves->AddMove(
168 Location::RegisterLocation(2),
169 Location::RegisterLocation(4),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100170 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000171 nullptr);
172 moves->AddMove(
173 Location::RegisterPairLocation(0, 1),
174 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100175 Primitive::kPrimLong,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000176 nullptr);
177 resolver.EmitNativeCode(moves);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000178 ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str());
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000179 }
180
181 {
182 TestParallelMoveResolver resolver(&allocator);
183 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
184 moves->AddMove(
185 Location::RegisterPairLocation(0, 1),
186 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100187 Primitive::kPrimLong,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000188 nullptr);
189 moves->AddMove(
190 Location::RegisterLocation(2),
191 Location::RegisterLocation(4),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100192 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000193 nullptr);
194 resolver.EmitNativeCode(moves);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000195 ASSERT_STREQ("(2 -> 4) (0,1 -> 2,3)", resolver.GetMessage().c_str());
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000196 }
197
198 {
199 TestParallelMoveResolver resolver(&allocator);
200 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
201 moves->AddMove(
202 Location::RegisterPairLocation(0, 1),
203 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100204 Primitive::kPrimLong,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000205 nullptr);
206 moves->AddMove(
207 Location::RegisterLocation(2),
208 Location::RegisterLocation(0),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100209 Primitive::kPrimInt,
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000210 nullptr);
211 resolver.EmitNativeCode(moves);
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000212 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str());
213 }
214 {
215 TestParallelMoveResolver resolver(&allocator);
216 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
217 moves->AddMove(
218 Location::RegisterLocation(2),
219 Location::RegisterLocation(7),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100220 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000221 nullptr);
222 moves->AddMove(
223 Location::RegisterLocation(7),
224 Location::RegisterLocation(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100225 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000226 nullptr);
227 moves->AddMove(
228 Location::RegisterPairLocation(0, 1),
229 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100230 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000231 nullptr);
232 resolver.EmitNativeCode(moves);
233 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str());
234 }
235 {
236 TestParallelMoveResolver resolver(&allocator);
237 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
238 moves->AddMove(
239 Location::RegisterLocation(2),
240 Location::RegisterLocation(7),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100241 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000242 nullptr);
243 moves->AddMove(
244 Location::RegisterPairLocation(0, 1),
245 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100246 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000247 nullptr);
248 moves->AddMove(
249 Location::RegisterLocation(7),
250 Location::RegisterLocation(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100251 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000252 nullptr);
253 resolver.EmitNativeCode(moves);
254 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str());
255 }
256 {
257 TestParallelMoveResolver resolver(&allocator);
258 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
259 moves->AddMove(
260 Location::RegisterPairLocation(0, 1),
261 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100262 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000263 nullptr);
264 moves->AddMove(
265 Location::RegisterLocation(2),
266 Location::RegisterLocation(7),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100267 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000268 nullptr);
269 moves->AddMove(
270 Location::RegisterLocation(7),
271 Location::RegisterLocation(1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100272 Primitive::kPrimInt,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000273 nullptr);
274 resolver.EmitNativeCode(moves);
275 ASSERT_STREQ("(0,1 <-> 2,3) (7 -> 1) (0 -> 7)", resolver.GetMessage().c_str());
276 }
277 {
278 TestParallelMoveResolver resolver(&allocator);
279 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
280 moves->AddMove(
281 Location::RegisterPairLocation(0, 1),
282 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100283 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000284 nullptr);
285 moves->AddMove(
286 Location::RegisterPairLocation(2, 3),
287 Location::RegisterPairLocation(0, 1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100288 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000289 nullptr);
290 resolver.EmitNativeCode(moves);
291 ASSERT_STREQ("(2,3 <-> 0,1)", resolver.GetMessage().c_str());
292 }
293 {
294 TestParallelMoveResolver resolver(&allocator);
295 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
296 moves->AddMove(
297 Location::RegisterPairLocation(2, 3),
298 Location::RegisterPairLocation(0, 1),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100299 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000300 nullptr);
301 moves->AddMove(
302 Location::RegisterPairLocation(0, 1),
303 Location::RegisterPairLocation(2, 3),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100304 Primitive::kPrimLong,
Nicolas Geoffrayf7a0c4e2015-02-10 17:08:47 +0000305 nullptr);
306 resolver.EmitNativeCode(moves);
307 ASSERT_STREQ("(0,1 <-> 2,3)", resolver.GetMessage().c_str());
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000308 }
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +0100309
310 {
311 // Test involving registers used in single context and pair context.
312 TestParallelMoveResolver resolver(&allocator);
313 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
314 moves->AddMove(
315 Location::RegisterLocation(10),
316 Location::RegisterLocation(5),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100317 Primitive::kPrimInt,
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +0100318 nullptr);
319 moves->AddMove(
320 Location::RegisterPairLocation(4, 5),
321 Location::DoubleStackSlot(32),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100322 Primitive::kPrimLong,
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +0100323 nullptr);
324 moves->AddMove(
325 Location::DoubleStackSlot(32),
326 Location::RegisterPairLocation(10, 11),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100327 Primitive::kPrimLong,
Nicolas Geoffraya2d15b52015-03-31 18:13:51 +0100328 nullptr);
329 resolver.EmitNativeCode(moves);
330 ASSERT_STREQ("(2x32(sp) <-> 10,11) (4,5 <-> 2x32(sp)) (4 -> 5)", resolver.GetMessage().c_str());
331 }
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +0000332}
333
Nicolas Geoffray90218252015-04-15 11:56:51 +0100334// Test that we do 64bits moves before 32bits moves.
335TEST(ParallelMoveTest, CyclesWith64BitsMoves) {
336 ArenaPool pool;
337 ArenaAllocator allocator(&pool);
338
339 {
340 TestParallelMoveResolver resolver(&allocator);
341 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
342 moves->AddMove(
343 Location::RegisterLocation(0),
344 Location::RegisterLocation(1),
345 Primitive::kPrimLong,
346 nullptr);
347 moves->AddMove(
348 Location::RegisterLocation(1),
349 Location::StackSlot(48),
350 Primitive::kPrimInt,
351 nullptr);
352 moves->AddMove(
353 Location::StackSlot(48),
354 Location::RegisterLocation(0),
355 Primitive::kPrimInt,
356 nullptr);
357 resolver.EmitNativeCode(moves);
358 ASSERT_STREQ("(0 <-> 1) (48(sp) <-> 0)", resolver.GetMessage().c_str());
359 }
360
361 {
362 TestParallelMoveResolver resolver(&allocator);
363 HParallelMove* moves = new (&allocator) HParallelMove(&allocator);
364 moves->AddMove(
365 Location::RegisterPairLocation(0, 1),
366 Location::RegisterPairLocation(2, 3),
367 Primitive::kPrimLong,
368 nullptr);
369 moves->AddMove(
370 Location::RegisterPairLocation(2, 3),
371 Location::DoubleStackSlot(32),
372 Primitive::kPrimLong,
373 nullptr);
374 moves->AddMove(
375 Location::DoubleStackSlot(32),
376 Location::RegisterPairLocation(0, 1),
377 Primitive::kPrimLong,
378 nullptr);
379 resolver.EmitNativeCode(moves);
380 ASSERT_STREQ("(2x32(sp) <-> 0,1) (2,3 <-> 2x32(sp))", resolver.GetMessage().c_str());
381 }
382}
383
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100384} // namespace art