blob: 856c5165a3bf37009ea039d09c10b77966dd785c [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/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010075 * Tiny three-register program exercising int constant folding on negation.
76 *
77 * 16-bit
78 * offset
79 * ------
80 * v0 <- 1 0. const/4 v0, #+1
81 * v1 <- -v0 1. neg-int v0, v1
82 * return v1 2. return v1
83 */
84TEST(ConstantFolding, IntConstantFoldingNegation) {
85 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
86 Instruction::CONST_4 | 0 << 8 | 1 << 12,
87 Instruction::NEG_INT | 1 << 8 | 0 << 12,
88 Instruction::RETURN | 1 << 8);
89
90 std::string expected_before =
91 "BasicBlock 0, succ: 1\n"
92 " 2: IntConstant [5]\n"
93 " 10: SuspendCheck\n"
94 " 11: Goto 1\n"
95 "BasicBlock 1, pred: 0, succ: 2\n"
96 " 5: Neg(2) [8]\n"
97 " 8: Return(5)\n"
98 "BasicBlock 2, pred: 1\n"
99 " 9: Exit\n";
100
101 // Expected difference after constant folding.
102 diff_t expected_cf_diff = {
103 { " 2: IntConstant [5]\n", " 2: IntConstant\n" },
104 { " 5: Neg(2) [8]\n", " 12: IntConstant [8]\n" },
105 { " 8: Return(5)\n", " 8: Return(12)\n" }
106 };
107 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
108
109 // Check the value of the computed constant.
110 auto check_after_cf = [](HGraph* graph) {
111 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
112 ASSERT_TRUE(inst->IsIntConstant());
113 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
114 };
115
116 // Expected difference after dead code elimination.
117 diff_t expected_dce_diff = {
118 { " 2: IntConstant\n", removed },
119 };
120 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
121
122 TestCode(data,
123 expected_before,
124 expected_after_cf,
125 expected_after_dce,
126 check_after_cf);
127}
128
129/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100130 * Tiny three-register program exercising int constant folding on addition.
131 *
132 * 16-bit
133 * offset
134 * ------
135 * v0 <- 1 0. const/4 v0, #+1
136 * v1 <- 2 1. const/4 v1, #+2
137 * v2 <- v0 + v1 2. add-int v2, v0, v1
138 * return v2 4. return v2
139 */
Roland Levillain75be2832014-10-17 17:02:00 +0100140TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100141 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
142 Instruction::CONST_4 | 0 << 8 | 1 << 12,
143 Instruction::CONST_4 | 1 << 8 | 2 << 12,
144 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
145 Instruction::RETURN | 2 << 8);
146
147 std::string expected_before =
148 "BasicBlock 0, succ: 1\n"
149 " 3: IntConstant [9]\n"
150 " 5: IntConstant [9]\n"
151 " 14: SuspendCheck\n"
152 " 15: Goto 1\n"
153 "BasicBlock 1, pred: 0, succ: 2\n"
154 " 9: Add(3, 5) [12]\n"
155 " 12: Return(9)\n"
156 "BasicBlock 2, pred: 1\n"
157 " 13: Exit\n";
158
Roland Levillain75be2832014-10-17 17:02:00 +0100159 // Expected difference after constant folding.
160 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100161 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
162 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
163 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
164 { " 12: Return(9)\n", " 12: Return(16)\n" }
165 };
Roland Levillain75be2832014-10-17 17:02:00 +0100166 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100167
Roland Levillain93445682014-10-06 19:24:02 +0100168 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100169 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100170 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
171 ASSERT_TRUE(inst->IsIntConstant());
172 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
173 };
174
Roland Levillain556c3d12014-09-18 15:25:07 +0100175 // Expected difference after dead code elimination.
176 diff_t expected_dce_diff = {
177 { " 3: IntConstant\n", removed },
178 { " 5: IntConstant\n", removed }
179 };
Roland Levillain75be2832014-10-17 17:02:00 +0100180 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100181
Roland Levillain93445682014-10-06 19:24:02 +0100182 TestCode(data,
183 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100184 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100185 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100186 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100187}
188
189/**
190 * Small three-register program exercising int constant folding on addition.
191 *
192 * 16-bit
193 * offset
194 * ------
195 * v0 <- 1 0. const/4 v0, #+1
196 * v1 <- 2 1. const/4 v1, #+2
197 * v0 <- v0 + v1 2. add-int/2addr v0, v1
198 * v1 <- 3 3. const/4 v1, #+3
199 * v2 <- 4 4. const/4 v2, #+4
200 * v1 <- v1 + v2 5. add-int/2addr v1, v2
201 * v2 <- v0 + v1 6. add-int v2, v0, v1
202 * return v2 8. return v2
203 */
Roland Levillain75be2832014-10-17 17:02:00 +0100204TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100205 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
206 Instruction::CONST_4 | 0 << 8 | 1 << 12,
207 Instruction::CONST_4 | 1 << 8 | 2 << 12,
208 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
209 Instruction::CONST_4 | 1 << 8 | 3 << 12,
210 Instruction::CONST_4 | 2 << 8 | 4 << 12,
211 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
212 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
213 Instruction::RETURN | 2 << 8);
214
215 std::string expected_before =
216 "BasicBlock 0, succ: 1\n"
217 " 3: IntConstant [9]\n"
218 " 5: IntConstant [9]\n"
219 " 11: IntConstant [17]\n"
220 " 13: IntConstant [17]\n"
221 " 26: SuspendCheck\n"
222 " 27: Goto 1\n"
223 "BasicBlock 1, pred: 0, succ: 2\n"
224 " 9: Add(3, 5) [21]\n"
225 " 17: Add(11, 13) [21]\n"
226 " 21: Add(9, 17) [24]\n"
227 " 24: Return(21)\n"
228 "BasicBlock 2, pred: 1\n"
229 " 25: Exit\n";
230
Roland Levillain75be2832014-10-17 17:02:00 +0100231 // Expected difference after constant folding.
232 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100233 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
234 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
235 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
236 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
237 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
238 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
239 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
240 { " 24: Return(21)\n", " 24: Return(30)\n" }
241 };
Roland Levillain75be2832014-10-17 17:02:00 +0100242 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100243
Roland Levillain93445682014-10-06 19:24:02 +0100244 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100245 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100246 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
247 ASSERT_TRUE(inst1->IsIntConstant());
248 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
249 HInstruction* inst2 = inst1->GetNext();
250 ASSERT_TRUE(inst2->IsIntConstant());
251 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
252 HInstruction* inst3 = inst2->GetNext();
253 ASSERT_TRUE(inst3->IsIntConstant());
254 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
255 };
256
Roland Levillain556c3d12014-09-18 15:25:07 +0100257 // Expected difference after dead code elimination.
258 diff_t expected_dce_diff = {
259 { " 3: IntConstant\n", removed },
260 { " 5: IntConstant\n", removed },
261 { " 11: IntConstant\n", removed },
262 { " 13: IntConstant\n", removed },
263 { " 28: IntConstant\n", removed },
264 { " 29: IntConstant\n", removed }
265 };
Roland Levillain75be2832014-10-17 17:02:00 +0100266 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100267
Roland Levillain93445682014-10-06 19:24:02 +0100268 TestCode(data,
269 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100270 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100271 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100272 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100273}
274
275/**
276 * Tiny three-register program exercising int constant folding on subtraction.
277 *
278 * 16-bit
279 * offset
280 * ------
281 * v0 <- 3 0. const/4 v0, #+3
282 * v1 <- 2 1. const/4 v1, #+2
283 * v2 <- v0 - v1 2. sub-int v2, v0, v1
284 * return v2 4. return v2
285 */
Roland Levillain75be2832014-10-17 17:02:00 +0100286TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100287 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
288 Instruction::CONST_4 | 0 << 8 | 3 << 12,
289 Instruction::CONST_4 | 1 << 8 | 2 << 12,
290 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
291 Instruction::RETURN | 2 << 8);
292
293 std::string expected_before =
294 "BasicBlock 0, succ: 1\n"
295 " 3: IntConstant [9]\n"
296 " 5: IntConstant [9]\n"
297 " 14: SuspendCheck\n"
298 " 15: Goto 1\n"
299 "BasicBlock 1, pred: 0, succ: 2\n"
300 " 9: Sub(3, 5) [12]\n"
301 " 12: Return(9)\n"
302 "BasicBlock 2, pred: 1\n"
303 " 13: Exit\n";
304
Roland Levillain75be2832014-10-17 17:02:00 +0100305 // Expected difference after constant folding.
306 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100307 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
308 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
309 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
310 { " 12: Return(9)\n", " 12: Return(16)\n" }
311 };
Roland Levillain75be2832014-10-17 17:02:00 +0100312 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100313
Roland Levillain93445682014-10-06 19:24:02 +0100314 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100315 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100316 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
317 ASSERT_TRUE(inst->IsIntConstant());
318 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
319 };
320
Roland Levillain556c3d12014-09-18 15:25:07 +0100321 // Expected difference after dead code elimination.
322 diff_t expected_dce_diff = {
323 { " 3: IntConstant\n", removed },
324 { " 5: IntConstant\n", removed }
325 };
Roland Levillain75be2832014-10-17 17:02:00 +0100326 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100327
Roland Levillain93445682014-10-06 19:24:02 +0100328 TestCode(data,
329 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100330 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100331 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100332 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100333}
334
Roland Levillain556c3d12014-09-18 15:25:07 +0100335/**
336 * Tiny three-register-pair program exercising long constant folding
337 * on addition.
338 *
339 * 16-bit
340 * offset
341 * ------
342 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
343 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
344 * (v4, v5) <-
345 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
346 * return (v4, v5) 6. return-wide v4
347 */
Roland Levillain75be2832014-10-17 17:02:00 +0100348TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100349 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
350 Instruction::CONST_WIDE_16 | 0 << 8, 1,
351 Instruction::CONST_WIDE_16 | 2 << 8, 2,
352 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
353 Instruction::RETURN_WIDE | 4 << 8);
354
355 std::string expected_before =
356 "BasicBlock 0, succ: 1\n"
357 " 6: LongConstant [12]\n"
358 " 8: LongConstant [12]\n"
359 " 17: SuspendCheck\n"
360 " 18: Goto 1\n"
361 "BasicBlock 1, pred: 0, succ: 2\n"
362 " 12: Add(6, 8) [15]\n"
363 " 15: Return(12)\n"
364 "BasicBlock 2, pred: 1\n"
365 " 16: Exit\n";
366
Roland Levillain75be2832014-10-17 17:02:00 +0100367 // Expected difference after constant folding.
368 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100369 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
370 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
371 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
372 { " 15: Return(12)\n", " 15: Return(19)\n" }
373 };
Roland Levillain75be2832014-10-17 17:02:00 +0100374 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100375
Roland Levillain93445682014-10-06 19:24:02 +0100376 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100377 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100378 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
379 ASSERT_TRUE(inst->IsLongConstant());
380 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
381 };
382
Roland Levillain556c3d12014-09-18 15:25:07 +0100383 // Expected difference after dead code elimination.
384 diff_t expected_dce_diff = {
385 { " 6: LongConstant\n", removed },
386 { " 8: LongConstant\n", removed }
387 };
Roland Levillain75be2832014-10-17 17:02:00 +0100388 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100389
Roland Levillain93445682014-10-06 19:24:02 +0100390 TestCode(data,
391 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100392 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100393 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100394 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100395 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100396}
397
398/**
399 * Tiny three-register-pair program exercising long constant folding
400 * on subtraction.
401 *
402 * 16-bit
403 * offset
404 * ------
405 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
406 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
407 * (v4, v5) <-
408 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
409 * return (v4, v5) 6. return-wide v4
410 */
Roland Levillain75be2832014-10-17 17:02:00 +0100411TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100412 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
413 Instruction::CONST_WIDE_16 | 0 << 8, 3,
414 Instruction::CONST_WIDE_16 | 2 << 8, 2,
415 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
416 Instruction::RETURN_WIDE | 4 << 8);
417
418 std::string expected_before =
419 "BasicBlock 0, succ: 1\n"
420 " 6: LongConstant [12]\n"
421 " 8: LongConstant [12]\n"
422 " 17: SuspendCheck\n"
423 " 18: Goto 1\n"
424 "BasicBlock 1, pred: 0, succ: 2\n"
425 " 12: Sub(6, 8) [15]\n"
426 " 15: Return(12)\n"
427 "BasicBlock 2, pred: 1\n"
428 " 16: Exit\n";
429
Roland Levillain75be2832014-10-17 17:02:00 +0100430 // Expected difference after constant folding.
431 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100432 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
433 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
434 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
435 { " 15: Return(12)\n", " 15: Return(19)\n" }
436 };
Roland Levillain75be2832014-10-17 17:02:00 +0100437 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100438
Roland Levillain93445682014-10-06 19:24:02 +0100439 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100440 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100441 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
442 ASSERT_TRUE(inst->IsLongConstant());
443 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
444 };
445
Roland Levillain556c3d12014-09-18 15:25:07 +0100446 // Expected difference after dead code elimination.
447 diff_t expected_dce_diff = {
448 { " 6: LongConstant\n", removed },
449 { " 8: LongConstant\n", removed }
450 };
Roland Levillain75be2832014-10-17 17:02:00 +0100451 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100452
Roland Levillain93445682014-10-06 19:24:02 +0100453 TestCode(data,
454 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100455 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100456 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100457 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100458 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100459}
460
461/**
462 * Three-register program with jumps leading to the creation of many
463 * blocks.
464 *
465 * The intent of this test is to ensure that all constant expressions
466 * are actually evaluated at compile-time, thanks to the reverse
467 * (forward) post-order traversal of the the dominator tree.
468 *
469 * 16-bit
470 * offset
471 * ------
472 * v0 <- 0 0. const/4 v0, #+0
473 * v1 <- 1 1. const/4 v1, #+1
474 * v2 <- v0 + v1 2. add-int v2, v0, v1
475 * goto L2 4. goto +4
476 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
477 * goto L3 7. goto +4
478 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
479 * goto L1 10. goto +(-5)
480 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
481 * return v2 13. return v2
482 */
Roland Levillain75be2832014-10-17 17:02:00 +0100483TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100484 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
485 Instruction::CONST_4 | 0 << 8 | 0 << 12,
486 Instruction::CONST_4 | 1 << 8 | 1 << 12,
487 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
488 Instruction::GOTO | 4 << 8,
489 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
490 Instruction::GOTO | 4 << 8,
491 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
492 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
493 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
494 Instruction::RETURN | 2 << 8);
495
496 std::string expected_before =
497 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100498 " 3: IntConstant [9]\n" // v0 <- 0
499 " 5: IntConstant [9]\n" // v1 <- 1
500 " 13: IntConstant [14]\n" // const 3
501 " 18: IntConstant [19]\n" // const 2
502 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100503 " 30: SuspendCheck\n"
504 " 31: Goto 1\n"
505 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100506 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
507 " 11: Goto 3\n" // goto L2
508 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
509 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
510 " 16: Goto 4\n" // goto L3
511 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
512 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100513 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100514 " 22: Goto 2\n" // goto L1
515 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
516 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
517 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100518 "BasicBlock 5, pred: 4\n"
519 " 29: Exit\n";
520
Roland Levillain75be2832014-10-17 17:02:00 +0100521 // Expected difference after constant folding.
522 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100523 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
524 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
525 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
526 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
527 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
528 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
529 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
530 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
531 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
532 { " 28: Return(25)\n", " 28: Return(35)\n"}
533 };
Roland Levillain75be2832014-10-17 17:02:00 +0100534 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100535
Roland Levillain93445682014-10-06 19:24:02 +0100536 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100537 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100538 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
539 ASSERT_TRUE(inst1->IsIntConstant());
540 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
541 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
542 ASSERT_TRUE(inst2->IsIntConstant());
543 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
544 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
545 ASSERT_TRUE(inst3->IsIntConstant());
546 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
547 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
548 ASSERT_TRUE(inst4->IsIntConstant());
549 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
550 };
551
Roland Levillain556c3d12014-09-18 15:25:07 +0100552 // Expected difference after dead code elimination.
553 diff_t expected_dce_diff = {
554 { " 3: IntConstant\n", removed },
555 { " 13: IntConstant\n", removed },
556 { " 18: IntConstant\n", removed },
557 { " 24: IntConstant\n", removed },
558 { " 34: IntConstant\n", removed },
559 };
Roland Levillain75be2832014-10-17 17:02:00 +0100560 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100561
Roland Levillain93445682014-10-06 19:24:02 +0100562 TestCode(data,
563 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100564 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100565 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100566 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100567}
568
569
570/**
571 * Three-register program with a constant (static) condition.
572 *
573 * 16-bit
574 * offset
575 * ------
576 * v1 <- 1 0. const/4 v1, #+1
577 * v0 <- 0 1. const/4 v0, #+0
578 * if v1 >= 0 goto L1 2. if-gez v1, +3
579 * v0 <- v1 4. move v0, v1
580 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
581 * return-void 7. return
582 */
Roland Levillain75be2832014-10-17 17:02:00 +0100583TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100584 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
585 Instruction::CONST_4 | 1 << 8 | 1 << 12,
586 Instruction::CONST_4 | 0 << 8 | 0 << 12,
587 Instruction::IF_GEZ | 1 << 8, 3,
588 Instruction::MOVE | 0 << 8 | 1 << 12,
589 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
590 Instruction::RETURN_VOID);
591
592 std::string expected_before =
593 "BasicBlock 0, succ: 1\n"
594 " 3: IntConstant [15, 22, 8]\n"
595 " 5: IntConstant [22, 8]\n"
596 " 19: SuspendCheck\n"
597 " 20: Goto 1\n"
598 "BasicBlock 1, pred: 0, succ: 5, 2\n"
599 " 8: GreaterThanOrEqual(3, 5) [9]\n"
600 " 9: If(8)\n"
601 "BasicBlock 2, pred: 1, succ: 3\n"
602 " 12: Goto 3\n"
603 "BasicBlock 3, pred: 2, 5, succ: 4\n"
604 " 22: Phi(3, 5) [15]\n"
605 " 15: Add(22, 3)\n"
606 " 17: ReturnVoid\n"
607 "BasicBlock 4, pred: 3\n"
608 " 18: Exit\n"
609 "BasicBlock 5, pred: 1, succ: 3\n"
610 " 21: Goto 3\n";
611
Roland Levillain75be2832014-10-17 17:02:00 +0100612 // Expected difference after constant folding.
613 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100614 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
615 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
616 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
617 { " 9: If(8)\n", " 9: If(23)\n" }
618 };
Roland Levillain75be2832014-10-17 17:02:00 +0100619 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100620
Roland Levillain93445682014-10-06 19:24:02 +0100621 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100622 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100623 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
624 ASSERT_TRUE(inst->IsIntConstant());
625 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
626 };
627
Roland Levillain556c3d12014-09-18 15:25:07 +0100628 // Expected difference after dead code elimination.
629 diff_t expected_dce_diff = {
630 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
631 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
632 { " 15: Add(22, 3)\n", removed }
633 };
Roland Levillain75be2832014-10-17 17:02:00 +0100634 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100635
Roland Levillain93445682014-10-06 19:24:02 +0100636 TestCode(data,
637 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100638 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100639 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100640 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100641}
642
643} // namespace art