blob: 5c8c7094397a90fb810f0b85837bee5717d4e058 [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
17#include "constant_propagation.h"
18#include "dead_code_elimination.h"
19#include "pretty_printer.h"
20#include "graph_checker.h"
21#include "optimizing_unit_test.h"
22
23#include "gtest/gtest.h"
24
25namespace art {
26
27static void TestCode(const uint16_t* data,
28 const std::string& expected_before,
29 const std::string& expected_after_cp,
30 const std::string& expected_after_dce) {
31 ArenaPool pool;
32 ArenaAllocator allocator(&pool);
33 HGraph* graph = CreateCFG(&allocator, data);
34 ASSERT_NE(graph, nullptr);
35
36 graph->BuildDominatorTree();
37 graph->TransformToSSA();
38
39 StringPrettyPrinter printer_before(graph);
40 printer_before.VisitInsertionOrder();
41 std::string actual_before = printer_before.str();
42 ASSERT_EQ(expected_before, actual_before);
43
44 ConstantPropagation(graph).Run();
45
46 StringPrettyPrinter printer_after_cp(graph);
47 printer_after_cp.VisitInsertionOrder();
48 std::string actual_after_cp = printer_after_cp.str();
49 ASSERT_EQ(expected_after_cp, actual_after_cp);
50
51 DeadCodeElimination(graph).Run();
52
53 StringPrettyPrinter printer_after_dce(graph);
54 printer_after_dce.VisitInsertionOrder();
55 std::string actual_after_dce = printer_after_dce.str();
56 ASSERT_EQ(expected_after_dce, actual_after_dce);
57
58 SSAChecker ssa_checker(&allocator, graph);
59 ssa_checker.VisitInsertionOrder();
60 ASSERT_TRUE(ssa_checker.IsValid());
61}
62
63
64/**
65 * Tiny three-register program exercising int constant folding on addition.
66 *
67 * 16-bit
68 * offset
69 * ------
70 * v0 <- 1 0. const/4 v0, #+1
71 * v1 <- 2 1. const/4 v1, #+2
72 * v2 <- v0 + v1 2. add-int v2, v0, v1
73 * return v2 4. return v2
74 */
75TEST(ConstantPropagation, IntConstantFoldingOnAddition1) {
76 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
77 Instruction::CONST_4 | 0 << 8 | 1 << 12,
78 Instruction::CONST_4 | 1 << 8 | 2 << 12,
79 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
80 Instruction::RETURN | 2 << 8);
81
82 std::string expected_before =
83 "BasicBlock 0, succ: 1\n"
84 " 3: IntConstant [9]\n"
85 " 5: IntConstant [9]\n"
86 " 14: SuspendCheck\n"
87 " 15: Goto 1\n"
88 "BasicBlock 1, pred: 0, succ: 2\n"
89 " 9: Add(3, 5) [12]\n"
90 " 12: Return(9)\n"
91 "BasicBlock 2, pred: 1\n"
92 " 13: Exit\n";
93
94 // Expected difference after constant propagation.
95 diff_t expected_cp_diff = {
96 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
97 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
98 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
99 { " 12: Return(9)\n", " 12: Return(16)\n" }
100 };
101 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
102
103 // Expected difference after dead code elimination.
104 diff_t expected_dce_diff = {
105 { " 3: IntConstant\n", removed },
106 { " 5: IntConstant\n", removed }
107 };
108 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
109
110 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
111}
112
113/**
114 * Small three-register program exercising int constant folding on addition.
115 *
116 * 16-bit
117 * offset
118 * ------
119 * v0 <- 1 0. const/4 v0, #+1
120 * v1 <- 2 1. const/4 v1, #+2
121 * v0 <- v0 + v1 2. add-int/2addr v0, v1
122 * v1 <- 3 3. const/4 v1, #+3
123 * v2 <- 4 4. const/4 v2, #+4
124 * v1 <- v1 + v2 5. add-int/2addr v1, v2
125 * v2 <- v0 + v1 6. add-int v2, v0, v1
126 * return v2 8. return v2
127 */
128TEST(ConstantPropagation, IntConstantFoldingOnAddition2) {
129 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
130 Instruction::CONST_4 | 0 << 8 | 1 << 12,
131 Instruction::CONST_4 | 1 << 8 | 2 << 12,
132 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
133 Instruction::CONST_4 | 1 << 8 | 3 << 12,
134 Instruction::CONST_4 | 2 << 8 | 4 << 12,
135 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
136 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
137 Instruction::RETURN | 2 << 8);
138
139 std::string expected_before =
140 "BasicBlock 0, succ: 1\n"
141 " 3: IntConstant [9]\n"
142 " 5: IntConstant [9]\n"
143 " 11: IntConstant [17]\n"
144 " 13: IntConstant [17]\n"
145 " 26: SuspendCheck\n"
146 " 27: Goto 1\n"
147 "BasicBlock 1, pred: 0, succ: 2\n"
148 " 9: Add(3, 5) [21]\n"
149 " 17: Add(11, 13) [21]\n"
150 " 21: Add(9, 17) [24]\n"
151 " 24: Return(21)\n"
152 "BasicBlock 2, pred: 1\n"
153 " 25: Exit\n";
154
155 // Expected difference after constant propagation.
156 diff_t expected_cp_diff = {
157 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
158 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
159 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
160 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
161 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
162 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
163 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
164 { " 24: Return(21)\n", " 24: Return(30)\n" }
165 };
166 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
167
168 // Expected difference after dead code elimination.
169 diff_t expected_dce_diff = {
170 { " 3: IntConstant\n", removed },
171 { " 5: IntConstant\n", removed },
172 { " 11: IntConstant\n", removed },
173 { " 13: IntConstant\n", removed },
174 { " 28: IntConstant\n", removed },
175 { " 29: IntConstant\n", removed }
176 };
177 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
178
179 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
180}
181
182/**
183 * Tiny three-register program exercising int constant folding on subtraction.
184 *
185 * 16-bit
186 * offset
187 * ------
188 * v0 <- 3 0. const/4 v0, #+3
189 * v1 <- 2 1. const/4 v1, #+2
190 * v2 <- v0 - v1 2. sub-int v2, v0, v1
191 * return v2 4. return v2
192 */
193TEST(ConstantPropagation, IntConstantFoldingOnSubtraction) {
194 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
195 Instruction::CONST_4 | 0 << 8 | 3 << 12,
196 Instruction::CONST_4 | 1 << 8 | 2 << 12,
197 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
198 Instruction::RETURN | 2 << 8);
199
200 std::string expected_before =
201 "BasicBlock 0, succ: 1\n"
202 " 3: IntConstant [9]\n"
203 " 5: IntConstant [9]\n"
204 " 14: SuspendCheck\n"
205 " 15: Goto 1\n"
206 "BasicBlock 1, pred: 0, succ: 2\n"
207 " 9: Sub(3, 5) [12]\n"
208 " 12: Return(9)\n"
209 "BasicBlock 2, pred: 1\n"
210 " 13: Exit\n";
211
212 // Expected difference after constant propagation.
213 diff_t expected_cp_diff = {
214 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
215 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
216 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
217 { " 12: Return(9)\n", " 12: Return(16)\n" }
218 };
219 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
220
221 // Expected difference after dead code elimination.
222 diff_t expected_dce_diff = {
223 { " 3: IntConstant\n", removed },
224 { " 5: IntConstant\n", removed }
225 };
226 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
227
228 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
229}
230
231#define SIX_REGISTERS_CODE_ITEM(...) \
232 { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
233
234/**
235 * Tiny three-register-pair program exercising long constant folding
236 * on addition.
237 *
238 * 16-bit
239 * offset
240 * ------
241 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
242 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
243 * (v4, v5) <-
244 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
245 * return (v4, v5) 6. return-wide v4
246 */
247TEST(ConstantPropagation, LongConstantFoldingOnAddition) {
248 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
249 Instruction::CONST_WIDE_16 | 0 << 8, 1,
250 Instruction::CONST_WIDE_16 | 2 << 8, 2,
251 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
252 Instruction::RETURN_WIDE | 4 << 8);
253
254 std::string expected_before =
255 "BasicBlock 0, succ: 1\n"
256 " 6: LongConstant [12]\n"
257 " 8: LongConstant [12]\n"
258 " 17: SuspendCheck\n"
259 " 18: Goto 1\n"
260 "BasicBlock 1, pred: 0, succ: 2\n"
261 " 12: Add(6, 8) [15]\n"
262 " 15: Return(12)\n"
263 "BasicBlock 2, pred: 1\n"
264 " 16: Exit\n";
265
266 // Expected difference after constant propagation.
267 diff_t expected_cp_diff = {
268 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
269 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
270 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
271 { " 15: Return(12)\n", " 15: Return(19)\n" }
272 };
273 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
274
275 // Expected difference after dead code elimination.
276 diff_t expected_dce_diff = {
277 { " 6: LongConstant\n", removed },
278 { " 8: LongConstant\n", removed }
279 };
280 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
281
282 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
283}
284
285/**
286 * Tiny three-register-pair program exercising long constant folding
287 * on subtraction.
288 *
289 * 16-bit
290 * offset
291 * ------
292 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
293 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
294 * (v4, v5) <-
295 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
296 * return (v4, v5) 6. return-wide v4
297 */
298TEST(ConstantPropagation, LongConstantFoldingOnSubtraction) {
299 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
300 Instruction::CONST_WIDE_16 | 0 << 8, 3,
301 Instruction::CONST_WIDE_16 | 2 << 8, 2,
302 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
303 Instruction::RETURN_WIDE | 4 << 8);
304
305 std::string expected_before =
306 "BasicBlock 0, succ: 1\n"
307 " 6: LongConstant [12]\n"
308 " 8: LongConstant [12]\n"
309 " 17: SuspendCheck\n"
310 " 18: Goto 1\n"
311 "BasicBlock 1, pred: 0, succ: 2\n"
312 " 12: Sub(6, 8) [15]\n"
313 " 15: Return(12)\n"
314 "BasicBlock 2, pred: 1\n"
315 " 16: Exit\n";
316
317 // Expected difference after constant propagation.
318 diff_t expected_cp_diff = {
319 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
320 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
321 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
322 { " 15: Return(12)\n", " 15: Return(19)\n" }
323 };
324 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
325
326 // Expected difference after dead code elimination.
327 diff_t expected_dce_diff = {
328 { " 6: LongConstant\n", removed },
329 { " 8: LongConstant\n", removed }
330 };
331 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
332
333 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
334}
335
336/**
337 * Three-register program with jumps leading to the creation of many
338 * blocks.
339 *
340 * The intent of this test is to ensure that all constant expressions
341 * are actually evaluated at compile-time, thanks to the reverse
342 * (forward) post-order traversal of the the dominator tree.
343 *
344 * 16-bit
345 * offset
346 * ------
347 * v0 <- 0 0. const/4 v0, #+0
348 * v1 <- 1 1. const/4 v1, #+1
349 * v2 <- v0 + v1 2. add-int v2, v0, v1
350 * goto L2 4. goto +4
351 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
352 * goto L3 7. goto +4
353 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
354 * goto L1 10. goto +(-5)
355 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
356 * return v2 13. return v2
357 */
358TEST(ConstantPropagation, IntConstantFoldingAndJumps) {
359 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
360 Instruction::CONST_4 | 0 << 8 | 0 << 12,
361 Instruction::CONST_4 | 1 << 8 | 1 << 12,
362 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
363 Instruction::GOTO | 4 << 8,
364 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
365 Instruction::GOTO | 4 << 8,
366 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
367 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
368 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
369 Instruction::RETURN | 2 << 8);
370
371 std::string expected_before =
372 "BasicBlock 0, succ: 1\n"
373 " 3: IntConstant [9]\n"
374 " 5: IntConstant [9]\n"
375 " 13: IntConstant [14]\n"
376 " 18: IntConstant [19]\n"
377 " 24: IntConstant [25]\n"
378 " 30: SuspendCheck\n"
379 " 31: Goto 1\n"
380 "BasicBlock 1, pred: 0, succ: 3\n"
381 " 9: Add(3, 5) [19]\n"
382 " 11: Goto 3\n"
383 "BasicBlock 2, pred: 3, succ: 4\n"
384 " 14: Add(19, 13) [25]\n"
385 " 16: Goto 4\n"
386 "BasicBlock 3, pred: 1, succ: 2\n"
387 " 19: Add(9, 18) [14]\n"
388 " 21: SuspendCheck\n"
389 " 22: Goto 2\n"
390 "BasicBlock 4, pred: 2, succ: 5\n"
391 " 25: Add(14, 24) [28]\n"
392 " 28: Return(25)\n"
393 "BasicBlock 5, pred: 4\n"
394 " 29: Exit\n";
395
396 // Expected difference after constant propagation.
397 diff_t expected_cp_diff = {
398 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
399 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
400 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
401 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
402 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
403 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
404 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
405 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
406 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
407 { " 28: Return(25)\n", " 28: Return(35)\n"}
408 };
409 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
410
411 // Expected difference after dead code elimination.
412 diff_t expected_dce_diff = {
413 { " 3: IntConstant\n", removed },
414 { " 13: IntConstant\n", removed },
415 { " 18: IntConstant\n", removed },
416 { " 24: IntConstant\n", removed },
417 { " 34: IntConstant\n", removed },
418 };
419 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
420
421 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
422}
423
424
425/**
426 * Three-register program with a constant (static) condition.
427 *
428 * 16-bit
429 * offset
430 * ------
431 * v1 <- 1 0. const/4 v1, #+1
432 * v0 <- 0 1. const/4 v0, #+0
433 * if v1 >= 0 goto L1 2. if-gez v1, +3
434 * v0 <- v1 4. move v0, v1
435 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
436 * return-void 7. return
437 */
438TEST(ConstantPropagation, ConstantCondition) {
439 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
440 Instruction::CONST_4 | 1 << 8 | 1 << 12,
441 Instruction::CONST_4 | 0 << 8 | 0 << 12,
442 Instruction::IF_GEZ | 1 << 8, 3,
443 Instruction::MOVE | 0 << 8 | 1 << 12,
444 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
445 Instruction::RETURN_VOID);
446
447 std::string expected_before =
448 "BasicBlock 0, succ: 1\n"
449 " 3: IntConstant [15, 22, 8]\n"
450 " 5: IntConstant [22, 8]\n"
451 " 19: SuspendCheck\n"
452 " 20: Goto 1\n"
453 "BasicBlock 1, pred: 0, succ: 5, 2\n"
454 " 8: GreaterThanOrEqual(3, 5) [9]\n"
455 " 9: If(8)\n"
456 "BasicBlock 2, pred: 1, succ: 3\n"
457 " 12: Goto 3\n"
458 "BasicBlock 3, pred: 2, 5, succ: 4\n"
459 " 22: Phi(3, 5) [15]\n"
460 " 15: Add(22, 3)\n"
461 " 17: ReturnVoid\n"
462 "BasicBlock 4, pred: 3\n"
463 " 18: Exit\n"
464 "BasicBlock 5, pred: 1, succ: 3\n"
465 " 21: Goto 3\n";
466
467 // Expected difference after constant propagation.
468 diff_t expected_cp_diff = {
469 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
470 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
471 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
472 { " 9: If(8)\n", " 9: If(23)\n" }
473 };
474 std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
475
476 // Expected difference after dead code elimination.
477 diff_t expected_dce_diff = {
478 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
479 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
480 { " 15: Add(22, 3)\n", removed }
481 };
482 std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
483
484 TestCode(data, expected_before, expected_after_cp, expected_after_dce);
485}
486
487} // namespace art