blob: a0fd5ffcb177a9c54e1004a0ee2f5472e6a94b99 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
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
Nicolas Geoffray360231a2014-10-08 21:07:48 +010017#include <functional>
Anton Kirilov3a2e78e2017-01-06 13:33:42 +000018#include <memory>
Nicolas Geoffray360231a2014-10-08 21:07:48 +010019
Alexandre Rames92730742014-10-01 12:55:56 +010020#include "base/macros.h"
David Sehrc431b9d2018-03-02 12:01:51 -080021#include "base/utils.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000022#include "builder.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010023#include "codegen_test_utils.h"
David Sehr9e734c72018-01-04 17:56:19 -080024#include "dex/dex_file.h"
25#include "dex/dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000026#include "driver/compiler_options.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000027#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000028#include "optimizing_unit_test.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070029#include "register_allocator_linear_scan.h"
Scott Wakelingfe885462016-09-22 10:24:38 +010030#include "utils/arm/assembler_arm_vixl.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010031#include "utils/arm/managed_register_arm.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020032#include "utils/mips/managed_register_mips.h"
Alexey Frunze4dda3372015-06-01 18:31:49 -070033#include "utils/mips64/managed_register_mips64.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010034#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035
36#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000037
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000038namespace art {
39
Scott Wakeling2c76e062016-08-31 09:48:54 +010040// Return all combinations of ISA and code generator that are executable on
41// hardware, or on simulator, and that we'd like to test.
42static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
43 ::std::vector<CodegenTargetConfig> v;
44 ::std::vector<CodegenTargetConfig> test_config_candidates = {
45#ifdef ART_ENABLE_CODEGEN_arm
Roland Levillain9983e302017-07-14 14:34:22 +010046 // TODO: Should't this be `kThumb2` instead of `kArm` here?
Vladimir Marko33bff252017-11-01 14:35:42 +000047 CodegenTargetConfig(InstructionSet::kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +010048#endif
49#ifdef ART_ENABLE_CODEGEN_arm64
Vladimir Marko33bff252017-11-01 14:35:42 +000050 CodegenTargetConfig(InstructionSet::kArm64, create_codegen_arm64),
Scott Wakeling2c76e062016-08-31 09:48:54 +010051#endif
52#ifdef ART_ENABLE_CODEGEN_x86
Vladimir Marko33bff252017-11-01 14:35:42 +000053 CodegenTargetConfig(InstructionSet::kX86, create_codegen_x86),
Scott Wakeling2c76e062016-08-31 09:48:54 +010054#endif
55#ifdef ART_ENABLE_CODEGEN_x86_64
Vladimir Marko33bff252017-11-01 14:35:42 +000056 CodegenTargetConfig(InstructionSet::kX86_64, create_codegen_x86_64),
Scott Wakeling2c76e062016-08-31 09:48:54 +010057#endif
58#ifdef ART_ENABLE_CODEGEN_mips
Vladimir Marko33bff252017-11-01 14:35:42 +000059 CodegenTargetConfig(InstructionSet::kMips, create_codegen_mips),
Scott Wakeling2c76e062016-08-31 09:48:54 +010060#endif
61#ifdef ART_ENABLE_CODEGEN_mips64
Vladimir Marko33bff252017-11-01 14:35:42 +000062 CodegenTargetConfig(InstructionSet::kMips64, create_codegen_mips64)
Scott Wakeling2c76e062016-08-31 09:48:54 +010063#endif
David Brazdil58282f42016-01-14 12:45:10 +000064 };
65
Vladimir Marko7d157fc2017-05-10 16:29:23 +010066 for (const CodegenTargetConfig& test_config : test_config_candidates) {
Scott Wakeling2c76e062016-08-31 09:48:54 +010067 if (CanExecute(test_config.GetInstructionSet())) {
68 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +000069 }
70 }
71
72 return v;
73}
74
Vladimir Markoca6fff82017-10-03 14:49:14 +010075class CodegenTest : public OptimizingUnitTest {
76 protected:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080077 void TestCode(const std::vector<uint16_t>& data, bool has_result = false, int32_t expected = 0);
78 void TestCodeLong(const std::vector<uint16_t>& data, bool has_result, int64_t expected);
Vladimir Markoca6fff82017-10-03 14:49:14 +010079 void TestComparison(IfCondition condition,
80 int64_t i,
81 int64_t j,
82 DataType::Type type,
83 const CodegenTargetConfig target_config);
84};
85
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080086void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, int32_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010087 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010088 ResetPoolAndAllocator();
89 HGraph* graph = CreateCFG(data);
David Brazdil58282f42016-01-14 12:45:10 +000090 // Remove suspend checks, they cannot be executed in this context.
91 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010092 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000093 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010094}
95
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080096void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
97 bool has_result, int64_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010098 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010099 ResetPoolAndAllocator();
100 HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
David Brazdil58282f42016-01-14 12:45:10 +0000101 // Remove suspend checks, they cannot be executed in this context.
102 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100103 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000104 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100105}
106
David Brazdil58282f42016-01-14 12:45:10 +0000107TEST_F(CodegenTest, ReturnVoid) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800108 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000109 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000110}
111
David Brazdil58282f42016-01-14 12:45:10 +0000112TEST_F(CodegenTest, CFG1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800113 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000114 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000115 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000116
David Brazdil58282f42016-01-14 12:45:10 +0000117 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000118}
119
David Brazdil58282f42016-01-14 12:45:10 +0000120TEST_F(CodegenTest, CFG2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800121 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000122 Instruction::GOTO | 0x100,
123 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000124 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000125
David Brazdil58282f42016-01-14 12:45:10 +0000126 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000127}
128
David Brazdil58282f42016-01-14 12:45:10 +0000129TEST_F(CodegenTest, CFG3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800130 const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000131 Instruction::GOTO | 0x200,
132 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000133 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000134
David Brazdil58282f42016-01-14 12:45:10 +0000135 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000136
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800137 const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000138 Instruction::GOTO_16, 3,
139 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000140 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000141
David Brazdil58282f42016-01-14 12:45:10 +0000142 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000143
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800144 const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000145 Instruction::GOTO_32, 4, 0,
146 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000147 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000148
David Brazdil58282f42016-01-14 12:45:10 +0000149 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150}
151
David Brazdil58282f42016-01-14 12:45:10 +0000152TEST_F(CodegenTest, CFG4) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800153 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000154 Instruction::RETURN_VOID,
155 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000156 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000157
David Brazdil58282f42016-01-14 12:45:10 +0000158 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000159}
160
David Brazdil58282f42016-01-14 12:45:10 +0000161TEST_F(CodegenTest, CFG5) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800162 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000163 Instruction::CONST_4 | 0 | 0,
164 Instruction::IF_EQ, 3,
165 Instruction::GOTO | 0x100,
166 Instruction::RETURN_VOID);
167
David Brazdil58282f42016-01-14 12:45:10 +0000168 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000169}
170
David Brazdil58282f42016-01-14 12:45:10 +0000171TEST_F(CodegenTest, IntConstant) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800172 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000173 Instruction::CONST_4 | 0 | 0,
174 Instruction::RETURN_VOID);
175
David Brazdil58282f42016-01-14 12:45:10 +0000176 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000177}
178
David Brazdil58282f42016-01-14 12:45:10 +0000179TEST_F(CodegenTest, Return1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800180 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000181 Instruction::CONST_4 | 0 | 0,
182 Instruction::RETURN | 0);
183
David Brazdil58282f42016-01-14 12:45:10 +0000184 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000185}
186
David Brazdil58282f42016-01-14 12:45:10 +0000187TEST_F(CodegenTest, Return2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800188 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000189 Instruction::CONST_4 | 0 | 0,
190 Instruction::CONST_4 | 0 | 1 << 8,
191 Instruction::RETURN | 1 << 8);
192
David Brazdil58282f42016-01-14 12:45:10 +0000193 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000194}
195
David Brazdil58282f42016-01-14 12:45:10 +0000196TEST_F(CodegenTest, Return3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800197 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000198 Instruction::CONST_4 | 0 | 0,
199 Instruction::CONST_4 | 1 << 8 | 1 << 12,
200 Instruction::RETURN | 1 << 8);
201
David Brazdil58282f42016-01-14 12:45:10 +0000202 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000203}
204
David Brazdil58282f42016-01-14 12:45:10 +0000205TEST_F(CodegenTest, ReturnIf1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800206 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000207 Instruction::CONST_4 | 0 | 0,
208 Instruction::CONST_4 | 1 << 8 | 1 << 12,
209 Instruction::IF_EQ, 3,
210 Instruction::RETURN | 0 << 8,
211 Instruction::RETURN | 1 << 8);
212
David Brazdil58282f42016-01-14 12:45:10 +0000213 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000214}
215
David Brazdil58282f42016-01-14 12:45:10 +0000216TEST_F(CodegenTest, ReturnIf2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800217 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000218 Instruction::CONST_4 | 0 | 0,
219 Instruction::CONST_4 | 1 << 8 | 1 << 12,
220 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
221 Instruction::RETURN | 0 << 8,
222 Instruction::RETURN | 1 << 8);
223
David Brazdil58282f42016-01-14 12:45:10 +0000224 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000225}
226
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100227// Exercise bit-wise (one's complement) not-int instruction.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800228#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
229TEST_F(CodegenTest, TEST_NAME) { \
230 const int32_t input = INPUT; \
231 const uint16_t input_lo = Low16Bits(input); \
232 const uint16_t input_hi = High16Bits(input); \
233 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( \
234 Instruction::CONST | 0 << 8, input_lo, input_hi, \
235 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
236 Instruction::RETURN | 1 << 8); \
237 \
238 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100239}
240
241NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
242NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
243NOT_INT_TEST(ReturnNotInt0, 0, -1)
244NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100245NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
246NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
247NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
248NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100249
250#undef NOT_INT_TEST
251
Roland Levillain55dcfb52014-10-24 18:09:09 +0100252// Exercise bit-wise (one's complement) not-long instruction.
253#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000254TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100255 const int64_t input = INPUT; \
256 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
257 const uint16_t word1 = High16Bits(Low32Bits(input)); \
258 const uint16_t word2 = Low16Bits(High32Bits(input)); \
259 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800260 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM( \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100261 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
262 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
263 Instruction::RETURN_WIDE | 2 << 8); \
264 \
David Brazdil58282f42016-01-14 12:45:10 +0000265 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100266}
267
268NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
269NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
270NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
271NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
272
273NOT_LONG_TEST(ReturnNotLongINT32_MIN,
274 INT64_C(-2147483648),
275 INT64_C(2147483647)) // (2^31) - 1
276NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
277 INT64_C(-2147483647),
278 INT64_C(2147483646)) // (2^31) - 2
279NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
280 INT64_C(2147483646),
281 INT64_C(-2147483647)) // -(2^31) - 1
282NOT_LONG_TEST(ReturnNotLongINT32_MAX,
283 INT64_C(2147483647),
284 INT64_C(-2147483648)) // -(2^31)
285
286// Note that the C++ compiler won't accept
287// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
288// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
289NOT_LONG_TEST(ReturnNotINT64_MIN,
290 INT64_C(-9223372036854775807)-1,
291 INT64_C(9223372036854775807)); // (2^63) - 1
292NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
293 INT64_C(-9223372036854775807),
294 INT64_C(9223372036854775806)); // (2^63) - 2
295NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
296 INT64_C(9223372036854775806),
297 INT64_C(-9223372036854775807)); // -(2^63) - 1
298NOT_LONG_TEST(ReturnNotLongINT64_MAX,
299 INT64_C(9223372036854775807),
300 INT64_C(-9223372036854775807)-1); // -(2^63)
301
302#undef NOT_LONG_TEST
303
David Brazdil58282f42016-01-14 12:45:10 +0000304TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000305 const int64_t input = INT64_C(4294967296); // 2^32
306 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
307 const uint16_t word1 = High16Bits(Low32Bits(input));
308 const uint16_t word2 = Low16Bits(High32Bits(input));
309 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800310 const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
Roland Levillain946e1432014-11-11 17:35:19 +0000311 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
312 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
313 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
314 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
315 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
316 Instruction::RETURN_WIDE | 2 << 8);
317
David Brazdil58282f42016-01-14 12:45:10 +0000318 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000319}
320
David Brazdil58282f42016-01-14 12:45:10 +0000321TEST_F(CodegenTest, ReturnAdd1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800322 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000323 Instruction::CONST_4 | 3 << 12 | 0,
324 Instruction::CONST_4 | 4 << 12 | 1 << 8,
325 Instruction::ADD_INT, 1 << 8 | 0,
326 Instruction::RETURN);
327
David Brazdil58282f42016-01-14 12:45:10 +0000328 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000329}
330
David Brazdil58282f42016-01-14 12:45:10 +0000331TEST_F(CodegenTest, ReturnAdd2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800332 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000333 Instruction::CONST_4 | 3 << 12 | 0,
334 Instruction::CONST_4 | 4 << 12 | 1 << 8,
335 Instruction::ADD_INT_2ADDR | 1 << 12,
336 Instruction::RETURN);
337
David Brazdil58282f42016-01-14 12:45:10 +0000338 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000339}
340
David Brazdil58282f42016-01-14 12:45:10 +0000341TEST_F(CodegenTest, ReturnAdd3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800342 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000343 Instruction::CONST_4 | 4 << 12 | 0 << 8,
344 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
345 Instruction::RETURN);
346
David Brazdil58282f42016-01-14 12:45:10 +0000347 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000348}
349
David Brazdil58282f42016-01-14 12:45:10 +0000350TEST_F(CodegenTest, ReturnAdd4) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800351 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000352 Instruction::CONST_4 | 4 << 12 | 0 << 8,
353 Instruction::ADD_INT_LIT16, 3,
354 Instruction::RETURN);
355
David Brazdil58282f42016-01-14 12:45:10 +0000356 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000357}
358
David Brazdil58282f42016-01-14 12:45:10 +0000359TEST_F(CodegenTest, ReturnMulInt) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800360 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100361 Instruction::CONST_4 | 3 << 12 | 0,
362 Instruction::CONST_4 | 4 << 12 | 1 << 8,
363 Instruction::MUL_INT, 1 << 8 | 0,
364 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100365
David Brazdil58282f42016-01-14 12:45:10 +0000366 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100367}
368
David Brazdil58282f42016-01-14 12:45:10 +0000369TEST_F(CodegenTest, ReturnMulInt2addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800370 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100371 Instruction::CONST_4 | 3 << 12 | 0,
372 Instruction::CONST_4 | 4 << 12 | 1 << 8,
373 Instruction::MUL_INT_2ADDR | 1 << 12,
374 Instruction::RETURN);
375
David Brazdil58282f42016-01-14 12:45:10 +0000376 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100377}
378
David Brazdil58282f42016-01-14 12:45:10 +0000379TEST_F(CodegenTest, ReturnMulLong) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800380 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000381 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
382 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100383 Instruction::MUL_LONG, 2 << 8 | 0,
384 Instruction::RETURN_WIDE);
385
David Brazdil58282f42016-01-14 12:45:10 +0000386 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100387}
388
David Brazdil58282f42016-01-14 12:45:10 +0000389TEST_F(CodegenTest, ReturnMulLong2addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800390 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000391 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
392 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100393 Instruction::MUL_LONG_2ADDR | 2 << 12,
394 Instruction::RETURN_WIDE);
395
David Brazdil58282f42016-01-14 12:45:10 +0000396 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100397}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100398
David Brazdil58282f42016-01-14 12:45:10 +0000399TEST_F(CodegenTest, ReturnMulIntLit8) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800400 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100401 Instruction::CONST_4 | 4 << 12 | 0 << 8,
402 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
403 Instruction::RETURN);
404
David Brazdil58282f42016-01-14 12:45:10 +0000405 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100406}
407
David Brazdil58282f42016-01-14 12:45:10 +0000408TEST_F(CodegenTest, ReturnMulIntLit16) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800409 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100410 Instruction::CONST_4 | 4 << 12 | 0 << 8,
411 Instruction::MUL_INT_LIT16, 3,
412 Instruction::RETURN);
413
David Brazdil58282f42016-01-14 12:45:10 +0000414 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100415}
416
David Brazdil58282f42016-01-14 12:45:10 +0000417TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100418 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100419 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000420
Vladimir Markoca6fff82017-10-03 14:49:14 +0100421 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000422 graph->AddBlock(entry);
423 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100424 entry->AddInstruction(new (GetAllocator()) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100425
Vladimir Markoca6fff82017-10-03 14:49:14 +0100426 HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000427 graph->AddBlock(first_block);
428 entry->AddSuccessor(first_block);
429 HIntConstant* constant0 = graph->GetIntConstant(0);
430 HIntConstant* constant1 = graph->GetIntConstant(1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100431 HEqual* equal = new (GetAllocator()) HEqual(constant0, constant0);
David Brazdil58282f42016-01-14 12:45:10 +0000432 first_block->AddInstruction(equal);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100433 first_block->AddInstruction(new (GetAllocator()) HIf(equal));
David Brazdil58282f42016-01-14 12:45:10 +0000434
Vladimir Markoca6fff82017-10-03 14:49:14 +0100435 HBasicBlock* then_block = new (GetAllocator()) HBasicBlock(graph);
436 HBasicBlock* else_block = new (GetAllocator()) HBasicBlock(graph);
437 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100438 graph->SetExitBlock(exit_block);
439
David Brazdil58282f42016-01-14 12:45:10 +0000440 graph->AddBlock(then_block);
441 graph->AddBlock(else_block);
442 graph->AddBlock(exit_block);
443 first_block->AddSuccessor(then_block);
444 first_block->AddSuccessor(else_block);
445 then_block->AddSuccessor(exit_block);
446 else_block->AddSuccessor(exit_block);
447
Vladimir Markoca6fff82017-10-03 14:49:14 +0100448 exit_block->AddInstruction(new (GetAllocator()) HExit());
449 then_block->AddInstruction(new (GetAllocator()) HReturn(constant0));
450 else_block->AddInstruction(new (GetAllocator()) HReturn(constant1));
David Brazdil58282f42016-01-14 12:45:10 +0000451
David Brazdilb11b0722016-01-28 16:22:40 +0000452 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000453 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000454 PrepareForRegisterAllocation(graph).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000455 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100456
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800457 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100458 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100459 HParallelMove* move = new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
Alexandre Rames92730742014-10-01 12:55:56 +0100460 block->InsertInstructionBefore(move, block->GetLastInstruction());
461 };
462
Scott Wakeling2c76e062016-08-31 09:48:54 +0100463 RunCode(target_config, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100464 }
465}
466
David Brazdil58282f42016-01-14 12:45:10 +0000467TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100468 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000469 // Check that condition are materialized correctly. A materialized condition
470 // should yield `1` if it evaluated to true, and `0` otherwise.
471 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100472
David Brazdil58282f42016-01-14 12:45:10 +0000473 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100474
David Brazdil58282f42016-01-14 12:45:10 +0000475 int lhs[] = {1, 2, -1, 2, 0xabc};
476 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100477
David Brazdil58282f42016-01-14 12:45:10 +0000478 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100479 HGraph* graph = CreateGraph();
Alexandre Rames92730742014-10-01 12:55:56 +0100480
Vladimir Markoca6fff82017-10-03 14:49:14 +0100481 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000482 graph->AddBlock(entry_block);
483 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100484 entry_block->AddInstruction(new (GetAllocator()) HGoto());
485 HBasicBlock* code_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000486 graph->AddBlock(code_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100487 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000488 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100489 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100490
David Brazdil58282f42016-01-14 12:45:10 +0000491 entry_block->AddSuccessor(code_block);
492 code_block->AddSuccessor(exit_block);
493 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100494
David Brazdil58282f42016-01-14 12:45:10 +0000495 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
496 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
497 HLessThan cmp_lt(cst_lhs, cst_rhs);
498 code_block->AddInstruction(&cmp_lt);
499 HReturn ret(&cmp_lt);
500 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100501
David Brazdilbadd8262016-02-02 16:28:56 +0000502 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000503 auto hook_before_codegen = [](HGraph* graph_in) {
504 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100505 HParallelMove* move =
506 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000507 block->InsertInstructionBefore(move, block->GetLastInstruction());
508 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100509 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000510 }
Alexandre Rames92730742014-10-01 12:55:56 +0100511 }
512}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100513
David Brazdil58282f42016-01-14 12:45:10 +0000514TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100515 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000516 // Check that HIf correctly interprets a materialized condition.
517 // We force the materialization of comparisons for different combinations of
518 // inputs. An HIf takes the materialized combination as input and returns a
519 // value that we verify.
520
521 int lhs[] = {1, 2, -1, 2, 0xabc};
522 int rhs[] = {2, 1, 2, -1, 0xabc};
523
524
525 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100526 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000527
Vladimir Markoca6fff82017-10-03 14:49:14 +0100528 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000529 graph->AddBlock(entry_block);
530 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100531 entry_block->AddInstruction(new (GetAllocator()) HGoto());
David Brazdil58282f42016-01-14 12:45:10 +0000532
Vladimir Markoca6fff82017-10-03 14:49:14 +0100533 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000534 graph->AddBlock(if_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100535 HBasicBlock* if_true_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000536 graph->AddBlock(if_true_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100537 HBasicBlock* if_false_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000538 graph->AddBlock(if_false_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100539 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000540 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100541 exit_block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil58282f42016-01-14 12:45:10 +0000542
543 graph->SetEntryBlock(entry_block);
544 entry_block->AddSuccessor(if_block);
545 if_block->AddSuccessor(if_true_block);
546 if_block->AddSuccessor(if_false_block);
547 if_true_block->AddSuccessor(exit_block);
548 if_false_block->AddSuccessor(exit_block);
549 graph->SetExitBlock(exit_block);
550
551 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
552 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
553 HLessThan cmp_lt(cst_lhs, cst_rhs);
554 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000555 // We insert a dummy instruction to separate the HIf from the HLessThan
556 // and force the materialization of the condition.
557 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000558 if_block->AddInstruction(&force_materialization);
559 HIf if_lt(&cmp_lt);
560 if_block->AddInstruction(&if_lt);
561
562 HIntConstant* cst_lt = graph->GetIntConstant(1);
563 HReturn ret_lt(cst_lt);
564 if_true_block->AddInstruction(&ret_lt);
565 HIntConstant* cst_ge = graph->GetIntConstant(0);
566 HReturn ret_ge(cst_ge);
567 if_false_block->AddInstruction(&ret_ge);
568
David Brazdilbadd8262016-02-02 16:28:56 +0000569 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000570 auto hook_before_codegen = [](HGraph* graph_in) {
571 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100572 HParallelMove* move =
573 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000574 block->InsertInstructionBefore(move, block->GetLastInstruction());
575 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100576 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000577 }
578 }
579}
580
581TEST_F(CodegenTest, ReturnDivIntLit8) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800582 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravled0d48522014-11-04 16:40:20 +0000583 Instruction::CONST_4 | 4 << 12 | 0 << 8,
584 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
585 Instruction::RETURN);
586
David Brazdil58282f42016-01-14 12:45:10 +0000587 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000588}
589
David Brazdil58282f42016-01-14 12:45:10 +0000590TEST_F(CodegenTest, ReturnDivInt2Addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800591 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Calin Juravle865fc882014-11-06 17:09:03 +0000592 Instruction::CONST_4 | 4 << 12 | 0,
593 Instruction::CONST_4 | 2 << 12 | 1 << 8,
594 Instruction::DIV_INT_2ADDR | 1 << 12,
595 Instruction::RETURN);
596
David Brazdil58282f42016-01-14 12:45:10 +0000597 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000598}
599
Aart Bike9f37602015-10-09 11:15:55 -0700600// Helper method.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100601void CodegenTest::TestComparison(IfCondition condition,
602 int64_t i,
603 int64_t j,
604 DataType::Type type,
605 const CodegenTargetConfig target_config) {
606 HGraph* graph = CreateGraph();
Aart Bike9f37602015-10-09 11:15:55 -0700607
Vladimir Markoca6fff82017-10-03 14:49:14 +0100608 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700609 graph->AddBlock(entry_block);
610 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100611 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Aart Bike9f37602015-10-09 11:15:55 -0700612
Vladimir Markoca6fff82017-10-03 14:49:14 +0100613 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700614 graph->AddBlock(block);
615
Vladimir Markoca6fff82017-10-03 14:49:14 +0100616 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700617 graph->AddBlock(exit_block);
618 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100619 exit_block->AddInstruction(new (GetAllocator()) HExit());
Aart Bike9f37602015-10-09 11:15:55 -0700620
621 entry_block->AddSuccessor(block);
622 block->AddSuccessor(exit_block);
623
624 HInstruction* op1;
625 HInstruction* op2;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100626 if (type == DataType::Type::kInt32) {
Aart Bike9f37602015-10-09 11:15:55 -0700627 op1 = graph->GetIntConstant(i);
628 op2 = graph->GetIntConstant(j);
629 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100630 DCHECK_EQ(type, DataType::Type::kInt64);
Aart Bike9f37602015-10-09 11:15:55 -0700631 op1 = graph->GetLongConstant(i);
632 op2 = graph->GetLongConstant(j);
633 }
634
635 HInstruction* comparison = nullptr;
636 bool expected_result = false;
637 const uint64_t x = i;
638 const uint64_t y = j;
639 switch (condition) {
640 case kCondEQ:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100641 comparison = new (GetAllocator()) HEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700642 expected_result = (i == j);
643 break;
644 case kCondNE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100645 comparison = new (GetAllocator()) HNotEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700646 expected_result = (i != j);
647 break;
648 case kCondLT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100649 comparison = new (GetAllocator()) HLessThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700650 expected_result = (i < j);
651 break;
652 case kCondLE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100653 comparison = new (GetAllocator()) HLessThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700654 expected_result = (i <= j);
655 break;
656 case kCondGT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100657 comparison = new (GetAllocator()) HGreaterThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700658 expected_result = (i > j);
659 break;
660 case kCondGE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100661 comparison = new (GetAllocator()) HGreaterThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700662 expected_result = (i >= j);
663 break;
664 case kCondB:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100665 comparison = new (GetAllocator()) HBelow(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700666 expected_result = (x < y);
667 break;
668 case kCondBE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100669 comparison = new (GetAllocator()) HBelowOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700670 expected_result = (x <= y);
671 break;
672 case kCondA:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100673 comparison = new (GetAllocator()) HAbove(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700674 expected_result = (x > y);
675 break;
676 case kCondAE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100677 comparison = new (GetAllocator()) HAboveOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700678 expected_result = (x >= y);
679 break;
680 }
681 block->AddInstruction(comparison);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100682 block->AddInstruction(new (GetAllocator()) HReturn(comparison));
Aart Bike9f37602015-10-09 11:15:55 -0700683
David Brazdilbadd8262016-02-02 16:28:56 +0000684 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +0100685 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700686}
687
David Brazdil58282f42016-01-14 12:45:10 +0000688TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100689 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000690 for (int64_t i = -1; i <= 1; i++) {
691 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100692 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100693 TestComparison(
694 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100695 }
David Brazdil58282f42016-01-14 12:45:10 +0000696 }
Aart Bike9f37602015-10-09 11:15:55 -0700697 }
698 }
699}
700
David Brazdil58282f42016-01-14 12:45:10 +0000701TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100702 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000703 for (int64_t i = -1; i <= 1; i++) {
704 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100705 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100706 TestComparison(
707 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100708 }
David Brazdil58282f42016-01-14 12:45:10 +0000709 }
Aart Bike9f37602015-10-09 11:15:55 -0700710 }
711 }
712}
713
Artem Serov4593f7d2016-12-29 16:21:49 +0000714#ifdef ART_ENABLE_CODEGEN_arm
715TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
716 std::unique_ptr<const ArmInstructionSetFeatures> features(
717 ArmInstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100718 HGraph* graph = CreateGraph();
Artem Serov4593f7d2016-12-29 16:21:49 +0000719 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
720
721 codegen.Initialize();
722
723 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
724 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
725 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
726 // LDR encoding. So the following code is a regression test for that situation.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100727 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100728 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
729 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
Artem Serov4593f7d2016-12-29 16:21:49 +0000730 codegen.GetMoveResolver()->EmitNativeCode(move);
731
732 InternalCodeAllocator code_allocator;
733 codegen.Finalize(&code_allocator);
734}
735#endif
736
Roland Levillain558dea12017-01-27 19:40:44 +0000737#ifdef ART_ENABLE_CODEGEN_arm64
738// Regression test for b/34760542.
739TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
740 std::unique_ptr<const Arm64InstructionSetFeatures> features(
741 Arm64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100742 HGraph* graph = CreateGraph();
Roland Levillain558dea12017-01-27 19:40:44 +0000743 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
744
745 codegen.Initialize();
746
747 // The following ParallelMove used to fail this assertion:
748 //
749 // Assertion failed (!available->IsEmpty())
750 //
Roland Levillain952b2352017-05-03 19:49:14 +0100751 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
752 // because of the following situation:
753 //
754 // 1. a temp register (IP0) is allocated as a scratch register by
755 // the parallel move resolver to solve a cycle (swap):
756 //
757 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
758 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
759 //
760 // 2. within CodeGeneratorARM64::MoveLocation, another temp
761 // register (IP1) is allocated to generate the swap between two
762 // double stack slots;
763 //
764 // 3. VIXL requires a third temp register to emit the `Ldr` or
765 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
766 // one of the stack slots' offsets cannot be encoded as an
767 // immediate), but the pool of (core) temp registers is now
768 // empty.
769 //
770 // The solution used so far is to use a floating-point temp register
771 // (D31) in step #2, so that IP1 is available for step #3.
772
Vladimir Markoca6fff82017-10-03 14:49:14 +0100773 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Roland Levillain558dea12017-01-27 19:40:44 +0000774 move->AddMove(Location::DoubleStackSlot(0),
775 Location::DoubleStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100776 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000777 nullptr);
778 move->AddMove(Location::DoubleStackSlot(257),
779 Location::DoubleStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100780 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000781 nullptr);
782 codegen.GetMoveResolver()->EmitNativeCode(move);
783
784 InternalCodeAllocator code_allocator;
785 codegen.Finalize(&code_allocator);
786}
Artem Serovd4bccf12017-04-03 18:47:32 +0100787
788// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
789TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
790 std::unique_ptr<const Arm64InstructionSetFeatures> features(
791 Arm64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100792 HGraph* graph = CreateGraph();
Artem Serovd4bccf12017-04-03 18:47:32 +0100793 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
794
795 codegen.Initialize();
796
797 graph->SetHasSIMD(true);
798 for (int i = 0; i < 2; i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100799 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Artem Serovd4bccf12017-04-03 18:47:32 +0100800 move->AddMove(Location::SIMDStackSlot(0),
801 Location::SIMDStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100802 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100803 nullptr);
804 move->AddMove(Location::SIMDStackSlot(257),
805 Location::SIMDStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100806 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100807 nullptr);
808 move->AddMove(Location::FpuRegisterLocation(0),
809 Location::FpuRegisterLocation(1),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100810 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100811 nullptr);
812 move->AddMove(Location::FpuRegisterLocation(1),
813 Location::FpuRegisterLocation(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100814 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100815 nullptr);
816 codegen.GetMoveResolver()->EmitNativeCode(move);
817 graph->SetHasSIMD(false);
818 }
819
820 InternalCodeAllocator code_allocator;
821 codegen.Finalize(&code_allocator);
822}
Roland Levillain558dea12017-01-27 19:40:44 +0000823#endif
824
Alexey Frunze58320ce2016-08-30 21:40:46 -0700825#ifdef ART_ENABLE_CODEGEN_mips
826TEST_F(CodegenTest, MipsClobberRA) {
827 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
828 MipsInstructionSetFeatures::FromCppDefines());
Vladimir Marko33bff252017-11-01 14:35:42 +0000829 if (!CanExecute(InstructionSet::kMips) || features_mips->IsR6()) {
Alexey Frunze58320ce2016-08-30 21:40:46 -0700830 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
831 // should only be generated on non-R6.
832 return;
833 }
834
Vladimir Markoca6fff82017-10-03 14:49:14 +0100835 HGraph* graph = CreateGraph();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700836
Vladimir Markoca6fff82017-10-03 14:49:14 +0100837 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700838 graph->AddBlock(entry_block);
839 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100840 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700841
Vladimir Markoca6fff82017-10-03 14:49:14 +0100842 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700843 graph->AddBlock(block);
844
Vladimir Markoca6fff82017-10-03 14:49:14 +0100845 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700846 graph->AddBlock(exit_block);
847 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100848 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700849
850 entry_block->AddSuccessor(block);
851 block->AddSuccessor(exit_block);
852
853 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
854 // Instead, generate HMipsComputeBaseMethodAddress directly.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100855 HMipsComputeBaseMethodAddress* base = new (GetAllocator()) HMipsComputeBaseMethodAddress();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700856 block->AddInstruction(base);
857 // HMipsComputeBaseMethodAddress is defined as int, so just make the
858 // compiled method return it.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100859 block->AddInstruction(new (GetAllocator()) HReturn(base));
Alexey Frunze58320ce2016-08-30 21:40:46 -0700860
861 graph->BuildDominatorTree();
862
863 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
864 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
865 // that RA is clobbered and the method entry code should generate a stack frame
866 // and preserve RA in it. And this is what we're testing here.
867 codegenMIPS.ClobberRA();
868 // Without ClobberRA() the code would be:
869 // nal # Sets RA to point to the jr instruction below
870 // move v0, ra # and the CPU falls into an infinite loop.
871 // jr ra
872 // nop
873 // The expected code is:
874 // addiu sp, sp, -16
875 // sw ra, 12(sp)
876 // sw a0, 0(sp)
877 // nal # Sets RA to point to the lw instruction below.
878 // move v0, ra
879 // lw ra, 12(sp)
880 // jr ra
881 // addiu sp, sp, 16
882 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
883}
884#endif
885
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000886} // namespace art