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