blob: 09bf2c8d7d1ab501c8b2f0e2e547c1ec53fe2d8e [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
335#define SIX_REGISTERS_CODE_ITEM(...) \
336 { 6, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
337
338/**
339 * Tiny three-register-pair program exercising long constant folding
340 * on addition.
341 *
342 * 16-bit
343 * offset
344 * ------
345 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
346 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
347 * (v4, v5) <-
348 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
349 * return (v4, v5) 6. return-wide v4
350 */
Roland Levillain75be2832014-10-17 17:02:00 +0100351TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100352 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
353 Instruction::CONST_WIDE_16 | 0 << 8, 1,
354 Instruction::CONST_WIDE_16 | 2 << 8, 2,
355 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
356 Instruction::RETURN_WIDE | 4 << 8);
357
358 std::string expected_before =
359 "BasicBlock 0, succ: 1\n"
360 " 6: LongConstant [12]\n"
361 " 8: LongConstant [12]\n"
362 " 17: SuspendCheck\n"
363 " 18: Goto 1\n"
364 "BasicBlock 1, pred: 0, succ: 2\n"
365 " 12: Add(6, 8) [15]\n"
366 " 15: Return(12)\n"
367 "BasicBlock 2, pred: 1\n"
368 " 16: Exit\n";
369
Roland Levillain75be2832014-10-17 17:02:00 +0100370 // Expected difference after constant folding.
371 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100372 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
373 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
374 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
375 { " 15: Return(12)\n", " 15: Return(19)\n" }
376 };
Roland Levillain75be2832014-10-17 17:02:00 +0100377 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100378
Roland Levillain93445682014-10-06 19:24:02 +0100379 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100380 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100381 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
382 ASSERT_TRUE(inst->IsLongConstant());
383 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
384 };
385
Roland Levillain556c3d12014-09-18 15:25:07 +0100386 // Expected difference after dead code elimination.
387 diff_t expected_dce_diff = {
388 { " 6: LongConstant\n", removed },
389 { " 8: LongConstant\n", removed }
390 };
Roland Levillain75be2832014-10-17 17:02:00 +0100391 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100392
Roland Levillain93445682014-10-06 19:24:02 +0100393 TestCode(data,
394 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100395 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100396 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100397 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100398 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100399}
400
401/**
402 * Tiny three-register-pair program exercising long constant folding
403 * on subtraction.
404 *
405 * 16-bit
406 * offset
407 * ------
408 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
409 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
410 * (v4, v5) <-
411 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
412 * return (v4, v5) 6. return-wide v4
413 */
Roland Levillain75be2832014-10-17 17:02:00 +0100414TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100415 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
416 Instruction::CONST_WIDE_16 | 0 << 8, 3,
417 Instruction::CONST_WIDE_16 | 2 << 8, 2,
418 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
419 Instruction::RETURN_WIDE | 4 << 8);
420
421 std::string expected_before =
422 "BasicBlock 0, succ: 1\n"
423 " 6: LongConstant [12]\n"
424 " 8: LongConstant [12]\n"
425 " 17: SuspendCheck\n"
426 " 18: Goto 1\n"
427 "BasicBlock 1, pred: 0, succ: 2\n"
428 " 12: Sub(6, 8) [15]\n"
429 " 15: Return(12)\n"
430 "BasicBlock 2, pred: 1\n"
431 " 16: Exit\n";
432
Roland Levillain75be2832014-10-17 17:02:00 +0100433 // Expected difference after constant folding.
434 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100435 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
436 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
437 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
438 { " 15: Return(12)\n", " 15: Return(19)\n" }
439 };
Roland Levillain75be2832014-10-17 17:02:00 +0100440 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100441
Roland Levillain93445682014-10-06 19:24:02 +0100442 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100443 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100444 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
445 ASSERT_TRUE(inst->IsLongConstant());
446 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
447 };
448
Roland Levillain556c3d12014-09-18 15:25:07 +0100449 // Expected difference after dead code elimination.
450 diff_t expected_dce_diff = {
451 { " 6: LongConstant\n", removed },
452 { " 8: LongConstant\n", removed }
453 };
Roland Levillain75be2832014-10-17 17:02:00 +0100454 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100455
Roland Levillain93445682014-10-06 19:24:02 +0100456 TestCode(data,
457 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100458 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100459 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100460 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100461 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100462}
463
464/**
465 * Three-register program with jumps leading to the creation of many
466 * blocks.
467 *
468 * The intent of this test is to ensure that all constant expressions
469 * are actually evaluated at compile-time, thanks to the reverse
470 * (forward) post-order traversal of the the dominator tree.
471 *
472 * 16-bit
473 * offset
474 * ------
475 * v0 <- 0 0. const/4 v0, #+0
476 * v1 <- 1 1. const/4 v1, #+1
477 * v2 <- v0 + v1 2. add-int v2, v0, v1
478 * goto L2 4. goto +4
479 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
480 * goto L3 7. goto +4
481 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
482 * goto L1 10. goto +(-5)
483 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
484 * return v2 13. return v2
485 */
Roland Levillain75be2832014-10-17 17:02:00 +0100486TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100487 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
488 Instruction::CONST_4 | 0 << 8 | 0 << 12,
489 Instruction::CONST_4 | 1 << 8 | 1 << 12,
490 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
491 Instruction::GOTO | 4 << 8,
492 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
493 Instruction::GOTO | 4 << 8,
494 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
495 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
496 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
497 Instruction::RETURN | 2 << 8);
498
499 std::string expected_before =
500 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100501 " 3: IntConstant [9]\n" // v0 <- 0
502 " 5: IntConstant [9]\n" // v1 <- 1
503 " 13: IntConstant [14]\n" // const 3
504 " 18: IntConstant [19]\n" // const 2
505 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100506 " 30: SuspendCheck\n"
507 " 31: Goto 1\n"
508 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100509 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
510 " 11: Goto 3\n" // goto L2
511 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
512 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
513 " 16: Goto 4\n" // goto L3
514 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
515 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100516 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100517 " 22: Goto 2\n" // goto L1
518 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
519 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
520 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100521 "BasicBlock 5, pred: 4\n"
522 " 29: Exit\n";
523
Roland Levillain75be2832014-10-17 17:02:00 +0100524 // Expected difference after constant folding.
525 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100526 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
527 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
528 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
529 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
530 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
531 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
532 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
533 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
534 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
535 { " 28: Return(25)\n", " 28: Return(35)\n"}
536 };
Roland Levillain75be2832014-10-17 17:02:00 +0100537 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100538
Roland Levillain93445682014-10-06 19:24:02 +0100539 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100540 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100541 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
542 ASSERT_TRUE(inst1->IsIntConstant());
543 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
544 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
545 ASSERT_TRUE(inst2->IsIntConstant());
546 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
547 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
548 ASSERT_TRUE(inst3->IsIntConstant());
549 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
550 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
551 ASSERT_TRUE(inst4->IsIntConstant());
552 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
553 };
554
Roland Levillain556c3d12014-09-18 15:25:07 +0100555 // Expected difference after dead code elimination.
556 diff_t expected_dce_diff = {
557 { " 3: IntConstant\n", removed },
558 { " 13: IntConstant\n", removed },
559 { " 18: IntConstant\n", removed },
560 { " 24: IntConstant\n", removed },
561 { " 34: IntConstant\n", removed },
562 };
Roland Levillain75be2832014-10-17 17:02:00 +0100563 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100564
Roland Levillain93445682014-10-06 19:24:02 +0100565 TestCode(data,
566 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100567 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100568 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100569 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100570}
571
572
573/**
574 * Three-register program with a constant (static) condition.
575 *
576 * 16-bit
577 * offset
578 * ------
579 * v1 <- 1 0. const/4 v1, #+1
580 * v0 <- 0 1. const/4 v0, #+0
581 * if v1 >= 0 goto L1 2. if-gez v1, +3
582 * v0 <- v1 4. move v0, v1
583 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
584 * return-void 7. return
585 */
Roland Levillain75be2832014-10-17 17:02:00 +0100586TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100587 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
588 Instruction::CONST_4 | 1 << 8 | 1 << 12,
589 Instruction::CONST_4 | 0 << 8 | 0 << 12,
590 Instruction::IF_GEZ | 1 << 8, 3,
591 Instruction::MOVE | 0 << 8 | 1 << 12,
592 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
593 Instruction::RETURN_VOID);
594
595 std::string expected_before =
596 "BasicBlock 0, succ: 1\n"
597 " 3: IntConstant [15, 22, 8]\n"
598 " 5: IntConstant [22, 8]\n"
599 " 19: SuspendCheck\n"
600 " 20: Goto 1\n"
601 "BasicBlock 1, pred: 0, succ: 5, 2\n"
602 " 8: GreaterThanOrEqual(3, 5) [9]\n"
603 " 9: If(8)\n"
604 "BasicBlock 2, pred: 1, succ: 3\n"
605 " 12: Goto 3\n"
606 "BasicBlock 3, pred: 2, 5, succ: 4\n"
607 " 22: Phi(3, 5) [15]\n"
608 " 15: Add(22, 3)\n"
609 " 17: ReturnVoid\n"
610 "BasicBlock 4, pred: 3\n"
611 " 18: Exit\n"
612 "BasicBlock 5, pred: 1, succ: 3\n"
613 " 21: Goto 3\n";
614
Roland Levillain75be2832014-10-17 17:02:00 +0100615 // Expected difference after constant folding.
616 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100617 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
618 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
619 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
620 { " 9: If(8)\n", " 9: If(23)\n" }
621 };
Roland Levillain75be2832014-10-17 17:02:00 +0100622 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100623
Roland Levillain93445682014-10-06 19:24:02 +0100624 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100625 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100626 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
627 ASSERT_TRUE(inst->IsIntConstant());
628 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
629 };
630
Roland Levillain556c3d12014-09-18 15:25:07 +0100631 // Expected difference after dead code elimination.
632 diff_t expected_dce_diff = {
633 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
634 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
635 { " 15: Add(22, 3)\n", removed }
636 };
Roland Levillain75be2832014-10-17 17:02:00 +0100637 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100638
Roland Levillain93445682014-10-06 19:24:02 +0100639 TestCode(data,
640 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100641 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100642 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100643 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100644}
645
646} // namespace art