blob: 024278f4b284224666a52f8f4f127b2c4f9adb75 [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;
Vladimir Markofa6b93c2015-09-15 10:15:55 +010067 for (HBasicBlock* block : graph->GetBlocks()) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010068 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010069 it.Current()->SetId(id++);
70 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010071 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010072 it.Current()->SetId(id++);
73 }
74 }
75}
76
77static void TestCode(const uint16_t* data, const char* expected) {
78 ArenaPool pool;
79 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010080 HGraph* graph = CreateGraph(&allocator);
David Brazdil5e8b1372015-01-23 14:39:08 +000081 HGraphBuilder builder(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010082 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
David Brazdil5e8b1372015-01-23 14:39:08 +000083 bool graph_built = builder.BuildGraph(*item);
84 ASSERT_TRUE(graph_built);
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010085
Nicolas Geoffray9ebc72c2014-09-25 16:33:42 +010086 graph->BuildDominatorTree();
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000087 // Suspend checks implementation may change in the future, and this test relies
88 // on how instructions are ordered.
89 RemoveSuspendChecks(graph);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000090 graph->TransformToSsa();
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010091 ReNumberInstructions(graph);
92
Nicolas Geoffray184d6402014-06-09 14:06:02 +010093 // Test that phis had their type set.
Vladimir Markofa6b93c2015-09-15 10:15:55 +010094 for (HBasicBlock* block : graph->GetBlocks()) {
95 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffray184d6402014-06-09 14:06:02 +010096 ASSERT_NE(it.Current()->GetType(), Primitive::kPrimVoid);
97 }
98 }
99
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +0100100 SsaPrettyPrinter printer(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100101 printer.VisitInsertionOrder();
102
103 ASSERT_STREQ(expected, printer.str().c_str());
104}
105
106TEST(SsaTest, CFG1) {
107 // Test that we get rid of loads and stores.
108 const char* expected =
109 "BasicBlock 0, succ: 1\n"
110 " 0: IntConstant 0 [2, 2]\n"
111 " 1: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100112 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100113 " 2: Equal(0, 0) [3]\n"
114 " 3: If(2)\n"
115 "BasicBlock 2, pred: 1, succ: 3\n"
116 " 4: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100117 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100118 " 5: ReturnVoid\n"
119 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100120 " 6: Exit\n"
121 // Synthesized block to avoid critical edge.
122 "BasicBlock 5, pred: 1, succ: 3\n"
123 " 7: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100124
125 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
126 Instruction::CONST_4 | 0 | 0,
127 Instruction::IF_EQ, 3,
128 Instruction::GOTO | 0x100,
129 Instruction::RETURN_VOID);
130
131 TestCode(data, expected);
132}
133
134TEST(SsaTest, CFG2) {
135 // Test that we create a phi for the join block of an if control flow instruction
136 // when there is only code in the else branch.
137 const char* expected =
138 "BasicBlock 0, succ: 1\n"
139 " 0: IntConstant 0 [6, 3, 3]\n"
140 " 1: IntConstant 4 [6]\n"
141 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100142 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100143 " 3: Equal(0, 0) [4]\n"
144 " 4: If(3)\n"
145 "BasicBlock 2, pred: 1, succ: 3\n"
146 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100147 "BasicBlock 3, pred: 5, 2, succ: 4\n"
148 " 6: Phi(0, 1) [7]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100149 " 7: Return(6)\n"
150 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100151 " 8: Exit\n"
152 // Synthesized block to avoid critical edge.
153 "BasicBlock 5, pred: 1, succ: 3\n"
154 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100155
156 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
157 Instruction::CONST_4 | 0 | 0,
158 Instruction::IF_EQ, 3,
159 Instruction::CONST_4 | 4 << 12 | 0,
160 Instruction::RETURN | 0 << 8);
161
162 TestCode(data, expected);
163}
164
165TEST(SsaTest, CFG3) {
166 // Test that we create a phi for the join block of an if control flow instruction
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100167 // when both branches update a local.
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100168 const char* expected =
169 "BasicBlock 0, succ: 1\n"
170 " 0: IntConstant 0 [4, 4]\n"
171 " 1: IntConstant 4 [8]\n"
172 " 2: IntConstant 5 [8]\n"
173 " 3: Goto\n"
174 "BasicBlock 1, pred: 0, succ: 3, 2\n"
175 " 4: Equal(0, 0) [5]\n"
176 " 5: If(4)\n"
177 "BasicBlock 2, pred: 1, succ: 4\n"
178 " 6: Goto\n"
179 "BasicBlock 3, pred: 1, succ: 4\n"
180 " 7: Goto\n"
181 "BasicBlock 4, pred: 2, 3, succ: 5\n"
182 " 8: Phi(1, 2) [9]\n"
183 " 9: Return(8)\n"
184 "BasicBlock 5, pred: 4\n"
185 " 10: Exit\n";
186
187 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
188 Instruction::CONST_4 | 0 | 0,
189 Instruction::IF_EQ, 4,
190 Instruction::CONST_4 | 4 << 12 | 0,
191 Instruction::GOTO | 0x200,
192 Instruction::CONST_4 | 5 << 12 | 0,
193 Instruction::RETURN | 0 << 8);
194
195 TestCode(data, expected);
196}
197
198TEST(SsaTest, Loop1) {
199 // Test that we create a phi for an initialized local at entry of a loop.
200 const char* expected =
201 "BasicBlock 0, succ: 1\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000202 " 0: IntConstant 0 [6, 3, 3]\n"
203 " 1: IntConstant 4 [6]\n"
204 " 2: Goto\n"
205 "BasicBlock 1, pred: 0, succ: 4, 2\n"
206 " 3: Equal(0, 0) [4]\n"
207 " 4: If(3)\n"
208 "BasicBlock 2, pred: 1, succ: 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100209 " 5: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000210 "BasicBlock 3, pred: 2, 4, succ: 5\n"
211 " 6: Phi(1, 0) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100212 " 7: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000213 "BasicBlock 4, pred: 1, succ: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100214 " 8: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000215 "BasicBlock 5, pred: 3, succ: 6\n"
216 " 9: Return(6)\n"
217 "BasicBlock 6, pred: 5\n"
218 " 10: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100219
220 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
221 Instruction::CONST_4 | 0 | 0,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000222 Instruction::IF_EQ, 4,
223 Instruction::CONST_4 | 4 << 12 | 0,
224 Instruction::GOTO | 0x200,
225 Instruction::GOTO | 0xFF00,
226 Instruction::RETURN | 0 << 8);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100227
228 TestCode(data, expected);
229}
230
231TEST(SsaTest, Loop2) {
232 // Simple loop with one preheader and one back edge.
233 const char* expected =
234 "BasicBlock 0, succ: 1\n"
235 " 0: IntConstant 0 [4]\n"
236 " 1: IntConstant 4 [4]\n"
237 " 2: Goto\n"
238 "BasicBlock 1, pred: 0, succ: 2\n"
239 " 3: Goto\n"
240 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
241 " 4: Phi(0, 1) [5, 5]\n"
242 " 5: Equal(4, 4) [6]\n"
243 " 6: If(5)\n"
244 "BasicBlock 3, pred: 2, succ: 2\n"
245 " 7: Goto\n"
246 "BasicBlock 4, pred: 2, succ: 5\n"
247 " 8: ReturnVoid\n"
248 "BasicBlock 5, pred: 4\n"
249 " 9: Exit\n";
250
251 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
252 Instruction::CONST_4 | 0 | 0,
253 Instruction::IF_EQ, 4,
254 Instruction::CONST_4 | 4 << 12 | 0,
255 Instruction::GOTO | 0xFD00,
256 Instruction::RETURN_VOID);
257
258 TestCode(data, expected);
259}
260
261TEST(SsaTest, Loop3) {
262 // Test that a local not yet defined at the entry of a loop is handled properly.
263 const char* expected =
264 "BasicBlock 0, succ: 1\n"
265 " 0: IntConstant 0 [5]\n"
266 " 1: IntConstant 4 [5]\n"
267 " 2: IntConstant 5 [9]\n"
268 " 3: Goto\n"
269 "BasicBlock 1, pred: 0, succ: 2\n"
270 " 4: Goto\n"
271 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
272 " 5: Phi(0, 1) [6, 6]\n"
273 " 6: Equal(5, 5) [7]\n"
274 " 7: If(6)\n"
275 "BasicBlock 3, pred: 2, succ: 2\n"
276 " 8: Goto\n"
277 "BasicBlock 4, pred: 2, succ: 5\n"
278 " 9: Return(2)\n"
279 "BasicBlock 5, pred: 4\n"
280 " 10: Exit\n";
281
282 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
283 Instruction::CONST_4 | 0 | 0,
284 Instruction::IF_EQ, 4,
285 Instruction::CONST_4 | 4 << 12 | 0,
286 Instruction::GOTO | 0xFD00,
287 Instruction::CONST_4 | 5 << 12 | 1 << 8,
288 Instruction::RETURN | 1 << 8);
289
290 TestCode(data, expected);
291}
292
293TEST(SsaTest, Loop4) {
294 // Make sure we support a preheader of a loop not being the first predecessor
295 // in the predecessor list of the header.
296 const char* expected =
297 "BasicBlock 0, succ: 1\n"
298 " 0: IntConstant 0 [4]\n"
299 " 1: IntConstant 4 [4]\n"
300 " 2: Goto\n"
301 "BasicBlock 1, pred: 0, succ: 4\n"
302 " 3: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100303 "BasicBlock 2, pred: 4, 3, succ: 5, 3\n"
304 " 4: Phi(0, 1) [9, 5, 5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100305 " 5: Equal(4, 4) [6]\n"
306 " 6: If(5)\n"
307 "BasicBlock 3, pred: 2, succ: 2\n"
308 " 7: Goto\n"
309 "BasicBlock 4, pred: 1, succ: 2\n"
310 " 8: Goto\n"
311 "BasicBlock 5, pred: 2, succ: 6\n"
312 " 9: Return(4)\n"
313 "BasicBlock 6, pred: 5\n"
314 " 10: Exit\n";
315
316 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
317 Instruction::CONST_4 | 0 | 0,
318 Instruction::GOTO | 0x500,
319 Instruction::IF_EQ, 5,
320 Instruction::CONST_4 | 4 << 12 | 0,
321 Instruction::GOTO | 0xFD00,
322 Instruction::GOTO | 0xFC00,
323 Instruction::RETURN | 0 << 8);
324
325 TestCode(data, expected);
326}
327
328TEST(SsaTest, Loop5) {
329 // Make sure we create a preheader of a loop when a header originally has two
330 // incoming blocks and one back edge.
331 const char* expected =
332 "BasicBlock 0, succ: 1\n"
333 " 0: IntConstant 0 [4, 4]\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000334 " 1: IntConstant 4 [13]\n"
335 " 2: IntConstant 5 [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100336 " 3: Goto\n"
337 "BasicBlock 1, pred: 0, succ: 3, 2\n"
338 " 4: Equal(0, 0) [5]\n"
339 " 5: If(4)\n"
340 "BasicBlock 2, pred: 1, succ: 8\n"
341 " 6: Goto\n"
342 "BasicBlock 3, pred: 1, succ: 8\n"
343 " 7: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100344 "BasicBlock 4, pred: 8, 5, succ: 6, 5\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000345 " 8: Equal(13, 13) [9]\n"
346 " 9: If(8)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100347 "BasicBlock 5, pred: 4, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000348 " 10: Goto\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100349 "BasicBlock 6, pred: 4, succ: 7\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000350 " 11: Return(13)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100351 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000352 " 12: Exit\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100353 "BasicBlock 8, pred: 2, 3, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000354 " 13: Phi(1, 2) [8, 8, 11]\n"
355 " 14: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100356
357 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
358 Instruction::CONST_4 | 0 | 0,
359 Instruction::IF_EQ, 4,
360 Instruction::CONST_4 | 4 << 12 | 0,
361 Instruction::GOTO | 0x200,
362 Instruction::CONST_4 | 5 << 12 | 0,
363 Instruction::IF_EQ, 3,
364 Instruction::GOTO | 0xFE00,
365 Instruction::RETURN | 0 << 8);
366
367 TestCode(data, expected);
368}
369
370TEST(SsaTest, Loop6) {
371 // Test a loop with one preheader and two back edges (e.g. continue).
372 const char* expected =
373 "BasicBlock 0, succ: 1\n"
374 " 0: IntConstant 0 [5]\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100375 " 1: IntConstant 4 [5, 8, 8]\n"
376 " 2: IntConstant 5 [5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100377 " 3: Goto\n"
378 "BasicBlock 1, pred: 0, succ: 2\n"
379 " 4: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100380 "BasicBlock 2, pred: 1, 4, 5, succ: 6, 3\n"
381 " 5: Phi(0, 2, 1) [12, 6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100382 " 6: Equal(5, 5) [7]\n"
383 " 7: If(6)\n"
384 "BasicBlock 3, pred: 2, succ: 5, 4\n"
385 " 8: Equal(1, 1) [9]\n"
386 " 9: If(8)\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100387 "BasicBlock 4, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100388 " 10: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100389 "BasicBlock 5, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100390 " 11: Goto\n"
391 "BasicBlock 6, pred: 2, succ: 7\n"
392 " 12: Return(5)\n"
393 "BasicBlock 7, pred: 6\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100394 " 13: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100395
396 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
397 Instruction::CONST_4 | 0 | 0,
398 Instruction::IF_EQ, 8,
399 Instruction::CONST_4 | 4 << 12 | 0,
400 Instruction::IF_EQ, 4,
401 Instruction::CONST_4 | 5 << 12 | 0,
402 Instruction::GOTO | 0xFA00,
403 Instruction::GOTO | 0xF900,
404 Instruction::RETURN | 0 << 8);
405
406 TestCode(data, expected);
407}
408
409TEST(SsaTest, Loop7) {
410 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break).
411 const char* expected =
412 "BasicBlock 0, succ: 1\n"
413 " 0: IntConstant 0 [5]\n"
414 " 1: IntConstant 4 [5, 8, 8]\n"
415 " 2: IntConstant 5 [12]\n"
416 " 3: Goto\n"
417 "BasicBlock 1, pred: 0, succ: 2\n"
418 " 4: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100419 "BasicBlock 2, pred: 1, 5, succ: 8, 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100420 " 5: Phi(0, 1) [12, 6, 6]\n"
421 " 6: Equal(5, 5) [7]\n"
422 " 7: If(6)\n"
423 "BasicBlock 3, pred: 2, succ: 5, 4\n"
424 " 8: Equal(1, 1) [9]\n"
425 " 9: If(8)\n"
426 "BasicBlock 4, pred: 3, succ: 6\n"
427 " 10: Goto\n"
428 "BasicBlock 5, pred: 3, succ: 2\n"
429 " 11: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100430 "BasicBlock 6, pred: 8, 4, succ: 7\n"
431 " 12: Phi(5, 2) [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100432 " 13: Return(12)\n"
433 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100434 " 14: Exit\n"
435 "BasicBlock 8, pred: 2, succ: 6\n"
436 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100437
438 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
439 Instruction::CONST_4 | 0 | 0,
440 Instruction::IF_EQ, 8,
441 Instruction::CONST_4 | 4 << 12 | 0,
442 Instruction::IF_EQ, 4,
443 Instruction::CONST_4 | 5 << 12 | 0,
444 Instruction::GOTO | 0x0200,
445 Instruction::GOTO | 0xF900,
446 Instruction::RETURN | 0 << 8);
447
448 TestCode(data, expected);
449}
450
451TEST(SsaTest, DeadLocal) {
452 // Test that we correctly handle a local not being used.
453 const char* expected =
454 "BasicBlock 0, succ: 1\n"
455 " 0: IntConstant 0\n"
456 " 1: Goto\n"
457 "BasicBlock 1, pred: 0, succ: 2\n"
458 " 2: ReturnVoid\n"
459 "BasicBlock 2, pred: 1\n"
460 " 3: Exit\n";
461
462 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
463 Instruction::CONST_4 | 0 | 0,
464 Instruction::RETURN_VOID);
465
466 TestCode(data, expected);
467}
468
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100469TEST(SsaTest, LocalInIf) {
470 // Test that we do not create a phi in the join block when one predecessor
471 // does not update the local.
472 const char* expected =
473 "BasicBlock 0, succ: 1\n"
474 " 0: IntConstant 0 [3, 3]\n"
475 " 1: IntConstant 4\n"
476 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100477 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100478 " 3: Equal(0, 0) [4]\n"
479 " 4: If(3)\n"
480 "BasicBlock 2, pred: 1, succ: 3\n"
481 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100482 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100483 " 6: ReturnVoid\n"
484 "BasicBlock 4, pred: 3\n"
485 " 7: Exit\n"
486 // Synthesized block to avoid critical edge.
487 "BasicBlock 5, pred: 1, succ: 3\n"
488 " 8: Goto\n";
489
490 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
491 Instruction::CONST_4 | 0 | 0,
492 Instruction::IF_EQ, 3,
493 Instruction::CONST_4 | 4 << 12 | 1 << 8,
494 Instruction::RETURN_VOID);
495
496 TestCode(data, expected);
497}
498
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100499TEST(SsaTest, MultiplePredecessors) {
500 // Test that we do not create a phi when one predecessor
501 // does not update the local.
502 const char* expected =
503 "BasicBlock 0, succ: 1\n"
504 " 0: IntConstant 0 [4, 8, 6, 6, 2, 2, 8, 4]\n"
505 " 1: Goto\n"
506 "BasicBlock 1, pred: 0, succ: 3, 2\n"
507 " 2: Equal(0, 0) [3]\n"
508 " 3: If(2)\n"
509 "BasicBlock 2, pred: 1, succ: 5\n"
510 " 4: Add(0, 0)\n"
511 " 5: Goto\n"
512 "BasicBlock 3, pred: 1, succ: 7, 4\n"
513 " 6: Equal(0, 0) [7]\n"
514 " 7: If(6)\n"
515 "BasicBlock 4, pred: 3, succ: 5\n"
516 " 8: Add(0, 0)\n"
517 " 9: Goto\n"
518 // This block should not get a phi for local 1.
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100519 "BasicBlock 5, pred: 2, 7, 4, succ: 6\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100520 " 10: ReturnVoid\n"
521 "BasicBlock 6, pred: 5\n"
522 " 11: Exit\n"
523 "BasicBlock 7, pred: 3, succ: 5\n"
524 " 12: Goto\n";
525
526 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
527 Instruction::CONST_4 | 0 | 0,
528 Instruction::IF_EQ, 5,
529 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
530 Instruction::GOTO | 0x0500,
531 Instruction::IF_EQ, 4,
532 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
533 Instruction::RETURN_VOID);
534
535 TestCode(data, expected);
536}
537
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100538} // namespace art