blob: c85a2e3e70176298430bbd6e7300f7d9b915ee2b [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
Aart Bik96709f12015-10-28 17:49:07 -070032/**
33 * Fixture class for the constant folding and dce tests.
34 */
David Brazdil4833f5a2015-12-16 10:37:39 +000035class ConstantFoldingTest : public CommonCompilerTest {
Aart Bik96709f12015-10-28 17:49:07 -070036 public:
37 ConstantFoldingTest() : pool_(), allocator_(&pool_) {
38 graph_ = CreateGraph(&allocator_);
39 }
Roland Levillain556c3d12014-09-18 15:25:07 +010040
Aart Bik96709f12015-10-28 17:49:07 -070041 void TestCode(const uint16_t* data,
42 const std::string& expected_before,
43 const std::string& expected_after_cf,
44 const std::string& expected_after_dce,
Andreas Gampeca620d72016-11-08 08:09:33 -080045 const std::function<void(HGraph*)>& check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010046 DataType::Type return_type = DataType::Type::kInt32) {
Aart Bik96709f12015-10-28 17:49:07 -070047 graph_ = CreateCFG(&allocator_, data, return_type);
48 TestCodeOnReadyGraph(expected_before,
49 expected_after_cf,
50 expected_after_dce,
51 check_after_cf);
52 }
Roland Levillain556c3d12014-09-18 15:25:07 +010053
Aart Bik96709f12015-10-28 17:49:07 -070054 void TestCodeOnReadyGraph(const std::string& expected_before,
55 const std::string& expected_after_cf,
56 const std::string& expected_after_dce,
Andreas Gampeca620d72016-11-08 08:09:33 -080057 const std::function<void(HGraph*)>& check_after_cf) {
Aart Bik96709f12015-10-28 17:49:07 -070058 ASSERT_NE(graph_, nullptr);
Roland Levillain556c3d12014-09-18 15:25:07 +010059
Aart Bik96709f12015-10-28 17:49:07 -070060 StringPrettyPrinter printer_before(graph_);
61 printer_before.VisitInsertionOrder();
62 std::string actual_before = printer_before.str();
63 EXPECT_EQ(expected_before, actual_before);
Roland Levillain556c3d12014-09-18 15:25:07 +010064
Aart Bik96709f12015-10-28 17:49:07 -070065 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
66 X86InstructionSetFeatures::FromCppDefines());
67 x86::CodeGeneratorX86 codegenX86(graph_, *features_x86.get(), CompilerOptions());
Andreas Gampeca620d72016-11-08 08:09:33 -080068 HConstantFolding(graph_, "constant_folding").Run();
David Brazdilbadd8262016-02-02 16:28:56 +000069 GraphChecker graph_checker_cf(graph_);
70 graph_checker_cf.Run();
71 ASSERT_TRUE(graph_checker_cf.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010072
Aart Bik96709f12015-10-28 17:49:07 -070073 StringPrettyPrinter printer_after_cf(graph_);
74 printer_after_cf.VisitInsertionOrder();
75 std::string actual_after_cf = printer_after_cf.str();
76 EXPECT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain93445682014-10-06 19:24:02 +010077
Aart Bik96709f12015-10-28 17:49:07 -070078 check_after_cf(graph_);
Roland Levillain556c3d12014-09-18 15:25:07 +010079
Andreas Gampeca620d72016-11-08 08:09:33 -080080 HDeadCodeElimination(graph_, nullptr /* stats */, "dead_code_elimination").Run();
David Brazdilbadd8262016-02-02 16:28:56 +000081 GraphChecker graph_checker_dce(graph_);
82 graph_checker_dce.Run();
83 ASSERT_TRUE(graph_checker_dce.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010084
Aart Bik96709f12015-10-28 17:49:07 -070085 StringPrettyPrinter printer_after_dce(graph_);
86 printer_after_dce.VisitInsertionOrder();
87 std::string actual_after_dce = printer_after_dce.str();
88 EXPECT_EQ(expected_after_dce, actual_after_dce);
89 }
90
91 ArenaPool pool_;
92 ArenaAllocator allocator_;
93 HGraph* graph_;
94};
Roland Levillain556c3d12014-09-18 15:25:07 +010095
96/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010097 * Tiny three-register program exercising int constant folding on negation.
98 *
99 * 16-bit
100 * offset
101 * ------
102 * v0 <- 1 0. const/4 v0, #+1
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000103 * v1 <- -v0 1. neg-int v1, v0
Roland Levillain9240d6a2014-10-20 16:47:04 +0100104 * return v1 2. return v1
105 */
Aart Bik96709f12015-10-28 17:49:07 -0700106TEST_F(ConstantFoldingTest, IntConstantFoldingNegation) {
Roland Levillain9240d6a2014-10-20 16:47:04 +0100107 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
108 Instruction::CONST_4 | 0 << 8 | 1 << 12,
109 Instruction::NEG_INT | 1 << 8 | 0 << 12,
110 Instruction::RETURN | 1 << 8);
111
112 std::string expected_before =
113 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000114 " 2: IntConstant [3]\n"
115 " 0: SuspendCheck\n"
116 " 1: Goto 1\n"
Roland Levillain9240d6a2014-10-20 16:47:04 +0100117 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000118 " 3: Neg(2) [4]\n"
119 " 4: Return(3)\n"
Roland Levillain9240d6a2014-10-20 16:47:04 +0100120 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000121 " 5: Exit\n";
Roland Levillain9240d6a2014-10-20 16:47:04 +0100122
123 // Expected difference after constant folding.
124 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000125 { " 2: IntConstant [3]\n", " 2: IntConstant\n"
126 " 6: IntConstant [4]\n" },
127 { " 3: Neg(2) [4]\n", removed },
128 { " 4: Return(3)\n", " 4: Return(6)\n" }
Roland Levillain9240d6a2014-10-20 16:47:04 +0100129 };
130 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
131
132 // Check the value of the computed constant.
133 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100134 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain9240d6a2014-10-20 16:47:04 +0100135 ASSERT_TRUE(inst->IsIntConstant());
136 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
137 };
138
139 // Expected difference after dead code elimination.
140 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000141 { " 2: IntConstant\n", removed },
Roland Levillain9240d6a2014-10-20 16:47:04 +0100142 };
143 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
144
145 TestCode(data,
146 expected_before,
147 expected_after_cf,
148 expected_after_dce,
149 check_after_cf);
150}
151
152/**
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000153 * Tiny three-register program exercising long constant folding on negation.
154 *
155 * 16-bit
156 * offset
157 * ------
158 * (v0, v1) <- 4294967296 0. const-wide v0 #+4294967296
159 * (v2, v3) <- -(v0, v1) 1. neg-long v2, v0
160 * return (v2, v3) 2. return-wide v2
161 */
Aart Bik96709f12015-10-28 17:49:07 -0700162TEST_F(ConstantFoldingTest, LongConstantFoldingNegation) {
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000163 const int64_t input = INT64_C(4294967296); // 2^32
164 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
165 const uint16_t word1 = High16Bits(Low32Bits(input));
166 const uint16_t word2 = Low16Bits(High32Bits(input));
167 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
168 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
169 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
170 Instruction::NEG_LONG | 2 << 8 | 0 << 12,
171 Instruction::RETURN_WIDE | 2 << 8);
172
173 std::string expected_before =
174 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000175 " 2: LongConstant [3]\n"
176 " 0: SuspendCheck\n"
177 " 1: Goto 1\n"
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000178 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000179 " 3: Neg(2) [4]\n"
180 " 4: Return(3)\n"
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000181 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000182 " 5: Exit\n";
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000183
184 // Expected difference after constant folding.
185 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000186 { " 2: LongConstant [3]\n", " 2: LongConstant\n"
187 " 6: LongConstant [4]\n" },
188 { " 3: Neg(2) [4]\n", removed },
189 { " 4: Return(3)\n", " 4: Return(6)\n" }
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000190 };
191 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
192
193 // Check the value of the computed constant.
194 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100195 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000196 ASSERT_TRUE(inst->IsLongConstant());
197 ASSERT_EQ(inst->AsLongConstant()->GetValue(), INT64_C(-4294967296));
198 };
199
200 // Expected difference after dead code elimination.
201 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000202 { " 2: LongConstant\n", removed },
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000203 };
204 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
205
206 TestCode(data,
207 expected_before,
208 expected_after_cf,
209 expected_after_dce,
210 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100211 DataType::Type::kInt64);
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000212}
213
214/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100215 * Tiny three-register program exercising int constant folding on addition.
216 *
217 * 16-bit
218 * offset
219 * ------
220 * v0 <- 1 0. const/4 v0, #+1
221 * v1 <- 2 1. const/4 v1, #+2
222 * v2 <- v0 + v1 2. add-int v2, v0, v1
223 * return v2 4. return v2
224 */
Aart Bik96709f12015-10-28 17:49:07 -0700225TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100226 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
227 Instruction::CONST_4 | 0 << 8 | 1 << 12,
228 Instruction::CONST_4 | 1 << 8 | 2 << 12,
229 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
230 Instruction::RETURN | 2 << 8);
231
232 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000233 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000234 " 2: IntConstant [4]\n"
235 " 3: IntConstant [4]\n"
236 " 0: SuspendCheck\n"
237 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000238 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000239 " 4: Add(2, 3) [5]\n"
240 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000241 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000242 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100243
Roland Levillain75be2832014-10-17 17:02:00 +0100244 // Expected difference after constant folding.
245 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000246 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
247 { " 3: IntConstant [4]\n", " 3: IntConstant\n"
248 " 7: IntConstant [5]\n" },
249 { " 4: Add(2, 3) [5]\n", removed },
250 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100251 };
Roland Levillain75be2832014-10-17 17:02:00 +0100252 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100253
Roland Levillain93445682014-10-06 19:24:02 +0100254 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100255 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100256 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100257 ASSERT_TRUE(inst->IsIntConstant());
258 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
259 };
260
Roland Levillain556c3d12014-09-18 15:25:07 +0100261 // Expected difference after dead code elimination.
262 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000263 { " 2: IntConstant\n", removed },
264 { " 3: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100265 };
Roland Levillain75be2832014-10-17 17:02:00 +0100266 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100267
Roland Levillain93445682014-10-06 19:24:02 +0100268 TestCode(data,
269 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100270 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100271 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100272 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100273}
274
275/**
276 * Small three-register program exercising int constant folding on addition.
277 *
278 * 16-bit
279 * offset
280 * ------
281 * v0 <- 1 0. const/4 v0, #+1
282 * v1 <- 2 1. const/4 v1, #+2
283 * v0 <- v0 + v1 2. add-int/2addr v0, v1
David Brazdil8d5b8b22015-03-24 10:51:52 +0000284 * v1 <- 4 3. const/4 v1, #+4
285 * v2 <- 5 4. const/4 v2, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100286 * v1 <- v1 + v2 5. add-int/2addr v1, v2
287 * v2 <- v0 + v1 6. add-int v2, v0, v1
288 * return v2 8. return v2
289 */
Aart Bik96709f12015-10-28 17:49:07 -0700290TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100291 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
292 Instruction::CONST_4 | 0 << 8 | 1 << 12,
293 Instruction::CONST_4 | 1 << 8 | 2 << 12,
294 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000295 Instruction::CONST_4 | 1 << 8 | 4 << 12,
296 Instruction::CONST_4 | 2 << 8 | 5 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100297 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
298 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
299 Instruction::RETURN | 2 << 8);
300
301 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000302 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000303 " 2: IntConstant [4]\n"
304 " 3: IntConstant [4]\n"
305 " 5: IntConstant [7]\n"
306 " 6: IntConstant [7]\n"
307 " 0: SuspendCheck\n"
308 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000309 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000310 " 4: Add(2, 3) [8]\n"
311 " 7: Add(5, 6) [8]\n"
312 " 8: Add(4, 7) [9]\n"
313 " 9: Return(8)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000314 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000315 " 10: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100316
Roland Levillain75be2832014-10-17 17:02:00 +0100317 // Expected difference after constant folding.
318 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000319 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
320 { " 3: IntConstant [4]\n", " 3: IntConstant\n" },
321 { " 5: IntConstant [7]\n", " 5: IntConstant\n" },
322 { " 6: IntConstant [7]\n", " 6: IntConstant\n"
323 " 11: IntConstant\n"
324 " 12: IntConstant\n"
325 " 13: IntConstant [9]\n" },
326 { " 4: Add(2, 3) [8]\n", removed },
327 { " 7: Add(5, 6) [8]\n", removed },
328 { " 8: Add(4, 7) [9]\n", removed },
329 { " 9: Return(8)\n", " 9: Return(13)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100330 };
Roland Levillain75be2832014-10-17 17:02:00 +0100331 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100332
Roland Levillain93445682014-10-06 19:24:02 +0100333 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100334 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100335 HInstruction* inst1 = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100336 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000337 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
338 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100339 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000340 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
341 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100342 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000343 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100344 };
345
Roland Levillain556c3d12014-09-18 15:25:07 +0100346 // Expected difference after dead code elimination.
347 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000348 { " 2: IntConstant\n", removed },
349 { " 3: IntConstant\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100350 { " 5: IntConstant\n", removed },
David Brazdildee58d62016-04-07 09:54:26 +0000351 { " 6: IntConstant\n", removed },
352 { " 11: IntConstant\n", removed },
353 { " 12: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100354 };
Roland Levillain75be2832014-10-17 17:02:00 +0100355 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100356
Roland Levillain93445682014-10-06 19:24:02 +0100357 TestCode(data,
358 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100359 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100360 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100361 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100362}
363
364/**
365 * Tiny three-register program exercising int constant folding on subtraction.
366 *
367 * 16-bit
368 * offset
369 * ------
370 * v0 <- 3 0. const/4 v0, #+3
371 * v1 <- 2 1. const/4 v1, #+2
372 * v2 <- v0 - v1 2. sub-int v2, v0, v1
373 * return v2 4. return v2
374 */
Aart Bik96709f12015-10-28 17:49:07 -0700375TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100376 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
377 Instruction::CONST_4 | 0 << 8 | 3 << 12,
378 Instruction::CONST_4 | 1 << 8 | 2 << 12,
379 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
380 Instruction::RETURN | 2 << 8);
381
382 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000383 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000384 " 2: IntConstant [4]\n"
385 " 3: IntConstant [4]\n"
386 " 0: SuspendCheck\n"
387 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000388 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000389 " 4: Sub(2, 3) [5]\n"
390 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000391 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000392 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100393
Roland Levillain75be2832014-10-17 17:02:00 +0100394 // Expected difference after constant folding.
395 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000396 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
397 { " 3: IntConstant [4]\n", " 3: IntConstant\n"
398 " 7: IntConstant [5]\n" },
399 { " 4: Sub(2, 3) [5]\n", removed },
400 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100401 };
Roland Levillain75be2832014-10-17 17:02:00 +0100402 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100403
Roland Levillain93445682014-10-06 19:24:02 +0100404 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100405 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100406 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100407 ASSERT_TRUE(inst->IsIntConstant());
408 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
409 };
410
Roland Levillain556c3d12014-09-18 15:25:07 +0100411 // Expected difference after dead code elimination.
412 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000413 { " 2: IntConstant\n", removed },
414 { " 3: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100415 };
Roland Levillain75be2832014-10-17 17:02:00 +0100416 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100417
Roland Levillain93445682014-10-06 19:24:02 +0100418 TestCode(data,
419 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100420 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100421 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100422 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100423}
424
Roland Levillain556c3d12014-09-18 15:25:07 +0100425/**
426 * Tiny three-register-pair program exercising long constant folding
427 * on addition.
428 *
429 * 16-bit
430 * offset
431 * ------
432 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
433 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
434 * (v4, v5) <-
435 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
436 * return (v4, v5) 6. return-wide v4
437 */
Aart Bik96709f12015-10-28 17:49:07 -0700438TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100439 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
440 Instruction::CONST_WIDE_16 | 0 << 8, 1,
441 Instruction::CONST_WIDE_16 | 2 << 8, 2,
442 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
443 Instruction::RETURN_WIDE | 4 << 8);
444
445 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000446 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000447 " 2: LongConstant [4]\n"
448 " 3: LongConstant [4]\n"
449 " 0: SuspendCheck\n"
450 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000451 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000452 " 4: Add(2, 3) [5]\n"
453 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000454 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000455 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100456
Roland Levillain75be2832014-10-17 17:02:00 +0100457 // Expected difference after constant folding.
458 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000459 { " 2: LongConstant [4]\n", " 2: LongConstant\n" },
460 { " 3: LongConstant [4]\n", " 3: LongConstant\n"
461 " 7: LongConstant [5]\n" },
462 { " 4: Add(2, 3) [5]\n", removed },
463 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100464 };
Roland Levillain75be2832014-10-17 17:02:00 +0100465 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100466
Roland Levillain93445682014-10-06 19:24:02 +0100467 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100468 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100469 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100470 ASSERT_TRUE(inst->IsLongConstant());
471 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
472 };
473
Roland Levillain556c3d12014-09-18 15:25:07 +0100474 // Expected difference after dead code elimination.
475 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000476 { " 2: LongConstant\n", removed },
477 { " 3: LongConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100478 };
Roland Levillain75be2832014-10-17 17:02:00 +0100479 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100480
Roland Levillain93445682014-10-06 19:24:02 +0100481 TestCode(data,
482 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100483 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100484 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100485 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100486 DataType::Type::kInt64);
Roland Levillain556c3d12014-09-18 15:25:07 +0100487}
488
489/**
490 * Tiny three-register-pair program exercising long constant folding
491 * on subtraction.
492 *
493 * 16-bit
494 * offset
495 * ------
496 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
497 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
498 * (v4, v5) <-
499 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
500 * return (v4, v5) 6. return-wide v4
501 */
Aart Bik96709f12015-10-28 17:49:07 -0700502TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100503 const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
504 Instruction::CONST_WIDE_16 | 0 << 8, 3,
505 Instruction::CONST_WIDE_16 | 2 << 8, 2,
506 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
507 Instruction::RETURN_WIDE | 4 << 8);
508
509 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000510 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000511 " 2: LongConstant [4]\n"
512 " 3: LongConstant [4]\n"
513 " 0: SuspendCheck\n"
514 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000515 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000516 " 4: Sub(2, 3) [5]\n"
517 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000518 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000519 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100520
Roland Levillain75be2832014-10-17 17:02:00 +0100521 // Expected difference after constant folding.
522 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000523 { " 2: LongConstant [4]\n", " 2: LongConstant\n" },
524 { " 3: LongConstant [4]\n", " 3: LongConstant\n"
525 " 7: LongConstant [5]\n" },
526 { " 4: Sub(2, 3) [5]\n", removed },
527 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100528 };
Roland Levillain75be2832014-10-17 17:02:00 +0100529 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100530
Roland Levillain93445682014-10-06 19:24:02 +0100531 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100532 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100533 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100534 ASSERT_TRUE(inst->IsLongConstant());
535 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
536 };
537
Roland Levillain556c3d12014-09-18 15:25:07 +0100538 // Expected difference after dead code elimination.
539 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000540 { " 2: LongConstant\n", removed },
541 { " 3: LongConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100542 };
Roland Levillain75be2832014-10-17 17:02:00 +0100543 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100544
Roland Levillain93445682014-10-06 19:24:02 +0100545 TestCode(data,
546 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100547 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100548 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100549 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100550 DataType::Type::kInt64);
Roland Levillain556c3d12014-09-18 15:25:07 +0100551}
552
553/**
554 * Three-register program with jumps leading to the creation of many
555 * blocks.
556 *
557 * The intent of this test is to ensure that all constant expressions
558 * are actually evaluated at compile-time, thanks to the reverse
559 * (forward) post-order traversal of the the dominator tree.
560 *
561 * 16-bit
562 * offset
563 * ------
David Brazdil8d5b8b22015-03-24 10:51:52 +0000564 * v0 <- 1 0. const/4 v0, #+1
565 * v1 <- 2 1. const/4 v1, #+2
Roland Levillain556c3d12014-09-18 15:25:07 +0100566 * v2 <- v0 + v1 2. add-int v2, v0, v1
567 * goto L2 4. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000568 * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100569 * goto L3 7. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000570 * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4
Roland Levillain556c3d12014-09-18 15:25:07 +0100571 * goto L1 10. goto +(-5)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000572 * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8
Roland Levillain556c3d12014-09-18 15:25:07 +0100573 * return v2 13. return v2
574 */
Aart Bik96709f12015-10-28 17:49:07 -0700575TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100576 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
David Brazdil8d5b8b22015-03-24 10:51:52 +0000577 Instruction::CONST_4 | 0 << 8 | 1 << 12,
578 Instruction::CONST_4 | 1 << 8 | 2 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100579 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
580 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000581 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Roland Levillain556c3d12014-09-18 15:25:07 +0100582 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000583 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
Andreas Gampe58554b72015-10-20 21:08:52 -0700584 static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8),
David Brazdil8d5b8b22015-03-24 10:51:52 +0000585 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Roland Levillain556c3d12014-09-18 15:25:07 +0100586 Instruction::RETURN | 2 << 8);
587
588 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000589 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000590 " 2: IntConstant [4]\n" // v0 <- 1
591 " 3: IntConstant [4]\n" // v1 <- 2
592 " 6: IntConstant [7]\n" // const 5
593 " 9: IntConstant [10]\n" // const 4
594 " 12: IntConstant [13]\n" // const 8
595 " 0: SuspendCheck\n"
596 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000597 "BasicBlock 1, pred: 0, succ: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000598 " 4: Add(2, 3) [7]\n" // v2 <- v0 + v1 = 1 + 2 = 3
599 " 5: Goto 3\n" // goto L2
David Brazdil86ea7ee2016-02-16 09:26:07 +0000600 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
David Brazdildee58d62016-04-07 09:54:26 +0000601 " 10: Add(7, 9) [13]\n" // v1 <- v0 + 3 = 7 + 5 = 12
602 " 11: Goto 4\n" // goto L3
David Brazdil86ea7ee2016-02-16 09:26:07 +0000603 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
David Brazdildee58d62016-04-07 09:54:26 +0000604 " 7: Add(4, 6) [10]\n" // v0 <- v2 + 2 = 3 + 4 = 7
605 " 8: Goto 2\n" // goto L1
David Brazdil86ea7ee2016-02-16 09:26:07 +0000606 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
David Brazdildee58d62016-04-07 09:54:26 +0000607 " 13: Add(10, 12) [14]\n" // v2 <- v1 + 4 = 12 + 8 = 20
608 " 14: Return(13)\n" // return v2
David Brazdil86ea7ee2016-02-16 09:26:07 +0000609 "BasicBlock 5, pred: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000610 " 15: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100611
Roland Levillain75be2832014-10-17 17:02:00 +0100612 // Expected difference after constant folding.
613 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000614 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
615 { " 3: IntConstant [4]\n", " 3: IntConstant\n" },
616 { " 6: IntConstant [7]\n", " 6: IntConstant\n" },
617 { " 9: IntConstant [10]\n", " 9: IntConstant\n" },
618 { " 12: IntConstant [13]\n", " 12: IntConstant\n"
619 " 16: IntConstant\n"
620 " 17: IntConstant\n"
621 " 18: IntConstant\n"
622 " 19: IntConstant [14]\n" },
623 { " 4: Add(2, 3) [7]\n", removed },
624 { " 10: Add(7, 9) [13]\n", removed },
625 { " 7: Add(4, 6) [10]\n", removed },
626 { " 13: Add(10, 12) [14]\n", removed },
627 { " 14: Return(13)\n", " 14: Return(19)\n"}
Roland Levillain556c3d12014-09-18 15:25:07 +0100628 };
Roland Levillain75be2832014-10-17 17:02:00 +0100629 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100630
Roland Levillain93445682014-10-06 19:24:02 +0100631 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100632 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100633 HInstruction* inst1 = graph->GetBlocks()[4]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100634 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000635 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
636 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100637 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000638 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
639 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100640 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000641 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
642 HInstruction* inst4 = inst3->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100643 ASSERT_TRUE(inst4->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000644 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100645 };
646
Roland Levillain556c3d12014-09-18 15:25:07 +0100647 // Expected difference after dead code elimination.
David Brazdil1c533c12015-04-24 17:04:38 +0100648 std::string expected_after_dce =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000649 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000650 " 19: IntConstant [14]\n"
651 " 0: SuspendCheck\n"
652 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000653 "BasicBlock 1, pred: 0, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000654 " 14: Return(19)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000655 "BasicBlock 5, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000656 " 15: Exit\n";
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
Roland Levillain556c3d12014-09-18 15:25:07 +0100665/**
666 * Three-register program with a constant (static) condition.
667 *
668 * 16-bit
669 * offset
670 * ------
671 * v1 <- 1 0. const/4 v1, #+1
672 * v0 <- 0 1. const/4 v0, #+0
673 * if v1 >= 0 goto L1 2. if-gez v1, +3
674 * v0 <- v1 4. move v0, v1
675 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
676 * return-void 7. return
677 */
Aart Bik96709f12015-10-28 17:49:07 -0700678TEST_F(ConstantFoldingTest, ConstantCondition) {
Roland Levillain556c3d12014-09-18 15:25:07 +0100679 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
680 Instruction::CONST_4 | 1 << 8 | 1 << 12,
681 Instruction::CONST_4 | 0 << 8 | 0 << 12,
682 Instruction::IF_GEZ | 1 << 8, 3,
683 Instruction::MOVE | 0 << 8 | 1 << 12,
684 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
685 Instruction::RETURN_VOID);
686
687 std::string expected_before =
David Brazdildee58d62016-04-07 09:54:26 +0000688 "BasicBlock 0, succ: 1\n"
689 " 3: IntConstant [9, 8, 5]\n"
690 " 4: IntConstant [8, 5]\n"
691 " 1: SuspendCheck\n"
692 " 2: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000693 "BasicBlock 1, pred: 0, succ: 5, 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000694 " 5: GreaterThanOrEqual(3, 4) [6]\n"
695 " 6: If(5)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000696 "BasicBlock 2, pred: 1, succ: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000697 " 7: Goto 3\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000698 "BasicBlock 3, pred: 5, 2, succ: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000699 " 8: Phi(4, 3) [9]\n"
700 " 9: Add(8, 3)\n"
701 " 10: ReturnVoid\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000702 "BasicBlock 4, pred: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000703 " 11: Exit\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000704 "BasicBlock 5, pred: 1, succ: 3\n"
705 " 0: Goto 3\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100706
Roland Levillain75be2832014-10-17 17:02:00 +0100707 // Expected difference after constant folding.
708 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000709 { " 3: IntConstant [9, 8, 5]\n", " 3: IntConstant [6, 9, 8]\n" },
710 { " 4: IntConstant [8, 5]\n", " 4: IntConstant [8]\n" },
711 { " 5: GreaterThanOrEqual(3, 4) [6]\n", removed },
712 { " 6: If(5)\n", " 6: If(3)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100713 };
Roland Levillain75be2832014-10-17 17:02:00 +0100714 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100715
Roland Levillain93445682014-10-06 19:24:02 +0100716 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100717 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100718 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100719 ASSERT_TRUE(inst->IsIntConstant());
720 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
721 };
722
David Brazdil1c533c12015-04-24 17:04:38 +0100723 // Expected graph after dead code elimination.
724 std::string expected_after_dce =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000725 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000726 " 1: SuspendCheck\n"
727 " 2: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000728 "BasicBlock 1, pred: 0, succ: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000729 " 10: ReturnVoid\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000730 "BasicBlock 4, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000731 " 11: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100732
Roland Levillain93445682014-10-06 19:24:02 +0100733 TestCode(data,
734 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100735 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100736 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100737 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100738}
739
Aart Bik96709f12015-10-28 17:49:07 -0700740/**
741 * Unsigned comparisons with zero. Since these instructions are not present
742 * in the bytecode, we need to set up the graph explicitly.
743 */
744TEST_F(ConstantFoldingTest, UnsignedComparisonsWithZero) {
745 graph_ = CreateGraph(&allocator_);
746 HBasicBlock* entry_block = new (&allocator_) HBasicBlock(graph_);
747 graph_->AddBlock(entry_block);
748 graph_->SetEntryBlock(entry_block);
749 HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
750 graph_->AddBlock(block);
751 HBasicBlock* exit_block = new (&allocator_) HBasicBlock(graph_);
752 graph_->AddBlock(exit_block);
753 graph_->SetExitBlock(exit_block);
754 entry_block->AddSuccessor(block);
755 block->AddSuccessor(exit_block);
756
757 // Make various unsigned comparisons with zero against a parameter.
758 HInstruction* parameter = new (&allocator_) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100759 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32, true);
Aart Bik96709f12015-10-28 17:49:07 -0700760 entry_block->AddInstruction(parameter);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000761 entry_block->AddInstruction(new (&allocator_) HGoto());
762
Aart Bik96709f12015-10-28 17:49:07 -0700763 HInstruction* zero = graph_->GetIntConstant(0);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000764
Aart Bik96709f12015-10-28 17:49:07 -0700765 HInstruction* last;
766 block->AddInstruction(last = new (&allocator_) HAbove(zero, parameter));
David Brazdilbadd8262016-02-02 16:28:56 +0000767 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700768 block->AddInstruction(last = new (&allocator_) HAbove(parameter, zero));
David Brazdilbadd8262016-02-02 16:28:56 +0000769 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700770 block->AddInstruction(last = new (&allocator_) HAboveOrEqual(zero, parameter));
David Brazdilbadd8262016-02-02 16:28:56 +0000771 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700772 block->AddInstruction(last = new (&allocator_) HAboveOrEqual(parameter, zero));
David Brazdilbadd8262016-02-02 16:28:56 +0000773 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700774 block->AddInstruction(last = new (&allocator_) HBelow(zero, parameter));
David Brazdilbadd8262016-02-02 16:28:56 +0000775 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700776 block->AddInstruction(last = new (&allocator_) HBelow(parameter, zero));
David Brazdilbadd8262016-02-02 16:28:56 +0000777 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700778 block->AddInstruction(last = new (&allocator_) HBelowOrEqual(zero, parameter));
David Brazdilbadd8262016-02-02 16:28:56 +0000779 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700780 block->AddInstruction(last = new (&allocator_) HBelowOrEqual(parameter, zero));
David Brazdilbadd8262016-02-02 16:28:56 +0000781 block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700782 block->AddInstruction(new (&allocator_) HReturn(zero));
David Brazdil86ea7ee2016-02-16 09:26:07 +0000783
Aart Bik96709f12015-10-28 17:49:07 -0700784 exit_block->AddInstruction(new (&allocator_) HExit());
785
David Brazdilbadd8262016-02-02 16:28:56 +0000786 graph_->BuildDominatorTree();
787
Aart Bik96709f12015-10-28 17:49:07 -0700788 const std::string expected_before =
789 "BasicBlock 0, succ: 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000790 " 0: ParameterValue [18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, "
791 "8, 8, 7, 6, 6, 5, 4, 4, 3]\n"
792 " 2: IntConstant [19, 17, 15, 13, 11, 9, 7, 5, 3]\n"
793 " 1: Goto 1\n"
Aart Bik96709f12015-10-28 17:49:07 -0700794 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000795 " 3: Above(2, 0) [4]\n"
796 " 4: Select(0, 0, 3)\n"
797 " 5: Above(0, 2) [6]\n"
798 " 6: Select(0, 0, 5)\n"
799 " 7: AboveOrEqual(2, 0) [8]\n"
800 " 8: Select(0, 0, 7)\n"
801 " 9: AboveOrEqual(0, 2) [10]\n"
802 " 10: Select(0, 0, 9)\n"
803 " 11: Below(2, 0) [12]\n"
804 " 12: Select(0, 0, 11)\n"
805 " 13: Below(0, 2) [14]\n"
806 " 14: Select(0, 0, 13)\n"
807 " 15: BelowOrEqual(2, 0) [16]\n"
808 " 16: Select(0, 0, 15)\n"
809 " 17: BelowOrEqual(0, 2) [18]\n"
810 " 18: Select(0, 0, 17)\n"
811 " 19: Return(2)\n"
Aart Bik96709f12015-10-28 17:49:07 -0700812 "BasicBlock 2, pred: 1\n"
813 " 20: Exit\n";
814
815 const std::string expected_after_cf =
816 "BasicBlock 0, succ: 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000817 " 0: ParameterValue [18, 18, 17, 16, 16, 14, 14, 12, 12, 11, 10, 10, "
818 "8, 8, 7, 6, 6, 5, 4, 4]\n"
819 " 2: IntConstant [14, 4, 19, 17, 11, 7, 5]\n"
820 " 21: IntConstant [16, 10]\n"
821 " 1: Goto 1\n"
Aart Bik96709f12015-10-28 17:49:07 -0700822 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000823 " 4: Select(0, 0, 2)\n"
824 " 5: Above(0, 2) [6]\n"
825 " 6: Select(0, 0, 5)\n"
826 " 7: AboveOrEqual(2, 0) [8]\n"
827 " 8: Select(0, 0, 7)\n"
828 " 10: Select(0, 0, 21)\n"
829 " 11: Below(2, 0) [12]\n"
830 " 12: Select(0, 0, 11)\n"
831 " 14: Select(0, 0, 2)\n"
832 " 16: Select(0, 0, 21)\n"
833 " 17: BelowOrEqual(0, 2) [18]\n"
834 " 18: Select(0, 0, 17)\n"
835 " 19: Return(2)\n"
Aart Bik96709f12015-10-28 17:49:07 -0700836 "BasicBlock 2, pred: 1\n"
837 " 20: Exit\n";
838
David Brazdilbadd8262016-02-02 16:28:56 +0000839 const std::string expected_after_dce =
840 "BasicBlock 0, succ: 1\n"
841 " 0: ParameterValue\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000842 " 2: IntConstant [19]\n"
843 " 1: Goto 1\n"
David Brazdilbadd8262016-02-02 16:28:56 +0000844 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000845 " 19: Return(2)\n"
David Brazdilbadd8262016-02-02 16:28:56 +0000846 "BasicBlock 2, pred: 1\n"
847 " 20: Exit\n";
Aart Bik96709f12015-10-28 17:49:07 -0700848
849 auto check_after_cf = [](HGraph* graph) {
850 CHECK(graph != nullptr);
851 };
852
853 TestCodeOnReadyGraph(expected_before,
854 expected_after_cf,
855 expected_after_dce,
856 check_after_cf);
857}
858
Roland Levillain556c3d12014-09-18 15:25:07 +0100859} // namespace art