blob: a56b9d9a1261d358e049b7f91e977638a88ee831 [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);
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000050 HConstantFolding(graph).Run();
Roland Levillain75be2832014-10-17 17:02:00 +010051 SSAChecker ssa_checker(&allocator, graph);
52 ssa_checker.Run();
53 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010054
Roland Levillain75be2832014-10-17 17:02:00 +010055 StringPrettyPrinter printer_after_cf(graph);
56 printer_after_cf.VisitInsertionOrder();
57 std::string actual_after_cf = printer_after_cf.str();
58 ASSERT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +010059
Roland Levillain75be2832014-10-17 17:02:00 +010060 check_after_cf(graph);
Roland Levillain93445682014-10-06 19:24:02 +010061
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000062 HDeadCodeElimination(graph).Run();
Roland Levillain75be2832014-10-17 17:02:00 +010063 ssa_checker.Run();
64 ASSERT_TRUE(ssa_checker.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010065
66 StringPrettyPrinter printer_after_dce(graph);
67 printer_after_dce.VisitInsertionOrder();
68 std::string actual_after_dce = printer_after_dce.str();
69 ASSERT_EQ(expected_after_dce, actual_after_dce);
Roland Levillain556c3d12014-09-18 15:25:07 +010070}
71
72
73/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010074 * Tiny three-register program exercising int constant folding on negation.
75 *
76 * 16-bit
77 * offset
78 * ------
79 * v0 <- 1 0. const/4 v0, #+1
80 * v1 <- -v0 1. neg-int v0, v1
81 * return v1 2. return v1
82 */
83TEST(ConstantFolding, IntConstantFoldingNegation) {
84 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
85 Instruction::CONST_4 | 0 << 8 | 1 << 12,
86 Instruction::NEG_INT | 1 << 8 | 0 << 12,
87 Instruction::RETURN | 1 << 8);
88
89 std::string expected_before =
90 "BasicBlock 0, succ: 1\n"
91 " 2: IntConstant [5]\n"
92 " 10: SuspendCheck\n"
93 " 11: Goto 1\n"
94 "BasicBlock 1, pred: 0, succ: 2\n"
95 " 5: Neg(2) [8]\n"
96 " 8: Return(5)\n"
97 "BasicBlock 2, pred: 1\n"
98 " 9: Exit\n";
99
100 // Expected difference after constant folding.
101 diff_t expected_cf_diff = {
102 { " 2: IntConstant [5]\n", " 2: IntConstant\n" },
103 { " 5: Neg(2) [8]\n", " 12: IntConstant [8]\n" },
104 { " 8: Return(5)\n", " 8: Return(12)\n" }
105 };
106 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
107
108 // Check the value of the computed constant.
109 auto check_after_cf = [](HGraph* graph) {
110 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
111 ASSERT_TRUE(inst->IsIntConstant());
112 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
113 };
114
115 // Expected difference after dead code elimination.
116 diff_t expected_dce_diff = {
117 { " 2: IntConstant\n", removed },
118 };
119 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
120
121 TestCode(data,
122 expected_before,
123 expected_after_cf,
124 expected_after_dce,
125 check_after_cf);
126}
127
128/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100129 * Tiny three-register program exercising int constant folding on addition.
130 *
131 * 16-bit
132 * offset
133 * ------
134 * v0 <- 1 0. const/4 v0, #+1
135 * v1 <- 2 1. const/4 v1, #+2
136 * v2 <- v0 + v1 2. add-int v2, v0, v1
137 * return v2 4. return v2
138 */
Roland Levillain75be2832014-10-17 17:02:00 +0100139TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100140 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
141 Instruction::CONST_4 | 0 << 8 | 1 << 12,
142 Instruction::CONST_4 | 1 << 8 | 2 << 12,
143 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
144 Instruction::RETURN | 2 << 8);
145
146 std::string expected_before =
147 "BasicBlock 0, succ: 1\n"
148 " 3: IntConstant [9]\n"
149 " 5: IntConstant [9]\n"
150 " 14: SuspendCheck\n"
151 " 15: Goto 1\n"
152 "BasicBlock 1, pred: 0, succ: 2\n"
153 " 9: Add(3, 5) [12]\n"
154 " 12: Return(9)\n"
155 "BasicBlock 2, pred: 1\n"
156 " 13: Exit\n";
157
Roland Levillain75be2832014-10-17 17:02:00 +0100158 // Expected difference after constant folding.
159 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100160 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
161 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
162 { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
163 { " 12: Return(9)\n", " 12: Return(16)\n" }
164 };
Roland Levillain75be2832014-10-17 17:02:00 +0100165 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100166
Roland Levillain93445682014-10-06 19:24:02 +0100167 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100168 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100169 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
170 ASSERT_TRUE(inst->IsIntConstant());
171 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
172 };
173
Roland Levillain556c3d12014-09-18 15:25:07 +0100174 // Expected difference after dead code elimination.
175 diff_t expected_dce_diff = {
176 { " 3: IntConstant\n", removed },
177 { " 5: IntConstant\n", removed }
178 };
Roland Levillain75be2832014-10-17 17:02:00 +0100179 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100180
Roland Levillain93445682014-10-06 19:24:02 +0100181 TestCode(data,
182 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100183 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100184 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100185 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100186}
187
188/**
189 * Small three-register program exercising int constant folding on addition.
190 *
191 * 16-bit
192 * offset
193 * ------
194 * v0 <- 1 0. const/4 v0, #+1
195 * v1 <- 2 1. const/4 v1, #+2
196 * v0 <- v0 + v1 2. add-int/2addr v0, v1
197 * v1 <- 3 3. const/4 v1, #+3
198 * v2 <- 4 4. const/4 v2, #+4
199 * v1 <- v1 + v2 5. add-int/2addr v1, v2
200 * v2 <- v0 + v1 6. add-int v2, v0, v1
201 * return v2 8. return v2
202 */
Roland Levillain75be2832014-10-17 17:02:00 +0100203TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100204 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
205 Instruction::CONST_4 | 0 << 8 | 1 << 12,
206 Instruction::CONST_4 | 1 << 8 | 2 << 12,
207 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
208 Instruction::CONST_4 | 1 << 8 | 3 << 12,
209 Instruction::CONST_4 | 2 << 8 | 4 << 12,
210 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
211 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
212 Instruction::RETURN | 2 << 8);
213
214 std::string expected_before =
215 "BasicBlock 0, succ: 1\n"
216 " 3: IntConstant [9]\n"
217 " 5: IntConstant [9]\n"
218 " 11: IntConstant [17]\n"
219 " 13: IntConstant [17]\n"
220 " 26: SuspendCheck\n"
221 " 27: Goto 1\n"
222 "BasicBlock 1, pred: 0, succ: 2\n"
223 " 9: Add(3, 5) [21]\n"
224 " 17: Add(11, 13) [21]\n"
225 " 21: Add(9, 17) [24]\n"
226 " 24: Return(21)\n"
227 "BasicBlock 2, pred: 1\n"
228 " 25: Exit\n";
229
Roland Levillain75be2832014-10-17 17:02:00 +0100230 // Expected difference after constant folding.
231 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100232 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
233 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
234 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
235 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
236 { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
237 { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
238 { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
239 { " 24: Return(21)\n", " 24: Return(30)\n" }
240 };
Roland Levillain75be2832014-10-17 17:02:00 +0100241 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100242
Roland Levillain93445682014-10-06 19:24:02 +0100243 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100244 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100245 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
246 ASSERT_TRUE(inst1->IsIntConstant());
247 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
248 HInstruction* inst2 = inst1->GetNext();
249 ASSERT_TRUE(inst2->IsIntConstant());
250 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
251 HInstruction* inst3 = inst2->GetNext();
252 ASSERT_TRUE(inst3->IsIntConstant());
253 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
254 };
255
Roland Levillain556c3d12014-09-18 15:25:07 +0100256 // Expected difference after dead code elimination.
257 diff_t expected_dce_diff = {
258 { " 3: IntConstant\n", removed },
259 { " 5: IntConstant\n", removed },
260 { " 11: IntConstant\n", removed },
261 { " 13: IntConstant\n", removed },
262 { " 28: IntConstant\n", removed },
263 { " 29: IntConstant\n", removed }
264 };
Roland Levillain75be2832014-10-17 17:02:00 +0100265 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100266
Roland Levillain93445682014-10-06 19:24:02 +0100267 TestCode(data,
268 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100269 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100270 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100271 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100272}
273
274/**
275 * Tiny three-register program exercising int constant folding on subtraction.
276 *
277 * 16-bit
278 * offset
279 * ------
280 * v0 <- 3 0. const/4 v0, #+3
281 * v1 <- 2 1. const/4 v1, #+2
282 * v2 <- v0 - v1 2. sub-int v2, v0, v1
283 * return v2 4. return v2
284 */
Roland Levillain75be2832014-10-17 17:02:00 +0100285TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100286 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
287 Instruction::CONST_4 | 0 << 8 | 3 << 12,
288 Instruction::CONST_4 | 1 << 8 | 2 << 12,
289 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
290 Instruction::RETURN | 2 << 8);
291
292 std::string expected_before =
293 "BasicBlock 0, succ: 1\n"
294 " 3: IntConstant [9]\n"
295 " 5: IntConstant [9]\n"
296 " 14: SuspendCheck\n"
297 " 15: Goto 1\n"
298 "BasicBlock 1, pred: 0, succ: 2\n"
299 " 9: Sub(3, 5) [12]\n"
300 " 12: Return(9)\n"
301 "BasicBlock 2, pred: 1\n"
302 " 13: Exit\n";
303
Roland Levillain75be2832014-10-17 17:02:00 +0100304 // Expected difference after constant folding.
305 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100306 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
307 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
308 { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
309 { " 12: Return(9)\n", " 12: Return(16)\n" }
310 };
Roland Levillain75be2832014-10-17 17:02:00 +0100311 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100312
Roland Levillain93445682014-10-06 19:24:02 +0100313 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100314 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100315 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
316 ASSERT_TRUE(inst->IsIntConstant());
317 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
318 };
319
Roland Levillain556c3d12014-09-18 15:25:07 +0100320 // Expected difference after dead code elimination.
321 diff_t expected_dce_diff = {
322 { " 3: IntConstant\n", removed },
323 { " 5: IntConstant\n", removed }
324 };
Roland Levillain75be2832014-10-17 17:02:00 +0100325 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100326
Roland Levillain93445682014-10-06 19:24:02 +0100327 TestCode(data,
328 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100329 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100330 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100331 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100332}
333
Roland Levillain556c3d12014-09-18 15:25:07 +0100334/**
335 * Tiny three-register-pair program exercising long constant folding
336 * on addition.
337 *
338 * 16-bit
339 * offset
340 * ------
341 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
342 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
343 * (v4, v5) <-
344 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
345 * return (v4, v5) 6. return-wide v4
346 */
Roland Levillain75be2832014-10-17 17:02:00 +0100347TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100348 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
349 Instruction::CONST_WIDE_16 | 0 << 8, 1,
350 Instruction::CONST_WIDE_16 | 2 << 8, 2,
351 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
352 Instruction::RETURN_WIDE | 4 << 8);
353
354 std::string expected_before =
355 "BasicBlock 0, succ: 1\n"
356 " 6: LongConstant [12]\n"
357 " 8: LongConstant [12]\n"
358 " 17: SuspendCheck\n"
359 " 18: Goto 1\n"
360 "BasicBlock 1, pred: 0, succ: 2\n"
361 " 12: Add(6, 8) [15]\n"
362 " 15: Return(12)\n"
363 "BasicBlock 2, pred: 1\n"
364 " 16: Exit\n";
365
Roland Levillain75be2832014-10-17 17:02:00 +0100366 // Expected difference after constant folding.
367 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100368 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
369 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
370 { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
371 { " 15: Return(12)\n", " 15: Return(19)\n" }
372 };
Roland Levillain75be2832014-10-17 17:02:00 +0100373 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100374
Roland Levillain93445682014-10-06 19:24:02 +0100375 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100376 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100377 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
378 ASSERT_TRUE(inst->IsLongConstant());
379 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
380 };
381
Roland Levillain556c3d12014-09-18 15:25:07 +0100382 // Expected difference after dead code elimination.
383 diff_t expected_dce_diff = {
384 { " 6: LongConstant\n", removed },
385 { " 8: LongConstant\n", removed }
386 };
Roland Levillain75be2832014-10-17 17:02:00 +0100387 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100388
Roland Levillain93445682014-10-06 19:24:02 +0100389 TestCode(data,
390 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100391 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100392 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100393 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100394 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100395}
396
397/**
398 * Tiny three-register-pair program exercising long constant folding
399 * on subtraction.
400 *
401 * 16-bit
402 * offset
403 * ------
404 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
405 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
406 * (v4, v5) <-
407 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
408 * return (v4, v5) 6. return-wide v4
409 */
Roland Levillain75be2832014-10-17 17:02:00 +0100410TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100411 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
412 Instruction::CONST_WIDE_16 | 0 << 8, 3,
413 Instruction::CONST_WIDE_16 | 2 << 8, 2,
414 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
415 Instruction::RETURN_WIDE | 4 << 8);
416
417 std::string expected_before =
418 "BasicBlock 0, succ: 1\n"
419 " 6: LongConstant [12]\n"
420 " 8: LongConstant [12]\n"
421 " 17: SuspendCheck\n"
422 " 18: Goto 1\n"
423 "BasicBlock 1, pred: 0, succ: 2\n"
424 " 12: Sub(6, 8) [15]\n"
425 " 15: Return(12)\n"
426 "BasicBlock 2, pred: 1\n"
427 " 16: Exit\n";
428
Roland Levillain75be2832014-10-17 17:02:00 +0100429 // Expected difference after constant folding.
430 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100431 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
432 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
433 { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
434 { " 15: Return(12)\n", " 15: Return(19)\n" }
435 };
Roland Levillain75be2832014-10-17 17:02:00 +0100436 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100437
Roland Levillain93445682014-10-06 19:24:02 +0100438 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100439 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100440 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
441 ASSERT_TRUE(inst->IsLongConstant());
442 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
443 };
444
Roland Levillain556c3d12014-09-18 15:25:07 +0100445 // Expected difference after dead code elimination.
446 diff_t expected_dce_diff = {
447 { " 6: LongConstant\n", removed },
448 { " 8: LongConstant\n", removed }
449 };
Roland Levillain75be2832014-10-17 17:02:00 +0100450 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100451
Roland Levillain93445682014-10-06 19:24:02 +0100452 TestCode(data,
453 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100454 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100455 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100456 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100457 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100458}
459
460/**
461 * Three-register program with jumps leading to the creation of many
462 * blocks.
463 *
464 * The intent of this test is to ensure that all constant expressions
465 * are actually evaluated at compile-time, thanks to the reverse
466 * (forward) post-order traversal of the the dominator tree.
467 *
468 * 16-bit
469 * offset
470 * ------
471 * v0 <- 0 0. const/4 v0, #+0
472 * v1 <- 1 1. const/4 v1, #+1
473 * v2 <- v0 + v1 2. add-int v2, v0, v1
474 * goto L2 4. goto +4
475 * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
476 * goto L3 7. goto +4
477 * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
478 * goto L1 10. goto +(-5)
479 * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
480 * return v2 13. return v2
481 */
Roland Levillain75be2832014-10-17 17:02:00 +0100482TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100483 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
484 Instruction::CONST_4 | 0 << 8 | 0 << 12,
485 Instruction::CONST_4 | 1 << 8 | 1 << 12,
486 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
487 Instruction::GOTO | 4 << 8,
488 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
489 Instruction::GOTO | 4 << 8,
490 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
491 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
492 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
493 Instruction::RETURN | 2 << 8);
494
495 std::string expected_before =
496 "BasicBlock 0, succ: 1\n"
Roland Levillain93445682014-10-06 19:24:02 +0100497 " 3: IntConstant [9]\n" // v0 <- 0
498 " 5: IntConstant [9]\n" // v1 <- 1
499 " 13: IntConstant [14]\n" // const 3
500 " 18: IntConstant [19]\n" // const 2
501 " 24: IntConstant [25]\n" // const 4
Roland Levillain556c3d12014-09-18 15:25:07 +0100502 " 30: SuspendCheck\n"
503 " 31: Goto 1\n"
504 "BasicBlock 1, pred: 0, succ: 3\n"
Roland Levillain93445682014-10-06 19:24:02 +0100505 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
506 " 11: Goto 3\n" // goto L2
507 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
508 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
509 " 16: Goto 4\n" // goto L3
510 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
511 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
Roland Levillain556c3d12014-09-18 15:25:07 +0100512 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100513 " 22: Goto 2\n" // goto L1
514 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
515 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
516 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100517 "BasicBlock 5, pred: 4\n"
518 " 29: Exit\n";
519
Roland Levillain75be2832014-10-17 17:02:00 +0100520 // Expected difference after constant folding.
521 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100522 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
523 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
524 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
525 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
526 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
527 { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
528 { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
529 { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
530 { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
531 { " 28: Return(25)\n", " 28: Return(35)\n"}
532 };
Roland Levillain75be2832014-10-17 17:02:00 +0100533 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100534
Roland Levillain93445682014-10-06 19:24:02 +0100535 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100536 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100537 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
538 ASSERT_TRUE(inst1->IsIntConstant());
539 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
540 HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
541 ASSERT_TRUE(inst2->IsIntConstant());
542 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
543 HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
544 ASSERT_TRUE(inst3->IsIntConstant());
545 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
546 HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
547 ASSERT_TRUE(inst4->IsIntConstant());
548 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
549 };
550
Roland Levillain556c3d12014-09-18 15:25:07 +0100551 // Expected difference after dead code elimination.
552 diff_t expected_dce_diff = {
553 { " 3: IntConstant\n", removed },
554 { " 13: IntConstant\n", removed },
555 { " 18: IntConstant\n", removed },
556 { " 24: IntConstant\n", removed },
557 { " 34: IntConstant\n", removed },
558 };
Roland Levillain75be2832014-10-17 17:02:00 +0100559 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100560
Roland Levillain93445682014-10-06 19:24:02 +0100561 TestCode(data,
562 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100563 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100564 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100565 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100566}
567
568
569/**
570 * Three-register program with a constant (static) condition.
571 *
572 * 16-bit
573 * offset
574 * ------
575 * v1 <- 1 0. const/4 v1, #+1
576 * v0 <- 0 1. const/4 v0, #+0
577 * if v1 >= 0 goto L1 2. if-gez v1, +3
578 * v0 <- v1 4. move v0, v1
579 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
580 * return-void 7. return
581 */
Roland Levillain75be2832014-10-17 17:02:00 +0100582TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100583 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
584 Instruction::CONST_4 | 1 << 8 | 1 << 12,
585 Instruction::CONST_4 | 0 << 8 | 0 << 12,
586 Instruction::IF_GEZ | 1 << 8, 3,
587 Instruction::MOVE | 0 << 8 | 1 << 12,
588 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
589 Instruction::RETURN_VOID);
590
591 std::string expected_before =
592 "BasicBlock 0, succ: 1\n"
593 " 3: IntConstant [15, 22, 8]\n"
594 " 5: IntConstant [22, 8]\n"
595 " 19: SuspendCheck\n"
596 " 20: Goto 1\n"
597 "BasicBlock 1, pred: 0, succ: 5, 2\n"
598 " 8: GreaterThanOrEqual(3, 5) [9]\n"
599 " 9: If(8)\n"
600 "BasicBlock 2, pred: 1, succ: 3\n"
601 " 12: Goto 3\n"
602 "BasicBlock 3, pred: 2, 5, succ: 4\n"
603 " 22: Phi(3, 5) [15]\n"
604 " 15: Add(22, 3)\n"
605 " 17: ReturnVoid\n"
606 "BasicBlock 4, pred: 3\n"
607 " 18: Exit\n"
608 "BasicBlock 5, pred: 1, succ: 3\n"
609 " 21: Goto 3\n";
610
Roland Levillain75be2832014-10-17 17:02:00 +0100611 // Expected difference after constant folding.
612 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100613 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
614 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
615 { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
616 { " 9: If(8)\n", " 9: If(23)\n" }
617 };
Roland Levillain75be2832014-10-17 17:02:00 +0100618 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100619
Roland Levillain93445682014-10-06 19:24:02 +0100620 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100621 auto check_after_cf = [](HGraph* graph) {
Roland Levillain93445682014-10-06 19:24:02 +0100622 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
623 ASSERT_TRUE(inst->IsIntConstant());
624 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
625 };
626
Roland Levillain556c3d12014-09-18 15:25:07 +0100627 // Expected difference after dead code elimination.
628 diff_t expected_dce_diff = {
629 { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
630 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
631 { " 15: Add(22, 3)\n", removed }
632 };
Roland Levillain75be2832014-10-17 17:02:00 +0100633 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100634
Roland Levillain93445682014-10-06 19:24:02 +0100635 TestCode(data,
636 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100637 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100638 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100639 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100640}
641
642} // namespace art