blob: 00c241b85ab600fe66f659046d5ac12591b089db [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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010018#include "base/stringprintf.h"
19#include "builder.h"
20#include "dex_file.h"
21#include "dex_instruction.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24#include "pretty_printer.h"
25#include "ssa_builder.h"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010026
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
Alexandre Rames2ed20af2015-03-06 13:55:35 +000035 void PrintInt(int value) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010036 str_ += StringPrintf("%d", value);
37 }
38
Alexandre Rames2ed20af2015-03-06 13:55:35 +000039 void PrintString(const char* value) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010040 str_ += value;
41 }
42
Alexandre Rames2ed20af2015-03-06 13:55:35 +000043 void PrintNewLine() OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010044 str_ += '\n';
45 }
46
47 void Clear() { str_.clear(); }
48
49 std::string str() const { return str_; }
50
Alexandre Rames2ed20af2015-03-06 13:55:35 +000051 void VisitIntConstant(HIntConstant* constant) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010052 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);
David Brazdil5e8b1372015-01-23 14:39:08 +000081 HGraph* graph = new (&allocator) HGraph(&allocator);
82 HGraphBuilder builder(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010083 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +000084 bool graph_built = builder.BuildGraph(*item);
85 ASSERT_TRUE(graph_built);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010086
Nicolas Geoffray9ebc72c2014-09-25 16:33:42 +010087 graph->BuildDominatorTree();
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000088 // Suspend checks implementation may change in the future, and this test relies
89 // on how instructions are ordered.
90 RemoveSuspendChecks(graph);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000091 graph->TransformToSsa();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010092 ReNumberInstructions(graph);
93
Nicolas Geoffray184d6402014-06-09 14:06:02 +010094 // Test that phis had their type set.
95 for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
96 for (HInstructionIterator it(graph->GetBlocks().Get(i)->GetPhis()); !it.Done(); it.Advance()) {
97 ASSERT_NE(it.Current()->GetType(), Primitive::kPrimVoid);
98 }
99 }
100
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100101 SsaPrettyPrinter printer(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100102 printer.VisitInsertionOrder();
103
104 ASSERT_STREQ(expected, printer.str().c_str());
105}
106
107TEST(SsaTest, CFG1) {
108 // Test that we get rid of loads and stores.
109 const char* expected =
110 "BasicBlock 0, succ: 1\n"
111 " 0: IntConstant 0 [2, 2]\n"
112 " 1: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100113 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100114 " 2: Equal(0, 0) [3]\n"
115 " 3: If(2)\n"
116 "BasicBlock 2, pred: 1, succ: 3\n"
117 " 4: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100118 "BasicBlock 3, pred: 2, 5, succ: 4\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100119 " 5: ReturnVoid\n"
120 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100121 " 6: Exit\n"
122 // Synthesized block to avoid critical edge.
123 "BasicBlock 5, pred: 1, succ: 3\n"
124 " 7: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100125
126 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
127 Instruction::CONST_4 | 0 | 0,
128 Instruction::IF_EQ, 3,
129 Instruction::GOTO | 0x100,
130 Instruction::RETURN_VOID);
131
132 TestCode(data, expected);
133}
134
135TEST(SsaTest, CFG2) {
136 // Test that we create a phi for the join block of an if control flow instruction
137 // when there is only code in the else branch.
138 const char* expected =
139 "BasicBlock 0, succ: 1\n"
140 " 0: IntConstant 0 [6, 3, 3]\n"
141 " 1: IntConstant 4 [6]\n"
142 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100143 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100144 " 3: Equal(0, 0) [4]\n"
145 " 4: If(3)\n"
146 "BasicBlock 2, pred: 1, succ: 3\n"
147 " 5: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100148 "BasicBlock 3, pred: 2, 5, succ: 4\n"
149 " 6: Phi(1, 0) [7]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100150 " 7: Return(6)\n"
151 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100152 " 8: Exit\n"
153 // Synthesized block to avoid critical edge.
154 "BasicBlock 5, pred: 1, succ: 3\n"
155 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100156
157 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
158 Instruction::CONST_4 | 0 | 0,
159 Instruction::IF_EQ, 3,
160 Instruction::CONST_4 | 4 << 12 | 0,
161 Instruction::RETURN | 0 << 8);
162
163 TestCode(data, expected);
164}
165
166TEST(SsaTest, CFG3) {
167 // Test that we create a phi for the join block of an if control flow instruction
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100168 // when both branches update a local.
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100169 const char* expected =
170 "BasicBlock 0, succ: 1\n"
171 " 0: IntConstant 0 [4, 4]\n"
172 " 1: IntConstant 4 [8]\n"
173 " 2: IntConstant 5 [8]\n"
174 " 3: Goto\n"
175 "BasicBlock 1, pred: 0, succ: 3, 2\n"
176 " 4: Equal(0, 0) [5]\n"
177 " 5: If(4)\n"
178 "BasicBlock 2, pred: 1, succ: 4\n"
179 " 6: Goto\n"
180 "BasicBlock 3, pred: 1, succ: 4\n"
181 " 7: Goto\n"
182 "BasicBlock 4, pred: 2, 3, succ: 5\n"
183 " 8: Phi(1, 2) [9]\n"
184 " 9: Return(8)\n"
185 "BasicBlock 5, pred: 4\n"
186 " 10: Exit\n";
187
188 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
189 Instruction::CONST_4 | 0 | 0,
190 Instruction::IF_EQ, 4,
191 Instruction::CONST_4 | 4 << 12 | 0,
192 Instruction::GOTO | 0x200,
193 Instruction::CONST_4 | 5 << 12 | 0,
194 Instruction::RETURN | 0 << 8);
195
196 TestCode(data, expected);
197}
198
199TEST(SsaTest, Loop1) {
200 // Test that we create a phi for an initialized local at entry of a loop.
201 const char* expected =
202 "BasicBlock 0, succ: 1\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000203 " 0: IntConstant 0 [6, 3, 3]\n"
204 " 1: IntConstant 4 [6]\n"
205 " 2: Goto\n"
206 "BasicBlock 1, pred: 0, succ: 4, 2\n"
207 " 3: Equal(0, 0) [4]\n"
208 " 4: If(3)\n"
209 "BasicBlock 2, pred: 1, succ: 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100210 " 5: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000211 "BasicBlock 3, pred: 2, 4, succ: 5\n"
212 " 6: Phi(1, 0) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100213 " 7: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000214 "BasicBlock 4, pred: 1, succ: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100215 " 8: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000216 "BasicBlock 5, pred: 3, succ: 6\n"
217 " 9: Return(6)\n"
218 "BasicBlock 6, pred: 5\n"
219 " 10: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100220
221 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
222 Instruction::CONST_4 | 0 | 0,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000223 Instruction::IF_EQ, 4,
224 Instruction::CONST_4 | 4 << 12 | 0,
225 Instruction::GOTO | 0x200,
226 Instruction::GOTO | 0xFF00,
227 Instruction::RETURN | 0 << 8);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100228
229 TestCode(data, expected);
230}
231
232TEST(SsaTest, Loop2) {
233 // Simple loop with one preheader and one back edge.
234 const char* expected =
235 "BasicBlock 0, succ: 1\n"
236 " 0: IntConstant 0 [4]\n"
237 " 1: IntConstant 4 [4]\n"
238 " 2: Goto\n"
239 "BasicBlock 1, pred: 0, succ: 2\n"
240 " 3: Goto\n"
241 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
242 " 4: Phi(0, 1) [5, 5]\n"
243 " 5: Equal(4, 4) [6]\n"
244 " 6: If(5)\n"
245 "BasicBlock 3, pred: 2, succ: 2\n"
246 " 7: Goto\n"
247 "BasicBlock 4, pred: 2, succ: 5\n"
248 " 8: ReturnVoid\n"
249 "BasicBlock 5, pred: 4\n"
250 " 9: Exit\n";
251
252 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
253 Instruction::CONST_4 | 0 | 0,
254 Instruction::IF_EQ, 4,
255 Instruction::CONST_4 | 4 << 12 | 0,
256 Instruction::GOTO | 0xFD00,
257 Instruction::RETURN_VOID);
258
259 TestCode(data, expected);
260}
261
262TEST(SsaTest, Loop3) {
263 // Test that a local not yet defined at the entry of a loop is handled properly.
264 const char* expected =
265 "BasicBlock 0, succ: 1\n"
266 " 0: IntConstant 0 [5]\n"
267 " 1: IntConstant 4 [5]\n"
268 " 2: IntConstant 5 [9]\n"
269 " 3: Goto\n"
270 "BasicBlock 1, pred: 0, succ: 2\n"
271 " 4: Goto\n"
272 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
273 " 5: Phi(0, 1) [6, 6]\n"
274 " 6: Equal(5, 5) [7]\n"
275 " 7: If(6)\n"
276 "BasicBlock 3, pred: 2, succ: 2\n"
277 " 8: Goto\n"
278 "BasicBlock 4, pred: 2, succ: 5\n"
279 " 9: Return(2)\n"
280 "BasicBlock 5, pred: 4\n"
281 " 10: Exit\n";
282
283 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
284 Instruction::CONST_4 | 0 | 0,
285 Instruction::IF_EQ, 4,
286 Instruction::CONST_4 | 4 << 12 | 0,
287 Instruction::GOTO | 0xFD00,
288 Instruction::CONST_4 | 5 << 12 | 1 << 8,
289 Instruction::RETURN | 1 << 8);
290
291 TestCode(data, expected);
292}
293
294TEST(SsaTest, Loop4) {
295 // Make sure we support a preheader of a loop not being the first predecessor
296 // in the predecessor list of the header.
297 const char* expected =
298 "BasicBlock 0, succ: 1\n"
299 " 0: IntConstant 0 [4]\n"
300 " 1: IntConstant 4 [4]\n"
301 " 2: Goto\n"
302 "BasicBlock 1, pred: 0, succ: 4\n"
303 " 3: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100304 "BasicBlock 2, pred: 4, 3, succ: 5, 3\n"
305 " 4: Phi(0, 1) [9, 5, 5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100306 " 5: Equal(4, 4) [6]\n"
307 " 6: If(5)\n"
308 "BasicBlock 3, pred: 2, succ: 2\n"
309 " 7: Goto\n"
310 "BasicBlock 4, pred: 1, succ: 2\n"
311 " 8: Goto\n"
312 "BasicBlock 5, pred: 2, succ: 6\n"
313 " 9: Return(4)\n"
314 "BasicBlock 6, pred: 5\n"
315 " 10: Exit\n";
316
317 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
318 Instruction::CONST_4 | 0 | 0,
319 Instruction::GOTO | 0x500,
320 Instruction::IF_EQ, 5,
321 Instruction::CONST_4 | 4 << 12 | 0,
322 Instruction::GOTO | 0xFD00,
323 Instruction::GOTO | 0xFC00,
324 Instruction::RETURN | 0 << 8);
325
326 TestCode(data, expected);
327}
328
329TEST(SsaTest, Loop5) {
330 // Make sure we create a preheader of a loop when a header originally has two
331 // incoming blocks and one back edge.
332 const char* expected =
333 "BasicBlock 0, succ: 1\n"
334 " 0: IntConstant 0 [4, 4]\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000335 " 1: IntConstant 4 [13]\n"
336 " 2: IntConstant 5 [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100337 " 3: Goto\n"
338 "BasicBlock 1, pred: 0, succ: 3, 2\n"
339 " 4: Equal(0, 0) [5]\n"
340 " 5: If(4)\n"
341 "BasicBlock 2, pred: 1, succ: 8\n"
342 " 6: Goto\n"
343 "BasicBlock 3, pred: 1, succ: 8\n"
344 " 7: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100345 "BasicBlock 4, pred: 8, 5, succ: 6, 5\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000346 " 8: Equal(13, 13) [9]\n"
347 " 9: If(8)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100348 "BasicBlock 5, pred: 4, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000349 " 10: Goto\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100350 "BasicBlock 6, pred: 4, succ: 7\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000351 " 11: Return(13)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100352 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000353 " 12: Exit\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100354 "BasicBlock 8, pred: 2, 3, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000355 " 13: Phi(1, 2) [8, 8, 11]\n"
356 " 14: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100357
358 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
359 Instruction::CONST_4 | 0 | 0,
360 Instruction::IF_EQ, 4,
361 Instruction::CONST_4 | 4 << 12 | 0,
362 Instruction::GOTO | 0x200,
363 Instruction::CONST_4 | 5 << 12 | 0,
364 Instruction::IF_EQ, 3,
365 Instruction::GOTO | 0xFE00,
366 Instruction::RETURN | 0 << 8);
367
368 TestCode(data, expected);
369}
370
371TEST(SsaTest, Loop6) {
372 // Test a loop with one preheader and two back edges (e.g. continue).
373 const char* expected =
374 "BasicBlock 0, succ: 1\n"
375 " 0: IntConstant 0 [5]\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100376 " 1: IntConstant 4 [14, 8, 8]\n"
377 " 2: IntConstant 5 [14]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100378 " 3: Goto\n"
379 "BasicBlock 1, pred: 0, succ: 2\n"
380 " 4: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100381 "BasicBlock 2, pred: 1, 8, succ: 6, 3\n"
382 " 5: Phi(0, 14) [12, 6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100383 " 6: Equal(5, 5) [7]\n"
384 " 7: If(6)\n"
385 "BasicBlock 3, pred: 2, succ: 5, 4\n"
386 " 8: Equal(1, 1) [9]\n"
387 " 9: If(8)\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100388 "BasicBlock 4, pred: 3, succ: 8\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100389 " 10: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100390 "BasicBlock 5, pred: 3, succ: 8\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100391 " 11: Goto\n"
392 "BasicBlock 6, pred: 2, succ: 7\n"
393 " 12: Return(5)\n"
394 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100395 " 13: Exit\n"
396 // Synthesized single back edge of loop.
397 "BasicBlock 8, pred: 5, 4, succ: 2\n"
398 " 14: Phi(1, 2) [5]\n"
399 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100400
401 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
402 Instruction::CONST_4 | 0 | 0,
403 Instruction::IF_EQ, 8,
404 Instruction::CONST_4 | 4 << 12 | 0,
405 Instruction::IF_EQ, 4,
406 Instruction::CONST_4 | 5 << 12 | 0,
407 Instruction::GOTO | 0xFA00,
408 Instruction::GOTO | 0xF900,
409 Instruction::RETURN | 0 << 8);
410
411 TestCode(data, expected);
412}
413
414TEST(SsaTest, Loop7) {
415 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break).
416 const char* expected =
417 "BasicBlock 0, succ: 1\n"
418 " 0: IntConstant 0 [5]\n"
419 " 1: IntConstant 4 [5, 8, 8]\n"
420 " 2: IntConstant 5 [12]\n"
421 " 3: Goto\n"
422 "BasicBlock 1, pred: 0, succ: 2\n"
423 " 4: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100424 "BasicBlock 2, pred: 1, 5, succ: 8, 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100425 " 5: Phi(0, 1) [12, 6, 6]\n"
426 " 6: Equal(5, 5) [7]\n"
427 " 7: If(6)\n"
428 "BasicBlock 3, pred: 2, succ: 5, 4\n"
429 " 8: Equal(1, 1) [9]\n"
430 " 9: If(8)\n"
431 "BasicBlock 4, pred: 3, succ: 6\n"
432 " 10: Goto\n"
433 "BasicBlock 5, pred: 3, succ: 2\n"
434 " 11: Goto\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100435 "BasicBlock 6, pred: 4, 8, succ: 7\n"
436 " 12: Phi(2, 5) [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100437 " 13: Return(12)\n"
438 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100439 " 14: Exit\n"
440 "BasicBlock 8, pred: 2, succ: 6\n"
441 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100442
443 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
444 Instruction::CONST_4 | 0 | 0,
445 Instruction::IF_EQ, 8,
446 Instruction::CONST_4 | 4 << 12 | 0,
447 Instruction::IF_EQ, 4,
448 Instruction::CONST_4 | 5 << 12 | 0,
449 Instruction::GOTO | 0x0200,
450 Instruction::GOTO | 0xF900,
451 Instruction::RETURN | 0 << 8);
452
453 TestCode(data, expected);
454}
455
456TEST(SsaTest, DeadLocal) {
457 // Test that we correctly handle a local not being used.
458 const char* expected =
459 "BasicBlock 0, succ: 1\n"
460 " 0: IntConstant 0\n"
461 " 1: Goto\n"
462 "BasicBlock 1, pred: 0, succ: 2\n"
463 " 2: ReturnVoid\n"
464 "BasicBlock 2, pred: 1\n"
465 " 3: Exit\n";
466
467 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
468 Instruction::CONST_4 | 0 | 0,
469 Instruction::RETURN_VOID);
470
471 TestCode(data, expected);
472}
473
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100474TEST(SsaTest, LocalInIf) {
475 // Test that we do not create a phi in the join block when one predecessor
476 // does not update the local.
477 const char* expected =
478 "BasicBlock 0, succ: 1\n"
479 " 0: IntConstant 0 [3, 3]\n"
480 " 1: IntConstant 4\n"
481 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100482 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100483 " 3: Equal(0, 0) [4]\n"
484 " 4: If(3)\n"
485 "BasicBlock 2, pred: 1, succ: 3\n"
486 " 5: Goto\n"
487 "BasicBlock 3, pred: 2, 5, succ: 4\n"
488 " 6: ReturnVoid\n"
489 "BasicBlock 4, pred: 3\n"
490 " 7: Exit\n"
491 // Synthesized block to avoid critical edge.
492 "BasicBlock 5, pred: 1, succ: 3\n"
493 " 8: Goto\n";
494
495 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
496 Instruction::CONST_4 | 0 | 0,
497 Instruction::IF_EQ, 3,
498 Instruction::CONST_4 | 4 << 12 | 1 << 8,
499 Instruction::RETURN_VOID);
500
501 TestCode(data, expected);
502}
503
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100504TEST(SsaTest, MultiplePredecessors) {
505 // Test that we do not create a phi when one predecessor
506 // does not update the local.
507 const char* expected =
508 "BasicBlock 0, succ: 1\n"
509 " 0: IntConstant 0 [4, 8, 6, 6, 2, 2, 8, 4]\n"
510 " 1: Goto\n"
511 "BasicBlock 1, pred: 0, succ: 3, 2\n"
512 " 2: Equal(0, 0) [3]\n"
513 " 3: If(2)\n"
514 "BasicBlock 2, pred: 1, succ: 5\n"
515 " 4: Add(0, 0)\n"
516 " 5: Goto\n"
517 "BasicBlock 3, pred: 1, succ: 7, 4\n"
518 " 6: Equal(0, 0) [7]\n"
519 " 7: If(6)\n"
520 "BasicBlock 4, pred: 3, succ: 5\n"
521 " 8: Add(0, 0)\n"
522 " 9: Goto\n"
523 // This block should not get a phi for local 1.
524 "BasicBlock 5, pred: 2, 4, 7, succ: 6\n"
525 " 10: ReturnVoid\n"
526 "BasicBlock 6, pred: 5\n"
527 " 11: Exit\n"
528 "BasicBlock 7, pred: 3, succ: 5\n"
529 " 12: Goto\n";
530
531 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
532 Instruction::CONST_4 | 0 | 0,
533 Instruction::IF_EQ, 5,
534 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
535 Instruction::GOTO | 0x0500,
536 Instruction::IF_EQ, 4,
537 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
538 Instruction::RETURN_VOID);
539
540 TestCode(data, expected);
541}
542
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100543} // namespace art