blob: ff44805ed2a16b89d2451b53c572635410afdc91 [file] [log] [blame]
Roland Levillain556c3d12014-09-18 15:25:07 +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
Roland Levillain93445682014-10-06 19:24:02 +010017#include <functional>
18
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000019#include "constant_propagation.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010020#include "dead_code_elimination.h"
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000021#include "pretty_printer.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010022#include "graph_checker.h"
23#include "optimizing_unit_test.h"
24
25#include "gtest/gtest.h"
26
27namespace art {
28
29static void TestCode(const uint16_t* data,
30 const std::string& expected_before,
31 const std::string& expected_after_cp,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010032 const std::string& expected_after_dce,
Roland Levillain93445682014-10-06 19:24:02 +010033 std::function<void(HGraph*)> check_after_cp,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010034 Primitive::Type return_type = Primitive::kPrimInt) {
Roland Levillain556c3d12014-09-18 15:25:07 +010035 ArenaPool pool;
36 ArenaAllocator allocator(&pool);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010037 HGraph* graph = CreateCFG(&allocator, data, return_type);
Roland Levillain556c3d12014-09-18 15:25:07 +010038 ASSERT_NE(graph, nullptr);
39
40 graph->BuildDominatorTree();
41 graph->TransformToSSA();
42
43 StringPrettyPrinter printer_before(graph);
44 printer_before.VisitInsertionOrder();
45 std::string actual_before = printer_before.str();
46 ASSERT_EQ(expected_before, actual_before);
47
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000048 ConstantPropagation(graph).Run();
Roland Levillain556c3d12014-09-18 15:25:07 +010049
50 StringPrettyPrinter printer_after_cp(graph);
51 printer_after_cp.VisitInsertionOrder();
52 std::string actual_after_cp = printer_after_cp.str();
53 ASSERT_EQ(expected_after_cp, actual_after_cp);
54
Roland Levillain93445682014-10-06 19:24:02 +010055 check_after_cp(graph);
56
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000057 DeadCodeElimination(graph).Run();
Roland Levillain556c3d12014-09-18 15:25:07 +010058
59 StringPrettyPrinter printer_after_dce(graph);
60 printer_after_dce.VisitInsertionOrder();
61 std::string actual_after_dce = printer_after_dce.str();
62 ASSERT_EQ(expected_after_dce, actual_after_dce);
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000063
64 SSAChecker ssa_checker(&allocator, graph);
Roland Levillain633021e2014-10-01 14:12:25 +010065 ssa_checker.Run();
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000066 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010067}
68
69
70/**
71 * Tiny three-register program exercising int constant folding on addition.
72 *
73 * 16-bit
74 * offset
75 * ------
76 * v0 <- 1 0. const/4 v0, #+1
77 * v1 <- 2 1. const/4 v1, #+2
78 * v2 <- v0 + v1 2. add-int v2, v0, v1
79 * return v2 4. return v2
80 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +000081TEST(ConstantPropagation, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +010082 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
83 Instruction::CONST_4 | 0 << 8 | 1 << 12,
84 Instruction::CONST_4 | 1 << 8 | 2 << 12,
85 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
86 Instruction::RETURN | 2 << 8);
87
88 std::string expected_before =
89 "BasicBlock 0, succ: 1\n"
90 " 3: IntConstant [9]\n"
91 " 5: IntConstant [9]\n"
92 " 14: SuspendCheck\n"
93 " 15: Goto 1\n"
94 "BasicBlock 1, pred: 0, succ: 2\n"
95 " 9: Add(3, 5) [12]\n"
96 " 12: Return(9)\n"
97 "BasicBlock 2, pred: 1\n"
98 " 13: Exit\n";
99
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000100 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100101 diff_t expected_cp_diff = {
102 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
103 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
104 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
105 { " 12: Return(9)\n", " 12: Return(16)\n" }
106 };
107 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
108
Roland Levillain93445682014-10-06 19:24:02 +0100109 // Check the value of the computed constant.
110 auto check_after_cp = [](HGraph* graph) {
111 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
112 ASSERT_TRUE(inst->IsIntConstant());
113 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
114 };
115
Roland Levillain556c3d12014-09-18 15:25:07 +0100116 // Expected difference after dead code elimination.
117 diff_t expected_dce_diff = {
118 { " 3: IntConstant\n", removed },
119 { " 5: IntConstant\n", removed }
120 };
121 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
122
Roland Levillain93445682014-10-06 19:24:02 +0100123 TestCode(data,
124 expected_before,
125 expected_after_cp,
126 expected_after_dce,
127 check_after_cp);
Roland Levillain556c3d12014-09-18 15:25:07 +0100128}
129
130/**
131 * Small three-register program exercising int constant folding on addition.
132 *
133 * 16-bit
134 * offset
135 * ------
136 * v0 <- 1 0. const/4 v0, #+1
137 * v1 <- 2 1. const/4 v1, #+2
138 * v0 <- v0 + v1 2. add-int/2addr v0, v1
139 * v1 <- 3 3. const/4 v1, #+3
140 * v2 <- 4 4. const/4 v2, #+4
141 * v1 <- v1 + v2 5. add-int/2addr v1, v2
142 * v2 <- v0 + v1 6. add-int v2, v0, v1
143 * return v2 8. return v2
144 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000145TEST(ConstantPropagation, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100146 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
147 Instruction::CONST_4 | 0 << 8 | 1 << 12,
148 Instruction::CONST_4 | 1 << 8 | 2 << 12,
149 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
150 Instruction::CONST_4 | 1 << 8 | 3 << 12,
151 Instruction::CONST_4 | 2 << 8 | 4 << 12,
152 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
153 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
154 Instruction::RETURN | 2 << 8);
155
156 std::string expected_before =
157 "BasicBlock 0, succ: 1\n"
158 " 3: IntConstant [9]\n"
159 " 5: IntConstant [9]\n"
160 " 11: IntConstant [17]\n"
161 " 13: IntConstant [17]\n"
162 " 26: SuspendCheck\n"
163 " 27: Goto 1\n"
164 "BasicBlock 1, pred: 0, succ: 2\n"
165 " 9: Add(3, 5) [21]\n"
166 " 17: Add(11, 13) [21]\n"
167 " 21: Add(9, 17) [24]\n"
168 " 24: Return(21)\n"
169 "BasicBlock 2, pred: 1\n"
170 " 25: Exit\n";
171
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000172 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100173 diff_t expected_cp_diff = {
174 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
175 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
176 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
177 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
178 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
179 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
180 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
181 { " 24: Return(21)\n", " 24: Return(30)\n" }
182 };
183 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
184
Roland Levillain93445682014-10-06 19:24:02 +0100185 // Check the values of the computed constants.
186 auto check_after_cp = [](HGraph* graph) {
187 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
188 ASSERT_TRUE(inst1->IsIntConstant());
189 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
190 HInstruction* inst2 = inst1->GetNext();
191 ASSERT_TRUE(inst2->IsIntConstant());
192 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
193 HInstruction* inst3 = inst2->GetNext();
194 ASSERT_TRUE(inst3->IsIntConstant());
195 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
196 };
197
Roland Levillain556c3d12014-09-18 15:25:07 +0100198 // Expected difference after dead code elimination.
199 diff_t expected_dce_diff = {
200 { " 3: IntConstant\n", removed },
201 { " 5: IntConstant\n", removed },
202 { " 11: IntConstant\n", removed },
203 { " 13: IntConstant\n", removed },
204 { " 28: IntConstant\n", removed },
205 { " 29: IntConstant\n", removed }
206 };
207 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
208
Roland Levillain93445682014-10-06 19:24:02 +0100209 TestCode(data,
210 expected_before,
211 expected_after_cp,
212 expected_after_dce,
213 check_after_cp);
Roland Levillain556c3d12014-09-18 15:25:07 +0100214}
215
216/**
217 * Tiny three-register program exercising int constant folding on subtraction.
218 *
219 * 16-bit
220 * offset
221 * ------
222 * v0 <- 3 0. const/4 v0, #+3
223 * v1 <- 2 1. const/4 v1, #+2
224 * v2 <- v0 - v1 2. sub-int v2, v0, v1
225 * return v2 4. return v2
226 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000227TEST(ConstantPropagation, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100228 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
229 Instruction::CONST_4 | 0 << 8 | 3 << 12,
230 Instruction::CONST_4 | 1 << 8 | 2 << 12,
231 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
232 Instruction::RETURN | 2 << 8);
233
234 std::string expected_before =
235 "BasicBlock 0, succ: 1\n"
236 " 3: IntConstant [9]\n"
237 " 5: IntConstant [9]\n"
238 " 14: SuspendCheck\n"
239 " 15: Goto 1\n"
240 "BasicBlock 1, pred: 0, succ: 2\n"
241 " 9: Sub(3, 5) [12]\n"
242 " 12: Return(9)\n"
243 "BasicBlock 2, pred: 1\n"
244 " 13: Exit\n";
245
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000246 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100247 diff_t expected_cp_diff = {
248 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
249 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
250 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
251 { " 12: Return(9)\n", " 12: Return(16)\n" }
252 };
253 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
254
Roland Levillain93445682014-10-06 19:24:02 +0100255 // Check the value of the computed constant.
256 auto check_after_cp = [](HGraph* graph) {
257 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
258 ASSERT_TRUE(inst->IsIntConstant());
259 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
260 };
261
Roland Levillain556c3d12014-09-18 15:25:07 +0100262 // Expected difference after dead code elimination.
263 diff_t expected_dce_diff = {
264 { " 3: IntConstant\n", removed },
265 { " 5: IntConstant\n", removed }
266 };
267 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
268
Roland Levillain93445682014-10-06 19:24:02 +0100269 TestCode(data,
270 expected_before,
271 expected_after_cp,
272 expected_after_dce,
273 check_after_cp);
Roland Levillain556c3d12014-09-18 15:25:07 +0100274}
275
276#define SIX_REGISTERS_CODE_ITEM(...) \
277 { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
278
279/**
280 * Tiny three-register-pair program exercising long constant folding
281 * on addition.
282 *
283 * 16-bit
284 * offset
285 * ------
286 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
287 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
288 * (v4, v5) <-
289 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
290 * return (v4, v5) 6. return-wide v4
291 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000292TEST(ConstantPropagation, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100293 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
294 Instruction::CONST_WIDE_16 | 0 << 8, 1,
295 Instruction::CONST_WIDE_16 | 2 << 8, 2,
296 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
297 Instruction::RETURN_WIDE | 4 << 8);
298
299 std::string expected_before =
300 "BasicBlock 0, succ: 1\n"
301 " 6: LongConstant [12]\n"
302 " 8: LongConstant [12]\n"
303 " 17: SuspendCheck\n"
304 " 18: Goto 1\n"
305 "BasicBlock 1, pred: 0, succ: 2\n"
306 " 12: Add(6, 8) [15]\n"
307 " 15: Return(12)\n"
308 "BasicBlock 2, pred: 1\n"
309 " 16: Exit\n";
310
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000311 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100312 diff_t expected_cp_diff = {
313 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
314 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
315 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
316 { " 15: Return(12)\n", " 15: Return(19)\n" }
317 };
318 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
319
Roland Levillain93445682014-10-06 19:24:02 +0100320 // Check the value of the computed constant.
321 auto check_after_cp = [](HGraph* graph) {
322 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
323 ASSERT_TRUE(inst->IsLongConstant());
324 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
325 };
326
Roland Levillain556c3d12014-09-18 15:25:07 +0100327 // Expected difference after dead code elimination.
328 diff_t expected_dce_diff = {
329 { " 6: LongConstant\n", removed },
330 { " 8: LongConstant\n", removed }
331 };
332 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
333
Roland Levillain93445682014-10-06 19:24:02 +0100334 TestCode(data,
335 expected_before,
336 expected_after_cp,
337 expected_after_dce,
338 check_after_cp,
339 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100340}
341
342/**
343 * Tiny three-register-pair program exercising long constant folding
344 * on subtraction.
345 *
346 * 16-bit
347 * offset
348 * ------
349 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
350 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
351 * (v4, v5) <-
352 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
353 * return (v4, v5) 6. return-wide v4
354 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000355TEST(ConstantPropagation, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100356 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
357 Instruction::CONST_WIDE_16 | 0 << 8, 3,
358 Instruction::CONST_WIDE_16 | 2 << 8, 2,
359 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
360 Instruction::RETURN_WIDE | 4 << 8);
361
362 std::string expected_before =
363 "BasicBlock 0, succ: 1\n"
364 " 6: LongConstant [12]\n"
365 " 8: LongConstant [12]\n"
366 " 17: SuspendCheck\n"
367 " 18: Goto 1\n"
368 "BasicBlock 1, pred: 0, succ: 2\n"
369 " 12: Sub(6, 8) [15]\n"
370 " 15: Return(12)\n"
371 "BasicBlock 2, pred: 1\n"
372 " 16: Exit\n";
373
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000374 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100375 diff_t expected_cp_diff = {
376 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
377 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
378 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
379 { " 15: Return(12)\n", " 15: Return(19)\n" }
380 };
381 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
382
Roland Levillain93445682014-10-06 19:24:02 +0100383 // Check the value of the computed constant.
384 auto check_after_cp = [](HGraph* graph) {
385 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
386 ASSERT_TRUE(inst->IsLongConstant());
387 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
388 };
389
Roland Levillain556c3d12014-09-18 15:25:07 +0100390 // Expected difference after dead code elimination.
391 diff_t expected_dce_diff = {
392 { " 6: LongConstant\n", removed },
393 { " 8: LongConstant\n", removed }
394 };
395 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
396
Roland Levillain93445682014-10-06 19:24:02 +0100397 TestCode(data,
398 expected_before,
399 expected_after_cp,
400 expected_after_dce,
401 check_after_cp,
402 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100403}
404
405/**
406 * Three-register program with jumps leading to the creation of many
407 * blocks.
408 *
409 * The intent of this test is to ensure that all constant expressions
410 * are actually evaluated at compile-time, thanks to the reverse
411 * (forward) post-order traversal of the the dominator tree.
412 *
413 * 16-bit
414 * offset
415 * ------
416 * v0 <- 0 0. const/4 v0, #+0
417 * v1 <- 1 1. const/4 v1, #+1
418 * v2 <- v0 + v1 2. add-int v2, v0, v1
419 * goto L2 4. goto +4
420 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
421 * goto L3 7. goto +4
422 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
423 * goto L1 10. goto +(-5)
424 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
425 * return v2 13. return v2
426 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000427TEST(ConstantPropagation, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100428 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
429 Instruction::CONST_4 | 0 << 8 | 0 << 12,
430 Instruction::CONST_4 | 1 << 8 | 1 << 12,
431 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
432 Instruction::GOTO | 4 << 8,
433 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
434 Instruction::GOTO | 4 << 8,
435 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
436 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
437 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
438 Instruction::RETURN | 2 << 8);
439
440 std::string expected_before =
441 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100442 " 3: IntConstant [9]\n" // v0 <- 0
443 " 5: IntConstant [9]\n" // v1 <- 1
444 " 13: IntConstant [14]\n" // const 3
445 " 18: IntConstant [19]\n" // const 2
446 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100447 " 30: SuspendCheck\n"
448 " 31: Goto 1\n"
449 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100450 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
451 " 11: Goto 3\n" // goto L2
452 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
453 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
454 " 16: Goto 4\n" // goto L3
455 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
456 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100457 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100458 " 22: Goto 2\n" // goto L1
459 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
460 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
461 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100462 "BasicBlock 5, pred: 4\n"
463 " 29: Exit\n";
464
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000465 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100466 diff_t expected_cp_diff = {
467 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
468 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
469 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
470 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
471 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
472 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
473 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
474 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
475 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
476 { " 28: Return(25)\n", " 28: Return(35)\n"}
477 };
478 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
479
Roland Levillain93445682014-10-06 19:24:02 +0100480 // Check the values of the computed constants.
481 auto check_after_cp = [](HGraph* graph) {
482 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
483 ASSERT_TRUE(inst1->IsIntConstant());
484 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
485 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
486 ASSERT_TRUE(inst2->IsIntConstant());
487 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
488 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
489 ASSERT_TRUE(inst3->IsIntConstant());
490 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
491 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
492 ASSERT_TRUE(inst4->IsIntConstant());
493 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
494 };
495
Roland Levillain556c3d12014-09-18 15:25:07 +0100496 // Expected difference after dead code elimination.
497 diff_t expected_dce_diff = {
498 { " 3: IntConstant\n", removed },
499 { " 13: IntConstant\n", removed },
500 { " 18: IntConstant\n", removed },
501 { " 24: IntConstant\n", removed },
502 { " 34: IntConstant\n", removed },
503 };
504 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
505
Roland Levillain93445682014-10-06 19:24:02 +0100506 TestCode(data,
507 expected_before,
508 expected_after_cp,
509 expected_after_dce,
510 check_after_cp);
Roland Levillain556c3d12014-09-18 15:25:07 +0100511}
512
513
514/**
515 * Three-register program with a constant (static) condition.
516 *
517 * 16-bit
518 * offset
519 * ------
520 * v1 <- 1 0. const/4 v1, #+1
521 * v0 <- 0 1. const/4 v0, #+0
522 * if v1 >= 0 goto L1 2. if-gez v1, +3
523 * v0 <- v1 4. move v0, v1
524 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
525 * return-void 7. return
526 */
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000527TEST(ConstantPropagation, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100528 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
529 Instruction::CONST_4 | 1 << 8 | 1 << 12,
530 Instruction::CONST_4 | 0 << 8 | 0 << 12,
531 Instruction::IF_GEZ | 1 << 8, 3,
532 Instruction::MOVE | 0 << 8 | 1 << 12,
533 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
534 Instruction::RETURN_VOID);
535
536 std::string expected_before =
537 "BasicBlock 0, succ: 1\n"
538 " 3: IntConstant [15, 22, 8]\n"
539 " 5: IntConstant [22, 8]\n"
540 " 19: SuspendCheck\n"
541 " 20: Goto 1\n"
542 "BasicBlock 1, pred: 0, succ: 5, 2\n"
543 " 8: GreaterThanOrEqual(3, 5) [9]\n"
544 " 9: If(8)\n"
545 "BasicBlock 2, pred: 1, succ: 3\n"
546 " 12: Goto 3\n"
547 "BasicBlock 3, pred: 2, 5, succ: 4\n"
548 " 22: Phi(3, 5) [15]\n"
549 " 15: Add(22, 3)\n"
550 " 17: ReturnVoid\n"
551 "BasicBlock 4, pred: 3\n"
552 " 18: Exit\n"
553 "BasicBlock 5, pred: 1, succ: 3\n"
554 " 21: Goto 3\n";
555
Nicolas Geoffray1ddbf6d2014-10-01 14:59:23 +0000556 // Expected difference after constant propagation.
Roland Levillain556c3d12014-09-18 15:25:07 +0100557 diff_t expected_cp_diff = {
558 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
559 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
560 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
561 { " 9: If(8)\n", " 9: If(23)\n" }
562 };
563 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
564
Roland Levillain93445682014-10-06 19:24:02 +0100565 // Check the values of the computed constants.
566 auto check_after_cp = [](HGraph* graph) {
567 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
568 ASSERT_TRUE(inst->IsIntConstant());
569 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
570 };
571
Roland Levillain556c3d12014-09-18 15:25:07 +0100572 // Expected difference after dead code elimination.
573 diff_t expected_dce_diff = {
574 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
575 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
576 { " 15: Add(22, 3)\n", removed }
577 };
578 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
579
Roland Levillain93445682014-10-06 19:24:02 +0100580 TestCode(data,
581 expected_before,
582 expected_after_cp,
583 expected_after_dce,
584 check_after_cp);
Roland Levillain556c3d12014-09-18 15:25:07 +0100585}
586
587} // namespace art