blob: ec2ff335908353617897e9511ee277466e56705c [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
Roland Levillain75be2832014-10-17 17:02:00 +010019#include "code_generator_x86.h"
20#include "constant_folding.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010021#include "dead_code_elimination.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010022#include "graph_checker.h"
23#include "optimizing_unit_test.h"
Roland Levillain75be2832014-10-17 17:02:00 +010024#include "pretty_printer.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010025
26#include "gtest/gtest.h"
27
28namespace art {
29
30static void TestCode(const uint16_t* data,
31 const std::string& expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +010032 const std::string& expected_after_cf,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010033 const std::string& expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +010034 std::function<void(HGraph*)> check_after_cf,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010035 Primitive::Type return_type = Primitive::kPrimInt) {
Roland Levillain556c3d12014-09-18 15:25:07 +010036 ArenaPool pool;
37 ArenaAllocator allocator(&pool);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010038 HGraph* graph = CreateCFG(&allocator, data, return_type);
Roland Levillain556c3d12014-09-18 15:25:07 +010039 ASSERT_NE(graph, nullptr);
40
41 graph->BuildDominatorTree();
42 graph->TransformToSSA();
43
44 StringPrettyPrinter printer_before(graph);
45 printer_before.VisitInsertionOrder();
46 std::string actual_before = printer_before.str();
47 ASSERT_EQ(expected_before, actual_before);
48
Roland Levillain75be2832014-10-17 17:02:00 +010049 x86::CodeGeneratorX86 codegen(graph);
50 HGraphVisualizer visualizer(nullptr, graph, codegen, "");
51 HConstantFolding(graph, visualizer).Run();
52 SSAChecker ssa_checker(&allocator, graph);
53 ssa_checker.Run();
54 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010055
Roland Levillain75be2832014-10-17 17:02:00 +010056 StringPrettyPrinter printer_after_cf(graph);
57 printer_after_cf.VisitInsertionOrder();
58 std::string actual_after_cf = printer_after_cf.str();
59 ASSERT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +010060
Roland Levillain75be2832014-10-17 17:02:00 +010061 check_after_cf(graph);
Roland Levillain93445682014-10-06 19:24:02 +010062
Roland Levillain75be2832014-10-17 17:02:00 +010063 HDeadCodeElimination(graph, visualizer).Run();
64 ssa_checker.Run();
65 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010066
67 StringPrettyPrinter printer_after_dce(graph);
68 printer_after_dce.VisitInsertionOrder();
69 std::string actual_after_dce = printer_after_dce.str();
70 ASSERT_EQ(expected_after_dce, actual_after_dce);
Roland Levillain556c3d12014-09-18 15:25:07 +010071}
72
73
74/**
75 * Tiny three-register program exercising int constant folding on addition.
76 *
77 * 16-bit
78 * offset
79 * ------
80 * v0 <- 1 0. const/4 v0, #+1
81 * v1 <- 2 1. const/4 v1, #+2
82 * v2 <- v0 + v1 2. add-int v2, v0, v1
83 * return v2 4. return v2
84 */
Roland Levillain75be2832014-10-17 17:02:00 +010085TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +010086 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
87 Instruction::CONST_4 | 0 << 8 | 1 << 12,
88 Instruction::CONST_4 | 1 << 8 | 2 << 12,
89 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
90 Instruction::RETURN | 2 << 8);
91
92 std::string expected_before =
93 "BasicBlock 0, succ: 1\n"
94 " 3: IntConstant [9]\n"
95 " 5: IntConstant [9]\n"
96 " 14: SuspendCheck\n"
97 " 15: Goto 1\n"
98 "BasicBlock 1, pred: 0, succ: 2\n"
99 " 9: Add(3, 5) [12]\n"
100 " 12: Return(9)\n"
101 "BasicBlock 2, pred: 1\n"
102 " 13: Exit\n";
103
Roland Levillain75be2832014-10-17 17:02:00 +0100104 // Expected difference after constant folding.
105 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100106 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
107 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
108 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
109 { " 12: Return(9)\n", " 12: Return(16)\n" }
110 };
Roland Levillain75be2832014-10-17 17:02:00 +0100111 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100112
Roland Levillain93445682014-10-06 19:24:02 +0100113 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100114 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100115 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
116 ASSERT_TRUE(inst->IsIntConstant());
117 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
118 };
119
Roland Levillain556c3d12014-09-18 15:25:07 +0100120 // Expected difference after dead code elimination.
121 diff_t expected_dce_diff = {
122 { " 3: IntConstant\n", removed },
123 { " 5: IntConstant\n", removed }
124 };
Roland Levillain75be2832014-10-17 17:02:00 +0100125 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100126
Roland Levillain93445682014-10-06 19:24:02 +0100127 TestCode(data,
128 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100129 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100130 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100131 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100132}
133
134/**
135 * Small three-register program exercising int constant folding on addition.
136 *
137 * 16-bit
138 * offset
139 * ------
140 * v0 <- 1 0. const/4 v0, #+1
141 * v1 <- 2 1. const/4 v1, #+2
142 * v0 <- v0 + v1 2. add-int/2addr v0, v1
143 * v1 <- 3 3. const/4 v1, #+3
144 * v2 <- 4 4. const/4 v2, #+4
145 * v1 <- v1 + v2 5. add-int/2addr v1, v2
146 * v2 <- v0 + v1 6. add-int v2, v0, v1
147 * return v2 8. return v2
148 */
Roland Levillain75be2832014-10-17 17:02:00 +0100149TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100150 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
151 Instruction::CONST_4 | 0 << 8 | 1 << 12,
152 Instruction::CONST_4 | 1 << 8 | 2 << 12,
153 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
154 Instruction::CONST_4 | 1 << 8 | 3 << 12,
155 Instruction::CONST_4 | 2 << 8 | 4 << 12,
156 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
157 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
158 Instruction::RETURN | 2 << 8);
159
160 std::string expected_before =
161 "BasicBlock 0, succ: 1\n"
162 " 3: IntConstant [9]\n"
163 " 5: IntConstant [9]\n"
164 " 11: IntConstant [17]\n"
165 " 13: IntConstant [17]\n"
166 " 26: SuspendCheck\n"
167 " 27: Goto 1\n"
168 "BasicBlock 1, pred: 0, succ: 2\n"
169 " 9: Add(3, 5) [21]\n"
170 " 17: Add(11, 13) [21]\n"
171 " 21: Add(9, 17) [24]\n"
172 " 24: Return(21)\n"
173 "BasicBlock 2, pred: 1\n"
174 " 25: Exit\n";
175
Roland Levillain75be2832014-10-17 17:02:00 +0100176 // Expected difference after constant folding.
177 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100178 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
179 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
180 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
181 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
182 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
183 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
184 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
185 { " 24: Return(21)\n", " 24: Return(30)\n" }
186 };
Roland Levillain75be2832014-10-17 17:02:00 +0100187 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100188
Roland Levillain93445682014-10-06 19:24:02 +0100189 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100190 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100191 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
192 ASSERT_TRUE(inst1->IsIntConstant());
193 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
194 HInstruction* inst2 = inst1->GetNext();
195 ASSERT_TRUE(inst2->IsIntConstant());
196 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
197 HInstruction* inst3 = inst2->GetNext();
198 ASSERT_TRUE(inst3->IsIntConstant());
199 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
200 };
201
Roland Levillain556c3d12014-09-18 15:25:07 +0100202 // Expected difference after dead code elimination.
203 diff_t expected_dce_diff = {
204 { " 3: IntConstant\n", removed },
205 { " 5: IntConstant\n", removed },
206 { " 11: IntConstant\n", removed },
207 { " 13: IntConstant\n", removed },
208 { " 28: IntConstant\n", removed },
209 { " 29: IntConstant\n", removed }
210 };
Roland Levillain75be2832014-10-17 17:02:00 +0100211 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100212
Roland Levillain93445682014-10-06 19:24:02 +0100213 TestCode(data,
214 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100215 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100216 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100217 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100218}
219
220/**
221 * Tiny three-register program exercising int constant folding on subtraction.
222 *
223 * 16-bit
224 * offset
225 * ------
226 * v0 <- 3 0. const/4 v0, #+3
227 * v1 <- 2 1. const/4 v1, #+2
228 * v2 <- v0 - v1 2. sub-int v2, v0, v1
229 * return v2 4. return v2
230 */
Roland Levillain75be2832014-10-17 17:02:00 +0100231TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100232 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
233 Instruction::CONST_4 | 0 << 8 | 3 << 12,
234 Instruction::CONST_4 | 1 << 8 | 2 << 12,
235 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
236 Instruction::RETURN | 2 << 8);
237
238 std::string expected_before =
239 "BasicBlock 0, succ: 1\n"
240 " 3: IntConstant [9]\n"
241 " 5: IntConstant [9]\n"
242 " 14: SuspendCheck\n"
243 " 15: Goto 1\n"
244 "BasicBlock 1, pred: 0, succ: 2\n"
245 " 9: Sub(3, 5) [12]\n"
246 " 12: Return(9)\n"
247 "BasicBlock 2, pred: 1\n"
248 " 13: Exit\n";
249
Roland Levillain75be2832014-10-17 17:02:00 +0100250 // Expected difference after constant folding.
251 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100252 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
253 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
254 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
255 { " 12: Return(9)\n", " 12: Return(16)\n" }
256 };
Roland Levillain75be2832014-10-17 17:02:00 +0100257 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100258
Roland Levillain93445682014-10-06 19:24:02 +0100259 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100260 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100261 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
262 ASSERT_TRUE(inst->IsIntConstant());
263 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
264 };
265
Roland Levillain556c3d12014-09-18 15:25:07 +0100266 // Expected difference after dead code elimination.
267 diff_t expected_dce_diff = {
268 { " 3: IntConstant\n", removed },
269 { " 5: IntConstant\n", removed }
270 };
Roland Levillain75be2832014-10-17 17:02:00 +0100271 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100272
Roland Levillain93445682014-10-06 19:24:02 +0100273 TestCode(data,
274 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100275 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100276 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100277 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100278}
279
280#define SIX_REGISTERS_CODE_ITEM(...) \
281 { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
282
283/**
284 * Tiny three-register-pair program exercising long constant folding
285 * on addition.
286 *
287 * 16-bit
288 * offset
289 * ------
290 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
291 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
292 * (v4, v5) <-
293 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
294 * return (v4, v5) 6. return-wide v4
295 */
Roland Levillain75be2832014-10-17 17:02:00 +0100296TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100297 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
298 Instruction::CONST_WIDE_16 | 0 << 8, 1,
299 Instruction::CONST_WIDE_16 | 2 << 8, 2,
300 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
301 Instruction::RETURN_WIDE | 4 << 8);
302
303 std::string expected_before =
304 "BasicBlock 0, succ: 1\n"
305 " 6: LongConstant [12]\n"
306 " 8: LongConstant [12]\n"
307 " 17: SuspendCheck\n"
308 " 18: Goto 1\n"
309 "BasicBlock 1, pred: 0, succ: 2\n"
310 " 12: Add(6, 8) [15]\n"
311 " 15: Return(12)\n"
312 "BasicBlock 2, pred: 1\n"
313 " 16: Exit\n";
314
Roland Levillain75be2832014-10-17 17:02:00 +0100315 // Expected difference after constant folding.
316 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100317 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
318 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
319 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
320 { " 15: Return(12)\n", " 15: Return(19)\n" }
321 };
Roland Levillain75be2832014-10-17 17:02:00 +0100322 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100323
Roland Levillain93445682014-10-06 19:24:02 +0100324 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100325 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100326 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
327 ASSERT_TRUE(inst->IsLongConstant());
328 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
329 };
330
Roland Levillain556c3d12014-09-18 15:25:07 +0100331 // Expected difference after dead code elimination.
332 diff_t expected_dce_diff = {
333 { " 6: LongConstant\n", removed },
334 { " 8: LongConstant\n", removed }
335 };
Roland Levillain75be2832014-10-17 17:02:00 +0100336 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100337
Roland Levillain93445682014-10-06 19:24:02 +0100338 TestCode(data,
339 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100340 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100341 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100342 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100343 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100344}
345
346/**
347 * Tiny three-register-pair program exercising long constant folding
348 * on subtraction.
349 *
350 * 16-bit
351 * offset
352 * ------
353 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
354 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
355 * (v4, v5) <-
356 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
357 * return (v4, v5) 6. return-wide v4
358 */
Roland Levillain75be2832014-10-17 17:02:00 +0100359TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100360 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
361 Instruction::CONST_WIDE_16 | 0 << 8, 3,
362 Instruction::CONST_WIDE_16 | 2 << 8, 2,
363 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
364 Instruction::RETURN_WIDE | 4 << 8);
365
366 std::string expected_before =
367 "BasicBlock 0, succ: 1\n"
368 " 6: LongConstant [12]\n"
369 " 8: LongConstant [12]\n"
370 " 17: SuspendCheck\n"
371 " 18: Goto 1\n"
372 "BasicBlock 1, pred: 0, succ: 2\n"
373 " 12: Sub(6, 8) [15]\n"
374 " 15: Return(12)\n"
375 "BasicBlock 2, pred: 1\n"
376 " 16: Exit\n";
377
Roland Levillain75be2832014-10-17 17:02:00 +0100378 // Expected difference after constant folding.
379 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100380 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
381 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
382 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
383 { " 15: Return(12)\n", " 15: Return(19)\n" }
384 };
Roland Levillain75be2832014-10-17 17:02:00 +0100385 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100386
Roland Levillain93445682014-10-06 19:24:02 +0100387 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100388 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100389 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
390 ASSERT_TRUE(inst->IsLongConstant());
391 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
392 };
393
Roland Levillain556c3d12014-09-18 15:25:07 +0100394 // Expected difference after dead code elimination.
395 diff_t expected_dce_diff = {
396 { " 6: LongConstant\n", removed },
397 { " 8: LongConstant\n", removed }
398 };
Roland Levillain75be2832014-10-17 17:02:00 +0100399 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100400
Roland Levillain93445682014-10-06 19:24:02 +0100401 TestCode(data,
402 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100403 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100404 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100405 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100406 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100407}
408
409/**
410 * Three-register program with jumps leading to the creation of many
411 * blocks.
412 *
413 * The intent of this test is to ensure that all constant expressions
414 * are actually evaluated at compile-time, thanks to the reverse
415 * (forward) post-order traversal of the the dominator tree.
416 *
417 * 16-bit
418 * offset
419 * ------
420 * v0 <- 0 0. const/4 v0, #+0
421 * v1 <- 1 1. const/4 v1, #+1
422 * v2 <- v0 + v1 2. add-int v2, v0, v1
423 * goto L2 4. goto +4
424 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
425 * goto L3 7. goto +4
426 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
427 * goto L1 10. goto +(-5)
428 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
429 * return v2 13. return v2
430 */
Roland Levillain75be2832014-10-17 17:02:00 +0100431TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100432 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
433 Instruction::CONST_4 | 0 << 8 | 0 << 12,
434 Instruction::CONST_4 | 1 << 8 | 1 << 12,
435 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
436 Instruction::GOTO | 4 << 8,
437 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
438 Instruction::GOTO | 4 << 8,
439 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
440 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
441 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
442 Instruction::RETURN | 2 << 8);
443
444 std::string expected_before =
445 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100446 " 3: IntConstant [9]\n" // v0 <- 0
447 " 5: IntConstant [9]\n" // v1 <- 1
448 " 13: IntConstant [14]\n" // const 3
449 " 18: IntConstant [19]\n" // const 2
450 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100451 " 30: SuspendCheck\n"
452 " 31: Goto 1\n"
453 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100454 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
455 " 11: Goto 3\n" // goto L2
456 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
457 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
458 " 16: Goto 4\n" // goto L3
459 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
460 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100461 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100462 " 22: Goto 2\n" // goto L1
463 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
464 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
465 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100466 "BasicBlock 5, pred: 4\n"
467 " 29: Exit\n";
468
Roland Levillain75be2832014-10-17 17:02:00 +0100469 // Expected difference after constant folding.
470 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100471 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
472 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
473 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
474 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
475 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
476 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
477 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
478 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
479 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
480 { " 28: Return(25)\n", " 28: Return(35)\n"}
481 };
Roland Levillain75be2832014-10-17 17:02:00 +0100482 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100483
Roland Levillain93445682014-10-06 19:24:02 +0100484 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100485 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100486 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
487 ASSERT_TRUE(inst1->IsIntConstant());
488 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
489 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
490 ASSERT_TRUE(inst2->IsIntConstant());
491 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
492 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
493 ASSERT_TRUE(inst3->IsIntConstant());
494 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
495 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
496 ASSERT_TRUE(inst4->IsIntConstant());
497 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
498 };
499
Roland Levillain556c3d12014-09-18 15:25:07 +0100500 // Expected difference after dead code elimination.
501 diff_t expected_dce_diff = {
502 { " 3: IntConstant\n", removed },
503 { " 13: IntConstant\n", removed },
504 { " 18: IntConstant\n", removed },
505 { " 24: IntConstant\n", removed },
506 { " 34: IntConstant\n", removed },
507 };
Roland Levillain75be2832014-10-17 17:02:00 +0100508 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100509
Roland Levillain93445682014-10-06 19:24:02 +0100510 TestCode(data,
511 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100512 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100513 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100514 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100515}
516
517
518/**
519 * Three-register program with a constant (static) condition.
520 *
521 * 16-bit
522 * offset
523 * ------
524 * v1 <- 1 0. const/4 v1, #+1
525 * v0 <- 0 1. const/4 v0, #+0
526 * if v1 >= 0 goto L1 2. if-gez v1, +3
527 * v0 <- v1 4. move v0, v1
528 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
529 * return-void 7. return
530 */
Roland Levillain75be2832014-10-17 17:02:00 +0100531TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100532 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
533 Instruction::CONST_4 | 1 << 8 | 1 << 12,
534 Instruction::CONST_4 | 0 << 8 | 0 << 12,
535 Instruction::IF_GEZ | 1 << 8, 3,
536 Instruction::MOVE | 0 << 8 | 1 << 12,
537 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
538 Instruction::RETURN_VOID);
539
540 std::string expected_before =
541 "BasicBlock 0, succ: 1\n"
542 " 3: IntConstant [15, 22, 8]\n"
543 " 5: IntConstant [22, 8]\n"
544 " 19: SuspendCheck\n"
545 " 20: Goto 1\n"
546 "BasicBlock 1, pred: 0, succ: 5, 2\n"
547 " 8: GreaterThanOrEqual(3, 5) [9]\n"
548 " 9: If(8)\n"
549 "BasicBlock 2, pred: 1, succ: 3\n"
550 " 12: Goto 3\n"
551 "BasicBlock 3, pred: 2, 5, succ: 4\n"
552 " 22: Phi(3, 5) [15]\n"
553 " 15: Add(22, 3)\n"
554 " 17: ReturnVoid\n"
555 "BasicBlock 4, pred: 3\n"
556 " 18: Exit\n"
557 "BasicBlock 5, pred: 1, succ: 3\n"
558 " 21: Goto 3\n";
559
Roland Levillain75be2832014-10-17 17:02:00 +0100560 // Expected difference after constant folding.
561 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100562 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
563 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
564 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
565 { " 9: If(8)\n", " 9: If(23)\n" }
566 };
Roland Levillain75be2832014-10-17 17:02:00 +0100567 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100568
Roland Levillain93445682014-10-06 19:24:02 +0100569 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100570 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100571 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
572 ASSERT_TRUE(inst->IsIntConstant());
573 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
574 };
575
Roland Levillain556c3d12014-09-18 15:25:07 +0100576 // Expected difference after dead code elimination.
577 diff_t expected_dce_diff = {
578 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
579 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
580 { " 15: Add(22, 3)\n", removed }
581 };
Roland Levillain75be2832014-10-17 17:02:00 +0100582 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100583
Roland Levillain93445682014-10-06 19:24:02 +0100584 TestCode(data,
585 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100586 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100587 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100588 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100589}
590
591} // namespace art