blob: 10e4bc98a694e870f587f7f91f314509b392a94d [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
Calin Juravle862aaef2015-04-22 13:31:47 +010065 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
Roland Levillainc90bc7c2014-12-11 12:14:33 +000084 * v1 <- -v0 1. neg-int v1, v0
Roland Levillain9240d6a2014-10-20 16:47:04 +010085 * 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 Levillainc90bc7c2014-12-11 12:14:33 +0000135 * Tiny three-register program exercising long constant folding on negation.
136 *
137 * 16-bit
138 * offset
139 * ------
140 * (v0, v1) <- 4294967296 0. const-wide v0 #+4294967296
141 * (v2, v3) <- -(v0, v1) 1. neg-long v2, v0
142 * return (v2, v3) 2. return-wide v2
143 */
144TEST(ConstantFolding, LongConstantFoldingNegation) {
145 const int64_t input = INT64_C(4294967296); // 2^32
146 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
147 const uint16_t word1 = High16Bits(Low32Bits(input));
148 const uint16_t word2 = Low16Bits(High32Bits(input));
149 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
150 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
151 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
152 Instruction::NEG_LONG | 2 << 8 | 0 << 12,
153 Instruction::RETURN_WIDE | 2 << 8);
154
155 std::string expected_before =
156 "BasicBlock 0, succ: 1\n"
157 " 4: LongConstant [7]\n"
158 " 12: SuspendCheck\n"
159 " 13: Goto 1\n"
160 "BasicBlock 1, pred: 0, succ: 2\n"
161 " 7: Neg(4) [10]\n"
162 " 10: Return(7)\n"
163 "BasicBlock 2, pred: 1\n"
164 " 11: Exit\n";
165
166 // Expected difference after constant folding.
167 diff_t expected_cf_diff = {
168 { " 4: LongConstant [7]\n", " 4: LongConstant\n" },
169 { " 12: SuspendCheck\n", " 12: SuspendCheck\n"
170 " 14: LongConstant [10]\n" },
171 { " 7: Neg(4) [10]\n", removed },
172 { " 10: Return(7)\n", " 10: Return(14)\n" }
173 };
174 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
175
176 // Check the value of the computed constant.
177 auto check_after_cf = [](HGraph* graph) {
178 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
179 ASSERT_TRUE(inst->IsLongConstant());
180 ASSERT_EQ(inst->AsLongConstant()->GetValue(), INT64_C(-4294967296));
181 };
182
183 // Expected difference after dead code elimination.
184 diff_t expected_dce_diff = {
185 { " 4: LongConstant\n", removed },
186 };
187 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
188
189 TestCode(data,
190 expected_before,
191 expected_after_cf,
192 expected_after_dce,
193 check_after_cf,
194 Primitive::kPrimLong);
195}
196
197/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100198 * Tiny three-register program exercising int constant folding on addition.
199 *
200 * 16-bit
201 * offset
202 * ------
203 * v0 <- 1 0. const/4 v0, #+1
204 * v1 <- 2 1. const/4 v1, #+2
205 * v2 <- v0 + v1 2. add-int v2, v0, v1
206 * return v2 4. return v2
207 */
Roland Levillain75be2832014-10-17 17:02:00 +0100208TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100209 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
210 Instruction::CONST_4 | 0 << 8 | 1 << 12,
211 Instruction::CONST_4 | 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 " 14: SuspendCheck\n"
220 " 15: Goto 1\n"
221 "BasicBlock 1, pred: 0, succ: 2\n"
222 " 9: Add(3, 5) [12]\n"
223 " 12: Return(9)\n"
224 "BasicBlock 2, pred: 1\n"
225 " 13: Exit\n";
226
Roland Levillain75be2832014-10-17 17:02:00 +0100227 // Expected difference after constant folding.
228 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100229 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
230 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000231 { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
232 " 16: IntConstant [12]\n" },
233 { " 9: Add(3, 5) [12]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100234 { " 12: Return(9)\n", " 12: Return(16)\n" }
235 };
Roland Levillain75be2832014-10-17 17:02:00 +0100236 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100237
Roland Levillain93445682014-10-06 19:24:02 +0100238 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100239 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000240 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100241 ASSERT_TRUE(inst->IsIntConstant());
242 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
243 };
244
Roland Levillain556c3d12014-09-18 15:25:07 +0100245 // Expected difference after dead code elimination.
246 diff_t expected_dce_diff = {
247 { " 3: IntConstant\n", removed },
248 { " 5: IntConstant\n", removed }
249 };
Roland Levillain75be2832014-10-17 17:02:00 +0100250 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100251
Roland Levillain93445682014-10-06 19:24:02 +0100252 TestCode(data,
253 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100254 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100255 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100256 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100257}
258
259/**
260 * Small three-register program exercising int constant folding on addition.
261 *
262 * 16-bit
263 * offset
264 * ------
265 * v0 <- 1 0. const/4 v0, #+1
266 * v1 <- 2 1. const/4 v1, #+2
267 * v0 <- v0 + v1 2. add-int/2addr v0, v1
David Brazdil8d5b8b22015-03-24 10:51:52 +0000268 * v1 <- 4 3. const/4 v1, #+4
269 * v2 <- 5 4. const/4 v2, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100270 * v1 <- v1 + v2 5. add-int/2addr v1, v2
271 * v2 <- v0 + v1 6. add-int v2, v0, v1
272 * return v2 8. return v2
273 */
Roland Levillain75be2832014-10-17 17:02:00 +0100274TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100275 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
276 Instruction::CONST_4 | 0 << 8 | 1 << 12,
277 Instruction::CONST_4 | 1 << 8 | 2 << 12,
278 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000279 Instruction::CONST_4 | 1 << 8 | 4 << 12,
280 Instruction::CONST_4 | 2 << 8 | 5 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100281 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
282 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
283 Instruction::RETURN | 2 << 8);
284
285 std::string expected_before =
286 "BasicBlock 0, succ: 1\n"
287 " 3: IntConstant [9]\n"
288 " 5: IntConstant [9]\n"
289 " 11: IntConstant [17]\n"
290 " 13: IntConstant [17]\n"
291 " 26: SuspendCheck\n"
292 " 27: Goto 1\n"
293 "BasicBlock 1, pred: 0, succ: 2\n"
294 " 9: Add(3, 5) [21]\n"
295 " 17: Add(11, 13) [21]\n"
296 " 21: Add(9, 17) [24]\n"
297 " 24: Return(21)\n"
298 "BasicBlock 2, pred: 1\n"
299 " 25: Exit\n";
300
Roland Levillain75be2832014-10-17 17:02:00 +0100301 // Expected difference after constant folding.
302 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100303 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
304 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
305 { " 11: IntConstant [17]\n", " 11: IntConstant\n" },
306 { " 13: IntConstant [17]\n", " 13: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000307 { " 26: SuspendCheck\n", " 26: SuspendCheck\n"
308 " 28: IntConstant\n"
309 " 29: IntConstant\n"
310 " 30: IntConstant [24]\n" },
311 { " 9: Add(3, 5) [21]\n", removed },
312 { " 17: Add(11, 13) [21]\n", removed },
313 { " 21: Add(9, 17) [24]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100314 { " 24: Return(21)\n", " 24: Return(30)\n" }
315 };
Roland Levillain75be2832014-10-17 17:02:00 +0100316 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100317
Roland Levillain93445682014-10-06 19:24:02 +0100318 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100319 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000320 HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100321 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000322 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
323 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100324 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000325 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
326 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100327 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000328 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100329 };
330
Roland Levillain556c3d12014-09-18 15:25:07 +0100331 // Expected difference after dead code elimination.
332 diff_t expected_dce_diff = {
333 { " 3: IntConstant\n", removed },
334 { " 5: IntConstant\n", removed },
335 { " 11: IntConstant\n", removed },
336 { " 13: IntConstant\n", removed },
337 { " 28: IntConstant\n", removed },
338 { " 29: IntConstant\n", removed }
339 };
Roland Levillain75be2832014-10-17 17:02:00 +0100340 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100341
Roland Levillain93445682014-10-06 19:24:02 +0100342 TestCode(data,
343 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100344 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100345 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100346 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100347}
348
349/**
350 * Tiny three-register program exercising int constant folding on subtraction.
351 *
352 * 16-bit
353 * offset
354 * ------
355 * v0 <- 3 0. const/4 v0, #+3
356 * v1 <- 2 1. const/4 v1, #+2
357 * v2 <- v0 - v1 2. sub-int v2, v0, v1
358 * return v2 4. return v2
359 */
Roland Levillain75be2832014-10-17 17:02:00 +0100360TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100361 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
362 Instruction::CONST_4 | 0 << 8 | 3 << 12,
363 Instruction::CONST_4 | 1 << 8 | 2 << 12,
364 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
365 Instruction::RETURN | 2 << 8);
366
367 std::string expected_before =
368 "BasicBlock 0, succ: 1\n"
369 " 3: IntConstant [9]\n"
370 " 5: IntConstant [9]\n"
371 " 14: SuspendCheck\n"
372 " 15: Goto 1\n"
373 "BasicBlock 1, pred: 0, succ: 2\n"
374 " 9: Sub(3, 5) [12]\n"
375 " 12: Return(9)\n"
376 "BasicBlock 2, pred: 1\n"
377 " 13: Exit\n";
378
Roland Levillain75be2832014-10-17 17:02:00 +0100379 // Expected difference after constant folding.
380 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100381 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
382 { " 5: IntConstant [9]\n", " 5: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000383 { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
384 " 16: IntConstant [12]\n" },
385 { " 9: Sub(3, 5) [12]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100386 { " 12: Return(9)\n", " 12: Return(16)\n" }
387 };
Roland Levillain75be2832014-10-17 17:02:00 +0100388 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100389
Roland Levillain93445682014-10-06 19:24:02 +0100390 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100391 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000392 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100393 ASSERT_TRUE(inst->IsIntConstant());
394 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
395 };
396
Roland Levillain556c3d12014-09-18 15:25:07 +0100397 // Expected difference after dead code elimination.
398 diff_t expected_dce_diff = {
399 { " 3: IntConstant\n", removed },
400 { " 5: IntConstant\n", removed }
401 };
Roland Levillain75be2832014-10-17 17:02:00 +0100402 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100403
Roland Levillain93445682014-10-06 19:24:02 +0100404 TestCode(data,
405 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100406 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100407 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100408 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100409}
410
Roland Levillain556c3d12014-09-18 15:25:07 +0100411/**
412 * Tiny three-register-pair program exercising long constant folding
413 * on addition.
414 *
415 * 16-bit
416 * offset
417 * ------
418 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
419 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
420 * (v4, v5) <-
421 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
422 * return (v4, v5) 6. return-wide v4
423 */
Roland Levillain75be2832014-10-17 17:02:00 +0100424TEST(ConstantFolding, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100425 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
426 Instruction::CONST_WIDE_16 | 0 << 8, 1,
427 Instruction::CONST_WIDE_16 | 2 << 8, 2,
428 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
429 Instruction::RETURN_WIDE | 4 << 8);
430
431 std::string expected_before =
432 "BasicBlock 0, succ: 1\n"
433 " 6: LongConstant [12]\n"
434 " 8: LongConstant [12]\n"
435 " 17: SuspendCheck\n"
436 " 18: Goto 1\n"
437 "BasicBlock 1, pred: 0, succ: 2\n"
438 " 12: Add(6, 8) [15]\n"
439 " 15: Return(12)\n"
440 "BasicBlock 2, pred: 1\n"
441 " 16: Exit\n";
442
Roland Levillain75be2832014-10-17 17:02:00 +0100443 // Expected difference after constant folding.
444 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100445 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
446 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000447 { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
448 " 19: LongConstant [15]\n" },
449 { " 12: Add(6, 8) [15]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100450 { " 15: Return(12)\n", " 15: Return(19)\n" }
451 };
Roland Levillain75be2832014-10-17 17:02:00 +0100452 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100453
Roland Levillain93445682014-10-06 19:24:02 +0100454 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100455 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000456 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100457 ASSERT_TRUE(inst->IsLongConstant());
458 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
459 };
460
Roland Levillain556c3d12014-09-18 15:25:07 +0100461 // Expected difference after dead code elimination.
462 diff_t expected_dce_diff = {
463 { " 6: LongConstant\n", removed },
464 { " 8: LongConstant\n", removed }
465 };
Roland Levillain75be2832014-10-17 17:02:00 +0100466 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100467
Roland Levillain93445682014-10-06 19:24:02 +0100468 TestCode(data,
469 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100470 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100471 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100472 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100473 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100474}
475
476/**
477 * Tiny three-register-pair program exercising long constant folding
478 * on subtraction.
479 *
480 * 16-bit
481 * offset
482 * ------
483 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
484 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
485 * (v4, v5) <-
486 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
487 * return (v4, v5) 6. return-wide v4
488 */
Roland Levillain75be2832014-10-17 17:02:00 +0100489TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100490 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
491 Instruction::CONST_WIDE_16 | 0 << 8, 3,
492 Instruction::CONST_WIDE_16 | 2 << 8, 2,
493 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
494 Instruction::RETURN_WIDE | 4 << 8);
495
496 std::string expected_before =
497 "BasicBlock 0, succ: 1\n"
498 " 6: LongConstant [12]\n"
499 " 8: LongConstant [12]\n"
500 " 17: SuspendCheck\n"
501 " 18: Goto 1\n"
502 "BasicBlock 1, pred: 0, succ: 2\n"
503 " 12: Sub(6, 8) [15]\n"
504 " 15: Return(12)\n"
505 "BasicBlock 2, pred: 1\n"
506 " 16: Exit\n";
507
Roland Levillain75be2832014-10-17 17:02:00 +0100508 // Expected difference after constant folding.
509 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100510 { " 6: LongConstant [12]\n", " 6: LongConstant\n" },
511 { " 8: LongConstant [12]\n", " 8: LongConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000512 { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
513 " 19: LongConstant [15]\n" },
514 { " 12: Sub(6, 8) [15]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100515 { " 15: Return(12)\n", " 15: Return(19)\n" }
516 };
Roland Levillain75be2832014-10-17 17:02:00 +0100517 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100518
Roland Levillain93445682014-10-06 19:24:02 +0100519 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100520 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000521 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100522 ASSERT_TRUE(inst->IsLongConstant());
523 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
524 };
525
Roland Levillain556c3d12014-09-18 15:25:07 +0100526 // Expected difference after dead code elimination.
527 diff_t expected_dce_diff = {
528 { " 6: LongConstant\n", removed },
529 { " 8: LongConstant\n", removed }
530 };
Roland Levillain75be2832014-10-17 17:02:00 +0100531 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100532
Roland Levillain93445682014-10-06 19:24:02 +0100533 TestCode(data,
534 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100535 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100536 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100537 check_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100538 Primitive::kPrimLong);
Roland Levillain556c3d12014-09-18 15:25:07 +0100539}
540
541/**
542 * Three-register program with jumps leading to the creation of many
543 * blocks.
544 *
545 * The intent of this test is to ensure that all constant expressions
546 * are actually evaluated at compile-time, thanks to the reverse
547 * (forward) post-order traversal of the the dominator tree.
548 *
549 * 16-bit
550 * offset
551 * ------
David Brazdil8d5b8b22015-03-24 10:51:52 +0000552 * v0 <- 1 0. const/4 v0, #+1
553 * v1 <- 2 1. const/4 v1, #+2
Roland Levillain556c3d12014-09-18 15:25:07 +0100554 * v2 <- v0 + v1 2. add-int v2, v0, v1
555 * goto L2 4. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000556 * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100557 * goto L3 7. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000558 * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4
Roland Levillain556c3d12014-09-18 15:25:07 +0100559 * goto L1 10. goto +(-5)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000560 * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8
Roland Levillain556c3d12014-09-18 15:25:07 +0100561 * return v2 13. return v2
562 */
Roland Levillain75be2832014-10-17 17:02:00 +0100563TEST(ConstantFolding, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100564 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
David Brazdil8d5b8b22015-03-24 10:51:52 +0000565 Instruction::CONST_4 | 0 << 8 | 1 << 12,
566 Instruction::CONST_4 | 1 << 8 | 2 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100567 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
568 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000569 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Roland Levillain556c3d12014-09-18 15:25:07 +0100570 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000571 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
Roland Levillain556c3d12014-09-18 15:25:07 +0100572 static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
David Brazdil8d5b8b22015-03-24 10:51:52 +0000573 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Roland Levillain556c3d12014-09-18 15:25:07 +0100574 Instruction::RETURN | 2 << 8);
575
576 std::string expected_before =
577 "BasicBlock 0, succ: 1\n"
David Brazdil8d5b8b22015-03-24 10:51:52 +0000578 " 3: IntConstant [9]\n" // v0 <- 1
579 " 5: IntConstant [9]\n" // v1 <- 2
580 " 13: IntConstant [14]\n" // const 5
581 " 18: IntConstant [19]\n" // const 4
582 " 24: IntConstant [25]\n" // const 8
Roland Levillain556c3d12014-09-18 15:25:07 +0100583 " 30: SuspendCheck\n"
584 " 31: Goto 1\n"
585 "BasicBlock 1, pred: 0, succ: 3\n"
David Brazdil8d5b8b22015-03-24 10:51:52 +0000586 " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 1 + 2 = 3
Roland Levillain93445682014-10-06 19:24:02 +0100587 " 11: Goto 3\n" // goto L2
588 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000589 " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 7 + 5 = 12
Roland Levillain93445682014-10-06 19:24:02 +0100590 " 16: Goto 4\n" // goto L3
591 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000592 " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 3 + 4 = 7
Roland Levillain556c3d12014-09-18 15:25:07 +0100593 " 21: SuspendCheck\n"
Roland Levillain93445682014-10-06 19:24:02 +0100594 " 22: Goto 2\n" // goto L1
595 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
David Brazdil8d5b8b22015-03-24 10:51:52 +0000596 " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 12 + 8 = 20
Roland Levillain93445682014-10-06 19:24:02 +0100597 " 28: Return(25)\n" // return v2
Roland Levillain556c3d12014-09-18 15:25:07 +0100598 "BasicBlock 5, pred: 4\n"
599 " 29: Exit\n";
600
Roland Levillain75be2832014-10-17 17:02:00 +0100601 // Expected difference after constant folding.
602 diff_t expected_cf_diff = {
Roland Levillain556c3d12014-09-18 15:25:07 +0100603 { " 3: IntConstant [9]\n", " 3: IntConstant\n" },
604 { " 5: IntConstant [9]\n", " 5: IntConstant []\n" },
605 { " 13: IntConstant [14]\n", " 13: IntConstant\n" },
606 { " 18: IntConstant [19]\n", " 18: IntConstant\n" },
607 { " 24: IntConstant [25]\n", " 24: IntConstant\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000608 { " 30: SuspendCheck\n", " 30: SuspendCheck\n"
609 " 32: IntConstant []\n"
610 " 33: IntConstant []\n"
611 " 34: IntConstant\n"
612 " 35: IntConstant [28]\n" },
613 { " 9: Add(3, 5) [19]\n", removed },
614 { " 14: Add(19, 13) [25]\n", removed },
615 { " 19: Add(9, 18) [14]\n", removed },
616 { " 25: Add(14, 24) [28]\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100617 { " 28: Return(25)\n", " 28: Return(35)\n"}
618 };
Roland Levillain75be2832014-10-17 17:02:00 +0100619 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100620
Roland Levillain93445682014-10-06 19:24:02 +0100621 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100622 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000623 HInstruction* inst1 = graph->GetBlock(4)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100624 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000625 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
626 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100627 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000628 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
629 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100630 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000631 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
632 HInstruction* inst4 = inst3->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100633 ASSERT_TRUE(inst4->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000634 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100635 };
636
Roland Levillain556c3d12014-09-18 15:25:07 +0100637 // Expected difference after dead code elimination.
David Brazdil1c533c12015-04-24 17:04:38 +0100638 std::string expected_after_dce =
639 "BasicBlock 0, succ: 1\n"
640 " 5: IntConstant []\n"
641 " 30: SuspendCheck\n"
642 " 32: IntConstant []\n"
643 " 33: IntConstant []\n"
644 " 35: IntConstant [28]\n"
645 " 31: Goto 1\n"
646 "BasicBlock 1, pred: 0, succ: 5\n"
647 " 21: SuspendCheck\n"
648 " 28: Return(35)\n"
649 "BasicBlock 5, pred: 1\n"
650 " 29: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100651
Roland Levillain93445682014-10-06 19:24:02 +0100652 TestCode(data,
653 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100654 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100655 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100656 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100657}
658
659
660/**
661 * Three-register program with a constant (static) condition.
662 *
663 * 16-bit
664 * offset
665 * ------
666 * v1 <- 1 0. const/4 v1, #+1
667 * v0 <- 0 1. const/4 v0, #+0
668 * if v1 >= 0 goto L1 2. if-gez v1, +3
669 * v0 <- v1 4. move v0, v1
670 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
671 * return-void 7. return
672 */
Roland Levillain75be2832014-10-17 17:02:00 +0100673TEST(ConstantFolding, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100674 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
675 Instruction::CONST_4 | 1 << 8 | 1 << 12,
676 Instruction::CONST_4 | 0 << 8 | 0 << 12,
677 Instruction::IF_GEZ | 1 << 8, 3,
678 Instruction::MOVE | 0 << 8 | 1 << 12,
679 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
680 Instruction::RETURN_VOID);
681
682 std::string expected_before =
683 "BasicBlock 0, succ: 1\n"
684 " 3: IntConstant [15, 22, 8]\n"
685 " 5: IntConstant [22, 8]\n"
686 " 19: SuspendCheck\n"
687 " 20: Goto 1\n"
688 "BasicBlock 1, pred: 0, succ: 5, 2\n"
689 " 8: GreaterThanOrEqual(3, 5) [9]\n"
690 " 9: If(8)\n"
691 "BasicBlock 2, pred: 1, succ: 3\n"
692 " 12: Goto 3\n"
Nicolas Geoffray8b20f882015-06-19 16:17:05 +0100693 "BasicBlock 3, pred: 5, 2, succ: 4\n"
694 " 22: Phi(5, 3) [15]\n"
Roland Levillain556c3d12014-09-18 15:25:07 +0100695 " 15: Add(22, 3)\n"
696 " 17: ReturnVoid\n"
697 "BasicBlock 4, pred: 3\n"
698 " 18: Exit\n"
699 "BasicBlock 5, pred: 1, succ: 3\n"
700 " 21: Goto 3\n";
701
Roland Levillain75be2832014-10-17 17:02:00 +0100702 // Expected difference after constant folding.
703 diff_t expected_cf_diff = {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000704 { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [9, 15, 22]\n" },
Roland Levillain556c3d12014-09-18 15:25:07 +0100705 { " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
David Brazdil8d5b8b22015-03-24 10:51:52 +0000706 { " 8: GreaterThanOrEqual(3, 5) [9]\n", removed },
707 { " 9: If(8)\n", " 9: If(3)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100708 };
Roland Levillain75be2832014-10-17 17:02:00 +0100709 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100710
Roland Levillain93445682014-10-06 19:24:02 +0100711 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100712 auto check_after_cf = [](HGraph* graph) {
David Brazdil8d5b8b22015-03-24 10:51:52 +0000713 HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100714 ASSERT_TRUE(inst->IsIntConstant());
715 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
716 };
717
David Brazdil1c533c12015-04-24 17:04:38 +0100718 // Expected graph after dead code elimination.
719 std::string expected_after_dce =
720 "BasicBlock 0, succ: 1\n"
721 " 19: SuspendCheck\n"
722 " 20: Goto 1\n"
723 "BasicBlock 1, pred: 0, succ: 4\n"
724 " 17: ReturnVoid\n"
725 "BasicBlock 4, pred: 1\n"
726 " 18: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100727
Roland Levillain93445682014-10-06 19:24:02 +0100728 TestCode(data,
729 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100730 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100731 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100732 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100733}
734
735} // namespace art