blob: aa4d35e92c362cc3f1356539ba8ebe474a532b0e [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"
191 " live out: (0100)\n"
192 " 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"
204 " kill: (0000)\n";
205
206 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
207 Instruction::CONST_4 | 0 | 0,
208 Instruction::IF_EQ, 3,
209 Instruction::CONST_4 | 4 << 12 | 0,
210 Instruction::RETURN | 0 << 8);
211
212 TestCode(data, expected);
213}
214
215TEST(LivenessTest, Loop1) {
216 // Simple loop with one preheader and one back edge.
217 // var a = 0;
218 // while (a == a) {
219 // a = 4;
220 // }
221 // return;
222 const char* expected =
223 "Block 0\n" // entry block
224 " live in: (0000)\n"
225 " live out: (1100)\n"
226 " kill: (1100)\n"
227 "Block 1\n" // pre header
228 " live in: (1100)\n"
229 " live out: (0100)\n"
230 " kill: (0000)\n"
231 "Block 2\n" // loop header
232 " live in: (0100)\n"
233 " live out: (0100)\n"
234 " kill: (0011)\n"
235 "Block 3\n" // back edge
236 " live in: (0100)\n"
237 " live out: (0100)\n"
238 " kill: (0000)\n"
239 "Block 4\n" // return block
240 " live in: (0000)\n"
241 " live out: (0000)\n"
242 " kill: (0000)\n"
243 "Block 5\n" // exit block
244 " live in: (0000)\n"
245 " live out: (0000)\n"
246 " kill: (0000)\n";
247
248
249 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
250 Instruction::CONST_4 | 0 | 0,
251 Instruction::IF_EQ, 4,
252 Instruction::CONST_4 | 4 << 12 | 0,
253 Instruction::GOTO | 0xFD00,
254 Instruction::RETURN_VOID);
255
256 TestCode(data, expected);
257}
258
259TEST(LivenessTest, Loop3) {
260 // Test that the returned value stays live in a preceding loop.
261 // var a = 0;
262 // while (a == a) {
263 // a = 4;
264 // }
265 // return 5;
266 const char* expected =
267 "Block 0\n"
268 " live in: (00000)\n"
269 " live out: (11100)\n"
270 " kill: (11100)\n"
271 "Block 1\n"
272 " live in: (11100)\n"
273 " live out: (01100)\n"
274 " kill: (00000)\n"
275 "Block 2\n" // loop header
276 " live in: (01100)\n"
277 " live out: (01100)\n"
278 " kill: (00011)\n"
279 "Block 3\n" // back edge
280 " live in: (01100)\n"
281 " live out: (01100)\n"
282 " kill: (00000)\n"
283 "Block 4\n" // return block
284 " live in: (00100)\n"
285 " live out: (00000)\n"
286 " kill: (00000)\n"
287 "Block 5\n" // exit block
288 " live in: (00000)\n"
289 " live out: (00000)\n"
290 " kill: (00000)\n";
291
292 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
293 Instruction::CONST_4 | 0 | 0,
294 Instruction::IF_EQ, 4,
295 Instruction::CONST_4 | 4 << 12 | 0,
296 Instruction::GOTO | 0xFD00,
297 Instruction::CONST_4 | 5 << 12 | 1 << 8,
298 Instruction::RETURN | 1 << 8);
299
300 TestCode(data, expected);
301}
302
303
304TEST(LivenessTest, Loop4) {
305 // Make sure we support a preheader of a loop not being the first predecessor
306 // in the predecessor list of the header.
307 // var a = 0;
308 // while (a == a) {
309 // a = 4;
310 // }
311 // return a;
312 // Bitsets are made of:
313 // (constant0, constant4, phi, equal test)
314 const char* expected =
315 "Block 0\n"
316 " live in: (0000)\n"
317 " live out: (1100)\n"
318 " kill: (1100)\n"
319 "Block 1\n"
320 " live in: (1100)\n"
321 " live out: (1100)\n"
322 " kill: (0000)\n"
323 "Block 2\n" // loop header
324 " live in: (0100)\n"
325 " live out: (0110)\n"
326 " kill: (0011)\n"
327 "Block 3\n" // back edge
328 " live in: (0100)\n"
329 " live out: (0100)\n"
330 " kill: (0000)\n"
331 "Block 4\n" // pre loop header
332 " live in: (1100)\n"
333 " live out: (0100)\n"
334 " kill: (0000)\n"
335 "Block 5\n" // return block
336 " live in: (0010)\n"
337 " live out: (0000)\n"
338 " kill: (0000)\n"
339 "Block 6\n" // exit block
340 " live in: (0000)\n"
341 " live out: (0000)\n"
342 " kill: (0000)\n";
343
344 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
345 Instruction::CONST_4 | 0 | 0,
346 Instruction::GOTO | 0x500,
347 Instruction::IF_EQ, 5,
348 Instruction::CONST_4 | 4 << 12 | 0,
349 Instruction::GOTO | 0xFD00,
350 Instruction::GOTO | 0xFC00,
351 Instruction::RETURN | 0 << 8);
352
353 TestCode(data, expected);
354}
355
356TEST(LivenessTest, Loop5) {
357 // Make sure we create a preheader of a loop when a header originally has two
358 // incoming blocks and one back edge.
359 // Bitsets are made of:
360 // (constant0, constant4, constant5, equal in block 1, phi in block 8, phi in block 4,
361 // equal in block 4)
362 const char* expected =
363 "Block 0\n"
364 " live in: (0000000)\n"
365 " live out: (1110000)\n"
366 " kill: (1110000)\n"
367 "Block 1\n"
368 " live in: (1110000)\n"
369 " live out: (0110000)\n"
370 " kill: (0001000)\n"
371 "Block 2\n"
372 " live in: (0100000)\n"
373 " live out: (0000000)\n"
374 " kill: (0000000)\n"
375 "Block 3\n"
376 " live in: (0010000)\n"
377 " live out: (0000000)\n"
378 " kill: (0000000)\n"
379 "Block 4\n" // loop header
380 " live in: (0000000)\n"
381 " live out: (0000010)\n"
382 " kill: (0000011)\n"
383 "Block 5\n" // back edge
384 " live in: (0000010)\n"
385 " live out: (0000000)\n"
386 " kill: (0000000)\n"
387 "Block 6\n" // return block
388 " live in: (0000010)\n"
389 " live out: (0000000)\n"
390 " kill: (0000000)\n"
391 "Block 7\n" // exit block
392 " live in: (0000000)\n"
393 " live out: (0000000)\n"
394 " kill: (0000000)\n"
395 "Block 8\n" // synthesized pre header
396 " live in: (0000000)\n"
397 " live out: (0000000)\n"
398 " kill: (0000100)\n";
399
400 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
401 Instruction::CONST_4 | 0 | 0,
402 Instruction::IF_EQ, 4,
403 Instruction::CONST_4 | 4 << 12 | 0,
404 Instruction::GOTO | 0x200,
405 Instruction::CONST_4 | 5 << 12 | 0,
406 Instruction::IF_EQ, 3,
407 Instruction::GOTO | 0xFE00,
408 Instruction::RETURN | 0 << 8);
409
410 TestCode(data, expected);
411}
412
413TEST(LivenessTest, Loop6) {
414 // Bitsets are made of:
415 // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3)
416 const char* expected =
417 "Block 0\n"
418 " live in: (000000)\n"
419 " live out: (111000)\n"
420 " kill: (111000)\n"
421 "Block 1\n"
422 " live in: (111000)\n"
423 " live out: (011000)\n"
424 " kill: (000000)\n"
425 "Block 2\n" // loop header
426 " live in: (011000)\n"
427 " live out: (011100)\n"
428 " kill: (000110)\n"
429 "Block 3\n"
430 " live in: (011000)\n"
431 " live out: (011000)\n"
432 " kill: (000001)\n"
433 "Block 4\n" // back edge
434 " live in: (011000)\n"
435 " live out: (011000)\n"
436 " kill: (000000)\n"
437 "Block 5\n" // back edge
438 " live in: (011000)\n"
439 " live out: (011000)\n"
440 " kill: (000000)\n"
441 "Block 6\n" // return block
442 " live in: (000100)\n"
443 " live out: (000000)\n"
444 " kill: (000000)\n"
445 "Block 7\n" // exit block
446 " live in: (000000)\n"
447 " live out: (000000)\n"
448 " kill: (000000)\n";
449
450 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
451 Instruction::CONST_4 | 0 | 0,
452 Instruction::IF_EQ, 8,
453 Instruction::CONST_4 | 4 << 12 | 0,
454 Instruction::IF_EQ, 4,
455 Instruction::CONST_4 | 5 << 12 | 0,
456 Instruction::GOTO | 0xFA00,
457 Instruction::GOTO | 0xF900,
458 Instruction::RETURN | 0 << 8);
459
460 TestCode(data, expected);
461}
462
463
464TEST(LivenessTest, Loop7) {
465 // Bitsets are made of:
466 // (constant0, constant4, constant5, phi in block 2, equal in block 2, equal in block 3,
467 // phi in block 6)
468 const char* expected =
469 "Block 0\n"
470 " live in: (0000000)\n"
471 " live out: (1110000)\n"
472 " kill: (1110000)\n"
473 "Block 1\n"
474 " live in: (1110000)\n"
475 " live out: (0110000)\n"
476 " kill: (0000000)\n"
477 "Block 2\n" // loop header
478 " live in: (0110000)\n"
479 " live out: (0110000)\n"
480 " kill: (0001100)\n"
481 "Block 3\n"
482 " live in: (0110000)\n"
483 " live out: (0110000)\n"
484 " kill: (0000010)\n"
485 "Block 4\n" // loop exit
486 " live in: (0010000)\n"
487 " live out: (0000000)\n"
488 " kill: (0000000)\n"
489 "Block 5\n" // back edge
490 " live in: (0110000)\n"
491 " live out: (0110000)\n"
492 " kill: (0000000)\n"
493 "Block 6\n" // return block
494 " live in: (0000000)\n"
495 " live out: (0000000)\n"
496 " kill: (0000001)\n"
497 "Block 7\n" // exit block
498 " live in: (0000000)\n"
499 " live out: (0000000)\n"
500 " kill: (0000000)\n";
501
502 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
503 Instruction::CONST_4 | 0 | 0,
504 Instruction::IF_EQ, 8,
505 Instruction::CONST_4 | 4 << 12 | 0,
506 Instruction::IF_EQ, 4,
507 Instruction::CONST_4 | 5 << 12 | 0,
508 Instruction::GOTO | 0x0200,
509 Instruction::GOTO | 0xF900,
510 Instruction::RETURN | 0 << 8);
511
512 TestCode(data, expected);
513}
514
515} // namespace art