blob: 53e7bbe4020551b365d4cc43393d17a705daaedd [file] [log] [blame]
Nicolas Geoffray804d0932014-05-02 08:46:00 +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
17#include "builder.h"
18#include "dex_file.h"
19#include "dex_instruction.h"
20#include "nodes.h"
21#include "optimizing_unit_test.h"
22#include "ssa_liveness_analysis.h"
23#include "utils/arena_allocator.h"
24
25#include "gtest/gtest.h"
26
27namespace art {
28
29static void TestCode(const uint16_t* data, const char* expected) {
30 ArenaPool pool;
31 ArenaAllocator allocator(&pool);
32 HGraphBuilder builder(&allocator);
33 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
34 HGraph* graph = builder.BuildGraph(*item);
35 ASSERT_NE(graph, nullptr);
36 graph->BuildDominatorTree();
37 graph->TransformToSSA();
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010038 graph->FindNaturalLoops();
Nicolas Geoffray804d0932014-05-02 08:46:00 +010039 SsaLivenessAnalysis liveness(*graph);
40 liveness.Analyze();
41
42 std::ostringstream buffer;
43 for (HInsertionOrderIterator it(*graph); !it.Done(); it.Advance()) {
44 HBasicBlock* block = it.Current();
45 buffer << "Block " << block->GetBlockId() << std::endl;
46 BitVector* live_in = liveness.GetLiveInSet(*block);
47 live_in->Dump(buffer, " live in: ");
48 BitVector* live_out = liveness.GetLiveOutSet(*block);
49 live_out->Dump(buffer, " live out: ");
50 BitVector* kill = liveness.GetKillSet(*block);
51 kill->Dump(buffer, " kill: ");
52 }
53 ASSERT_STREQ(expected, buffer.str().c_str());
54}
55
56TEST(LivenessTest, CFG1) {
57 const char* expected =
58 "Block 0\n"
59 " live in: ()\n"
60 " live out: ()\n"
61 " kill: ()\n"
62 "Block 1\n"
63 " live in: ()\n"
64 " live out: ()\n"
65 " kill: ()\n"
66 "Block 2\n"
67 " live in: ()\n"
68 " live out: ()\n"
69 " kill: ()\n";
70
71 // Constant is not used.
72 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
73 Instruction::CONST_4 | 0 | 0,
74 Instruction::RETURN_VOID);
75
76 TestCode(data, expected);
77}
78
79TEST(LivenessTest, CFG2) {
80 const char* expected =
81 "Block 0\n"
82 " live in: (0)\n"
83 " live out: (1)\n"
84 " kill: (1)\n"
85 "Block 1\n"
86 " live in: (1)\n"
87 " live out: (0)\n"
88 " kill: (0)\n"
89 "Block 2\n"
90 " live in: (0)\n"
91 " live out: (0)\n"
92 " kill: (0)\n";
93
94 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
95 Instruction::CONST_4 | 0 | 0,
96 Instruction::RETURN);
97
98 TestCode(data, expected);
99}
100
101TEST(LivenessTest, CFG3) {
102 const char* expected =
103 "Block 0\n" // entry block
104 " live in: (000)\n"
105 " live out: (110)\n"
106 " kill: (110)\n"
107 "Block 1\n" // block with add
108 " live in: (110)\n"
109 " live out: (001)\n"
110 " kill: (001)\n"
111 "Block 2\n" // block with return
112 " live in: (001)\n"
113 " live out: (000)\n"
114 " kill: (000)\n"
115 "Block 3\n" // exit block
116 " live in: (000)\n"
117 " live out: (000)\n"
118 " kill: (000)\n";
119
120 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
121 Instruction::CONST_4 | 3 << 12 | 0,
122 Instruction::CONST_4 | 4 << 12 | 1 << 8,
123 Instruction::ADD_INT_2ADDR | 1 << 12,
124 Instruction::GOTO | 0x100,
125 Instruction::RETURN);
126
127 TestCode(data, expected);
128}
129
130TEST(LivenessTest, CFG4) {
131 // var a;
132 // if (0 == 0) {
133 // a = 5;
134 // } else {
135 // a = 4;
136 // }
137 // return a;
138 //
139 // Bitsets are made of:
140 // (constant0, constant4, constant5, phi, equal test)
141 const char* expected =
142 "Block 0\n" // entry block
143 " live in: (00000)\n"
144 " live out: (11100)\n"
145 " kill: (11100)\n"
146 "Block 1\n" // block with if
147 " live in: (11100)\n"
148 " live out: (01100)\n"
149 " kill: (00010)\n"
150 "Block 2\n" // else block
151 " live in: (01000)\n"
152 " live out: (00000)\n"
153 " kill: (00000)\n"
154 "Block 3\n" // then block
155 " live in: (00100)\n"
156 " live out: (00000)\n"
157 " kill: (00000)\n"
158 "Block 4\n" // return block
159 " live in: (00000)\n"
160 " live out: (00000)\n"
161 " kill: (00001)\n"
162 "Block 5\n" // exit block
163 " live in: (00000)\n"
164 " live out: (00000)\n"
165 " kill: (00000)\n";
166
167 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
168 Instruction::CONST_4 | 0 | 0,
169 Instruction::IF_EQ, 4,
170 Instruction::CONST_4 | 4 << 12 | 0,
171 Instruction::GOTO | 0x200,
172 Instruction::CONST_4 | 5 << 12 | 0,
173 Instruction::RETURN | 0 << 8);
174
175 TestCode(data, expected);
176}
177
178TEST(LivenessTest, CFG5) {
179 // var a = 0;
180 // if (0 == 0) {
181 // } else {
182 // a = 4;
183 // }
184 // return a;
185 const char* expected =
186 "Block 0\n" // entry block
187 " live in: (0000)\n"
188 " live out: (1100)\n"
189 " kill: (1100)\n"
190 "Block 1\n" // block with if
191 " live in: (1100)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100192 " live out: (1100)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100193 " kill: (0010)\n"
194 "Block 2\n" // else block
195 " live in: (0100)\n"
196 " live out: (0000)\n"
197 " kill: (0000)\n"
198 "Block 3\n" // return block
199 " live in: (0000)\n"
200 " live out: (0000)\n"
201 " kill: (0001)\n"
202 "Block 4\n" // exit block
203 " live in: (0000)\n"
204 " live out: (0000)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100205 " kill: (0000)\n"
206 "Block 5\n" // block to avoid critical edge. Predecessor is 1, successor is 3.
207 " live in: (1000)\n"
208 " live out: (0000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100209 " kill: (0000)\n";
210
211 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
212 Instruction::CONST_4 | 0 | 0,
213 Instruction::IF_EQ, 3,
214 Instruction::CONST_4 | 4 << 12 | 0,
215 Instruction::RETURN | 0 << 8);
216
217 TestCode(data, expected);
218}
219
220TEST(LivenessTest, Loop1) {
221 // Simple loop with one preheader and one back edge.
222 // var a = 0;
223 // while (a == a) {
224 // a = 4;
225 // }
226 // return;
227 const char* expected =
228 "Block 0\n" // entry block
229 " live in: (0000)\n"
230 " live out: (1100)\n"
231 " kill: (1100)\n"
232 "Block 1\n" // pre header
233 " live in: (1100)\n"
234 " live out: (0100)\n"
235 " kill: (0000)\n"
236 "Block 2\n" // loop header
237 " live in: (0100)\n"
238 " live out: (0100)\n"
239 " kill: (0011)\n"
240 "Block 3\n" // back edge
241 " live in: (0100)\n"
242 " live out: (0100)\n"
243 " kill: (0000)\n"
244 "Block 4\n" // return block
245 " live in: (0000)\n"
246 " live out: (0000)\n"
247 " kill: (0000)\n"
248 "Block 5\n" // exit block
249 " live in: (0000)\n"
250 " live out: (0000)\n"
251 " kill: (0000)\n";
252
253
254 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
255 Instruction::CONST_4 | 0 | 0,
256 Instruction::IF_EQ, 4,
257 Instruction::CONST_4 | 4 << 12 | 0,
258 Instruction::GOTO | 0xFD00,
259 Instruction::RETURN_VOID);
260
261 TestCode(data, expected);
262}
263
264TEST(LivenessTest, Loop3) {
265 // Test that the returned value stays live in a preceding loop.
266 // var a = 0;
267 // while (a == a) {
268 // a = 4;
269 // }
270 // return 5;
271 const char* expected =
272 "Block 0\n"
273 " live in: (00000)\n"
274 " live out: (11100)\n"
275 " kill: (11100)\n"
276 "Block 1\n"
277 " live in: (11100)\n"
278 " live out: (01100)\n"
279 " kill: (00000)\n"
280 "Block 2\n" // loop header
281 " live in: (01100)\n"
282 " live out: (01100)\n"
283 " kill: (00011)\n"
284 "Block 3\n" // back edge
285 " live in: (01100)\n"
286 " live out: (01100)\n"
287 " kill: (00000)\n"
288 "Block 4\n" // return block
289 " live in: (00100)\n"
290 " live out: (00000)\n"
291 " kill: (00000)\n"
292 "Block 5\n" // exit block
293 " live in: (00000)\n"
294 " live out: (00000)\n"
295 " kill: (00000)\n";
296
297 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
298 Instruction::CONST_4 | 0 | 0,
299 Instruction::IF_EQ, 4,
300 Instruction::CONST_4 | 4 << 12 | 0,
301 Instruction::GOTO | 0xFD00,
302 Instruction::CONST_4 | 5 << 12 | 1 << 8,
303 Instruction::RETURN | 1 << 8);
304
305 TestCode(data, expected);
306}
307
308
309TEST(LivenessTest, Loop4) {
310 // Make sure we support a preheader of a loop not being the first predecessor
311 // in the predecessor list of the header.
312 // var a = 0;
313 // while (a == a) {
314 // a = 4;
315 // }
316 // return a;
317 // Bitsets are made of:
318 // (constant0, constant4, phi, equal test)
319 const char* expected =
320 "Block 0\n"
321 " live in: (0000)\n"
322 " live out: (1100)\n"
323 " kill: (1100)\n"
324 "Block 1\n"
325 " live in: (1100)\n"
326 " live out: (1100)\n"
327 " kill: (0000)\n"
328 "Block 2\n" // loop header
329 " live in: (0100)\n"
330 " live out: (0110)\n"
331 " kill: (0011)\n"
332 "Block 3\n" // back edge
333 " live in: (0100)\n"
334 " live out: (0100)\n"
335 " kill: (0000)\n"
336 "Block 4\n" // pre loop header
337 " live in: (1100)\n"
338 " live out: (0100)\n"
339 " kill: (0000)\n"
340 "Block 5\n" // return block
341 " live in: (0010)\n"
342 " live out: (0000)\n"
343 " kill: (0000)\n"
344 "Block 6\n" // exit block
345 " live in: (0000)\n"
346 " live out: (0000)\n"
347 " kill: (0000)\n";
348
349 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
350 Instruction::CONST_4 | 0 | 0,
351 Instruction::GOTO | 0x500,
352 Instruction::IF_EQ, 5,
353 Instruction::CONST_4 | 4 << 12 | 0,
354 Instruction::GOTO | 0xFD00,
355 Instruction::GOTO | 0xFC00,
356 Instruction::RETURN | 0 << 8);
357
358 TestCode(data, expected);
359}
360
361TEST(LivenessTest, Loop5) {
362 // Make sure we create a preheader of a loop when a header originally has two
363 // incoming blocks and one back edge.
364 // Bitsets are made of:
365 // (constant0, constant4, constant5, equal in block 1, phi in block 8, phi in block 4,
366 // equal in block 4)
367 const char* expected =
368 "Block 0\n"
369 " live in: (0000000)\n"
370 " live out: (1110000)\n"
371 " kill: (1110000)\n"
372 "Block 1\n"
373 " live in: (1110000)\n"
374 " live out: (0110000)\n"
375 " kill: (0001000)\n"
376 "Block 2\n"
377 " live in: (0100000)\n"
378 " live out: (0000000)\n"
379 " kill: (0000000)\n"
380 "Block 3\n"
381 " live in: (0010000)\n"
382 " live out: (0000000)\n"
383 " kill: (0000000)\n"
384 "Block 4\n" // loop header
385 " live in: (0000000)\n"
386 " live out: (0000010)\n"
387 " kill: (0000011)\n"
388 "Block 5\n" // back edge
389 " live in: (0000010)\n"
390 " live out: (0000000)\n"
391 " kill: (0000000)\n"
392 "Block 6\n" // return block
393 " live in: (0000010)\n"
394 " live out: (0000000)\n"
395 " kill: (0000000)\n"
396 "Block 7\n" // exit block
397 " live in: (0000000)\n"
398 " live out: (0000000)\n"
399 " kill: (0000000)\n"
400 "Block 8\n" // synthesized pre header
401 " live in: (0000000)\n"
402 " live out: (0000000)\n"
403 " kill: (0000100)\n";
404
405 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
406 Instruction::CONST_4 | 0 | 0,
407 Instruction::IF_EQ, 4,
408 Instruction::CONST_4 | 4 << 12 | 0,
409 Instruction::GOTO | 0x200,
410 Instruction::CONST_4 | 5 << 12 | 0,
411 Instruction::IF_EQ, 3,
412 Instruction::GOTO | 0xFE00,
413 Instruction::RETURN | 0 << 8);
414
415 TestCode(data, expected);
416}
417
418TEST(LivenessTest, Loop6) {
419 // Bitsets are made of:
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100420 // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3,
421 // phi in block 8)
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100422 const char* expected =
423 "Block 0\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100424 " live in: (0000000)\n"
425 " live out: (1110000)\n"
426 " kill: (1110000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100427 "Block 1\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100428 " live in: (1110000)\n"
429 " live out: (0110000)\n"
430 " kill: (0000000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100431 "Block 2\n" // loop header
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100432 " live in: (0110000)\n"
433 " live out: (0111000)\n"
434 " kill: (0001100)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100435 "Block 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100436 " live in: (0110000)\n"
437 " live out: (0110000)\n"
438 " kill: (0000010)\n"
439 "Block 4\n" // original back edge
440 " live in: (0110000)\n"
441 " live out: (0110000)\n"
442 " kill: (0000000)\n"
443 "Block 5\n" // original back edge
444 " live in: (0110000)\n"
445 " live out: (0110000)\n"
446 " kill: (0000000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100447 "Block 6\n" // return block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100448 " live in: (0001000)\n"
449 " live out: (0000000)\n"
450 " kill: (0000000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100451 "Block 7\n" // exit block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100452 " live in: (0000000)\n"
453 " live out: (0000000)\n"
454 " kill: (0000000)\n"
455 "Block 8\n" // synthesized back edge
456 " live in: (0110000)\n"
457 " live out: (0110000)\n"
458 " kill: (0000001)\n";
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100459
460 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
461 Instruction::CONST_4 | 0 | 0,
462 Instruction::IF_EQ, 8,
463 Instruction::CONST_4 | 4 << 12 | 0,
464 Instruction::IF_EQ, 4,
465 Instruction::CONST_4 | 5 << 12 | 0,
466 Instruction::GOTO | 0xFA00,
467 Instruction::GOTO | 0xF900,
468 Instruction::RETURN | 0 << 8);
469
470 TestCode(data, expected);
471}
472
473
474TEST(LivenessTest, Loop7) {
475 // Bitsets are made of:
476 // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3,
477 // phi in block 6)
478 const char* expected =
479 "Block 0\n"
480 " live in: (0000000)\n"
481 " live out: (1110000)\n"
482 " kill: (1110000)\n"
483 "Block 1\n"
484 " live in: (1110000)\n"
485 " live out: (0110000)\n"
486 " kill: (0000000)\n"
487 "Block 2\n" // loop header
488 " live in: (0110000)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100489 " live out: (0111000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100490 " kill: (0001100)\n"
491 "Block 3\n"
492 " live in: (0110000)\n"
493 " live out: (0110000)\n"
494 " kill: (0000010)\n"
495 "Block 4\n" // loop exit
496 " live in: (0010000)\n"
497 " live out: (0000000)\n"
498 " kill: (0000000)\n"
499 "Block 5\n" // back edge
500 " live in: (0110000)\n"
501 " live out: (0110000)\n"
502 " kill: (0000000)\n"
503 "Block 6\n" // return block
504 " live in: (0000000)\n"
505 " live out: (0000000)\n"
506 " kill: (0000001)\n"
507 "Block 7\n" // exit block
508 " live in: (0000000)\n"
509 " live out: (0000000)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100510 " kill: (0000000)\n"
511 "Block 8\n" // synthesized block to avoid critical edge.
512 " live in: (0001000)\n"
513 " live out: (0000000)\n"
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100514 " kill: (0000000)\n";
515
516 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
517 Instruction::CONST_4 | 0 | 0,
518 Instruction::IF_EQ, 8,
519 Instruction::CONST_4 | 4 << 12 | 0,
520 Instruction::IF_EQ, 4,
521 Instruction::CONST_4 | 5 << 12 | 0,
522 Instruction::GOTO | 0x0200,
523 Instruction::GOTO | 0xF900,
524 Instruction::RETURN | 0 << 8);
525
526 TestCode(data, expected);
527}
528
529} // namespace art