blob: 02ad675dc310c292dc0c45b9c3cb5755f4194386 [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
Mark Mendellfb8d2792015-03-31 22:16:59 -040019#include "arch/x86/instruction_set_features_x86.h"
Roland Levillain75be2832014-10-17 17:02:00 +010020#include "code_generator_x86.h"
21#include "constant_folding.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010022#include "dead_code_elimination.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000023#include "driver/compiler_options.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010024#include "graph_checker.h"
25#include "optimizing_unit_test.h"
Roland Levillain75be2832014-10-17 17:02:00 +010026#include "pretty_printer.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010027
28#include "gtest/gtest.h"
29
30namespace art {
31
32static void TestCode(const uint16_t* data,
33 const std::string& expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +010034 const std::string& expected_after_cf,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010035 const std::string& expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +010036 std::function<void(HGraph*)> check_after_cf,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010037 Primitive::Type return_type = Primitive::kPrimInt) {
Roland Levillain556c3d12014-09-18 15:25:07 +010038 ArenaPool pool;
39 ArenaAllocator allocator(&pool);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010040 HGraph* graph = CreateCFG(&allocator, data, return_type);
Roland Levillain556c3d12014-09-18 15:25:07 +010041 ASSERT_NE(graph, nullptr);
42
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000043 graph->TryBuildingSsa();
Roland Levillain556c3d12014-09-18 15:25:07 +010044
45 StringPrettyPrinter printer_before(graph);
46 printer_before.VisitInsertionOrder();
47 std::string actual_before = printer_before.str();
48 ASSERT_EQ(expected_before, actual_before);
49
Mark Mendellfb8d2792015-03-31 22:16:59 -040050 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
51 X86InstructionSetFeatures::FromCppDefines());
52 x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000053 HConstantFolding(graph).Run();
Nicolas Geoffray942a3782014-12-17 17:10:47 +000054 SSAChecker ssa_checker_cf(&allocator, graph);
55 ssa_checker_cf.Run();
56 ASSERT_TRUE(ssa_checker_cf.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010057
Roland Levillain75be2832014-10-17 17:02:00 +010058 StringPrettyPrinter printer_after_cf(graph);
59 printer_after_cf.VisitInsertionOrder();
60 std::string actual_after_cf = printer_after_cf.str();
61 ASSERT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +010062
Roland Levillain75be2832014-10-17 17:02:00 +010063 check_after_cf(graph);
Roland Levillain93445682014-10-06 19:24:02 +010064
Nicolas Geoffray5e6916c2014-11-18 16:53:35 +000065 HDeadCodeElimination(graph).Run();
Nicolas Geoffray942a3782014-12-17 17:10:47 +000066 SSAChecker ssa_checker_dce(&allocator, graph);
67 ssa_checker_dce.Run();
68 ASSERT_TRUE(ssa_checker_dce.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010069
70 StringPrettyPrinter printer_after_dce(graph);
71 printer_after_dce.VisitInsertionOrder();
72 std::string actual_after_dce = printer_after_dce.str();
73 ASSERT_EQ(expected_after_dce, actual_after_dce);
Roland Levillain556c3d12014-09-18 15:25:07 +010074}
75
76
77/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010078 * Tiny three-register program exercising int constant folding on negation.
79 *
80 * 16-bit
81 * offset
82 * ------
83 * v0 <- 1 0. const/4 v0, #+1
84 * v1 <- -v0 1. neg-int v0, v1
85 * return v1 2. return v1
86 */
87TEST(ConstantFolding, IntConstantFoldingNegation) {
88 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
89 Instruction::CONST_4 | 0 << 8 | 1 << 12,
90 Instruction::NEG_INT | 1 << 8 | 0 << 12,
91 Instruction::RETURN | 1 << 8);
92
93 std::string expected_before =
94 "BasicBlock 0, succ: 1\n"
95 " 2: IntConstant [5]\n"
96 " 10: SuspendCheck\n"
97 " 11: Goto 1\n"
98 "BasicBlock 1, pred: 0, succ: 2\n"
99 " 5: Neg(2) [8]\n"
100 " 8: Return(5)\n"
101 "BasicBlock 2, pred: 1\n"
102 " 9: Exit\n";
103
104 // Expected difference after constant folding.
105 diff_t expected_cf_diff = {
106 { " 2: IntConstant [5]\n", " 2: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000107 { " 10: SuspendCheck\n", " 10: SuspendCheck\n"
108 " 12: IntConstant [8]\n" },
109 { " 5: Neg(2) [8]\n", removed },
Roland Levillain9240d6a2014-10-20 16:47:04 +0100110 { " 8: Return(5)\n", " 8: Return(12)\n" }
111 };
112 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
113
114 // Check the value of the computed constant.
115 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000116 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain9240d6a2014-10-20 16:47:04 +0100117 ASSERT_TRUE(inst->IsIntConstant());
118 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
119 };
120
121 // Expected difference after dead code elimination.
122 diff_t expected_dce_diff = {
123 { " 2: IntConstant\n", removed },
124 };
125 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
126
127 TestCode(data,
128 expected_before,
129 expected_after_cf,
130 expected_after_dce,
131 check_after_cf);
132}
133
134/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100135 * Tiny three-register program exercising int constant folding on addition.
136 *
137 * 16-bit
138 * offset
139 * ------
140 * v0 <- 1 0. const/4 v0, #+1
141 * v1 <- 2 1. const/4 v1, #+2
142 * v2 <- v0 + v1 2. add-int v2, v0, v1
143 * return v2 4. return v2
144 */
Roland Levillain75be2832014-10-17 17:02:00 +0100145TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100146 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
147 Instruction::CONST_4 | 0 << 8 | 1 << 12,
148 Instruction::CONST_4 | 1 << 8 | 2 << 12,
149 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
150 Instruction::RETURN | 2 << 8);
151
152 std::string expected_before =
153 "BasicBlock 0, succ: 1\n"
154 " 3: IntConstant [9]\n"
155 " 5: IntConstant [9]\n"
156 " 14: SuspendCheck\n"
157 " 15: Goto 1\n"
158 "BasicBlock 1, pred: 0, succ: 2\n"
159 " 9: Add(3, 5) [12]\n"
160 " 12: Return(9)\n"
161 "BasicBlock 2, pred: 1\n"
162 " 13: Exit\n";
163
Roland Levillain75be2832014-10-17 17:02:00 +0100164 // Expected difference after constant folding.
165 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100166 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
167 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000168 { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
169 " 16: IntConstant [12]\n" },
170 { " 9: Add(3, 5) [12]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100171 { " 12: Return(9)\n", " 12: Return(16)\n" }
172 };
Roland Levillain75be2832014-10-17 17:02:00 +0100173 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100174
Roland Levillain93445682014-10-06 19:24:02 +0100175 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100176 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000177 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100178 ASSERT_TRUE(inst->IsIntConstant());
179 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
180 };
181
Roland Levillain556c3d12014-09-18 15:25:07 +0100182 // Expected difference after dead code elimination.
183 diff_t expected_dce_diff = {
184 { " 3: IntConstant\n", removed },
185 { " 5: IntConstant\n", removed }
186 };
Roland Levillain75be2832014-10-17 17:02:00 +0100187 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100188
Roland Levillain93445682014-10-06 19:24:02 +0100189 TestCode(data,
190 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100191 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100192 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100193 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100194}
195
196/**
197 * Small three-register program exercising int constant folding on addition.
198 *
199 * 16-bit
200 * offset
201 * ------
202 * v0 <- 1 0. const/4 v0, #+1
203 * v1 <- 2 1. const/4 v1, #+2
204 * v0 <- v0 + v1 2. add-int/2addr v0, v1
David Brazdil8d5b8b22015-03-24 10:51:52 +0000205 * v1 <- 4 3. const/4 v1, #+4
206 * v2 <- 5 4. const/4 v2, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100207 * v1 <- v1 + v2 5. add-int/2addr v1, v2
208 * v2 <- v0 + v1 6. add-int v2, v0, v1
209 * return v2 8. return v2
210 */
Roland Levillain75be2832014-10-17 17:02:00 +0100211TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100212 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
213 Instruction::CONST_4 | 0 << 8 | 1 << 12,
214 Instruction::CONST_4 | 1 << 8 | 2 << 12,
215 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000216 Instruction::CONST_4 | 1 << 8 | 4 << 12,
217 Instruction::CONST_4 | 2 << 8 | 5 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100218 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
219 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
220 Instruction::RETURN | 2 << 8);
221
222 std::string expected_before =
223 "BasicBlock 0, succ: 1\n"
224 " 3: IntConstant [9]\n"
225 " 5: IntConstant [9]\n"
226 " 11: IntConstant [17]\n"
227 " 13: IntConstant [17]\n"
228 " 26: SuspendCheck\n"
229 " 27: Goto 1\n"
230 "BasicBlock 1, pred: 0, succ: 2\n"
231 " 9: Add(3, 5) [21]\n"
232 " 17: Add(11, 13) [21]\n"
233 " 21: Add(9, 17) [24]\n"
234 " 24: Return(21)\n"
235 "BasicBlock 2, pred: 1\n"
236 " 25: Exit\n";
237
Roland Levillain75be2832014-10-17 17:02:00 +0100238 // Expected difference after constant folding.
239 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100240 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
241 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
242 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
243 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000244 { " 26: SuspendCheck\n", " 26: SuspendCheck\n"
245 " 28: IntConstant\n"
246 " 29: IntConstant\n"
247 " 30: IntConstant [24]\n" },
248 { " 9: Add(3, 5) [21]\n", removed },
249 { " 17: Add(11, 13) [21]\n", removed },
250 { " 21: Add(9, 17) [24]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100251 { " 24: Return(21)\n", " 24: Return(30)\n" }
252 };
Roland Levillain75be2832014-10-17 17:02:00 +0100253 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100254
Roland Levillain93445682014-10-06 19:24:02 +0100255 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100256 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000257 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100258 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000259 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
260 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100261 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000262 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
263 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100264 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000265 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100266 };
267
Roland Levillain556c3d12014-09-18 15:25:07 +0100268 // Expected difference after dead code elimination.
269 diff_t expected_dce_diff = {
270 { " 3: IntConstant\n", removed },
271 { " 5: IntConstant\n", removed },
272 { " 11: IntConstant\n", removed },
273 { " 13: IntConstant\n", removed },
274 { " 28: IntConstant\n", removed },
275 { " 29: IntConstant\n", removed }
276 };
Roland Levillain75be2832014-10-17 17:02:00 +0100277 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100278
Roland Levillain93445682014-10-06 19:24:02 +0100279 TestCode(data,
280 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100281 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100282 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100283 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100284}
285
286/**
287 * Tiny three-register program exercising int constant folding on subtraction.
288 *
289 * 16-bit
290 * offset
291 * ------
292 * v0 <- 3 0. const/4 v0, #+3
293 * v1 <- 2 1. const/4 v1, #+2
294 * v2 <- v0 - v1 2. sub-int v2, v0, v1
295 * return v2 4. return v2
296 */
Roland Levillain75be2832014-10-17 17:02:00 +0100297TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100298 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
299 Instruction::CONST_4 | 0 << 8 | 3 << 12,
300 Instruction::CONST_4 | 1 << 8 | 2 << 12,
301 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
302 Instruction::RETURN | 2 << 8);
303
304 std::string expected_before =
305 "BasicBlock 0, succ: 1\n"
306 " 3: IntConstant [9]\n"
307 " 5: IntConstant [9]\n"
308 " 14: SuspendCheck\n"
309 " 15: Goto 1\n"
310 "BasicBlock 1, pred: 0, succ: 2\n"
311 " 9: Sub(3, 5) [12]\n"
312 " 12: Return(9)\n"
313 "BasicBlock 2, pred: 1\n"
314 " 13: Exit\n";
315
Roland Levillain75be2832014-10-17 17:02:00 +0100316 // Expected difference after constant folding.
317 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100318 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
319 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000320 { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
321 " 16: IntConstant [12]\n" },
322 { " 9: Sub(3, 5) [12]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100323 { " 12: Return(9)\n", " 12: Return(16)\n" }
324 };
Roland Levillain75be2832014-10-17 17:02:00 +0100325 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100326
Roland Levillain93445682014-10-06 19:24:02 +0100327 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100328 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000329 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100330 ASSERT_TRUE(inst->IsIntConstant());
331 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
332 };
333
Roland Levillain556c3d12014-09-18 15:25:07 +0100334 // Expected difference after dead code elimination.
335 diff_t expected_dce_diff = {
336 { " 3: IntConstant\n", removed },
337 { " 5: IntConstant\n", removed }
338 };
Roland Levillain75be2832014-10-17 17:02:00 +0100339 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100340
Roland Levillain93445682014-10-06 19:24:02 +0100341 TestCode(data,
342 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100343 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100344 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100345 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100346}
347
Roland Levillain556c3d12014-09-18 15:25:07 +0100348/**
349 * Tiny three-register-pair program exercising long constant folding
350 * on addition.
351 *
352 * 16-bit
353 * offset
354 * ------
355 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
356 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
357 * (v4, v5) <-
358 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
359 * return (v4, v5) 6. return-wide v4
360 */
Roland Levillain75be2832014-10-17 17:02:00 +0100361TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100362 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
363 Instruction::CONST_WIDE_16 | 0 << 8, 1,
364 Instruction::CONST_WIDE_16 | 2 << 8, 2,
365 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
366 Instruction::RETURN_WIDE | 4 << 8);
367
368 std::string expected_before =
369 "BasicBlock 0, succ: 1\n"
370 " 6: LongConstant [12]\n"
371 " 8: LongConstant [12]\n"
372 " 17: SuspendCheck\n"
373 " 18: Goto 1\n"
374 "BasicBlock 1, pred: 0, succ: 2\n"
375 " 12: Add(6, 8) [15]\n"
376 " 15: Return(12)\n"
377 "BasicBlock 2, pred: 1\n"
378 " 16: Exit\n";
379
Roland Levillain75be2832014-10-17 17:02:00 +0100380 // Expected difference after constant folding.
381 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100382 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
383 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000384 { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
385 " 19: LongConstant [15]\n" },
386 { " 12: Add(6, 8) [15]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100387 { " 15: Return(12)\n", " 15: Return(19)\n" }
388 };
Roland Levillain75be2832014-10-17 17:02:00 +0100389 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100390
Roland Levillain93445682014-10-06 19:24:02 +0100391 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100392 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000393 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100394 ASSERT_TRUE(inst->IsLongConstant());
395 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
396 };
397
Roland Levillain556c3d12014-09-18 15:25:07 +0100398 // Expected difference after dead code elimination.
399 diff_t expected_dce_diff = {
400 { " 6: LongConstant\n", removed },
401 { " 8: LongConstant\n", removed }
402 };
Roland Levillain75be2832014-10-17 17:02:00 +0100403 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100404
Roland Levillain93445682014-10-06 19:24:02 +0100405 TestCode(data,
406 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100407 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100408 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100409 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100410 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100411}
412
413/**
414 * Tiny three-register-pair program exercising long constant folding
415 * on subtraction.
416 *
417 * 16-bit
418 * offset
419 * ------
420 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
421 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
422 * (v4, v5) <-
423 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
424 * return (v4, v5) 6. return-wide v4
425 */
Roland Levillain75be2832014-10-17 17:02:00 +0100426TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100427 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
428 Instruction::CONST_WIDE_16 | 0 << 8, 3,
429 Instruction::CONST_WIDE_16 | 2 << 8, 2,
430 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
431 Instruction::RETURN_WIDE | 4 << 8);
432
433 std::string expected_before =
434 "BasicBlock 0, succ: 1\n"
435 " 6: LongConstant [12]\n"
436 " 8: LongConstant [12]\n"
437 " 17: SuspendCheck\n"
438 " 18: Goto 1\n"
439 "BasicBlock 1, pred: 0, succ: 2\n"
440 " 12: Sub(6, 8) [15]\n"
441 " 15: Return(12)\n"
442 "BasicBlock 2, pred: 1\n"
443 " 16: Exit\n";
444
Roland Levillain75be2832014-10-17 17:02:00 +0100445 // Expected difference after constant folding.
446 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100447 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
448 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000449 { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
450 " 19: LongConstant [15]\n" },
451 { " 12: Sub(6, 8) [15]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100452 { " 15: Return(12)\n", " 15: Return(19)\n" }
453 };
Roland Levillain75be2832014-10-17 17:02:00 +0100454 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100455
Roland Levillain93445682014-10-06 19:24:02 +0100456 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100457 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000458 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100459 ASSERT_TRUE(inst->IsLongConstant());
460 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
461 };
462
Roland Levillain556c3d12014-09-18 15:25:07 +0100463 // Expected difference after dead code elimination.
464 diff_t expected_dce_diff = {
465 { " 6: LongConstant\n", removed },
466 { " 8: LongConstant\n", removed }
467 };
Roland Levillain75be2832014-10-17 17:02:00 +0100468 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100469
Roland Levillain93445682014-10-06 19:24:02 +0100470 TestCode(data,
471 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100472 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100473 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100474 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100475 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100476}
477
478/**
479 * Three-register program with jumps leading to the creation of many
480 * blocks.
481 *
482 * The intent of this test is to ensure that all constant expressions
483 * are actually evaluated at compile-time, thanks to the reverse
484 * (forward) post-order traversal of the the dominator tree.
485 *
486 * 16-bit
487 * offset
488 * ------
David Brazdil8d5b8b22015-03-24 10:51:52 +0000489 * v0 <- 1 0. const/4 v0, #+1
490 * v1 <- 2 1. const/4 v1, #+2
Roland Levillain556c3d12014-09-18 15:25:07 +0100491 * v2 <- v0 + v1 2. add-int v2, v0, v1
492 * goto L2 4. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000493 * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100494 * goto L3 7. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000495 * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4
Roland Levillain556c3d12014-09-18 15:25:07 +0100496 * goto L1 10. goto +(-5)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000497 * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8
Roland Levillain556c3d12014-09-18 15:25:07 +0100498 * return v2 13. return v2
499 */
Roland Levillain75be2832014-10-17 17:02:00 +0100500TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100501 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
David Brazdil8d5b8b22015-03-24 10:51:52 +0000502 Instruction::CONST_4 | 0 << 8 | 1 << 12,
503 Instruction::CONST_4 | 1 << 8 | 2 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100504 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
505 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000506 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Roland Levillain556c3d12014-09-18 15:25:07 +0100507 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000508 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
Roland Levillain556c3d12014-09-18 15:25:07 +0100509 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
David Brazdil8d5b8b22015-03-24 10:51:52 +0000510 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Roland Levillain556c3d12014-09-18 15:25:07 +0100511 Instruction::RETURN | 2 << 8);
512
513 std::string expected_before =
514 "BasicBlock 0, succ: 1\n"
David Brazdil8d5b8b22015-03-24 10:51:52 +0000515 " 3: IntConstant [9]\n" // v0 <- 1
516 " 5: IntConstant [9]\n" // v1 <- 2
517 " 13: IntConstant [14]\n" // const 5
518 " 18: IntConstant [19]\n" // const 4
519 " 24: IntConstant [25]\n" // const 8
Roland Levillain556c3d12014-09-18 15:25:07 +0100520 " 30: SuspendCheck\n"
521 " 31: Goto 1\n"
522 "BasicBlock 1, pred: 0, succ: 3\n"
David Brazdil8d5b8b22015-03-24 10:51:52 +0000523 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 1 + 2 = 3
Roland Levillain93445682014-10-06 19:24:02 +0100524 " 11: Goto 3\n" // goto L2
525 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000526 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 7 + 5 = 12
Roland Levillain93445682014-10-06 19:24:02 +0100527 " 16: Goto 4\n" // goto L3
528 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000529 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 3 + 4 = 7
Roland Levillain556c3d12014-09-18 15:25:07 +0100530 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100531 " 22: Goto 2\n" // goto L1
532 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000533 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 12 + 8 = 20
Roland Levillain93445682014-10-06 19:24:02 +0100534 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100535 "BasicBlock 5, pred: 4\n"
536 " 29: Exit\n";
537
Roland Levillain75be2832014-10-17 17:02:00 +0100538 // Expected difference after constant folding.
539 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100540 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
541 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
542 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
543 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
544 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000545 { " 30: SuspendCheck\n", " 30: SuspendCheck\n"
546 " 32: IntConstant []\n"
547 " 33: IntConstant []\n"
548 " 34: IntConstant\n"
549 " 35: IntConstant [28]\n" },
550 { " 9: Add(3, 5) [19]\n", removed },
551 { " 14: Add(19, 13) [25]\n", removed },
552 { " 19: Add(9, 18) [14]\n", removed },
553 { " 25: Add(14, 24) [28]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100554 { " 28: Return(25)\n", " 28: Return(35)\n"}
555 };
Roland Levillain75be2832014-10-17 17:02:00 +0100556 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100557
Roland Levillain93445682014-10-06 19:24:02 +0100558 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100559 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000560 HInstruction* inst1 = graph->GetBlock(4)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100561 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000562 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
563 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100564 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000565 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
566 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100567 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000568 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
569 HInstruction* inst4 = inst3->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100570 ASSERT_TRUE(inst4->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000571 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100572 };
573
Roland Levillain556c3d12014-09-18 15:25:07 +0100574 // Expected difference after dead code elimination.
575 diff_t expected_dce_diff = {
576 { " 3: IntConstant\n", removed },
577 { " 13: IntConstant\n", removed },
578 { " 18: IntConstant\n", removed },
579 { " 24: IntConstant\n", removed },
580 { " 34: IntConstant\n", removed },
581 };
Roland Levillain75be2832014-10-17 17:02:00 +0100582 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100583
Roland Levillain93445682014-10-06 19:24:02 +0100584 TestCode(data,
585 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100586 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100587 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100588 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100589}
590
591
592/**
593 * Three-register program with a constant (static) condition.
594 *
595 * 16-bit
596 * offset
597 * ------
598 * v1 <- 1 0. const/4 v1, #+1
599 * v0 <- 0 1. const/4 v0, #+0
600 * if v1 >= 0 goto L1 2. if-gez v1, +3
601 * v0 <- v1 4. move v0, v1
602 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
603 * return-void 7. return
604 */
Roland Levillain75be2832014-10-17 17:02:00 +0100605TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100606 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
607 Instruction::CONST_4 | 1 << 8 | 1 << 12,
608 Instruction::CONST_4 | 0 << 8 | 0 << 12,
609 Instruction::IF_GEZ | 1 << 8, 3,
610 Instruction::MOVE | 0 << 8 | 1 << 12,
611 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
612 Instruction::RETURN_VOID);
613
614 std::string expected_before =
615 "BasicBlock 0, succ: 1\n"
616 " 3: IntConstant [15, 22, 8]\n"
617 " 5: IntConstant [22, 8]\n"
618 " 19: SuspendCheck\n"
619 " 20: Goto 1\n"
620 "BasicBlock 1, pred: 0, succ: 5, 2\n"
621 " 8: GreaterThanOrEqual(3, 5) [9]\n"
622 " 9: If(8)\n"
623 "BasicBlock 2, pred: 1, succ: 3\n"
624 " 12: Goto 3\n"
625 "BasicBlock 3, pred: 2, 5, succ: 4\n"
626 " 22: Phi(3, 5) [15]\n"
627 " 15: Add(22, 3)\n"
628 " 17: ReturnVoid\n"
629 "BasicBlock 4, pred: 3\n"
630 " 18: Exit\n"
631 "BasicBlock 5, pred: 1, succ: 3\n"
632 " 21: Goto 3\n";
633
Roland Levillain75be2832014-10-17 17:02:00 +0100634 // Expected difference after constant folding.
635 diff_t expected_cf_diff = {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000636 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [9, 15, 22]\n" },
Roland Levillain556c3d12014-09-18 15:25:07 +0100637 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000638 { " 8: GreaterThanOrEqual(3, 5) [9]\n", removed },
639 { " 9: If(8)\n", " 9: If(3)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100640 };
Roland Levillain75be2832014-10-17 17:02:00 +0100641 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100642
Roland Levillain93445682014-10-06 19:24:02 +0100643 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100644 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000645 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100646 ASSERT_TRUE(inst->IsIntConstant());
647 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
648 };
649
Roland Levillain556c3d12014-09-18 15:25:07 +0100650 // Expected difference after dead code elimination.
651 diff_t expected_dce_diff = {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000652 { " 3: IntConstant [9, 15, 22]\n", " 3: IntConstant [9, 22]\n" },
653 { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
654 { " 15: Add(22, 3)\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100655 };
Roland Levillain75be2832014-10-17 17:02:00 +0100656 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100657
Roland Levillain93445682014-10-06 19:24:02 +0100658 TestCode(data,
659 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100660 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100661 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100662 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100663}
664
665} // namespace art