blob: 85ed06eb9b590ac3ed9f782418d242707af48750 [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
Andreas Gampe46ee31b2016-12-14 10:11:49 -080017#include "android-base/stringprintf.h"
18
Mathieu Chartierb666f482015-02-18 14:33:14 -080019#include "base/arena_allocator.h"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010020#include "builder.h"
David Sehr9e734c72018-01-04 17:56:19 -080021#include "dex/dex_file.h"
22#include "dex/dex_instruction.h"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010023#include "nodes.h"
24#include "optimizing_unit_test.h"
25#include "pretty_printer.h"
26#include "ssa_builder.h"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010027
28#include "gtest/gtest.h"
29
30namespace art {
31
Vladimir Markoca6fff82017-10-03 14:49:14 +010032class SsaTest : public OptimizingUnitTest {
33 protected:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080034 void TestCode(const std::vector<uint16_t>& data, const char* expected);
Vladimir Markoca6fff82017-10-03 14:49:14 +010035};
David Brazdil4833f5a2015-12-16 10:37:39 +000036
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010037class SsaPrettyPrinter : public HPrettyPrinter {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010038 public:
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010039 explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {}
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010040
Alexandre Rames2ed20af2015-03-06 13:55:35 +000041 void PrintInt(int value) OVERRIDE {
Andreas Gampe46ee31b2016-12-14 10:11:49 -080042 str_ += android::base::StringPrintf("%d", value);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010043 }
44
Alexandre Rames2ed20af2015-03-06 13:55:35 +000045 void PrintString(const char* value) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010046 str_ += value;
47 }
48
Alexandre Rames2ed20af2015-03-06 13:55:35 +000049 void PrintNewLine() OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010050 str_ += '\n';
51 }
52
53 void Clear() { str_.clear(); }
54
55 std::string str() const { return str_; }
56
Alexandre Rames2ed20af2015-03-06 13:55:35 +000057 void VisitIntConstant(HIntConstant* constant) OVERRIDE {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010058 PrintPreInstruction(constant);
59 str_ += constant->DebugName();
60 str_ += " ";
61 PrintInt(constant->GetValue());
62 PrintPostInstruction(constant);
63 }
64
65 private:
66 std::string str_;
67
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010068 DISALLOW_COPY_AND_ASSIGN(SsaPrettyPrinter);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010069};
70
71static void ReNumberInstructions(HGraph* graph) {
72 int id = 0;
Vladimir Markofa6b93c2015-09-15 10:15:55 +010073 for (HBasicBlock* block : graph->GetBlocks()) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010074 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010075 it.Current()->SetId(id++);
76 }
Nicolas Geoffrayf635e632014-05-14 09:43:38 +010077 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010078 it.Current()->SetId(id++);
79 }
80 }
81}
82
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080083void SsaTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010084 HGraph* graph = CreateCFG(data);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000085 // Suspend checks implementation may change in the future, and this test relies
86 // on how instructions are ordered.
87 RemoveSuspendChecks(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010088 ReNumberInstructions(graph);
89
Nicolas Geoffray184d6402014-06-09 14:06:02 +010090 // Test that phis had their type set.
Vladimir Markofa6b93c2015-09-15 10:15:55 +010091 for (HBasicBlock* block : graph->GetBlocks()) {
92 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010093 ASSERT_NE(it.Current()->GetType(), DataType::Type::kVoid);
Nicolas Geoffray184d6402014-06-09 14:06:02 +010094 }
95 }
96
Nicolas Geoffray0d3f5782014-05-14 09:43:38 +010097 SsaPrettyPrinter printer(graph);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +010098 printer.VisitInsertionOrder();
99
100 ASSERT_STREQ(expected, printer.str().c_str());
101}
102
David Brazdil4833f5a2015-12-16 10:37:39 +0000103TEST_F(SsaTest, CFG1) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100104 // Test that we get rid of loads and stores.
105 const char* expected =
106 "BasicBlock 0, succ: 1\n"
107 " 0: IntConstant 0 [2, 2]\n"
108 " 1: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100109 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100110 " 2: Equal(0, 0) [3]\n"
111 " 3: If(2)\n"
112 "BasicBlock 2, pred: 1, succ: 3\n"
113 " 4: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100114 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100115 " 5: ReturnVoid\n"
116 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100117 " 6: Exit\n"
118 // Synthesized block to avoid critical edge.
119 "BasicBlock 5, pred: 1, succ: 3\n"
120 " 7: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100121
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800122 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100123 Instruction::CONST_4 | 0 | 0,
124 Instruction::IF_EQ, 3,
125 Instruction::GOTO | 0x100,
126 Instruction::RETURN_VOID);
127
128 TestCode(data, expected);
129}
130
David Brazdil4833f5a2015-12-16 10:37:39 +0000131TEST_F(SsaTest, CFG2) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100132 // Test that we create a phi for the join block of an if control flow instruction
133 // when there is only code in the else branch.
134 const char* expected =
135 "BasicBlock 0, succ: 1\n"
136 " 0: IntConstant 0 [6, 3, 3]\n"
137 " 1: IntConstant 4 [6]\n"
138 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100139 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100140 " 3: Equal(0, 0) [4]\n"
141 " 4: If(3)\n"
142 "BasicBlock 2, pred: 1, succ: 3\n"
143 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100144 "BasicBlock 3, pred: 5, 2, succ: 4\n"
145 " 6: Phi(0, 1) [7]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100146 " 7: Return(6)\n"
147 "BasicBlock 4, pred: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100148 " 8: Exit\n"
149 // Synthesized block to avoid critical edge.
150 "BasicBlock 5, pred: 1, succ: 3\n"
151 " 9: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100152
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800153 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100154 Instruction::CONST_4 | 0 | 0,
155 Instruction::IF_EQ, 3,
156 Instruction::CONST_4 | 4 << 12 | 0,
157 Instruction::RETURN | 0 << 8);
158
159 TestCode(data, expected);
160}
161
David Brazdil4833f5a2015-12-16 10:37:39 +0000162TEST_F(SsaTest, CFG3) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100163 // Test that we create a phi for the join block of an if control flow instruction
Nicolas Geoffray804d0932014-05-02 08:46:00 +0100164 // when both branches update a local.
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100165 const char* expected =
166 "BasicBlock 0, succ: 1\n"
167 " 0: IntConstant 0 [4, 4]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000168 " 1: IntConstant 5 [8]\n"
169 " 2: IntConstant 4 [8]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100170 " 3: Goto\n"
171 "BasicBlock 1, pred: 0, succ: 3, 2\n"
172 " 4: Equal(0, 0) [5]\n"
173 " 5: If(4)\n"
174 "BasicBlock 2, pred: 1, succ: 4\n"
175 " 6: Goto\n"
176 "BasicBlock 3, pred: 1, succ: 4\n"
177 " 7: Goto\n"
178 "BasicBlock 4, pred: 2, 3, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000179 " 8: Phi(2, 1) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100180 " 9: Return(8)\n"
181 "BasicBlock 5, pred: 4\n"
182 " 10: Exit\n";
183
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800184 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100185 Instruction::CONST_4 | 0 | 0,
186 Instruction::IF_EQ, 4,
187 Instruction::CONST_4 | 4 << 12 | 0,
188 Instruction::GOTO | 0x200,
189 Instruction::CONST_4 | 5 << 12 | 0,
190 Instruction::RETURN | 0 << 8);
191
192 TestCode(data, expected);
193}
194
David Brazdil4833f5a2015-12-16 10:37:39 +0000195TEST_F(SsaTest, Loop1) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100196 // Test that we create a phi for an initialized local at entry of a loop.
197 const char* expected =
198 "BasicBlock 0, succ: 1\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000199 " 0: IntConstant 0 [6, 3, 3]\n"
200 " 1: IntConstant 4 [6]\n"
201 " 2: Goto\n"
202 "BasicBlock 1, pred: 0, succ: 4, 2\n"
203 " 3: Equal(0, 0) [4]\n"
204 " 4: If(3)\n"
205 "BasicBlock 2, pred: 1, succ: 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100206 " 5: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000207 "BasicBlock 3, pred: 2, 4, succ: 5\n"
208 " 6: Phi(1, 0) [9]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100209 " 7: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000210 "BasicBlock 4, pred: 1, succ: 3\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100211 " 8: Goto\n"
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000212 "BasicBlock 5, pred: 3, succ: 6\n"
213 " 9: Return(6)\n"
214 "BasicBlock 6, pred: 5\n"
215 " 10: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100216
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800217 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100218 Instruction::CONST_4 | 0 | 0,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000219 Instruction::IF_EQ, 4,
220 Instruction::CONST_4 | 4 << 12 | 0,
221 Instruction::GOTO | 0x200,
222 Instruction::GOTO | 0xFF00,
223 Instruction::RETURN | 0 << 8);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100224
225 TestCode(data, expected);
226}
227
David Brazdil4833f5a2015-12-16 10:37:39 +0000228TEST_F(SsaTest, Loop2) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100229 // Simple loop with one preheader and one back edge.
230 const char* expected =
231 "BasicBlock 0, succ: 1\n"
232 " 0: IntConstant 0 [4]\n"
233 " 1: IntConstant 4 [4]\n"
234 " 2: Goto\n"
235 "BasicBlock 1, pred: 0, succ: 2\n"
236 " 3: Goto\n"
237 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
238 " 4: Phi(0, 1) [5, 5]\n"
239 " 5: Equal(4, 4) [6]\n"
240 " 6: If(5)\n"
241 "BasicBlock 3, pred: 2, succ: 2\n"
242 " 7: Goto\n"
243 "BasicBlock 4, pred: 2, succ: 5\n"
244 " 8: ReturnVoid\n"
245 "BasicBlock 5, pred: 4\n"
246 " 9: Exit\n";
247
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800248 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100249 Instruction::CONST_4 | 0 | 0,
250 Instruction::IF_EQ, 4,
251 Instruction::CONST_4 | 4 << 12 | 0,
252 Instruction::GOTO | 0xFD00,
253 Instruction::RETURN_VOID);
254
255 TestCode(data, expected);
256}
257
David Brazdil4833f5a2015-12-16 10:37:39 +0000258TEST_F(SsaTest, Loop3) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100259 // Test that a local not yet defined at the entry of a loop is handled properly.
260 const char* expected =
261 "BasicBlock 0, succ: 1\n"
262 " 0: IntConstant 0 [5]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000263 " 1: IntConstant 5 [9]\n"
264 " 2: IntConstant 4 [5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100265 " 3: Goto\n"
266 "BasicBlock 1, pred: 0, succ: 2\n"
267 " 4: Goto\n"
268 "BasicBlock 2, pred: 1, 3, succ: 4, 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000269 " 5: Phi(0, 2) [6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100270 " 6: Equal(5, 5) [7]\n"
271 " 7: If(6)\n"
272 "BasicBlock 3, pred: 2, succ: 2\n"
273 " 8: Goto\n"
274 "BasicBlock 4, pred: 2, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000275 " 9: Return(1)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100276 "BasicBlock 5, pred: 4\n"
277 " 10: Exit\n";
278
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800279 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100280 Instruction::CONST_4 | 0 | 0,
281 Instruction::IF_EQ, 4,
282 Instruction::CONST_4 | 4 << 12 | 0,
283 Instruction::GOTO | 0xFD00,
284 Instruction::CONST_4 | 5 << 12 | 1 << 8,
285 Instruction::RETURN | 1 << 8);
286
287 TestCode(data, expected);
288}
289
David Brazdil4833f5a2015-12-16 10:37:39 +0000290TEST_F(SsaTest, Loop4) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100291 // Make sure we support a preheader of a loop not being the first predecessor
292 // in the predecessor list of the header.
293 const char* expected =
294 "BasicBlock 0, succ: 1\n"
295 " 0: IntConstant 0 [4]\n"
296 " 1: IntConstant 4 [4]\n"
297 " 2: Goto\n"
298 "BasicBlock 1, pred: 0, succ: 4\n"
299 " 3: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100300 "BasicBlock 2, pred: 4, 3, succ: 5, 3\n"
301 " 4: Phi(0, 1) [9, 5, 5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100302 " 5: Equal(4, 4) [6]\n"
303 " 6: If(5)\n"
304 "BasicBlock 3, pred: 2, succ: 2\n"
305 " 7: Goto\n"
306 "BasicBlock 4, pred: 1, succ: 2\n"
307 " 8: Goto\n"
308 "BasicBlock 5, pred: 2, succ: 6\n"
309 " 9: Return(4)\n"
310 "BasicBlock 6, pred: 5\n"
311 " 10: Exit\n";
312
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800313 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100314 Instruction::CONST_4 | 0 | 0,
315 Instruction::GOTO | 0x500,
316 Instruction::IF_EQ, 5,
317 Instruction::CONST_4 | 4 << 12 | 0,
318 Instruction::GOTO | 0xFD00,
319 Instruction::GOTO | 0xFC00,
320 Instruction::RETURN | 0 << 8);
321
322 TestCode(data, expected);
323}
324
David Brazdil4833f5a2015-12-16 10:37:39 +0000325TEST_F(SsaTest, Loop5) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100326 // Make sure we create a preheader of a loop when a header originally has two
327 // incoming blocks and one back edge.
328 const char* expected =
329 "BasicBlock 0, succ: 1\n"
330 " 0: IntConstant 0 [4, 4]\n"
David Brazdildee58d62016-04-07 09:54:26 +0000331 " 1: IntConstant 5 [13]\n"
332 " 2: IntConstant 4 [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100333 " 3: Goto\n"
334 "BasicBlock 1, pred: 0, succ: 3, 2\n"
335 " 4: Equal(0, 0) [5]\n"
336 " 5: If(4)\n"
337 "BasicBlock 2, pred: 1, succ: 8\n"
338 " 6: Goto\n"
339 "BasicBlock 3, pred: 1, succ: 8\n"
340 " 7: Goto\n"
Nicolas Geoffrayc83d4412014-09-18 16:46:20 +0100341 "BasicBlock 4, pred: 8, 5, succ: 6, 5\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000342 " 8: Equal(13, 13) [9]\n"
343 " 9: If(8)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100344 "BasicBlock 5, pred: 4, succ: 4\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000345 " 10: Goto\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100346 "BasicBlock 6, pred: 4, succ: 7\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000347 " 11: Return(13)\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100348 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000349 " 12: Exit\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100350 "BasicBlock 8, pred: 2, 3, succ: 4\n"
Vladimir Marko3c19d3e2016-04-19 14:36:35 +0100351 " 13: Phi(2, 1) [11, 8, 8]\n"
Nicolas Geoffray3afca782015-03-10 18:59:31 +0000352 " 14: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100353
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800354 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100355 Instruction::CONST_4 | 0 | 0,
356 Instruction::IF_EQ, 4,
357 Instruction::CONST_4 | 4 << 12 | 0,
358 Instruction::GOTO | 0x200,
359 Instruction::CONST_4 | 5 << 12 | 0,
360 Instruction::IF_EQ, 3,
361 Instruction::GOTO | 0xFE00,
362 Instruction::RETURN | 0 << 8);
363
364 TestCode(data, expected);
365}
366
David Brazdil4833f5a2015-12-16 10:37:39 +0000367TEST_F(SsaTest, Loop6) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100368 // Test a loop with one preheader and two back edges (e.g. continue).
369 const char* expected =
370 "BasicBlock 0, succ: 1\n"
371 " 0: IntConstant 0 [5]\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100372 " 1: IntConstant 4 [5, 8, 8]\n"
373 " 2: IntConstant 5 [5]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100374 " 3: Goto\n"
375 "BasicBlock 1, pred: 0, succ: 2\n"
376 " 4: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100377 "BasicBlock 2, pred: 1, 4, 5, succ: 6, 3\n"
378 " 5: Phi(0, 2, 1) [12, 6, 6]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100379 " 6: Equal(5, 5) [7]\n"
380 " 7: If(6)\n"
381 "BasicBlock 3, pred: 2, succ: 5, 4\n"
382 " 8: Equal(1, 1) [9]\n"
383 " 9: If(8)\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100384 "BasicBlock 4, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100385 " 10: Goto\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100386 "BasicBlock 5, pred: 3, succ: 2\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100387 " 11: Goto\n"
388 "BasicBlock 6, pred: 2, succ: 7\n"
389 " 12: Return(5)\n"
390 "BasicBlock 7, pred: 6\n"
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100391 " 13: Exit\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100392
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800393 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100394 Instruction::CONST_4 | 0 | 0,
395 Instruction::IF_EQ, 8,
396 Instruction::CONST_4 | 4 << 12 | 0,
397 Instruction::IF_EQ, 4,
398 Instruction::CONST_4 | 5 << 12 | 0,
399 Instruction::GOTO | 0xFA00,
400 Instruction::GOTO | 0xF900,
401 Instruction::RETURN | 0 << 8);
402
403 TestCode(data, expected);
404}
405
David Brazdil4833f5a2015-12-16 10:37:39 +0000406TEST_F(SsaTest, Loop7) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100407 // Test a loop with one preheader, one back edge, and two exit edges (e.g. break).
408 const char* expected =
409 "BasicBlock 0, succ: 1\n"
410 " 0: IntConstant 0 [5]\n"
411 " 1: IntConstant 4 [5, 8, 8]\n"
412 " 2: IntConstant 5 [12]\n"
413 " 3: Goto\n"
414 "BasicBlock 1, pred: 0, succ: 2\n"
415 " 4: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100416 "BasicBlock 2, pred: 1, 5, succ: 8, 3\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100417 " 5: Phi(0, 1) [12, 6, 6]\n"
418 " 6: Equal(5, 5) [7]\n"
419 " 7: If(6)\n"
420 "BasicBlock 3, pred: 2, succ: 5, 4\n"
421 " 8: Equal(1, 1) [9]\n"
422 " 9: If(8)\n"
423 "BasicBlock 4, pred: 3, succ: 6\n"
424 " 10: Goto\n"
425 "BasicBlock 5, pred: 3, succ: 2\n"
426 " 11: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100427 "BasicBlock 6, pred: 8, 4, succ: 7\n"
428 " 12: Phi(5, 2) [13]\n"
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100429 " 13: Return(12)\n"
430 "BasicBlock 7, pred: 6\n"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100431 " 14: Exit\n"
432 "BasicBlock 8, pred: 2, succ: 6\n"
433 " 15: Goto\n";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100434
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800435 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100436 Instruction::CONST_4 | 0 | 0,
437 Instruction::IF_EQ, 8,
438 Instruction::CONST_4 | 4 << 12 | 0,
439 Instruction::IF_EQ, 4,
440 Instruction::CONST_4 | 5 << 12 | 0,
441 Instruction::GOTO | 0x0200,
442 Instruction::GOTO | 0xF900,
443 Instruction::RETURN | 0 << 8);
444
445 TestCode(data, expected);
446}
447
David Brazdil4833f5a2015-12-16 10:37:39 +0000448TEST_F(SsaTest, DeadLocal) {
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100449 // Test that we correctly handle a local not being used.
450 const char* expected =
451 "BasicBlock 0, succ: 1\n"
452 " 0: IntConstant 0\n"
453 " 1: Goto\n"
454 "BasicBlock 1, pred: 0, succ: 2\n"
455 " 2: ReturnVoid\n"
456 "BasicBlock 2, pred: 1\n"
457 " 3: Exit\n";
458
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800459 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100460 Instruction::CONST_4 | 0 | 0,
461 Instruction::RETURN_VOID);
462
463 TestCode(data, expected);
464}
465
David Brazdil4833f5a2015-12-16 10:37:39 +0000466TEST_F(SsaTest, LocalInIf) {
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100467 // Test that we do not create a phi in the join block when one predecessor
468 // does not update the local.
469 const char* expected =
470 "BasicBlock 0, succ: 1\n"
471 " 0: IntConstant 0 [3, 3]\n"
472 " 1: IntConstant 4\n"
473 " 2: Goto\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100474 "BasicBlock 1, pred: 0, succ: 5, 2\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100475 " 3: Equal(0, 0) [4]\n"
476 " 4: If(3)\n"
477 "BasicBlock 2, pred: 1, succ: 3\n"
478 " 5: Goto\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100479 "BasicBlock 3, pred: 5, 2, succ: 4\n"
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100480 " 6: ReturnVoid\n"
481 "BasicBlock 4, pred: 3\n"
482 " 7: Exit\n"
483 // Synthesized block to avoid critical edge.
484 "BasicBlock 5, pred: 1, succ: 3\n"
485 " 8: Goto\n";
486
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800487 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray7c3560f2014-06-04 12:12:08 +0100488 Instruction::CONST_4 | 0 | 0,
489 Instruction::IF_EQ, 3,
490 Instruction::CONST_4 | 4 << 12 | 1 << 8,
491 Instruction::RETURN_VOID);
492
493 TestCode(data, expected);
494}
495
David Brazdil4833f5a2015-12-16 10:37:39 +0000496TEST_F(SsaTest, MultiplePredecessors) {
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100497 // Test that we do not create a phi when one predecessor
498 // does not update the local.
499 const char* expected =
500 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000501 " 0: IntConstant 0 [4, 4, 8, 8, 6, 6, 2, 2]\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100502 " 1: Goto\n"
503 "BasicBlock 1, pred: 0, succ: 3, 2\n"
504 " 2: Equal(0, 0) [3]\n"
505 " 3: If(2)\n"
506 "BasicBlock 2, pred: 1, succ: 5\n"
507 " 4: Add(0, 0)\n"
508 " 5: Goto\n"
509 "BasicBlock 3, pred: 1, succ: 7, 4\n"
510 " 6: Equal(0, 0) [7]\n"
511 " 7: If(6)\n"
512 "BasicBlock 4, pred: 3, succ: 5\n"
513 " 8: Add(0, 0)\n"
514 " 9: Goto\n"
515 // This block should not get a phi for local 1.
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100516 "BasicBlock 5, pred: 2, 7, 4, succ: 6\n"
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100517 " 10: ReturnVoid\n"
518 "BasicBlock 6, pred: 5\n"
519 " 11: Exit\n"
520 "BasicBlock 7, pred: 3, succ: 5\n"
521 " 12: Goto\n";
522
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800523 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100524 Instruction::CONST_4 | 0 | 0,
525 Instruction::IF_EQ, 5,
526 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
527 Instruction::GOTO | 0x0500,
528 Instruction::IF_EQ, 4,
529 Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
530 Instruction::RETURN_VOID);
531
532 TestCode(data, expected);
533}
534
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100535} // namespace art