blob: cad66835773e61f31a0d24bb237587e1e3b253f6 [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
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000041 graph->TryBuildingSsa();
Roland Levillain556c3d12014-09-18 15:25:07 +010042
43 StringPrettyPrinter printer_before(graph);
44 printer_before.VisitInsertionOrder();
45 std::string actual_before = printer_before.str();
46 ASSERT_EQ(expected_before, actual_before);
47
Roland Levillain75be2832014-10-17 17:02:00 +010048 x86::CodeGeneratorX86 codegen(graph);
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000049 HConstantFolding(graph).Run();
Roland Levillain75be2832014-10-17 17:02:00 +010050 SSAChecker ssa_checker(&allocator, graph);
51 ssa_checker.Run();
52 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010053
Roland Levillain75be2832014-10-17 17:02:00 +010054 StringPrettyPrinter printer_after_cf(graph);
55 printer_after_cf.VisitInsertionOrder();
56 std::string actual_after_cf = printer_after_cf.str();
57 ASSERT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +010058
Roland Levillain75be2832014-10-17 17:02:00 +010059 check_after_cf(graph);
Roland Levillain93445682014-10-06 19:24:02 +010060
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000061 HDeadCodeElimination(graph).Run();
Roland Levillain75be2832014-10-17 17:02:00 +010062 ssa_checker.Run();
63 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010064
65 StringPrettyPrinter printer_after_dce(graph);
66 printer_after_dce.VisitInsertionOrder();
67 std::string actual_after_dce = printer_after_dce.str();
68 ASSERT_EQ(expected_after_dce, actual_after_dce);
Roland Levillain556c3d12014-09-18 15:25:07 +010069}
70
71
72/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010073 * Tiny three-register program exercising int constant folding on negation.
74 *
75 * 16-bit
76 * offset
77 * ------
78 * v0 <- 1 0. const/4 v0, #+1
79 * v1 <- -v0 1. neg-int v0, v1
80 * return v1 2. return v1
81 */
82TEST(ConstantFolding, IntConstantFoldingNegation) {
83 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
84 Instruction::CONST_4 | 0 << 8 | 1 << 12,
85 Instruction::NEG_INT | 1 << 8 | 0 << 12,
86 Instruction::RETURN | 1 << 8);
87
88 std::string expected_before =
89 "BasicBlock 0, succ: 1\n"
90 " 2: IntConstant [5]\n"
91 " 10: SuspendCheck\n"
92 " 11: Goto 1\n"
93 "BasicBlock 1, pred: 0, succ: 2\n"
94 " 5: Neg(2) [8]\n"
95 " 8: Return(5)\n"
96 "BasicBlock 2, pred: 1\n"
97 " 9: Exit\n";
98
99 // Expected difference after constant folding.
100 diff_t expected_cf_diff = {
101 { " 2: IntConstant [5]\n", " 2: IntConstant\n" },
102 { " 5: Neg(2) [8]\n", " 12: IntConstant [8]\n" },
103 { " 8: Return(5)\n", " 8: Return(12)\n" }
104 };
105 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
106
107 // Check the value of the computed constant.
108 auto check_after_cf = [](HGraph* graph) {
109 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
110 ASSERT_TRUE(inst->IsIntConstant());
111 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
112 };
113
114 // Expected difference after dead code elimination.
115 diff_t expected_dce_diff = {
116 { " 2: IntConstant\n", removed },
117 };
118 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
119
120 TestCode(data,
121 expected_before,
122 expected_after_cf,
123 expected_after_dce,
124 check_after_cf);
125}
126
127/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100128 * Tiny three-register program exercising int constant folding on addition.
129 *
130 * 16-bit
131 * offset
132 * ------
133 * v0 <- 1 0. const/4 v0, #+1
134 * v1 <- 2 1. const/4 v1, #+2
135 * v2 <- v0 + v1 2. add-int v2, v0, v1
136 * return v2 4. return v2
137 */
Roland Levillain75be2832014-10-17 17:02:00 +0100138TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100139 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
140 Instruction::CONST_4 | 0 << 8 | 1 << 12,
141 Instruction::CONST_4 | 1 << 8 | 2 << 12,
142 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
143 Instruction::RETURN | 2 << 8);
144
145 std::string expected_before =
146 "BasicBlock 0, succ: 1\n"
147 " 3: IntConstant [9]\n"
148 " 5: IntConstant [9]\n"
149 " 14: SuspendCheck\n"
150 " 15: Goto 1\n"
151 "BasicBlock 1, pred: 0, succ: 2\n"
152 " 9: Add(3, 5) [12]\n"
153 " 12: Return(9)\n"
154 "BasicBlock 2, pred: 1\n"
155 " 13: Exit\n";
156
Roland Levillain75be2832014-10-17 17:02:00 +0100157 // Expected difference after constant folding.
158 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100159 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
160 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
161 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
162 { " 12: Return(9)\n", " 12: Return(16)\n" }
163 };
Roland Levillain75be2832014-10-17 17:02:00 +0100164 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100165
Roland Levillain93445682014-10-06 19:24:02 +0100166 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100167 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100168 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
169 ASSERT_TRUE(inst->IsIntConstant());
170 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
171 };
172
Roland Levillain556c3d12014-09-18 15:25:07 +0100173 // Expected difference after dead code elimination.
174 diff_t expected_dce_diff = {
175 { " 3: IntConstant\n", removed },
176 { " 5: IntConstant\n", removed }
177 };
Roland Levillain75be2832014-10-17 17:02:00 +0100178 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100179
Roland Levillain93445682014-10-06 19:24:02 +0100180 TestCode(data,
181 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100182 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100183 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100184 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100185}
186
187/**
188 * Small three-register program exercising int constant folding on addition.
189 *
190 * 16-bit
191 * offset
192 * ------
193 * v0 <- 1 0. const/4 v0, #+1
194 * v1 <- 2 1. const/4 v1, #+2
195 * v0 <- v0 + v1 2. add-int/2addr v0, v1
196 * v1 <- 3 3. const/4 v1, #+3
197 * v2 <- 4 4. const/4 v2, #+4
198 * v1 <- v1 + v2 5. add-int/2addr v1, v2
199 * v2 <- v0 + v1 6. add-int v2, v0, v1
200 * return v2 8. return v2
201 */
Roland Levillain75be2832014-10-17 17:02:00 +0100202TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100203 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
204 Instruction::CONST_4 | 0 << 8 | 1 << 12,
205 Instruction::CONST_4 | 1 << 8 | 2 << 12,
206 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
207 Instruction::CONST_4 | 1 << 8 | 3 << 12,
208 Instruction::CONST_4 | 2 << 8 | 4 << 12,
209 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
210 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
211 Instruction::RETURN | 2 << 8);
212
213 std::string expected_before =
214 "BasicBlock 0, succ: 1\n"
215 " 3: IntConstant [9]\n"
216 " 5: IntConstant [9]\n"
217 " 11: IntConstant [17]\n"
218 " 13: IntConstant [17]\n"
219 " 26: SuspendCheck\n"
220 " 27: Goto 1\n"
221 "BasicBlock 1, pred: 0, succ: 2\n"
222 " 9: Add(3, 5) [21]\n"
223 " 17: Add(11, 13) [21]\n"
224 " 21: Add(9, 17) [24]\n"
225 " 24: Return(21)\n"
226 "BasicBlock 2, pred: 1\n"
227 " 25: Exit\n";
228
Roland Levillain75be2832014-10-17 17:02:00 +0100229 // Expected difference after constant folding.
230 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100231 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
232 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
233 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
234 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
235 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
236 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
237 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
238 { " 24: Return(21)\n", " 24: Return(30)\n" }
239 };
Roland Levillain75be2832014-10-17 17:02:00 +0100240 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100241
Roland Levillain93445682014-10-06 19:24:02 +0100242 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100243 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100244 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
245 ASSERT_TRUE(inst1->IsIntConstant());
246 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
247 HInstruction* inst2 = inst1->GetNext();
248 ASSERT_TRUE(inst2->IsIntConstant());
249 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
250 HInstruction* inst3 = inst2->GetNext();
251 ASSERT_TRUE(inst3->IsIntConstant());
252 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
253 };
254
Roland Levillain556c3d12014-09-18 15:25:07 +0100255 // Expected difference after dead code elimination.
256 diff_t expected_dce_diff = {
257 { " 3: IntConstant\n", removed },
258 { " 5: IntConstant\n", removed },
259 { " 11: IntConstant\n", removed },
260 { " 13: IntConstant\n", removed },
261 { " 28: IntConstant\n", removed },
262 { " 29: IntConstant\n", removed }
263 };
Roland Levillain75be2832014-10-17 17:02:00 +0100264 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100265
Roland Levillain93445682014-10-06 19:24:02 +0100266 TestCode(data,
267 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100268 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100269 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100270 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100271}
272
273/**
274 * Tiny three-register program exercising int constant folding on subtraction.
275 *
276 * 16-bit
277 * offset
278 * ------
279 * v0 <- 3 0. const/4 v0, #+3
280 * v1 <- 2 1. const/4 v1, #+2
281 * v2 <- v0 - v1 2. sub-int v2, v0, v1
282 * return v2 4. return v2
283 */
Roland Levillain75be2832014-10-17 17:02:00 +0100284TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100285 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
286 Instruction::CONST_4 | 0 << 8 | 3 << 12,
287 Instruction::CONST_4 | 1 << 8 | 2 << 12,
288 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
289 Instruction::RETURN | 2 << 8);
290
291 std::string expected_before =
292 "BasicBlock 0, succ: 1\n"
293 " 3: IntConstant [9]\n"
294 " 5: IntConstant [9]\n"
295 " 14: SuspendCheck\n"
296 " 15: Goto 1\n"
297 "BasicBlock 1, pred: 0, succ: 2\n"
298 " 9: Sub(3, 5) [12]\n"
299 " 12: Return(9)\n"
300 "BasicBlock 2, pred: 1\n"
301 " 13: Exit\n";
302
Roland Levillain75be2832014-10-17 17:02:00 +0100303 // Expected difference after constant folding.
304 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100305 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
306 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
307 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
308 { " 12: Return(9)\n", " 12: Return(16)\n" }
309 };
Roland Levillain75be2832014-10-17 17:02:00 +0100310 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100311
Roland Levillain93445682014-10-06 19:24:02 +0100312 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100313 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100314 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
315 ASSERT_TRUE(inst->IsIntConstant());
316 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
317 };
318
Roland Levillain556c3d12014-09-18 15:25:07 +0100319 // Expected difference after dead code elimination.
320 diff_t expected_dce_diff = {
321 { " 3: IntConstant\n", removed },
322 { " 5: IntConstant\n", removed }
323 };
Roland Levillain75be2832014-10-17 17:02:00 +0100324 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100325
Roland Levillain93445682014-10-06 19:24:02 +0100326 TestCode(data,
327 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100328 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100329 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100330 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100331}
332
Roland Levillain556c3d12014-09-18 15:25:07 +0100333/**
334 * Tiny three-register-pair program exercising long constant folding
335 * on addition.
336 *
337 * 16-bit
338 * offset
339 * ------
340 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
341 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
342 * (v4, v5) <-
343 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
344 * return (v4, v5) 6. return-wide v4
345 */
Roland Levillain75be2832014-10-17 17:02:00 +0100346TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100347 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
348 Instruction::CONST_WIDE_16 | 0 << 8, 1,
349 Instruction::CONST_WIDE_16 | 2 << 8, 2,
350 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
351 Instruction::RETURN_WIDE | 4 << 8);
352
353 std::string expected_before =
354 "BasicBlock 0, succ: 1\n"
355 " 6: LongConstant [12]\n"
356 " 8: LongConstant [12]\n"
357 " 17: SuspendCheck\n"
358 " 18: Goto 1\n"
359 "BasicBlock 1, pred: 0, succ: 2\n"
360 " 12: Add(6, 8) [15]\n"
361 " 15: Return(12)\n"
362 "BasicBlock 2, pred: 1\n"
363 " 16: Exit\n";
364
Roland Levillain75be2832014-10-17 17:02:00 +0100365 // Expected difference after constant folding.
366 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100367 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
368 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
369 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
370 { " 15: Return(12)\n", " 15: Return(19)\n" }
371 };
Roland Levillain75be2832014-10-17 17:02:00 +0100372 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100373
Roland Levillain93445682014-10-06 19:24:02 +0100374 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100375 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100376 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
377 ASSERT_TRUE(inst->IsLongConstant());
378 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
379 };
380
Roland Levillain556c3d12014-09-18 15:25:07 +0100381 // Expected difference after dead code elimination.
382 diff_t expected_dce_diff = {
383 { " 6: LongConstant\n", removed },
384 { " 8: LongConstant\n", removed }
385 };
Roland Levillain75be2832014-10-17 17:02:00 +0100386 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100387
Roland Levillain93445682014-10-06 19:24:02 +0100388 TestCode(data,
389 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100390 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100391 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100392 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100393 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100394}
395
396/**
397 * Tiny three-register-pair program exercising long constant folding
398 * on subtraction.
399 *
400 * 16-bit
401 * offset
402 * ------
403 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
404 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
405 * (v4, v5) <-
406 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
407 * return (v4, v5) 6. return-wide v4
408 */
Roland Levillain75be2832014-10-17 17:02:00 +0100409TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100410 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
411 Instruction::CONST_WIDE_16 | 0 << 8, 3,
412 Instruction::CONST_WIDE_16 | 2 << 8, 2,
413 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
414 Instruction::RETURN_WIDE | 4 << 8);
415
416 std::string expected_before =
417 "BasicBlock 0, succ: 1\n"
418 " 6: LongConstant [12]\n"
419 " 8: LongConstant [12]\n"
420 " 17: SuspendCheck\n"
421 " 18: Goto 1\n"
422 "BasicBlock 1, pred: 0, succ: 2\n"
423 " 12: Sub(6, 8) [15]\n"
424 " 15: Return(12)\n"
425 "BasicBlock 2, pred: 1\n"
426 " 16: Exit\n";
427
Roland Levillain75be2832014-10-17 17:02:00 +0100428 // Expected difference after constant folding.
429 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100430 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
431 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
432 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
433 { " 15: Return(12)\n", " 15: Return(19)\n" }
434 };
Roland Levillain75be2832014-10-17 17:02:00 +0100435 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100436
Roland Levillain93445682014-10-06 19:24:02 +0100437 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100438 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100439 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
440 ASSERT_TRUE(inst->IsLongConstant());
441 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
442 };
443
Roland Levillain556c3d12014-09-18 15:25:07 +0100444 // Expected difference after dead code elimination.
445 diff_t expected_dce_diff = {
446 { " 6: LongConstant\n", removed },
447 { " 8: LongConstant\n", removed }
448 };
Roland Levillain75be2832014-10-17 17:02:00 +0100449 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100450
Roland Levillain93445682014-10-06 19:24:02 +0100451 TestCode(data,
452 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100453 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100454 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100455 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100456 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100457}
458
459/**
460 * Three-register program with jumps leading to the creation of many
461 * blocks.
462 *
463 * The intent of this test is to ensure that all constant expressions
464 * are actually evaluated at compile-time, thanks to the reverse
465 * (forward) post-order traversal of the the dominator tree.
466 *
467 * 16-bit
468 * offset
469 * ------
470 * v0 <- 0 0. const/4 v0, #+0
471 * v1 <- 1 1. const/4 v1, #+1
472 * v2 <- v0 + v1 2. add-int v2, v0, v1
473 * goto L2 4. goto +4
474 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
475 * goto L3 7. goto +4
476 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
477 * goto L1 10. goto +(-5)
478 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
479 * return v2 13. return v2
480 */
Roland Levillain75be2832014-10-17 17:02:00 +0100481TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100482 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
483 Instruction::CONST_4 | 0 << 8 | 0 << 12,
484 Instruction::CONST_4 | 1 << 8 | 1 << 12,
485 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
486 Instruction::GOTO | 4 << 8,
487 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
488 Instruction::GOTO | 4 << 8,
489 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
490 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
491 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
492 Instruction::RETURN | 2 << 8);
493
494 std::string expected_before =
495 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100496 " 3: IntConstant [9]\n" // v0 <- 0
497 " 5: IntConstant [9]\n" // v1 <- 1
498 " 13: IntConstant [14]\n" // const 3
499 " 18: IntConstant [19]\n" // const 2
500 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100501 " 30: SuspendCheck\n"
502 " 31: Goto 1\n"
503 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100504 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
505 " 11: Goto 3\n" // goto L2
506 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
507 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
508 " 16: Goto 4\n" // goto L3
509 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
510 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100511 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100512 " 22: Goto 2\n" // goto L1
513 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
514 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
515 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100516 "BasicBlock 5, pred: 4\n"
517 " 29: Exit\n";
518
Roland Levillain75be2832014-10-17 17:02:00 +0100519 // Expected difference after constant folding.
520 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100521 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
522 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
523 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
524 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
525 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
526 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
527 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
528 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
529 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
530 { " 28: Return(25)\n", " 28: Return(35)\n"}
531 };
Roland Levillain75be2832014-10-17 17:02:00 +0100532 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100533
Roland Levillain93445682014-10-06 19:24:02 +0100534 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100535 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100536 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
537 ASSERT_TRUE(inst1->IsIntConstant());
538 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
539 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
540 ASSERT_TRUE(inst2->IsIntConstant());
541 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
542 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
543 ASSERT_TRUE(inst3->IsIntConstant());
544 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
545 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
546 ASSERT_TRUE(inst4->IsIntConstant());
547 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
548 };
549
Roland Levillain556c3d12014-09-18 15:25:07 +0100550 // Expected difference after dead code elimination.
551 diff_t expected_dce_diff = {
552 { " 3: IntConstant\n", removed },
553 { " 13: IntConstant\n", removed },
554 { " 18: IntConstant\n", removed },
555 { " 24: IntConstant\n", removed },
556 { " 34: IntConstant\n", removed },
557 };
Roland Levillain75be2832014-10-17 17:02:00 +0100558 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100559
Roland Levillain93445682014-10-06 19:24:02 +0100560 TestCode(data,
561 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100562 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100563 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100564 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100565}
566
567
568/**
569 * Three-register program with a constant (static) condition.
570 *
571 * 16-bit
572 * offset
573 * ------
574 * v1 <- 1 0. const/4 v1, #+1
575 * v0 <- 0 1. const/4 v0, #+0
576 * if v1 >= 0 goto L1 2. if-gez v1, +3
577 * v0 <- v1 4. move v0, v1
578 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
579 * return-void 7. return
580 */
Roland Levillain75be2832014-10-17 17:02:00 +0100581TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100582 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
583 Instruction::CONST_4 | 1 << 8 | 1 << 12,
584 Instruction::CONST_4 | 0 << 8 | 0 << 12,
585 Instruction::IF_GEZ | 1 << 8, 3,
586 Instruction::MOVE | 0 << 8 | 1 << 12,
587 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
588 Instruction::RETURN_VOID);
589
590 std::string expected_before =
591 "BasicBlock 0, succ: 1\n"
592 " 3: IntConstant [15, 22, 8]\n"
593 " 5: IntConstant [22, 8]\n"
594 " 19: SuspendCheck\n"
595 " 20: Goto 1\n"
596 "BasicBlock 1, pred: 0, succ: 5, 2\n"
597 " 8: GreaterThanOrEqual(3, 5) [9]\n"
598 " 9: If(8)\n"
599 "BasicBlock 2, pred: 1, succ: 3\n"
600 " 12: Goto 3\n"
601 "BasicBlock 3, pred: 2, 5, succ: 4\n"
602 " 22: Phi(3, 5) [15]\n"
603 " 15: Add(22, 3)\n"
604 " 17: ReturnVoid\n"
605 "BasicBlock 4, pred: 3\n"
606 " 18: Exit\n"
607 "BasicBlock 5, pred: 1, succ: 3\n"
608 " 21: Goto 3\n";
609
Roland Levillain75be2832014-10-17 17:02:00 +0100610 // Expected difference after constant folding.
611 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100612 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
613 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
614 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
615 { " 9: If(8)\n", " 9: If(23)\n" }
616 };
Roland Levillain75be2832014-10-17 17:02:00 +0100617 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100618
Roland Levillain93445682014-10-06 19:24:02 +0100619 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100620 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100621 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
622 ASSERT_TRUE(inst->IsIntConstant());
623 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
624 };
625
Roland Levillain556c3d12014-09-18 15:25:07 +0100626 // Expected difference after dead code elimination.
627 diff_t expected_dce_diff = {
628 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
629 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
630 { " 15: Add(22, 3)\n", removed }
631 };
Roland Levillain75be2832014-10-17 17:02:00 +0100632 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100633
Roland Levillain93445682014-10-06 19:24:02 +0100634 TestCode(data,
635 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100636 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100637 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100638 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100639}
640
641} // namespace art