blob: d10461980d415271e3127923ab769639615d95e3 [file] [log] [blame]
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +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 "base/stringprintf.h"
18#include "builder.h"
19#include "dex_file.h"
20#include "dex_instruction.h"
21#include "nodes.h"
22#include "optimizing_unit_test.h"
23#include "pretty_printer.h"
24#include "ssa_builder.h"
25#include "utils/arena_allocator.h"
26
27#include "gtest/gtest.h"
28
29namespace art {
30
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010031class SsaPrettyPrinter : public HPrettyPrinter {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010032 public:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010033 explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {}
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010034
35 virtual void PrintInt(int value) {
36 str_ += StringPrintf("%d", value);
37 }
38
39 virtual void PrintString(const char* value) {
40 str_ += value;
41 }
42
43 virtual void PrintNewLine() {
44 str_ += '\n';
45 }
46
47 void Clear() { str_.clear(); }
48
49 std::string str() const { return str_; }
50
51 virtual void VisitIntConstant(HIntConstant* constant) {
52 PrintPreInstruction(constant);
53 str_ += constant->DebugName();
54 str_ += " ";
55 PrintInt(constant->GetValue());
56 PrintPostInstruction(constant);
57 }
58
59 private:
60 std::string str_;
61
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010062 DISALLOW_COPY_AND_ASSIGN(SsaPrettyPrinter);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010063};
64
65static void ReNumberInstructions(HGraph* graph) {
66 int id = 0;
Nicolas Geoffray804d0932014-05-02 08:46:00 +010067 for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
68 HBasicBlock* block = graph->GetBlocks().Get(i);
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010069 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010070 it.Current()->SetId(id++);
71 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010072 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010073 it.Current()->SetId(id++);
74 }
75 }
76}
77
78static void TestCode(const uint16_t* data, const char* expected) {
79 ArenaPool pool;
80 ArenaAllocator allocator(&pool);
81 HGraphBuilder builder(&allocator);
82 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
83 HGraph* graph = builder.BuildGraph(*item);
84 ASSERT_NE(graph, nullptr);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010085
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010086 graph->BuildDominatorTree();
87 graph->TransformToSSA();
88 ReNumberInstructions(graph);
89
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010090 SsaPrettyPrinter printer(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010091 printer.VisitInsertionOrder();
92
93 ASSERT_STREQ(expected, printer.str().c_str());
94}
95
96TEST(SsaTest, CFG1) {
97 // Test that we get rid of loads and stores.
98 const char* expected =
99 "BasicBlock 0, succ: 1\n"
100 " 0: IntConstant 0 [2, 2]\n"
101 " 1: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100102 "BasicBlock 1, pred: 0, succ: 2, 5\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100103 " 2: Equal(0, 0) [3]\n"
104 " 3: If(2)\n"
105 "BasicBlock 2, pred: 1, succ: 3\n"
106 " 4: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100107 "BasicBlock 3, pred: 2, 5, succ: 4\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100108 " 5: ReturnVoid\n"
109 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100110 " 6: Exit\n"
111 // Synthesized block to avoid critical edge.
112 "BasicBlock 5, pred: 1, succ: 3\n"
113 " 7: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100114
115 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
116 Instruction::CONST_4 | 0 | 0,
117 Instruction::IF_EQ, 3,
118 Instruction::GOTO | 0x100,
119 Instruction::RETURN_VOID);
120
121 TestCode(data, expected);
122}
123
124TEST(SsaTest, CFG2) {
125 // Test that we create a phi for the join block of an if control flow instruction
126 // when there is only code in the else branch.
127 const char* expected =
128 "BasicBlock 0, succ: 1\n"
129 " 0: IntConstant 0 [6, 3, 3]\n"
130 " 1: IntConstant 4 [6]\n"
131 " 2: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100132 "BasicBlock 1, pred: 0, succ: 2, 5\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100133 " 3: Equal(0, 0) [4]\n"
134 " 4: If(3)\n"
135 "BasicBlock 2, pred: 1, succ: 3\n"
136 " 5: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100137 "BasicBlock 3, pred: 2, 5, succ: 4\n"
138 " 6: Phi(1, 0) [7]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100139 " 7: Return(6)\n"
140 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100141 " 8: Exit\n"
142 // Synthesized block to avoid critical edge.
143 "BasicBlock 5, pred: 1, succ: 3\n"
144 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100145
146 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
147 Instruction::CONST_4 | 0 | 0,
148 Instruction::IF_EQ, 3,
149 Instruction::CONST_4 | 4 << 12 | 0,
150 Instruction::RETURN | 0 << 8);
151
152 TestCode(data, expected);
153}
154
155TEST(SsaTest, CFG3) {
156 // Test that we create a phi for the join block of an if control flow instruction
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100157 // when both branches update a local.
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100158 const char* expected =
159 "BasicBlock 0, succ: 1\n"
160 " 0: IntConstant 0 [4, 4]\n"
161 " 1: IntConstant 4 [8]\n"
162 " 2: IntConstant 5 [8]\n"
163 " 3: Goto\n"
164 "BasicBlock 1, pred: 0, succ: 3, 2\n"
165 " 4: Equal(0, 0) [5]\n"
166 " 5: If(4)\n"
167 "BasicBlock 2, pred: 1, succ: 4\n"
168 " 6: Goto\n"
169 "BasicBlock 3, pred: 1, succ: 4\n"
170 " 7: Goto\n"
171 "BasicBlock 4, pred: 2, 3, succ: 5\n"
172 " 8: Phi(1, 2) [9]\n"
173 " 9: Return(8)\n"
174 "BasicBlock 5, pred: 4\n"
175 " 10: Exit\n";
176
177 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
178 Instruction::CONST_4 | 0 | 0,
179 Instruction::IF_EQ, 4,
180 Instruction::CONST_4 | 4 << 12 | 0,
181 Instruction::GOTO | 0x200,
182 Instruction::CONST_4 | 5 << 12 | 0,
183 Instruction::RETURN | 0 << 8);
184
185 TestCode(data, expected);
186}
187
188TEST(SsaTest, Loop1) {
189 // Test that we create a phi for an initialized local at entry of a loop.
190 const char* expected =
191 "BasicBlock 0, succ: 1\n"
192 " 0: IntConstant 0 [6, 4, 2, 2]\n"
193 " 1: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100194 "BasicBlock 1, pred: 0, succ: 5, 6\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100195 " 2: Equal(0, 0) [3]\n"
196 " 3: If(2)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100197 "BasicBlock 2, pred: 3, 6, succ: 3\n"
198 " 4: Phi(6, 0) [6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100199 " 5: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100200 "BasicBlock 3, pred: 2, 5, succ: 2\n"
201 " 6: Phi(4, 0) [4]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100202 " 7: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100203 "BasicBlock 4\n"
204 // Synthesized blocks to avoid critical edge.
205 "BasicBlock 5, pred: 1, succ: 3\n"
206 " 8: Goto\n"
207 "BasicBlock 6, pred: 1, succ: 2\n"
208 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100209
210 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
211 Instruction::CONST_4 | 0 | 0,
212 Instruction::IF_EQ, 3,
213 Instruction::GOTO | 0x100,
214 Instruction::GOTO | 0xFF00);
215
216 TestCode(data, expected);
217}
218
219TEST(SsaTest, Loop2) {
220 // Simple loop with one preheader and one back edge.
221 const char* expected =
222 "BasicBlock 0, succ: 1\n"
223 " 0: IntConstant 0 [4]\n"
224 " 1: IntConstant 4 [4]\n"
225 " 2: Goto\n"
226 "BasicBlock 1, pred: 0, succ: 2\n"
227 " 3: Goto\n"
228 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
229 " 4: Phi(0, 1) [5, 5]\n"
230 " 5: Equal(4, 4) [6]\n"
231 " 6: If(5)\n"
232 "BasicBlock 3, pred: 2, succ: 2\n"
233 " 7: Goto\n"
234 "BasicBlock 4, pred: 2, succ: 5\n"
235 " 8: ReturnVoid\n"
236 "BasicBlock 5, pred: 4\n"
237 " 9: Exit\n";
238
239 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
240 Instruction::CONST_4 | 0 | 0,
241 Instruction::IF_EQ, 4,
242 Instruction::CONST_4 | 4 << 12 | 0,
243 Instruction::GOTO | 0xFD00,
244 Instruction::RETURN_VOID);
245
246 TestCode(data, expected);
247}
248
249TEST(SsaTest, Loop3) {
250 // Test that a local not yet defined at the entry of a loop is handled properly.
251 const char* expected =
252 "BasicBlock 0, succ: 1\n"
253 " 0: IntConstant 0 [5]\n"
254 " 1: IntConstant 4 [5]\n"
255 " 2: IntConstant 5 [9]\n"
256 " 3: Goto\n"
257 "BasicBlock 1, pred: 0, succ: 2\n"
258 " 4: Goto\n"
259 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
260 " 5: Phi(0, 1) [6, 6]\n"
261 " 6: Equal(5, 5) [7]\n"
262 " 7: If(6)\n"
263 "BasicBlock 3, pred: 2, succ: 2\n"
264 " 8: Goto\n"
265 "BasicBlock 4, pred: 2, succ: 5\n"
266 " 9: Return(2)\n"
267 "BasicBlock 5, pred: 4\n"
268 " 10: Exit\n";
269
270 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
271 Instruction::CONST_4 | 0 | 0,
272 Instruction::IF_EQ, 4,
273 Instruction::CONST_4 | 4 << 12 | 0,
274 Instruction::GOTO | 0xFD00,
275 Instruction::CONST_4 | 5 << 12 | 1 << 8,
276 Instruction::RETURN | 1 << 8);
277
278 TestCode(data, expected);
279}
280
281TEST(SsaTest, Loop4) {
282 // Make sure we support a preheader of a loop not being the first predecessor
283 // in the predecessor list of the header.
284 const char* expected =
285 "BasicBlock 0, succ: 1\n"
286 " 0: IntConstant 0 [4]\n"
287 " 1: IntConstant 4 [4]\n"
288 " 2: Goto\n"
289 "BasicBlock 1, pred: 0, succ: 4\n"
290 " 3: Goto\n"
291 "BasicBlock 2, pred: 3, 4, succ: 5, 3\n"
292 " 4: Phi(1, 0) [9, 5, 5]\n"
293 " 5: Equal(4, 4) [6]\n"
294 " 6: If(5)\n"
295 "BasicBlock 3, pred: 2, succ: 2\n"
296 " 7: Goto\n"
297 "BasicBlock 4, pred: 1, succ: 2\n"
298 " 8: Goto\n"
299 "BasicBlock 5, pred: 2, succ: 6\n"
300 " 9: Return(4)\n"
301 "BasicBlock 6, pred: 5\n"
302 " 10: Exit\n";
303
304 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
305 Instruction::CONST_4 | 0 | 0,
306 Instruction::GOTO | 0x500,
307 Instruction::IF_EQ, 5,
308 Instruction::CONST_4 | 4 << 12 | 0,
309 Instruction::GOTO | 0xFD00,
310 Instruction::GOTO | 0xFC00,
311 Instruction::RETURN | 0 << 8);
312
313 TestCode(data, expected);
314}
315
316TEST(SsaTest, Loop5) {
317 // Make sure we create a preheader of a loop when a header originally has two
318 // incoming blocks and one back edge.
319 const char* expected =
320 "BasicBlock 0, succ: 1\n"
321 " 0: IntConstant 0 [4, 4]\n"
322 " 1: IntConstant 4 [14]\n"
323 " 2: IntConstant 5 [14]\n"
324 " 3: Goto\n"
325 "BasicBlock 1, pred: 0, succ: 3, 2\n"
326 " 4: Equal(0, 0) [5]\n"
327 " 5: If(4)\n"
328 "BasicBlock 2, pred: 1, succ: 8\n"
329 " 6: Goto\n"
330 "BasicBlock 3, pred: 1, succ: 8\n"
331 " 7: Goto\n"
332 "BasicBlock 4, pred: 5, 8, succ: 6, 5\n"
333 " 8: Phi(8, 14) [8, 12, 9, 9]\n"
334 " 9: Equal(8, 8) [10]\n"
335 " 10: If(9)\n"
336 "BasicBlock 5, pred: 4, succ: 4\n"
337 " 11: Goto\n"
338 "BasicBlock 6, pred: 4, succ: 7\n"
339 " 12: Return(8)\n"
340 "BasicBlock 7, pred: 6\n"
341 " 13: Exit\n"
342 "BasicBlock 8, pred: 2, 3, succ: 4\n"
343 " 14: Phi(1, 2) [8]\n"
344 " 15: Goto\n";
345
346 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
347 Instruction::CONST_4 | 0 | 0,
348 Instruction::IF_EQ, 4,
349 Instruction::CONST_4 | 4 << 12 | 0,
350 Instruction::GOTO | 0x200,
351 Instruction::CONST_4 | 5 << 12 | 0,
352 Instruction::IF_EQ, 3,
353 Instruction::GOTO | 0xFE00,
354 Instruction::RETURN | 0 << 8);
355
356 TestCode(data, expected);
357}
358
359TEST(SsaTest, Loop6) {
360 // Test a loop with one preheader and two back edges (e.g. continue).
361 const char* expected =
362 "BasicBlock 0, succ: 1\n"
363 " 0: IntConstant 0 [5]\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100364 " 1: IntConstant 4 [14, 8, 8]\n"
365 " 2: IntConstant 5 [14]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100366 " 3: Goto\n"
367 "BasicBlock 1, pred: 0, succ: 2\n"
368 " 4: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100369 "BasicBlock 2, pred: 1, 8, succ: 6, 3\n"
370 " 5: Phi(0, 14) [12, 6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100371 " 6: Equal(5, 5) [7]\n"
372 " 7: If(6)\n"
373 "BasicBlock 3, pred: 2, succ: 5, 4\n"
374 " 8: Equal(1, 1) [9]\n"
375 " 9: If(8)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100376 "BasicBlock 4, pred: 3, succ: 8\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100377 " 10: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100378 "BasicBlock 5, pred: 3, succ: 8\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100379 " 11: Goto\n"
380 "BasicBlock 6, pred: 2, succ: 7\n"
381 " 12: Return(5)\n"
382 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100383 " 13: Exit\n"
384 // Synthesized single back edge of loop.
385 "BasicBlock 8, pred: 5, 4, succ: 2\n"
386 " 14: Phi(1, 2) [5]\n"
387 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100388
389 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
390 Instruction::CONST_4 | 0 | 0,
391 Instruction::IF_EQ, 8,
392 Instruction::CONST_4 | 4 << 12 | 0,
393 Instruction::IF_EQ, 4,
394 Instruction::CONST_4 | 5 << 12 | 0,
395 Instruction::GOTO | 0xFA00,
396 Instruction::GOTO | 0xF900,
397 Instruction::RETURN | 0 << 8);
398
399 TestCode(data, expected);
400}
401
402TEST(SsaTest, Loop7) {
403 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break).
404 const char* expected =
405 "BasicBlock 0, succ: 1\n"
406 " 0: IntConstant 0 [5]\n"
407 " 1: IntConstant 4 [5, 8, 8]\n"
408 " 2: IntConstant 5 [12]\n"
409 " 3: Goto\n"
410 "BasicBlock 1, pred: 0, succ: 2\n"
411 " 4: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100412 "BasicBlock 2, pred: 1, 5, succ: 3, 8\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100413 " 5: Phi(0, 1) [12, 6, 6]\n"
414 " 6: Equal(5, 5) [7]\n"
415 " 7: If(6)\n"
416 "BasicBlock 3, pred: 2, succ: 5, 4\n"
417 " 8: Equal(1, 1) [9]\n"
418 " 9: If(8)\n"
419 "BasicBlock 4, pred: 3, succ: 6\n"
420 " 10: Goto\n"
421 "BasicBlock 5, pred: 3, succ: 2\n"
422 " 11: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100423 "BasicBlock 6, pred: 4, 8, succ: 7\n"
424 " 12: Phi(2, 5) [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100425 " 13: Return(12)\n"
426 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100427 " 14: Exit\n"
428 "BasicBlock 8, pred: 2, succ: 6\n"
429 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100430
431 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
432 Instruction::CONST_4 | 0 | 0,
433 Instruction::IF_EQ, 8,
434 Instruction::CONST_4 | 4 << 12 | 0,
435 Instruction::IF_EQ, 4,
436 Instruction::CONST_4 | 5 << 12 | 0,
437 Instruction::GOTO | 0x0200,
438 Instruction::GOTO | 0xF900,
439 Instruction::RETURN | 0 << 8);
440
441 TestCode(data, expected);
442}
443
444TEST(SsaTest, DeadLocal) {
445 // Test that we correctly handle a local not being used.
446 const char* expected =
447 "BasicBlock 0, succ: 1\n"
448 " 0: IntConstant 0\n"
449 " 1: Goto\n"
450 "BasicBlock 1, pred: 0, succ: 2\n"
451 " 2: ReturnVoid\n"
452 "BasicBlock 2, pred: 1\n"
453 " 3: Exit\n";
454
455 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
456 Instruction::CONST_4 | 0 | 0,
457 Instruction::RETURN_VOID);
458
459 TestCode(data, expected);
460}
461
462} // namespace art