blob: 2730fc7c82be3e0f3acf85c886a5bb7a12cd85a5 [file] [log] [blame]
Roland Levillain556c3d12014-09-18 15:25:07 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Roland Levillain93445682014-10-06 19:24:02 +010017#include <functional>
18
Roland Levillain75be2832014-10-17 17:02:00 +010019#include "constant_folding.h"
Vladimir Markoe2727152019-10-10 10:46:42 +010020
21#include "base/macros.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
Vladimir Markoe2727152019-10-10 10:46:42 +010030namespace art HIDDEN {
Roland Levillain556c3d12014-09-18 15:25:07 +010031
Aart Bik96709f12015-10-28 17:49:07 -070032/**
33 * Fixture class for the constant folding and dce tests.
34 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010035class ConstantFoldingTest : public OptimizingUnitTest {
Aart Bik96709f12015-10-28 17:49:07 -070036 public:
Vladimir Markoca6fff82017-10-03 14:49:14 +010037 ConstantFoldingTest() : graph_(nullptr) { }
Roland Levillain556c3d12014-09-18 15:25:07 +010038
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080039 void TestCode(const std::vector<uint16_t>& data,
Aart Bik96709f12015-10-28 17:49:07 -070040 const std::string& expected_before,
41 const std::string& expected_after_cf,
42 const std::string& expected_after_dce,
Andreas Gampeca620d72016-11-08 08:09:33 -080043 const std::function<void(HGraph*)>& check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010044 DataType::Type return_type = DataType::Type::kInt32) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010045 graph_ = CreateCFG(data, return_type);
Aart Bik96709f12015-10-28 17:49:07 -070046 TestCodeOnReadyGraph(expected_before,
47 expected_after_cf,
48 expected_after_dce,
49 check_after_cf);
50 }
Roland Levillain556c3d12014-09-18 15:25:07 +010051
Aart Bik96709f12015-10-28 17:49:07 -070052 void TestCodeOnReadyGraph(const std::string& expected_before,
53 const std::string& expected_after_cf,
54 const std::string& expected_after_dce,
Andreas Gampeca620d72016-11-08 08:09:33 -080055 const std::function<void(HGraph*)>& check_after_cf) {
Aart Bik96709f12015-10-28 17:49:07 -070056 ASSERT_NE(graph_, nullptr);
Roland Levillain556c3d12014-09-18 15:25:07 +010057
Aart Bik96709f12015-10-28 17:49:07 -070058 StringPrettyPrinter printer_before(graph_);
59 printer_before.VisitInsertionOrder();
60 std::string actual_before = printer_before.str();
61 EXPECT_EQ(expected_before, actual_before);
Roland Levillain556c3d12014-09-18 15:25:07 +010062
Andreas Gampeca620d72016-11-08 08:09:33 -080063 HConstantFolding(graph_, "constant_folding").Run();
David Brazdilbadd8262016-02-02 16:28:56 +000064 GraphChecker graph_checker_cf(graph_);
65 graph_checker_cf.Run();
66 ASSERT_TRUE(graph_checker_cf.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010067
Aart Bik96709f12015-10-28 17:49:07 -070068 StringPrettyPrinter printer_after_cf(graph_);
69 printer_after_cf.VisitInsertionOrder();
70 std::string actual_after_cf = printer_after_cf.str();
71 EXPECT_EQ(expected_after_cf, actual_after_cf);
Roland Levillain93445682014-10-06 19:24:02 +010072
Aart Bik96709f12015-10-28 17:49:07 -070073 check_after_cf(graph_);
Roland Levillain556c3d12014-09-18 15:25:07 +010074
Andreas Gampe3db70682018-12-26 15:12:03 -080075 HDeadCodeElimination(graph_, /* stats= */ nullptr, "dead_code_elimination").Run();
David Brazdilbadd8262016-02-02 16:28:56 +000076 GraphChecker graph_checker_dce(graph_);
77 graph_checker_dce.Run();
78 ASSERT_TRUE(graph_checker_dce.IsValid());
Roland Levillain556c3d12014-09-18 15:25:07 +010079
Aart Bik96709f12015-10-28 17:49:07 -070080 StringPrettyPrinter printer_after_dce(graph_);
81 printer_after_dce.VisitInsertionOrder();
82 std::string actual_after_dce = printer_after_dce.str();
83 EXPECT_EQ(expected_after_dce, actual_after_dce);
84 }
85
Aart Bik96709f12015-10-28 17:49:07 -070086 HGraph* graph_;
87};
Roland Levillain556c3d12014-09-18 15:25:07 +010088
89/**
Roland Levillain9240d6a2014-10-20 16:47:04 +010090 * Tiny three-register program exercising int constant folding on negation.
91 *
92 * 16-bit
93 * offset
94 * ------
95 * v0 <- 1 0. const/4 v0, #+1
Roland Levillainc90bc7c2014-12-11 12:14:33 +000096 * v1 <- -v0 1. neg-int v1, v0
Roland Levillain9240d6a2014-10-20 16:47:04 +010097 * return v1 2. return v1
98 */
Aart Bik96709f12015-10-28 17:49:07 -070099TEST_F(ConstantFoldingTest, IntConstantFoldingNegation) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800100 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Roland Levillain9240d6a2014-10-20 16:47:04 +0100101 Instruction::CONST_4 | 0 << 8 | 1 << 12,
102 Instruction::NEG_INT | 1 << 8 | 0 << 12,
103 Instruction::RETURN | 1 << 8);
104
105 std::string expected_before =
106 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000107 " 2: IntConstant [3]\n"
108 " 0: SuspendCheck\n"
109 " 1: Goto 1\n"
Roland Levillain9240d6a2014-10-20 16:47:04 +0100110 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000111 " 3: Neg(2) [4]\n"
112 " 4: Return(3)\n"
Roland Levillain9240d6a2014-10-20 16:47:04 +0100113 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000114 " 5: Exit\n";
Roland Levillain9240d6a2014-10-20 16:47:04 +0100115
116 // Expected difference after constant folding.
117 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000118 { " 2: IntConstant [3]\n", " 2: IntConstant\n"
119 " 6: IntConstant [4]\n" },
120 { " 3: Neg(2) [4]\n", removed },
121 { " 4: Return(3)\n", " 4: Return(6)\n" }
Roland Levillain9240d6a2014-10-20 16:47:04 +0100122 };
123 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
124
125 // Check the value of the computed constant.
126 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100127 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain9240d6a2014-10-20 16:47:04 +0100128 ASSERT_TRUE(inst->IsIntConstant());
129 ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
130 };
131
132 // Expected difference after dead code elimination.
133 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000134 { " 2: IntConstant\n", removed },
Roland Levillain9240d6a2014-10-20 16:47:04 +0100135 };
136 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
137
138 TestCode(data,
139 expected_before,
140 expected_after_cf,
141 expected_after_dce,
142 check_after_cf);
143}
144
145/**
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000146 * Tiny three-register program exercising long constant folding on negation.
147 *
148 * 16-bit
149 * offset
150 * ------
151 * (v0, v1) <- 4294967296 0. const-wide v0 #+4294967296
152 * (v2, v3) <- -(v0, v1) 1. neg-long v2, v0
153 * return (v2, v3) 2. return-wide v2
154 */
Aart Bik96709f12015-10-28 17:49:07 -0700155TEST_F(ConstantFoldingTest, LongConstantFoldingNegation) {
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000156 const int64_t input = INT64_C(4294967296); // 2^32
157 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
158 const uint16_t word1 = High16Bits(Low32Bits(input));
159 const uint16_t word2 = Low16Bits(High32Bits(input));
160 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800161 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000162 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
163 Instruction::NEG_LONG | 2 << 8 | 0 << 12,
164 Instruction::RETURN_WIDE | 2 << 8);
165
166 std::string expected_before =
167 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000168 " 2: LongConstant [3]\n"
169 " 0: SuspendCheck\n"
170 " 1: Goto 1\n"
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000171 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000172 " 3: Neg(2) [4]\n"
173 " 4: Return(3)\n"
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000174 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000175 " 5: Exit\n";
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000176
177 // Expected difference after constant folding.
178 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000179 { " 2: LongConstant [3]\n", " 2: LongConstant\n"
180 " 6: LongConstant [4]\n" },
181 { " 3: Neg(2) [4]\n", removed },
182 { " 4: Return(3)\n", " 4: Return(6)\n" }
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000183 };
184 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
185
186 // Check the value of the computed constant.
187 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100188 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000189 ASSERT_TRUE(inst->IsLongConstant());
190 ASSERT_EQ(inst->AsLongConstant()->GetValue(), INT64_C(-4294967296));
191 };
192
193 // Expected difference after dead code elimination.
194 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000195 { " 2: LongConstant\n", removed },
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000196 };
197 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
198
199 TestCode(data,
200 expected_before,
201 expected_after_cf,
202 expected_after_dce,
203 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100204 DataType::Type::kInt64);
Roland Levillainc90bc7c2014-12-11 12:14:33 +0000205}
206
207/**
Roland Levillain556c3d12014-09-18 15:25:07 +0100208 * Tiny three-register program exercising int constant folding on addition.
209 *
210 * 16-bit
211 * offset
212 * ------
213 * v0 <- 1 0. const/4 v0, #+1
214 * v1 <- 2 1. const/4 v1, #+2
215 * v2 <- v0 + v1 2. add-int v2, v0, v1
216 * return v2 4. return v2
217 */
Aart Bik96709f12015-10-28 17:49:07 -0700218TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800219 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100220 Instruction::CONST_4 | 0 << 8 | 1 << 12,
221 Instruction::CONST_4 | 1 << 8 | 2 << 12,
222 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
223 Instruction::RETURN | 2 << 8);
224
225 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000226 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000227 " 2: IntConstant [4]\n"
228 " 3: IntConstant [4]\n"
229 " 0: SuspendCheck\n"
230 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000231 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000232 " 4: Add(2, 3) [5]\n"
233 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000234 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000235 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100236
Roland Levillain75be2832014-10-17 17:02:00 +0100237 // Expected difference after constant folding.
238 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000239 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
240 { " 3: IntConstant [4]\n", " 3: IntConstant\n"
241 " 7: IntConstant [5]\n" },
242 { " 4: Add(2, 3) [5]\n", removed },
243 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100244 };
Roland Levillain75be2832014-10-17 17:02:00 +0100245 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100246
Roland Levillain93445682014-10-06 19:24:02 +0100247 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100248 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100249 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100250 ASSERT_TRUE(inst->IsIntConstant());
251 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
252 };
253
Roland Levillain556c3d12014-09-18 15:25:07 +0100254 // Expected difference after dead code elimination.
255 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000256 { " 2: IntConstant\n", removed },
257 { " 3: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100258 };
Roland Levillain75be2832014-10-17 17:02:00 +0100259 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100260
Roland Levillain93445682014-10-06 19:24:02 +0100261 TestCode(data,
262 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100263 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100264 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100265 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100266}
267
268/**
269 * Small three-register program exercising int constant folding on addition.
270 *
271 * 16-bit
272 * offset
273 * ------
274 * v0 <- 1 0. const/4 v0, #+1
275 * v1 <- 2 1. const/4 v1, #+2
276 * v0 <- v0 + v1 2. add-int/2addr v0, v1
David Brazdil8d5b8b22015-03-24 10:51:52 +0000277 * v1 <- 4 3. const/4 v1, #+4
278 * v2 <- 5 4. const/4 v2, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100279 * v1 <- v1 + v2 5. add-int/2addr v1, v2
280 * v2 <- v0 + v1 6. add-int v2, v0, v1
281 * return v2 8. return v2
282 */
Aart Bik96709f12015-10-28 17:49:07 -0700283TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800284 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100285 Instruction::CONST_4 | 0 << 8 | 1 << 12,
286 Instruction::CONST_4 | 1 << 8 | 2 << 12,
287 Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000288 Instruction::CONST_4 | 1 << 8 | 4 << 12,
289 Instruction::CONST_4 | 2 << 8 | 5 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100290 Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
291 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
292 Instruction::RETURN | 2 << 8);
293
294 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000295 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000296 " 2: IntConstant [4]\n"
297 " 3: IntConstant [4]\n"
298 " 5: IntConstant [7]\n"
299 " 6: IntConstant [7]\n"
300 " 0: SuspendCheck\n"
301 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000302 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000303 " 4: Add(2, 3) [8]\n"
304 " 7: Add(5, 6) [8]\n"
305 " 8: Add(4, 7) [9]\n"
306 " 9: Return(8)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000307 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000308 " 10: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100309
Roland Levillain75be2832014-10-17 17:02:00 +0100310 // Expected difference after constant folding.
311 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000312 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
313 { " 3: IntConstant [4]\n", " 3: IntConstant\n" },
314 { " 5: IntConstant [7]\n", " 5: IntConstant\n" },
315 { " 6: IntConstant [7]\n", " 6: IntConstant\n"
316 " 11: IntConstant\n"
317 " 12: IntConstant\n"
318 " 13: IntConstant [9]\n" },
319 { " 4: Add(2, 3) [8]\n", removed },
320 { " 7: Add(5, 6) [8]\n", removed },
321 { " 8: Add(4, 7) [9]\n", removed },
322 { " 9: Return(8)\n", " 9: Return(13)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100323 };
Roland Levillain75be2832014-10-17 17:02:00 +0100324 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100325
Roland Levillain93445682014-10-06 19:24:02 +0100326 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100327 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100328 HInstruction* inst1 = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100329 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000330 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
331 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100332 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000333 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
334 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100335 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000336 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100337 };
338
Roland Levillain556c3d12014-09-18 15:25:07 +0100339 // Expected difference after dead code elimination.
340 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000341 { " 2: IntConstant\n", removed },
342 { " 3: IntConstant\n", removed },
Roland Levillain556c3d12014-09-18 15:25:07 +0100343 { " 5: IntConstant\n", removed },
David Brazdildee58d62016-04-07 09:54:26 +0000344 { " 6: IntConstant\n", removed },
345 { " 11: IntConstant\n", removed },
346 { " 12: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100347 };
Roland Levillain75be2832014-10-17 17:02:00 +0100348 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100349
Roland Levillain93445682014-10-06 19:24:02 +0100350 TestCode(data,
351 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100352 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100353 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100354 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100355}
356
357/**
358 * Tiny three-register program exercising int constant folding on subtraction.
359 *
360 * 16-bit
361 * offset
362 * ------
363 * v0 <- 3 0. const/4 v0, #+3
364 * v1 <- 2 1. const/4 v1, #+2
365 * v2 <- v0 - v1 2. sub-int v2, v0, v1
366 * return v2 4. return v2
367 */
Aart Bik96709f12015-10-28 17:49:07 -0700368TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800369 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100370 Instruction::CONST_4 | 0 << 8 | 3 << 12,
371 Instruction::CONST_4 | 1 << 8 | 2 << 12,
372 Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
373 Instruction::RETURN | 2 << 8);
374
375 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000376 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000377 " 2: IntConstant [4]\n"
378 " 3: IntConstant [4]\n"
379 " 0: SuspendCheck\n"
380 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000381 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000382 " 4: Sub(2, 3) [5]\n"
383 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000384 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000385 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100386
Roland Levillain75be2832014-10-17 17:02:00 +0100387 // Expected difference after constant folding.
388 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000389 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
390 { " 3: IntConstant [4]\n", " 3: IntConstant\n"
391 " 7: IntConstant [5]\n" },
392 { " 4: Sub(2, 3) [5]\n", removed },
393 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100394 };
Roland Levillain75be2832014-10-17 17:02:00 +0100395 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100396
Roland Levillain93445682014-10-06 19:24:02 +0100397 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100398 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100399 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100400 ASSERT_TRUE(inst->IsIntConstant());
401 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
402 };
403
Roland Levillain556c3d12014-09-18 15:25:07 +0100404 // Expected difference after dead code elimination.
405 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000406 { " 2: IntConstant\n", removed },
407 { " 3: IntConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100408 };
Roland Levillain75be2832014-10-17 17:02:00 +0100409 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100410
Roland Levillain93445682014-10-06 19:24:02 +0100411 TestCode(data,
412 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100413 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100414 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100415 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100416}
417
Roland Levillain556c3d12014-09-18 15:25:07 +0100418/**
419 * Tiny three-register-pair program exercising long constant folding
420 * on addition.
421 *
422 * 16-bit
423 * offset
424 * ------
425 * (v0, v1) <- 1 0. const-wide/16 v0, #+1
426 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
427 * (v4, v5) <-
428 * (v0, v1) + (v1, v2) 4. add-long v4, v0, v2
429 * return (v4, v5) 6. return-wide v4
430 */
Aart Bik96709f12015-10-28 17:49:07 -0700431TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800432 const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100433 Instruction::CONST_WIDE_16 | 0 << 8, 1,
434 Instruction::CONST_WIDE_16 | 2 << 8, 2,
435 Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
436 Instruction::RETURN_WIDE | 4 << 8);
437
438 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000439 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000440 " 2: LongConstant [4]\n"
441 " 3: LongConstant [4]\n"
442 " 0: SuspendCheck\n"
443 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000444 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000445 " 4: Add(2, 3) [5]\n"
446 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000447 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000448 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100449
Roland Levillain75be2832014-10-17 17:02:00 +0100450 // Expected difference after constant folding.
451 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000452 { " 2: LongConstant [4]\n", " 2: LongConstant\n" },
453 { " 3: LongConstant [4]\n", " 3: LongConstant\n"
454 " 7: LongConstant [5]\n" },
455 { " 4: Add(2, 3) [5]\n", removed },
456 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100457 };
Roland Levillain75be2832014-10-17 17:02:00 +0100458 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100459
Roland Levillain93445682014-10-06 19:24:02 +0100460 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100461 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100462 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100463 ASSERT_TRUE(inst->IsLongConstant());
464 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
465 };
466
Roland Levillain556c3d12014-09-18 15:25:07 +0100467 // Expected difference after dead code elimination.
468 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000469 { " 2: LongConstant\n", removed },
470 { " 3: LongConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100471 };
Roland Levillain75be2832014-10-17 17:02:00 +0100472 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100473
Roland Levillain93445682014-10-06 19:24:02 +0100474 TestCode(data,
475 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100476 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100477 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100478 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100479 DataType::Type::kInt64);
Roland Levillain556c3d12014-09-18 15:25:07 +0100480}
481
482/**
483 * Tiny three-register-pair program exercising long constant folding
484 * on subtraction.
485 *
486 * 16-bit
487 * offset
488 * ------
489 * (v0, v1) <- 3 0. const-wide/16 v0, #+3
490 * (v2, v3) <- 2 2. const-wide/16 v2, #+2
491 * (v4, v5) <-
492 * (v0, v1) - (v1, v2) 4. sub-long v4, v0, v2
493 * return (v4, v5) 6. return-wide v4
494 */
Aart Bik96709f12015-10-28 17:49:07 -0700495TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800496 const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100497 Instruction::CONST_WIDE_16 | 0 << 8, 3,
498 Instruction::CONST_WIDE_16 | 2 << 8, 2,
499 Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
500 Instruction::RETURN_WIDE | 4 << 8);
501
502 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000503 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000504 " 2: LongConstant [4]\n"
505 " 3: LongConstant [4]\n"
506 " 0: SuspendCheck\n"
507 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000508 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000509 " 4: Sub(2, 3) [5]\n"
510 " 5: Return(4)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000511 "BasicBlock 2, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000512 " 6: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100513
Roland Levillain75be2832014-10-17 17:02:00 +0100514 // Expected difference after constant folding.
515 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000516 { " 2: LongConstant [4]\n", " 2: LongConstant\n" },
517 { " 3: LongConstant [4]\n", " 3: LongConstant\n"
518 " 7: LongConstant [5]\n" },
519 { " 4: Sub(2, 3) [5]\n", removed },
520 { " 5: Return(4)\n", " 5: Return(7)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100521 };
Roland Levillain75be2832014-10-17 17:02:00 +0100522 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100523
Roland Levillain93445682014-10-06 19:24:02 +0100524 // Check the value of the computed constant.
Roland Levillain75be2832014-10-17 17:02:00 +0100525 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100526 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100527 ASSERT_TRUE(inst->IsLongConstant());
528 ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
529 };
530
Roland Levillain556c3d12014-09-18 15:25:07 +0100531 // Expected difference after dead code elimination.
532 diff_t expected_dce_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000533 { " 2: LongConstant\n", removed },
534 { " 3: LongConstant\n", removed }
Roland Levillain556c3d12014-09-18 15:25:07 +0100535 };
Roland Levillain75be2832014-10-17 17:02:00 +0100536 std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100537
Roland Levillain93445682014-10-06 19:24:02 +0100538 TestCode(data,
539 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100540 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100541 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100542 check_after_cf,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100543 DataType::Type::kInt64);
Roland Levillain556c3d12014-09-18 15:25:07 +0100544}
545
546/**
547 * Three-register program with jumps leading to the creation of many
548 * blocks.
549 *
550 * The intent of this test is to ensure that all constant expressions
551 * are actually evaluated at compile-time, thanks to the reverse
552 * (forward) post-order traversal of the the dominator tree.
553 *
554 * 16-bit
555 * offset
556 * ------
David Brazdil8d5b8b22015-03-24 10:51:52 +0000557 * v0 <- 1 0. const/4 v0, #+1
558 * v1 <- 2 1. const/4 v1, #+2
Roland Levillain556c3d12014-09-18 15:25:07 +0100559 * v2 <- v0 + v1 2. add-int v2, v0, v1
560 * goto L2 4. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000561 * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5
Roland Levillain556c3d12014-09-18 15:25:07 +0100562 * goto L3 7. goto +4
David Brazdil8d5b8b22015-03-24 10:51:52 +0000563 * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4
Roland Levillain556c3d12014-09-18 15:25:07 +0100564 * goto L1 10. goto +(-5)
David Brazdil8d5b8b22015-03-24 10:51:52 +0000565 * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8
Roland Levillain556c3d12014-09-18 15:25:07 +0100566 * return v2 13. return v2
567 */
Aart Bik96709f12015-10-28 17:49:07 -0700568TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800569 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
David Brazdil8d5b8b22015-03-24 10:51:52 +0000570 Instruction::CONST_4 | 0 << 8 | 1 << 12,
571 Instruction::CONST_4 | 1 << 8 | 2 << 12,
Roland Levillain556c3d12014-09-18 15:25:07 +0100572 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
573 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000574 Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Roland Levillain556c3d12014-09-18 15:25:07 +0100575 Instruction::GOTO | 4 << 8,
David Brazdil8d5b8b22015-03-24 10:51:52 +0000576 Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
Andreas Gampe58554b72015-10-20 21:08:52 -0700577 static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8),
David Brazdil8d5b8b22015-03-24 10:51:52 +0000578 Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Roland Levillain556c3d12014-09-18 15:25:07 +0100579 Instruction::RETURN | 2 << 8);
580
581 std::string expected_before =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000582 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000583 " 2: IntConstant [4]\n" // v0 <- 1
584 " 3: IntConstant [4]\n" // v1 <- 2
585 " 6: IntConstant [7]\n" // const 5
586 " 9: IntConstant [10]\n" // const 4
587 " 12: IntConstant [13]\n" // const 8
588 " 0: SuspendCheck\n"
589 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000590 "BasicBlock 1, pred: 0, succ: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000591 " 4: Add(2, 3) [7]\n" // v2 <- v0 + v1 = 1 + 2 = 3
592 " 5: Goto 3\n" // goto L2
David Brazdil86ea7ee2016-02-16 09:26:07 +0000593 "BasicBlock 2, pred: 3, succ: 4\n" // L1:
David Brazdildee58d62016-04-07 09:54:26 +0000594 " 10: Add(7, 9) [13]\n" // v1 <- v0 + 3 = 7 + 5 = 12
595 " 11: Goto 4\n" // goto L3
David Brazdil86ea7ee2016-02-16 09:26:07 +0000596 "BasicBlock 3, pred: 1, succ: 2\n" // L2:
David Brazdildee58d62016-04-07 09:54:26 +0000597 " 7: Add(4, 6) [10]\n" // v0 <- v2 + 2 = 3 + 4 = 7
598 " 8: Goto 2\n" // goto L1
David Brazdil86ea7ee2016-02-16 09:26:07 +0000599 "BasicBlock 4, pred: 2, succ: 5\n" // L3:
David Brazdildee58d62016-04-07 09:54:26 +0000600 " 13: Add(10, 12) [14]\n" // v2 <- v1 + 4 = 12 + 8 = 20
601 " 14: Return(13)\n" // return v2
David Brazdil86ea7ee2016-02-16 09:26:07 +0000602 "BasicBlock 5, pred: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000603 " 15: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100604
Roland Levillain75be2832014-10-17 17:02:00 +0100605 // Expected difference after constant folding.
606 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000607 { " 2: IntConstant [4]\n", " 2: IntConstant\n" },
608 { " 3: IntConstant [4]\n", " 3: IntConstant\n" },
609 { " 6: IntConstant [7]\n", " 6: IntConstant\n" },
610 { " 9: IntConstant [10]\n", " 9: IntConstant\n" },
611 { " 12: IntConstant [13]\n", " 12: IntConstant\n"
612 " 16: IntConstant\n"
613 " 17: IntConstant\n"
614 " 18: IntConstant\n"
615 " 19: IntConstant [14]\n" },
616 { " 4: Add(2, 3) [7]\n", removed },
617 { " 10: Add(7, 9) [13]\n", removed },
618 { " 7: Add(4, 6) [10]\n", removed },
619 { " 13: Add(10, 12) [14]\n", removed },
620 { " 14: Return(13)\n", " 14: Return(19)\n"}
Roland Levillain556c3d12014-09-18 15:25:07 +0100621 };
Roland Levillain75be2832014-10-17 17:02:00 +0100622 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100623
Roland Levillain93445682014-10-06 19:24:02 +0100624 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100625 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100626 HInstruction* inst1 = graph->GetBlocks()[4]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100627 ASSERT_TRUE(inst1->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000628 ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
629 HInstruction* inst2 = inst1->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100630 ASSERT_TRUE(inst2->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000631 ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
632 HInstruction* inst3 = inst2->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100633 ASSERT_TRUE(inst3->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000634 ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
635 HInstruction* inst4 = inst3->GetPrevious();
Roland Levillain93445682014-10-06 19:24:02 +0100636 ASSERT_TRUE(inst4->IsIntConstant());
David Brazdil8d5b8b22015-03-24 10:51:52 +0000637 ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
Roland Levillain93445682014-10-06 19:24:02 +0100638 };
639
Roland Levillain556c3d12014-09-18 15:25:07 +0100640 // Expected difference after dead code elimination.
David Brazdil1c533c12015-04-24 17:04:38 +0100641 std::string expected_after_dce =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000642 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000643 " 19: IntConstant [14]\n"
644 " 0: SuspendCheck\n"
645 " 1: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000646 "BasicBlock 1, pred: 0, succ: 5\n"
David Brazdildee58d62016-04-07 09:54:26 +0000647 " 14: Return(19)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000648 "BasicBlock 5, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000649 " 15: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100650
Roland Levillain93445682014-10-06 19:24:02 +0100651 TestCode(data,
652 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100653 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100654 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100655 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100656}
657
Roland Levillain556c3d12014-09-18 15:25:07 +0100658/**
659 * Three-register program with a constant (static) condition.
660 *
661 * 16-bit
662 * offset
663 * ------
664 * v1 <- 1 0. const/4 v1, #+1
665 * v0 <- 0 1. const/4 v0, #+0
666 * if v1 >= 0 goto L1 2. if-gez v1, +3
667 * v0 <- v1 4. move v0, v1
668 * L1: v2 <- v0 + v1 5. add-int v2, v0, v1
669 * return-void 7. return
670 */
Aart Bik96709f12015-10-28 17:49:07 -0700671TEST_F(ConstantFoldingTest, ConstantCondition) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800672 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Roland Levillain556c3d12014-09-18 15:25:07 +0100673 Instruction::CONST_4 | 1 << 8 | 1 << 12,
674 Instruction::CONST_4 | 0 << 8 | 0 << 12,
675 Instruction::IF_GEZ | 1 << 8, 3,
676 Instruction::MOVE | 0 << 8 | 1 << 12,
677 Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
678 Instruction::RETURN_VOID);
679
680 std::string expected_before =
David Brazdildee58d62016-04-07 09:54:26 +0000681 "BasicBlock 0, succ: 1\n"
682 " 3: IntConstant [9, 8, 5]\n"
683 " 4: IntConstant [8, 5]\n"
684 " 1: SuspendCheck\n"
685 " 2: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000686 "BasicBlock 1, pred: 0, succ: 5, 2\n"
David Brazdildee58d62016-04-07 09:54:26 +0000687 " 5: GreaterThanOrEqual(3, 4) [6]\n"
688 " 6: If(5)\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000689 "BasicBlock 2, pred: 1, succ: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000690 " 7: Goto 3\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000691 "BasicBlock 3, pred: 5, 2, succ: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000692 " 8: Phi(4, 3) [9]\n"
693 " 9: Add(8, 3)\n"
694 " 10: ReturnVoid\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000695 "BasicBlock 4, pred: 3\n"
David Brazdildee58d62016-04-07 09:54:26 +0000696 " 11: Exit\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000697 "BasicBlock 5, pred: 1, succ: 3\n"
698 " 0: Goto 3\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100699
Roland Levillain75be2832014-10-17 17:02:00 +0100700 // Expected difference after constant folding.
701 diff_t expected_cf_diff = {
David Brazdildee58d62016-04-07 09:54:26 +0000702 { " 3: IntConstant [9, 8, 5]\n", " 3: IntConstant [6, 9, 8]\n" },
703 { " 4: IntConstant [8, 5]\n", " 4: IntConstant [8]\n" },
704 { " 5: GreaterThanOrEqual(3, 4) [6]\n", removed },
705 { " 6: If(5)\n", " 6: If(3)\n" }
Roland Levillain556c3d12014-09-18 15:25:07 +0100706 };
Roland Levillain75be2832014-10-17 17:02:00 +0100707 std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
Roland Levillain556c3d12014-09-18 15:25:07 +0100708
Roland Levillain93445682014-10-06 19:24:02 +0100709 // Check the values of the computed constants.
Roland Levillain75be2832014-10-17 17:02:00 +0100710 auto check_after_cf = [](HGraph* graph) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100711 HInstruction* inst = graph->GetBlocks()[1]->GetFirstInstruction()->InputAt(0);
Roland Levillain93445682014-10-06 19:24:02 +0100712 ASSERT_TRUE(inst->IsIntConstant());
713 ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
714 };
715
David Brazdil1c533c12015-04-24 17:04:38 +0100716 // Expected graph after dead code elimination.
717 std::string expected_after_dce =
David Brazdil86ea7ee2016-02-16 09:26:07 +0000718 "BasicBlock 0, succ: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000719 " 1: SuspendCheck\n"
720 " 2: Goto 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000721 "BasicBlock 1, pred: 0, succ: 4\n"
David Brazdildee58d62016-04-07 09:54:26 +0000722 " 10: ReturnVoid\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000723 "BasicBlock 4, pred: 1\n"
David Brazdildee58d62016-04-07 09:54:26 +0000724 " 11: Exit\n";
Roland Levillain556c3d12014-09-18 15:25:07 +0100725
Roland Levillain93445682014-10-06 19:24:02 +0100726 TestCode(data,
727 expected_before,
Roland Levillain75be2832014-10-17 17:02:00 +0100728 expected_after_cf,
Roland Levillain93445682014-10-06 19:24:02 +0100729 expected_after_dce,
Roland Levillain75be2832014-10-17 17:02:00 +0100730 check_after_cf);
Roland Levillain556c3d12014-09-18 15:25:07 +0100731}
732
Aart Bik96709f12015-10-28 17:49:07 -0700733/**
734 * Unsigned comparisons with zero. Since these instructions are not present
735 * in the bytecode, we need to set up the graph explicitly.
736 */
737TEST_F(ConstantFoldingTest, UnsignedComparisonsWithZero) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100738 graph_ = CreateGraph();
739 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik96709f12015-10-28 17:49:07 -0700740 graph_->AddBlock(entry_block);
741 graph_->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100742 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik96709f12015-10-28 17:49:07 -0700743 graph_->AddBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100744 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik96709f12015-10-28 17:49:07 -0700745 graph_->AddBlock(exit_block);
746 graph_->SetExitBlock(exit_block);
747 entry_block->AddSuccessor(block);
748 block->AddSuccessor(exit_block);
749
750 // Make various unsigned comparisons with zero against a parameter.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100751 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100752 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32, true);
Aart Bik96709f12015-10-28 17:49:07 -0700753 entry_block->AddInstruction(parameter);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100754 entry_block->AddInstruction(new (GetAllocator()) HGoto());
David Brazdil86ea7ee2016-02-16 09:26:07 +0000755
Aart Bik96709f12015-10-28 17:49:07 -0700756 HInstruction* zero = graph_->GetIntConstant(0);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000757
Aart Bik96709f12015-10-28 17:49:07 -0700758 HInstruction* last;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100759 block->AddInstruction(last = new (GetAllocator()) HAbove(zero, parameter));
760 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
761 block->AddInstruction(last = new (GetAllocator()) HAbove(parameter, zero));
762 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
763 block->AddInstruction(last = new (GetAllocator()) HAboveOrEqual(zero, parameter));
764 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
765 block->AddInstruction(last = new (GetAllocator()) HAboveOrEqual(parameter, zero));
766 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
767 block->AddInstruction(last = new (GetAllocator()) HBelow(zero, parameter));
768 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
769 block->AddInstruction(last = new (GetAllocator()) HBelow(parameter, zero));
770 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
771 block->AddInstruction(last = new (GetAllocator()) HBelowOrEqual(zero, parameter));
772 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
773 block->AddInstruction(last = new (GetAllocator()) HBelowOrEqual(parameter, zero));
774 block->AddInstruction(new (GetAllocator()) HSelect(last, parameter, parameter, 0));
775 block->AddInstruction(new (GetAllocator()) HReturn(zero));
David Brazdil86ea7ee2016-02-16 09:26:07 +0000776
Vladimir Markoca6fff82017-10-03 14:49:14 +0100777 exit_block->AddInstruction(new (GetAllocator()) HExit());
Aart Bik96709f12015-10-28 17:49:07 -0700778
David Brazdilbadd8262016-02-02 16:28:56 +0000779 graph_->BuildDominatorTree();
780
Aart Bik96709f12015-10-28 17:49:07 -0700781 const std::string expected_before =
782 "BasicBlock 0, succ: 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000783 " 0: ParameterValue [18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, "
784 "8, 8, 7, 6, 6, 5, 4, 4, 3]\n"
785 " 2: IntConstant [19, 17, 15, 13, 11, 9, 7, 5, 3]\n"
786 " 1: Goto 1\n"
Aart Bik96709f12015-10-28 17:49:07 -0700787 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000788 " 3: Above(2, 0) [4]\n"
789 " 4: Select(0, 0, 3)\n"
790 " 5: Above(0, 2) [6]\n"
791 " 6: Select(0, 0, 5)\n"
792 " 7: AboveOrEqual(2, 0) [8]\n"
793 " 8: Select(0, 0, 7)\n"
794 " 9: AboveOrEqual(0, 2) [10]\n"
795 " 10: Select(0, 0, 9)\n"
796 " 11: Below(2, 0) [12]\n"
797 " 12: Select(0, 0, 11)\n"
798 " 13: Below(0, 2) [14]\n"
799 " 14: Select(0, 0, 13)\n"
800 " 15: BelowOrEqual(2, 0) [16]\n"
801 " 16: Select(0, 0, 15)\n"
802 " 17: BelowOrEqual(0, 2) [18]\n"
803 " 18: Select(0, 0, 17)\n"
804 " 19: Return(2)\n"
Aart Bik96709f12015-10-28 17:49:07 -0700805 "BasicBlock 2, pred: 1\n"
806 " 20: Exit\n";
807
808 const std::string expected_after_cf =
809 "BasicBlock 0, succ: 1\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000810 " 0: ParameterValue [18, 18, 17, 16, 16, 14, 14, 12, 12, 11, 10, 10, "
811 "8, 8, 7, 6, 6, 5, 4, 4]\n"
812 " 2: IntConstant [14, 4, 19, 17, 11, 7, 5]\n"
813 " 21: IntConstant [16, 10]\n"
814 " 1: Goto 1\n"
Aart Bik96709f12015-10-28 17:49:07 -0700815 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000816 " 4: Select(0, 0, 2)\n"
817 " 5: Above(0, 2) [6]\n"
818 " 6: Select(0, 0, 5)\n"
819 " 7: AboveOrEqual(2, 0) [8]\n"
820 " 8: Select(0, 0, 7)\n"
821 " 10: Select(0, 0, 21)\n"
822 " 11: Below(2, 0) [12]\n"
823 " 12: Select(0, 0, 11)\n"
824 " 14: Select(0, 0, 2)\n"
825 " 16: Select(0, 0, 21)\n"
826 " 17: BelowOrEqual(0, 2) [18]\n"
827 " 18: Select(0, 0, 17)\n"
828 " 19: Return(2)\n"
Aart Bik96709f12015-10-28 17:49:07 -0700829 "BasicBlock 2, pred: 1\n"
830 " 20: Exit\n";
831
David Brazdilbadd8262016-02-02 16:28:56 +0000832 const std::string expected_after_dce =
833 "BasicBlock 0, succ: 1\n"
834 " 0: ParameterValue\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000835 " 2: IntConstant [19]\n"
836 " 1: Goto 1\n"
David Brazdilbadd8262016-02-02 16:28:56 +0000837 "BasicBlock 1, pred: 0, succ: 2\n"
David Brazdil86ea7ee2016-02-16 09:26:07 +0000838 " 19: Return(2)\n"
David Brazdilbadd8262016-02-02 16:28:56 +0000839 "BasicBlock 2, pred: 1\n"
840 " 20: Exit\n";
Aart Bik96709f12015-10-28 17:49:07 -0700841
842 auto check_after_cf = [](HGraph* graph) {
843 CHECK(graph != nullptr);
844 };
845
846 TestCodeOnReadyGraph(expected_before,
847 expected_after_cf,
848 expected_after_dce,
849 check_after_cf);
850}
851
Roland Levillain556c3d12014-09-18 15:25:07 +0100852} // namespace art