blob: 429763423cff2c028c62c565ebdb6f220a4cfdc5 [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
David Brazdil4833f5a2015-12-16 10:37:39 +000031class SsaTest : public CommonCompilerTest {};
32
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010033class SsaPrettyPrinter : public HPrettyPrinter {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010034 public:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010035 explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {}
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010036
Alexandre Rames2ed20af2015-03-06 13:55:35 +000037 void PrintInt(int value) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010038 str_ += StringPrintf("%d", value);
39 }
40
Alexandre Rames2ed20af2015-03-06 13:55:35 +000041 void PrintString(const char* value) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010042 str_ += value;
43 }
44
Alexandre Rames2ed20af2015-03-06 13:55:35 +000045 void PrintNewLine() OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010046 str_ += '\n';
47 }
48
49 void Clear() { str_.clear(); }
50
51 std::string str() const { return str_; }
52
Alexandre Rames2ed20af2015-03-06 13:55:35 +000053 void VisitIntConstant(HIntConstant* constant) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010054 PrintPreInstruction(constant);
55 str_ += constant->DebugName();
56 str_ += " ";
57 PrintInt(constant->GetValue());
58 PrintPostInstruction(constant);
59 }
60
61 private:
62 std::string str_;
63
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010064 DISALLOW_COPY_AND_ASSIGN(SsaPrettyPrinter);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010065};
66
67static void ReNumberInstructions(HGraph* graph) {
68 int id = 0;
Vladimir Markofa6b93c2015-09-15 10:15:55 +010069 for (HBasicBlock* block : graph->GetBlocks()) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010070 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010071 it.Current()->SetId(id++);
72 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010073 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010074 it.Current()->SetId(id++);
75 }
76 }
77}
78
79static void TestCode(const uint16_t* data, const char* expected) {
80 ArenaPool pool;
81 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000082 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000083 // Suspend checks implementation may change in the future, and this test relies
84 // on how instructions are ordered.
85 RemoveSuspendChecks(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010086 ReNumberInstructions(graph);
87
Nicolas Geoffray184d6402014-06-09 14:06:02 +010088 // Test that phis had their type set.
Vladimir Markofa6b93c2015-09-15 10:15:55 +010089 for (HBasicBlock* block : graph->GetBlocks()) {
90 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffray184d6402014-06-09 14:06:02 +010091 ASSERT_NE(it.Current()->GetType(), Primitive::kPrimVoid);
92 }
93 }
94
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010095 SsaPrettyPrinter printer(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010096 printer.VisitInsertionOrder();
97
98 ASSERT_STREQ(expected, printer.str().c_str());
99}
100
David Brazdil4833f5a2015-12-16 10:37:39 +0000101TEST_F(SsaTest, CFG1) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100102 // Test that we get rid of loads and stores.
103 const char* expected =
104 "BasicBlock 0, succ: 1\n"
105 " 0: IntConstant 0 [2, 2]\n"
106 " 1: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100107 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100108 " 2: Equal(0, 0) [3]\n"
109 " 3: If(2)\n"
110 "BasicBlock 2, pred: 1, succ: 3\n"
111 " 4: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100112 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100113 " 5: ReturnVoid\n"
114 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100115 " 6: Exit\n"
116 // Synthesized block to avoid critical edge.
117 "BasicBlock 5, pred: 1, succ: 3\n"
118 " 7: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100119
120 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
121 Instruction::CONST_4 | 0 | 0,
122 Instruction::IF_EQ, 3,
123 Instruction::GOTO | 0x100,
124 Instruction::RETURN_VOID);
125
126 TestCode(data, expected);
127}
128
David Brazdil4833f5a2015-12-16 10:37:39 +0000129TEST_F(SsaTest, CFG2) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100130 // Test that we create a phi for the join block of an if control flow instruction
131 // when there is only code in the else branch.
132 const char* expected =
133 "BasicBlock 0, succ: 1\n"
134 " 0: IntConstant 0 [6, 3, 3]\n"
135 " 1: IntConstant 4 [6]\n"
136 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100137 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100138 " 3: Equal(0, 0) [4]\n"
139 " 4: If(3)\n"
140 "BasicBlock 2, pred: 1, succ: 3\n"
141 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100142 "BasicBlock 3, pred: 5, 2, succ: 4\n"
143 " 6: Phi(0, 1) [7]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100144 " 7: Return(6)\n"
145 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100146 " 8: Exit\n"
147 // Synthesized block to avoid critical edge.
148 "BasicBlock 5, pred: 1, succ: 3\n"
149 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100150
151 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
152 Instruction::CONST_4 | 0 | 0,
153 Instruction::IF_EQ, 3,
154 Instruction::CONST_4 | 4 << 12 | 0,
155 Instruction::RETURN | 0 << 8);
156
157 TestCode(data, expected);
158}
159
David Brazdil4833f5a2015-12-16 10:37:39 +0000160TEST_F(SsaTest, CFG3) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100161 // Test that we create a phi for the join block of an if control flow instruction
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100162 // when both branches update a local.
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100163 const char* expected =
164 "BasicBlock 0, succ: 1\n"
165 " 0: IntConstant 0 [4, 4]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000166 " 1: IntConstant 5 [8]\n"
167 " 2: IntConstant 4 [8]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100168 " 3: Goto\n"
169 "BasicBlock 1, pred: 0, succ: 3, 2\n"
170 " 4: Equal(0, 0) [5]\n"
171 " 5: If(4)\n"
172 "BasicBlock 2, pred: 1, succ: 4\n"
173 " 6: Goto\n"
174 "BasicBlock 3, pred: 1, succ: 4\n"
175 " 7: Goto\n"
176 "BasicBlock 4, pred: 2, 3, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000177 " 8: Phi(2, 1) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100178 " 9: Return(8)\n"
179 "BasicBlock 5, pred: 4\n"
180 " 10: Exit\n";
181
182 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
183 Instruction::CONST_4 | 0 | 0,
184 Instruction::IF_EQ, 4,
185 Instruction::CONST_4 | 4 << 12 | 0,
186 Instruction::GOTO | 0x200,
187 Instruction::CONST_4 | 5 << 12 | 0,
188 Instruction::RETURN | 0 << 8);
189
190 TestCode(data, expected);
191}
192
David Brazdil4833f5a2015-12-16 10:37:39 +0000193TEST_F(SsaTest, Loop1) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100194 // Test that we create a phi for an initialized local at entry of a loop.
195 const char* expected =
196 "BasicBlock 0, succ: 1\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000197 " 0: IntConstant 0 [6, 3, 3]\n"
198 " 1: IntConstant 4 [6]\n"
199 " 2: Goto\n"
200 "BasicBlock 1, pred: 0, succ: 4, 2\n"
201 " 3: Equal(0, 0) [4]\n"
202 " 4: If(3)\n"
203 "BasicBlock 2, pred: 1, succ: 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100204 " 5: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000205 "BasicBlock 3, pred: 2, 4, succ: 5\n"
206 " 6: Phi(1, 0) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100207 " 7: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000208 "BasicBlock 4, pred: 1, succ: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100209 " 8: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000210 "BasicBlock 5, pred: 3, succ: 6\n"
211 " 9: Return(6)\n"
212 "BasicBlock 6, pred: 5\n"
213 " 10: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100214
215 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
216 Instruction::CONST_4 | 0 | 0,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000217 Instruction::IF_EQ, 4,
218 Instruction::CONST_4 | 4 << 12 | 0,
219 Instruction::GOTO | 0x200,
220 Instruction::GOTO | 0xFF00,
221 Instruction::RETURN | 0 << 8);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100222
223 TestCode(data, expected);
224}
225
David Brazdil4833f5a2015-12-16 10:37:39 +0000226TEST_F(SsaTest, Loop2) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100227 // Simple loop with one preheader and one back edge.
228 const char* expected =
229 "BasicBlock 0, succ: 1\n"
230 " 0: IntConstant 0 [4]\n"
231 " 1: IntConstant 4 [4]\n"
232 " 2: Goto\n"
233 "BasicBlock 1, pred: 0, succ: 2\n"
234 " 3: Goto\n"
235 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
236 " 4: Phi(0, 1) [5, 5]\n"
237 " 5: Equal(4, 4) [6]\n"
238 " 6: If(5)\n"
239 "BasicBlock 3, pred: 2, succ: 2\n"
240 " 7: Goto\n"
241 "BasicBlock 4, pred: 2, succ: 5\n"
242 " 8: ReturnVoid\n"
243 "BasicBlock 5, pred: 4\n"
244 " 9: Exit\n";
245
246 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
247 Instruction::CONST_4 | 0 | 0,
248 Instruction::IF_EQ, 4,
249 Instruction::CONST_4 | 4 << 12 | 0,
250 Instruction::GOTO | 0xFD00,
251 Instruction::RETURN_VOID);
252
253 TestCode(data, expected);
254}
255
David Brazdil4833f5a2015-12-16 10:37:39 +0000256TEST_F(SsaTest, Loop3) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100257 // Test that a local not yet defined at the entry of a loop is handled properly.
258 const char* expected =
259 "BasicBlock 0, succ: 1\n"
260 " 0: IntConstant 0 [5]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000261 " 1: IntConstant 5 [9]\n"
262 " 2: IntConstant 4 [5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100263 " 3: Goto\n"
264 "BasicBlock 1, pred: 0, succ: 2\n"
265 " 4: Goto\n"
266 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000267 " 5: Phi(0, 2) [6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100268 " 6: Equal(5, 5) [7]\n"
269 " 7: If(6)\n"
270 "BasicBlock 3, pred: 2, succ: 2\n"
271 " 8: Goto\n"
272 "BasicBlock 4, pred: 2, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000273 " 9: Return(1)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100274 "BasicBlock 5, pred: 4\n"
275 " 10: Exit\n";
276
277 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
278 Instruction::CONST_4 | 0 | 0,
279 Instruction::IF_EQ, 4,
280 Instruction::CONST_4 | 4 << 12 | 0,
281 Instruction::GOTO | 0xFD00,
282 Instruction::CONST_4 | 5 << 12 | 1 << 8,
283 Instruction::RETURN | 1 << 8);
284
285 TestCode(data, expected);
286}
287
David Brazdil4833f5a2015-12-16 10:37:39 +0000288TEST_F(SsaTest, Loop4) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100289 // Make sure we support a preheader of a loop not being the first predecessor
290 // in the predecessor list of the header.
291 const char* expected =
292 "BasicBlock 0, succ: 1\n"
293 " 0: IntConstant 0 [4]\n"
294 " 1: IntConstant 4 [4]\n"
295 " 2: Goto\n"
296 "BasicBlock 1, pred: 0, succ: 4\n"
297 " 3: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100298 "BasicBlock 2, pred: 4, 3, succ: 5, 3\n"
299 " 4: Phi(0, 1) [9, 5, 5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100300 " 5: Equal(4, 4) [6]\n"
301 " 6: If(5)\n"
302 "BasicBlock 3, pred: 2, succ: 2\n"
303 " 7: Goto\n"
304 "BasicBlock 4, pred: 1, succ: 2\n"
305 " 8: Goto\n"
306 "BasicBlock 5, pred: 2, succ: 6\n"
307 " 9: Return(4)\n"
308 "BasicBlock 6, pred: 5\n"
309 " 10: Exit\n";
310
311 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
312 Instruction::CONST_4 | 0 | 0,
313 Instruction::GOTO | 0x500,
314 Instruction::IF_EQ, 5,
315 Instruction::CONST_4 | 4 << 12 | 0,
316 Instruction::GOTO | 0xFD00,
317 Instruction::GOTO | 0xFC00,
318 Instruction::RETURN | 0 << 8);
319
320 TestCode(data, expected);
321}
322
David Brazdil4833f5a2015-12-16 10:37:39 +0000323TEST_F(SsaTest, Loop5) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100324 // Make sure we create a preheader of a loop when a header originally has two
325 // incoming blocks and one back edge.
326 const char* expected =
327 "BasicBlock 0, succ: 1\n"
328 " 0: IntConstant 0 [4, 4]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000329 " 1: IntConstant 5 [13]\n"
330 " 2: IntConstant 4 [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100331 " 3: Goto\n"
332 "BasicBlock 1, pred: 0, succ: 3, 2\n"
333 " 4: Equal(0, 0) [5]\n"
334 " 5: If(4)\n"
335 "BasicBlock 2, pred: 1, succ: 8\n"
336 " 6: Goto\n"
337 "BasicBlock 3, pred: 1, succ: 8\n"
338 " 7: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100339 "BasicBlock 4, pred: 8, 5, succ: 6, 5\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000340 " 8: Equal(13, 13) [9]\n"
341 " 9: If(8)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100342 "BasicBlock 5, pred: 4, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000343 " 10: Goto\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100344 "BasicBlock 6, pred: 4, succ: 7\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000345 " 11: Return(13)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100346 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000347 " 12: Exit\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100348 "BasicBlock 8, pred: 2, 3, succ: 4\n"
Vladimir Marko3c19d3e2016-04-19 14:36:35 +0100349 " 13: Phi(2, 1) [11, 8, 8]\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000350 " 14: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100351
352 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
353 Instruction::CONST_4 | 0 | 0,
354 Instruction::IF_EQ, 4,
355 Instruction::CONST_4 | 4 << 12 | 0,
356 Instruction::GOTO | 0x200,
357 Instruction::CONST_4 | 5 << 12 | 0,
358 Instruction::IF_EQ, 3,
359 Instruction::GOTO | 0xFE00,
360 Instruction::RETURN | 0 << 8);
361
362 TestCode(data, expected);
363}
364
David Brazdil4833f5a2015-12-16 10:37:39 +0000365TEST_F(SsaTest, Loop6) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100366 // Test a loop with one preheader and two back edges (e.g. continue).
367 const char* expected =
368 "BasicBlock 0, succ: 1\n"
369 " 0: IntConstant 0 [5]\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100370 " 1: IntConstant 4 [5, 8, 8]\n"
371 " 2: IntConstant 5 [5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100372 " 3: Goto\n"
373 "BasicBlock 1, pred: 0, succ: 2\n"
374 " 4: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100375 "BasicBlock 2, pred: 1, 4, 5, succ: 6, 3\n"
376 " 5: Phi(0, 2, 1) [12, 6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100377 " 6: Equal(5, 5) [7]\n"
378 " 7: If(6)\n"
379 "BasicBlock 3, pred: 2, succ: 5, 4\n"
380 " 8: Equal(1, 1) [9]\n"
381 " 9: If(8)\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100382 "BasicBlock 4, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100383 " 10: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100384 "BasicBlock 5, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100385 " 11: Goto\n"
386 "BasicBlock 6, pred: 2, succ: 7\n"
387 " 12: Return(5)\n"
388 "BasicBlock 7, pred: 6\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100389 " 13: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100390
391 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
392 Instruction::CONST_4 | 0 | 0,
393 Instruction::IF_EQ, 8,
394 Instruction::CONST_4 | 4 << 12 | 0,
395 Instruction::IF_EQ, 4,
396 Instruction::CONST_4 | 5 << 12 | 0,
397 Instruction::GOTO | 0xFA00,
398 Instruction::GOTO | 0xF900,
399 Instruction::RETURN | 0 << 8);
400
401 TestCode(data, expected);
402}
403
David Brazdil4833f5a2015-12-16 10:37:39 +0000404TEST_F(SsaTest, Loop7) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100405 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break).
406 const char* expected =
407 "BasicBlock 0, succ: 1\n"
408 " 0: IntConstant 0 [5]\n"
409 " 1: IntConstant 4 [5, 8, 8]\n"
410 " 2: IntConstant 5 [12]\n"
411 " 3: Goto\n"
412 "BasicBlock 1, pred: 0, succ: 2\n"
413 " 4: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100414 "BasicBlock 2, pred: 1, 5, succ: 8, 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100415 " 5: Phi(0, 1) [12, 6, 6]\n"
416 " 6: Equal(5, 5) [7]\n"
417 " 7: If(6)\n"
418 "BasicBlock 3, pred: 2, succ: 5, 4\n"
419 " 8: Equal(1, 1) [9]\n"
420 " 9: If(8)\n"
421 "BasicBlock 4, pred: 3, succ: 6\n"
422 " 10: Goto\n"
423 "BasicBlock 5, pred: 3, succ: 2\n"
424 " 11: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100425 "BasicBlock 6, pred: 8, 4, succ: 7\n"
426 " 12: Phi(5, 2) [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100427 " 13: Return(12)\n"
428 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100429 " 14: Exit\n"
430 "BasicBlock 8, pred: 2, succ: 6\n"
431 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100432
433 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
434 Instruction::CONST_4 | 0 | 0,
435 Instruction::IF_EQ, 8,
436 Instruction::CONST_4 | 4 << 12 | 0,
437 Instruction::IF_EQ, 4,
438 Instruction::CONST_4 | 5 << 12 | 0,
439 Instruction::GOTO | 0x0200,
440 Instruction::GOTO | 0xF900,
441 Instruction::RETURN | 0 << 8);
442
443 TestCode(data, expected);
444}
445
David Brazdil4833f5a2015-12-16 10:37:39 +0000446TEST_F(SsaTest, DeadLocal) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100447 // Test that we correctly handle a local not being used.
448 const char* expected =
449 "BasicBlock 0, succ: 1\n"
450 " 0: IntConstant 0\n"
451 " 1: Goto\n"
452 "BasicBlock 1, pred: 0, succ: 2\n"
453 " 2: ReturnVoid\n"
454 "BasicBlock 2, pred: 1\n"
455 " 3: Exit\n";
456
457 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
458 Instruction::CONST_4 | 0 | 0,
459 Instruction::RETURN_VOID);
460
461 TestCode(data, expected);
462}
463
David Brazdil4833f5a2015-12-16 10:37:39 +0000464TEST_F(SsaTest, LocalInIf) {
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100465 // Test that we do not create a phi in the join block when one predecessor
466 // does not update the local.
467 const char* expected =
468 "BasicBlock 0, succ: 1\n"
469 " 0: IntConstant 0 [3, 3]\n"
470 " 1: IntConstant 4\n"
471 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100472 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100473 " 3: Equal(0, 0) [4]\n"
474 " 4: If(3)\n"
475 "BasicBlock 2, pred: 1, succ: 3\n"
476 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100477 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100478 " 6: ReturnVoid\n"
479 "BasicBlock 4, pred: 3\n"
480 " 7: Exit\n"
481 // Synthesized block to avoid critical edge.
482 "BasicBlock 5, pred: 1, succ: 3\n"
483 " 8: Goto\n";
484
485 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
486 Instruction::CONST_4 | 0 | 0,
487 Instruction::IF_EQ, 3,
488 Instruction::CONST_4 | 4 << 12 | 1 << 8,
489 Instruction::RETURN_VOID);
490
491 TestCode(data, expected);
492}
493
David Brazdil4833f5a2015-12-16 10:37:39 +0000494TEST_F(SsaTest, MultiplePredecessors) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100495 // Test that we do not create a phi when one predecessor
496 // does not update the local.
497 const char* expected =
498 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000499 " 0: IntConstant 0 [4, 4, 8, 8, 6, 6, 2, 2]\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100500 " 1: Goto\n"
501 "BasicBlock 1, pred: 0, succ: 3, 2\n"
502 " 2: Equal(0, 0) [3]\n"
503 " 3: If(2)\n"
504 "BasicBlock 2, pred: 1, succ: 5\n"
505 " 4: Add(0, 0)\n"
506 " 5: Goto\n"
507 "BasicBlock 3, pred: 1, succ: 7, 4\n"
508 " 6: Equal(0, 0) [7]\n"
509 " 7: If(6)\n"
510 "BasicBlock 4, pred: 3, succ: 5\n"
511 " 8: Add(0, 0)\n"
512 " 9: Goto\n"
513 // This block should not get a phi for local 1.
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100514 "BasicBlock 5, pred: 2, 7, 4, succ: 6\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100515 " 10: ReturnVoid\n"
516 "BasicBlock 6, pred: 5\n"
517 " 11: Exit\n"
518 "BasicBlock 7, pred: 3, succ: 5\n"
519 " 12: Goto\n";
520
521 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
522 Instruction::CONST_4 | 0 | 0,
523 Instruction::IF_EQ, 5,
524 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
525 Instruction::GOTO | 0x0500,
526 Instruction::IF_EQ, 4,
527 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
528 Instruction::RETURN_VOID);
529
530 TestCode(data, expected);
531}
532
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100533} // namespace art