blob: 26d07bd5920c2b7bed6a9670426201c69e730999 [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);
Vladimir Markoa0431112018-06-25 09:32:54 +010092 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
93 RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000094 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010095}
96
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080097void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
98 bool has_result, int64_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010099 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100100 ResetPoolAndAllocator();
101 HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
David Brazdil58282f42016-01-14 12:45:10 +0000102 // Remove suspend checks, they cannot be executed in this context.
103 RemoveSuspendChecks(graph);
Vladimir Markoa0431112018-06-25 09:32:54 +0100104 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
105 RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000106 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100107}
108
David Brazdil58282f42016-01-14 12:45:10 +0000109TEST_F(CodegenTest, ReturnVoid) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800110 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000111 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000112}
113
David Brazdil58282f42016-01-14 12:45:10 +0000114TEST_F(CodegenTest, CFG1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800115 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000116 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000117 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000118
David Brazdil58282f42016-01-14 12:45:10 +0000119 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000120}
121
David Brazdil58282f42016-01-14 12:45:10 +0000122TEST_F(CodegenTest, CFG2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800123 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000124 Instruction::GOTO | 0x100,
125 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000126 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000127
David Brazdil58282f42016-01-14 12:45:10 +0000128 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000129}
130
David Brazdil58282f42016-01-14 12:45:10 +0000131TEST_F(CodegenTest, CFG3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800132 const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000133 Instruction::GOTO | 0x200,
134 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000135 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000136
David Brazdil58282f42016-01-14 12:45:10 +0000137 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000138
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800139 const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000140 Instruction::GOTO_16, 3,
141 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000142 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000143
David Brazdil58282f42016-01-14 12:45:10 +0000144 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000145
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800146 const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000147 Instruction::GOTO_32, 4, 0,
148 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000149 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150
David Brazdil58282f42016-01-14 12:45:10 +0000151 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000152}
153
David Brazdil58282f42016-01-14 12:45:10 +0000154TEST_F(CodegenTest, CFG4) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800155 const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000156 Instruction::RETURN_VOID,
157 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000158 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000159
David Brazdil58282f42016-01-14 12:45:10 +0000160 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000161}
162
David Brazdil58282f42016-01-14 12:45:10 +0000163TEST_F(CodegenTest, CFG5) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800164 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000165 Instruction::CONST_4 | 0 | 0,
166 Instruction::IF_EQ, 3,
167 Instruction::GOTO | 0x100,
168 Instruction::RETURN_VOID);
169
David Brazdil58282f42016-01-14 12:45:10 +0000170 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000171}
172
David Brazdil58282f42016-01-14 12:45:10 +0000173TEST_F(CodegenTest, IntConstant) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800174 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000175 Instruction::CONST_4 | 0 | 0,
176 Instruction::RETURN_VOID);
177
David Brazdil58282f42016-01-14 12:45:10 +0000178 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000179}
180
David Brazdil58282f42016-01-14 12:45:10 +0000181TEST_F(CodegenTest, Return1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800182 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000183 Instruction::CONST_4 | 0 | 0,
184 Instruction::RETURN | 0);
185
David Brazdil58282f42016-01-14 12:45:10 +0000186 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000187}
188
David Brazdil58282f42016-01-14 12:45:10 +0000189TEST_F(CodegenTest, Return2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800190 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000191 Instruction::CONST_4 | 0 | 0,
192 Instruction::CONST_4 | 0 | 1 << 8,
193 Instruction::RETURN | 1 << 8);
194
David Brazdil58282f42016-01-14 12:45:10 +0000195 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000196}
197
David Brazdil58282f42016-01-14 12:45:10 +0000198TEST_F(CodegenTest, Return3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800199 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000200 Instruction::CONST_4 | 0 | 0,
201 Instruction::CONST_4 | 1 << 8 | 1 << 12,
202 Instruction::RETURN | 1 << 8);
203
David Brazdil58282f42016-01-14 12:45:10 +0000204 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000205}
206
David Brazdil58282f42016-01-14 12:45:10 +0000207TEST_F(CodegenTest, ReturnIf1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800208 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000209 Instruction::CONST_4 | 0 | 0,
210 Instruction::CONST_4 | 1 << 8 | 1 << 12,
211 Instruction::IF_EQ, 3,
212 Instruction::RETURN | 0 << 8,
213 Instruction::RETURN | 1 << 8);
214
David Brazdil58282f42016-01-14 12:45:10 +0000215 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000216}
217
David Brazdil58282f42016-01-14 12:45:10 +0000218TEST_F(CodegenTest, ReturnIf2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800219 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000220 Instruction::CONST_4 | 0 | 0,
221 Instruction::CONST_4 | 1 << 8 | 1 << 12,
222 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
223 Instruction::RETURN | 0 << 8,
224 Instruction::RETURN | 1 << 8);
225
David Brazdil58282f42016-01-14 12:45:10 +0000226 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000227}
228
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100229// Exercise bit-wise (one's complement) not-int instruction.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800230#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
231TEST_F(CodegenTest, TEST_NAME) { \
232 const int32_t input = INPUT; \
233 const uint16_t input_lo = Low16Bits(input); \
234 const uint16_t input_hi = High16Bits(input); \
235 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( \
236 Instruction::CONST | 0 << 8, input_lo, input_hi, \
237 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
238 Instruction::RETURN | 1 << 8); \
239 \
240 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100241}
242
243NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
244NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
245NOT_INT_TEST(ReturnNotInt0, 0, -1)
246NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100247NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
248NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
249NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
250NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100251
252#undef NOT_INT_TEST
253
Roland Levillain55dcfb52014-10-24 18:09:09 +0100254// Exercise bit-wise (one's complement) not-long instruction.
255#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000256TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100257 const int64_t input = INPUT; \
258 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
259 const uint16_t word1 = High16Bits(Low32Bits(input)); \
260 const uint16_t word2 = Low16Bits(High32Bits(input)); \
261 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800262 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM( \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100263 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
264 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
265 Instruction::RETURN_WIDE | 2 << 8); \
266 \
David Brazdil58282f42016-01-14 12:45:10 +0000267 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100268}
269
270NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
271NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
272NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
273NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
274
275NOT_LONG_TEST(ReturnNotLongINT32_MIN,
276 INT64_C(-2147483648),
277 INT64_C(2147483647)) // (2^31) - 1
278NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
279 INT64_C(-2147483647),
280 INT64_C(2147483646)) // (2^31) - 2
281NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
282 INT64_C(2147483646),
283 INT64_C(-2147483647)) // -(2^31) - 1
284NOT_LONG_TEST(ReturnNotLongINT32_MAX,
285 INT64_C(2147483647),
286 INT64_C(-2147483648)) // -(2^31)
287
288// Note that the C++ compiler won't accept
289// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
290// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
291NOT_LONG_TEST(ReturnNotINT64_MIN,
292 INT64_C(-9223372036854775807)-1,
293 INT64_C(9223372036854775807)); // (2^63) - 1
294NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
295 INT64_C(-9223372036854775807),
296 INT64_C(9223372036854775806)); // (2^63) - 2
297NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
298 INT64_C(9223372036854775806),
299 INT64_C(-9223372036854775807)); // -(2^63) - 1
300NOT_LONG_TEST(ReturnNotLongINT64_MAX,
301 INT64_C(9223372036854775807),
302 INT64_C(-9223372036854775807)-1); // -(2^63)
303
304#undef NOT_LONG_TEST
305
David Brazdil58282f42016-01-14 12:45:10 +0000306TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000307 const int64_t input = INT64_C(4294967296); // 2^32
308 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
309 const uint16_t word1 = High16Bits(Low32Bits(input));
310 const uint16_t word2 = Low16Bits(High32Bits(input));
311 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800312 const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
Roland Levillain946e1432014-11-11 17:35:19 +0000313 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
314 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
315 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
316 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
317 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
318 Instruction::RETURN_WIDE | 2 << 8);
319
David Brazdil58282f42016-01-14 12:45:10 +0000320 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000321}
322
David Brazdil58282f42016-01-14 12:45:10 +0000323TEST_F(CodegenTest, ReturnAdd1) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800324 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000325 Instruction::CONST_4 | 3 << 12 | 0,
326 Instruction::CONST_4 | 4 << 12 | 1 << 8,
327 Instruction::ADD_INT, 1 << 8 | 0,
328 Instruction::RETURN);
329
David Brazdil58282f42016-01-14 12:45:10 +0000330 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000331}
332
David Brazdil58282f42016-01-14 12:45:10 +0000333TEST_F(CodegenTest, ReturnAdd2) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800334 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000335 Instruction::CONST_4 | 3 << 12 | 0,
336 Instruction::CONST_4 | 4 << 12 | 1 << 8,
337 Instruction::ADD_INT_2ADDR | 1 << 12,
338 Instruction::RETURN);
339
David Brazdil58282f42016-01-14 12:45:10 +0000340 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000341}
342
David Brazdil58282f42016-01-14 12:45:10 +0000343TEST_F(CodegenTest, ReturnAdd3) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800344 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000345 Instruction::CONST_4 | 4 << 12 | 0 << 8,
346 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
347 Instruction::RETURN);
348
David Brazdil58282f42016-01-14 12:45:10 +0000349 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000350}
351
David Brazdil58282f42016-01-14 12:45:10 +0000352TEST_F(CodegenTest, ReturnAdd4) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800353 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000354 Instruction::CONST_4 | 4 << 12 | 0 << 8,
355 Instruction::ADD_INT_LIT16, 3,
356 Instruction::RETURN);
357
David Brazdil58282f42016-01-14 12:45:10 +0000358 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000359}
360
David Brazdil58282f42016-01-14 12:45:10 +0000361TEST_F(CodegenTest, ReturnMulInt) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800362 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100363 Instruction::CONST_4 | 3 << 12 | 0,
364 Instruction::CONST_4 | 4 << 12 | 1 << 8,
365 Instruction::MUL_INT, 1 << 8 | 0,
366 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100367
David Brazdil58282f42016-01-14 12:45:10 +0000368 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100369}
370
David Brazdil58282f42016-01-14 12:45:10 +0000371TEST_F(CodegenTest, ReturnMulInt2addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800372 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100373 Instruction::CONST_4 | 3 << 12 | 0,
374 Instruction::CONST_4 | 4 << 12 | 1 << 8,
375 Instruction::MUL_INT_2ADDR | 1 << 12,
376 Instruction::RETURN);
377
David Brazdil58282f42016-01-14 12:45:10 +0000378 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100379}
380
David Brazdil58282f42016-01-14 12:45:10 +0000381TEST_F(CodegenTest, ReturnMulLong) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800382 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000383 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
384 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100385 Instruction::MUL_LONG, 2 << 8 | 0,
386 Instruction::RETURN_WIDE);
387
David Brazdil58282f42016-01-14 12:45:10 +0000388 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100389}
390
David Brazdil58282f42016-01-14 12:45:10 +0000391TEST_F(CodegenTest, ReturnMulLong2addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800392 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000393 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
394 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100395 Instruction::MUL_LONG_2ADDR | 2 << 12,
396 Instruction::RETURN_WIDE);
397
David Brazdil58282f42016-01-14 12:45:10 +0000398 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100399}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100400
David Brazdil58282f42016-01-14 12:45:10 +0000401TEST_F(CodegenTest, ReturnMulIntLit8) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800402 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100403 Instruction::CONST_4 | 4 << 12 | 0 << 8,
404 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
405 Instruction::RETURN);
406
David Brazdil58282f42016-01-14 12:45:10 +0000407 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100408}
409
David Brazdil58282f42016-01-14 12:45:10 +0000410TEST_F(CodegenTest, ReturnMulIntLit16) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800411 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100412 Instruction::CONST_4 | 4 << 12 | 0 << 8,
413 Instruction::MUL_INT_LIT16, 3,
414 Instruction::RETURN);
415
David Brazdil58282f42016-01-14 12:45:10 +0000416 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100417}
418
David Brazdil58282f42016-01-14 12:45:10 +0000419TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100420 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100421 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000422
Vladimir Markoca6fff82017-10-03 14:49:14 +0100423 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000424 graph->AddBlock(entry);
425 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100426 entry->AddInstruction(new (GetAllocator()) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100427
Vladimir Markoca6fff82017-10-03 14:49:14 +0100428 HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000429 graph->AddBlock(first_block);
430 entry->AddSuccessor(first_block);
431 HIntConstant* constant0 = graph->GetIntConstant(0);
432 HIntConstant* constant1 = graph->GetIntConstant(1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100433 HEqual* equal = new (GetAllocator()) HEqual(constant0, constant0);
David Brazdil58282f42016-01-14 12:45:10 +0000434 first_block->AddInstruction(equal);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100435 first_block->AddInstruction(new (GetAllocator()) HIf(equal));
David Brazdil58282f42016-01-14 12:45:10 +0000436
Vladimir Markoca6fff82017-10-03 14:49:14 +0100437 HBasicBlock* then_block = new (GetAllocator()) HBasicBlock(graph);
438 HBasicBlock* else_block = new (GetAllocator()) HBasicBlock(graph);
439 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100440 graph->SetExitBlock(exit_block);
441
David Brazdil58282f42016-01-14 12:45:10 +0000442 graph->AddBlock(then_block);
443 graph->AddBlock(else_block);
444 graph->AddBlock(exit_block);
445 first_block->AddSuccessor(then_block);
446 first_block->AddSuccessor(else_block);
447 then_block->AddSuccessor(exit_block);
448 else_block->AddSuccessor(exit_block);
449
Vladimir Markoca6fff82017-10-03 14:49:14 +0100450 exit_block->AddInstruction(new (GetAllocator()) HExit());
451 then_block->AddInstruction(new (GetAllocator()) HReturn(constant0));
452 else_block->AddInstruction(new (GetAllocator()) HReturn(constant1));
David Brazdil58282f42016-01-14 12:45:10 +0000453
David Brazdilb11b0722016-01-28 16:22:40 +0000454 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000455 graph->BuildDominatorTree();
Nicolas Geoffray61ba8d22018-08-07 09:55:57 +0100456 PrepareForRegisterAllocation(graph, *compiler_options_).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000457 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100458
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800459 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100460 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100461 HParallelMove* move = new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
Alexandre Rames92730742014-10-01 12:55:56 +0100462 block->InsertInstructionBefore(move, block->GetLastInstruction());
463 };
464
Vladimir Markoa0431112018-06-25 09:32:54 +0100465 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
466 RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100467 }
468}
469
David Brazdil58282f42016-01-14 12:45:10 +0000470TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100471 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000472 // Check that condition are materialized correctly. A materialized condition
473 // should yield `1` if it evaluated to true, and `0` otherwise.
474 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100475
David Brazdil58282f42016-01-14 12:45:10 +0000476 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100477
David Brazdil58282f42016-01-14 12:45:10 +0000478 int lhs[] = {1, 2, -1, 2, 0xabc};
479 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100480
David Brazdil58282f42016-01-14 12:45:10 +0000481 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100482 HGraph* graph = CreateGraph();
Alexandre Rames92730742014-10-01 12:55:56 +0100483
Vladimir Markoca6fff82017-10-03 14:49:14 +0100484 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000485 graph->AddBlock(entry_block);
486 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100487 entry_block->AddInstruction(new (GetAllocator()) HGoto());
488 HBasicBlock* code_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000489 graph->AddBlock(code_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100490 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000491 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100492 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100493
David Brazdil58282f42016-01-14 12:45:10 +0000494 entry_block->AddSuccessor(code_block);
495 code_block->AddSuccessor(exit_block);
496 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100497
David Brazdil58282f42016-01-14 12:45:10 +0000498 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
499 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
500 HLessThan cmp_lt(cst_lhs, cst_rhs);
501 code_block->AddInstruction(&cmp_lt);
502 HReturn ret(&cmp_lt);
503 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100504
David Brazdilbadd8262016-02-02 16:28:56 +0000505 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000506 auto hook_before_codegen = [](HGraph* graph_in) {
507 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100508 HParallelMove* move =
509 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000510 block->InsertInstructionBefore(move, block->GetLastInstruction());
511 };
Vladimir Markoa0431112018-06-25 09:32:54 +0100512 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
513 RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000514 }
Alexandre Rames92730742014-10-01 12:55:56 +0100515 }
516}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100517
David Brazdil58282f42016-01-14 12:45:10 +0000518TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100519 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000520 // Check that HIf correctly interprets a materialized condition.
521 // We force the materialization of comparisons for different combinations of
522 // inputs. An HIf takes the materialized combination as input and returns a
523 // value that we verify.
524
525 int lhs[] = {1, 2, -1, 2, 0xabc};
526 int rhs[] = {2, 1, 2, -1, 0xabc};
527
528
529 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100530 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000531
Vladimir Markoca6fff82017-10-03 14:49:14 +0100532 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000533 graph->AddBlock(entry_block);
534 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100535 entry_block->AddInstruction(new (GetAllocator()) HGoto());
David Brazdil58282f42016-01-14 12:45:10 +0000536
Vladimir Markoca6fff82017-10-03 14:49:14 +0100537 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000538 graph->AddBlock(if_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100539 HBasicBlock* if_true_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000540 graph->AddBlock(if_true_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100541 HBasicBlock* if_false_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000542 graph->AddBlock(if_false_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100543 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000544 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100545 exit_block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil58282f42016-01-14 12:45:10 +0000546
547 graph->SetEntryBlock(entry_block);
548 entry_block->AddSuccessor(if_block);
549 if_block->AddSuccessor(if_true_block);
550 if_block->AddSuccessor(if_false_block);
551 if_true_block->AddSuccessor(exit_block);
552 if_false_block->AddSuccessor(exit_block);
553 graph->SetExitBlock(exit_block);
554
555 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
556 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
557 HLessThan cmp_lt(cst_lhs, cst_rhs);
558 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000559 // We insert a dummy instruction to separate the HIf from the HLessThan
560 // and force the materialization of the condition.
561 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000562 if_block->AddInstruction(&force_materialization);
563 HIf if_lt(&cmp_lt);
564 if_block->AddInstruction(&if_lt);
565
566 HIntConstant* cst_lt = graph->GetIntConstant(1);
567 HReturn ret_lt(cst_lt);
568 if_true_block->AddInstruction(&ret_lt);
569 HIntConstant* cst_ge = graph->GetIntConstant(0);
570 HReturn ret_ge(cst_ge);
571 if_false_block->AddInstruction(&ret_ge);
572
David Brazdilbadd8262016-02-02 16:28:56 +0000573 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000574 auto hook_before_codegen = [](HGraph* graph_in) {
575 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100576 HParallelMove* move =
577 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000578 block->InsertInstructionBefore(move, block->GetLastInstruction());
579 };
Vladimir Markoa0431112018-06-25 09:32:54 +0100580 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
581 RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000582 }
583 }
584}
585
586TEST_F(CodegenTest, ReturnDivIntLit8) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800587 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravled0d48522014-11-04 16:40:20 +0000588 Instruction::CONST_4 | 4 << 12 | 0 << 8,
589 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
590 Instruction::RETURN);
591
David Brazdil58282f42016-01-14 12:45:10 +0000592 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000593}
594
David Brazdil58282f42016-01-14 12:45:10 +0000595TEST_F(CodegenTest, ReturnDivInt2Addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800596 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Calin Juravle865fc882014-11-06 17:09:03 +0000597 Instruction::CONST_4 | 4 << 12 | 0,
598 Instruction::CONST_4 | 2 << 12 | 1 << 8,
599 Instruction::DIV_INT_2ADDR | 1 << 12,
600 Instruction::RETURN);
601
David Brazdil58282f42016-01-14 12:45:10 +0000602 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000603}
604
Aart Bike9f37602015-10-09 11:15:55 -0700605// Helper method.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100606void CodegenTest::TestComparison(IfCondition condition,
607 int64_t i,
608 int64_t j,
609 DataType::Type type,
610 const CodegenTargetConfig target_config) {
611 HGraph* graph = CreateGraph();
Aart Bike9f37602015-10-09 11:15:55 -0700612
Vladimir Markoca6fff82017-10-03 14:49:14 +0100613 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700614 graph->AddBlock(entry_block);
615 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100616 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Aart Bike9f37602015-10-09 11:15:55 -0700617
Vladimir Markoca6fff82017-10-03 14:49:14 +0100618 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700619 graph->AddBlock(block);
620
Vladimir Markoca6fff82017-10-03 14:49:14 +0100621 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700622 graph->AddBlock(exit_block);
623 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100624 exit_block->AddInstruction(new (GetAllocator()) HExit());
Aart Bike9f37602015-10-09 11:15:55 -0700625
626 entry_block->AddSuccessor(block);
627 block->AddSuccessor(exit_block);
628
629 HInstruction* op1;
630 HInstruction* op2;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100631 if (type == DataType::Type::kInt32) {
Aart Bike9f37602015-10-09 11:15:55 -0700632 op1 = graph->GetIntConstant(i);
633 op2 = graph->GetIntConstant(j);
634 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100635 DCHECK_EQ(type, DataType::Type::kInt64);
Aart Bike9f37602015-10-09 11:15:55 -0700636 op1 = graph->GetLongConstant(i);
637 op2 = graph->GetLongConstant(j);
638 }
639
640 HInstruction* comparison = nullptr;
641 bool expected_result = false;
642 const uint64_t x = i;
643 const uint64_t y = j;
644 switch (condition) {
645 case kCondEQ:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100646 comparison = new (GetAllocator()) HEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700647 expected_result = (i == j);
648 break;
649 case kCondNE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100650 comparison = new (GetAllocator()) HNotEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700651 expected_result = (i != j);
652 break;
653 case kCondLT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100654 comparison = new (GetAllocator()) HLessThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700655 expected_result = (i < j);
656 break;
657 case kCondLE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100658 comparison = new (GetAllocator()) HLessThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700659 expected_result = (i <= j);
660 break;
661 case kCondGT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100662 comparison = new (GetAllocator()) HGreaterThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700663 expected_result = (i > j);
664 break;
665 case kCondGE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100666 comparison = new (GetAllocator()) HGreaterThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700667 expected_result = (i >= j);
668 break;
669 case kCondB:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100670 comparison = new (GetAllocator()) HBelow(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700671 expected_result = (x < y);
672 break;
673 case kCondBE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100674 comparison = new (GetAllocator()) HBelowOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700675 expected_result = (x <= y);
676 break;
677 case kCondA:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100678 comparison = new (GetAllocator()) HAbove(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700679 expected_result = (x > y);
680 break;
681 case kCondAE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100682 comparison = new (GetAllocator()) HAboveOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700683 expected_result = (x >= y);
684 break;
685 }
686 block->AddInstruction(comparison);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100687 block->AddInstruction(new (GetAllocator()) HReturn(comparison));
Aart Bike9f37602015-10-09 11:15:55 -0700688
David Brazdilbadd8262016-02-02 16:28:56 +0000689 graph->BuildDominatorTree();
Vladimir Markoa0431112018-06-25 09:32:54 +0100690 OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
691 RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700692}
693
David Brazdil58282f42016-01-14 12:45:10 +0000694TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100695 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000696 for (int64_t i = -1; i <= 1; i++) {
697 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100698 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100699 TestComparison(
700 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100701 }
David Brazdil58282f42016-01-14 12:45:10 +0000702 }
Aart Bike9f37602015-10-09 11:15:55 -0700703 }
704 }
705}
706
David Brazdil58282f42016-01-14 12:45:10 +0000707TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100708 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000709 for (int64_t i = -1; i <= 1; i++) {
710 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100711 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100712 TestComparison(
713 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100714 }
David Brazdil58282f42016-01-14 12:45:10 +0000715 }
Aart Bike9f37602015-10-09 11:15:55 -0700716 }
717 }
718}
719
Artem Serov4593f7d2016-12-29 16:21:49 +0000720#ifdef ART_ENABLE_CODEGEN_arm
721TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100722 OverrideInstructionSetFeatures(InstructionSet::kThumb2, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100723 HGraph* graph = CreateGraph();
Vladimir Markoa0431112018-06-25 09:32:54 +0100724 arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_);
Artem Serov4593f7d2016-12-29 16:21:49 +0000725
726 codegen.Initialize();
727
728 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
729 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
730 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
731 // LDR encoding. So the following code is a regression test for that situation.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100732 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100733 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
734 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
Artem Serov4593f7d2016-12-29 16:21:49 +0000735 codegen.GetMoveResolver()->EmitNativeCode(move);
736
737 InternalCodeAllocator code_allocator;
738 codegen.Finalize(&code_allocator);
739}
740#endif
741
Roland Levillain558dea12017-01-27 19:40:44 +0000742#ifdef ART_ENABLE_CODEGEN_arm64
743// Regression test for b/34760542.
744TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100745 OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100746 HGraph* graph = CreateGraph();
Vladimir Markoa0431112018-06-25 09:32:54 +0100747 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
Roland Levillain558dea12017-01-27 19:40:44 +0000748
749 codegen.Initialize();
750
751 // The following ParallelMove used to fail this assertion:
752 //
753 // Assertion failed (!available->IsEmpty())
754 //
Roland Levillain952b2352017-05-03 19:49:14 +0100755 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
756 // because of the following situation:
757 //
758 // 1. a temp register (IP0) is allocated as a scratch register by
759 // the parallel move resolver to solve a cycle (swap):
760 //
761 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
762 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
763 //
764 // 2. within CodeGeneratorARM64::MoveLocation, another temp
765 // register (IP1) is allocated to generate the swap between two
766 // double stack slots;
767 //
768 // 3. VIXL requires a third temp register to emit the `Ldr` or
769 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
770 // one of the stack slots' offsets cannot be encoded as an
771 // immediate), but the pool of (core) temp registers is now
772 // empty.
773 //
774 // The solution used so far is to use a floating-point temp register
775 // (D31) in step #2, so that IP1 is available for step #3.
776
Vladimir Markoca6fff82017-10-03 14:49:14 +0100777 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Roland Levillain558dea12017-01-27 19:40:44 +0000778 move->AddMove(Location::DoubleStackSlot(0),
779 Location::DoubleStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100780 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000781 nullptr);
782 move->AddMove(Location::DoubleStackSlot(257),
783 Location::DoubleStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100784 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000785 nullptr);
786 codegen.GetMoveResolver()->EmitNativeCode(move);
787
788 InternalCodeAllocator code_allocator;
789 codegen.Finalize(&code_allocator);
790}
Artem Serovd4bccf12017-04-03 18:47:32 +0100791
792// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
793TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100794 OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100795 HGraph* graph = CreateGraph();
Vladimir Markoa0431112018-06-25 09:32:54 +0100796 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
Artem Serovd4bccf12017-04-03 18:47:32 +0100797
798 codegen.Initialize();
799
800 graph->SetHasSIMD(true);
801 for (int i = 0; i < 2; i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100802 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Artem Serovd4bccf12017-04-03 18:47:32 +0100803 move->AddMove(Location::SIMDStackSlot(0),
804 Location::SIMDStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100805 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100806 nullptr);
807 move->AddMove(Location::SIMDStackSlot(257),
808 Location::SIMDStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100809 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100810 nullptr);
811 move->AddMove(Location::FpuRegisterLocation(0),
812 Location::FpuRegisterLocation(1),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100813 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100814 nullptr);
815 move->AddMove(Location::FpuRegisterLocation(1),
816 Location::FpuRegisterLocation(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100817 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100818 nullptr);
819 codegen.GetMoveResolver()->EmitNativeCode(move);
820 graph->SetHasSIMD(false);
821 }
822
823 InternalCodeAllocator code_allocator;
824 codegen.Finalize(&code_allocator);
825}
Artem Serovaa6f4832018-11-21 18:57:54 +0000826
827// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a75 as example).
828TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA75) {
829 OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a75");
830 HGraph* graph = CreateGraph();
831 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
832 vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
833
834 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
835 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kDotProduct));
836 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kFPHalf));
837 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kAtomics));
838}
839
840// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a53 as example).
841TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA53) {
842 OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a53");
843 HGraph* graph = CreateGraph();
844 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
845 vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
846
847 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
848 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kDotProduct));
849 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kFPHalf));
850 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kAtomics));
851}
852
Artem Serov6a0b6572019-07-26 20:38:37 +0100853constexpr static size_t kExpectedFPSpillSize = 8 * vixl::aarch64::kDRegSizeInBytes;
854
855// The following two tests check that for both SIMD and non-SIMD graphs exactly 64-bit is
856// allocated on stack per callee-saved FP register to be preserved in the frame entry as
857// ABI states.
858TEST_F(CodegenTest, ARM64FrameSizeSIMD) {
859 OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
860 HGraph* graph = CreateGraph();
861 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
862
863 codegen.Initialize();
864 graph->SetHasSIMD(true);
865
866 DCHECK_EQ(arm64::callee_saved_fp_registers.GetCount(), 8);
867 vixl::aarch64::CPURegList reg_list = arm64::callee_saved_fp_registers;
868 while (!reg_list.IsEmpty()) {
869 uint32_t reg_code = reg_list.PopLowestIndex().GetCode();
870 codegen.AddAllocatedRegister(Location::FpuRegisterLocation(reg_code));
871 }
872 codegen.ComputeSpillMask();
873
874 EXPECT_EQ(codegen.GetFpuSpillSize(), kExpectedFPSpillSize);
875}
876
877TEST_F(CodegenTest, ARM64FrameSizeNoSIMD) {
878 OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
879 HGraph* graph = CreateGraph();
880 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
881
882 codegen.Initialize();
883 graph->SetHasSIMD(false);
884
885 DCHECK_EQ(arm64::callee_saved_fp_registers.GetCount(), 8);
886 vixl::aarch64::CPURegList reg_list = arm64::callee_saved_fp_registers;
887 while (!reg_list.IsEmpty()) {
888 uint32_t reg_code = reg_list.PopLowestIndex().GetCode();
889 codegen.AddAllocatedRegister(Location::FpuRegisterLocation(reg_code));
890 }
891 codegen.ComputeSpillMask();
892
893 EXPECT_EQ(codegen.GetFpuSpillSize(), kExpectedFPSpillSize);
894}
895
Roland Levillain558dea12017-01-27 19:40:44 +0000896#endif
897
Alexey Frunze58320ce2016-08-30 21:40:46 -0700898#ifdef ART_ENABLE_CODEGEN_mips
899TEST_F(CodegenTest, MipsClobberRA) {
Vladimir Markoa0431112018-06-25 09:32:54 +0100900 OverrideInstructionSetFeatures(InstructionSet::kMips, "mips32r");
901 CHECK(!instruction_set_features_->AsMipsInstructionSetFeatures()->IsR6());
902 if (!CanExecute(InstructionSet::kMips)) {
Alexey Frunze58320ce2016-08-30 21:40:46 -0700903 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
904 // should only be generated on non-R6.
905 return;
906 }
907
Vladimir Markoca6fff82017-10-03 14:49:14 +0100908 HGraph* graph = CreateGraph();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700909
Vladimir Markoca6fff82017-10-03 14:49:14 +0100910 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700911 graph->AddBlock(entry_block);
912 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100913 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700914
Vladimir Markoca6fff82017-10-03 14:49:14 +0100915 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700916 graph->AddBlock(block);
917
Vladimir Markoca6fff82017-10-03 14:49:14 +0100918 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700919 graph->AddBlock(exit_block);
920 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100921 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700922
923 entry_block->AddSuccessor(block);
924 block->AddSuccessor(exit_block);
925
926 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
927 // Instead, generate HMipsComputeBaseMethodAddress directly.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100928 HMipsComputeBaseMethodAddress* base = new (GetAllocator()) HMipsComputeBaseMethodAddress();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700929 block->AddInstruction(base);
930 // HMipsComputeBaseMethodAddress is defined as int, so just make the
931 // compiled method return it.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100932 block->AddInstruction(new (GetAllocator()) HReturn(base));
Alexey Frunze58320ce2016-08-30 21:40:46 -0700933
934 graph->BuildDominatorTree();
935
Vladimir Markoa0431112018-06-25 09:32:54 +0100936 mips::CodeGeneratorMIPS codegenMIPS(graph, *compiler_options_);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700937 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
938 // that RA is clobbered and the method entry code should generate a stack frame
939 // and preserve RA in it. And this is what we're testing here.
940 codegenMIPS.ClobberRA();
941 // Without ClobberRA() the code would be:
942 // nal # Sets RA to point to the jr instruction below
943 // move v0, ra # and the CPU falls into an infinite loop.
944 // jr ra
945 // nop
946 // The expected code is:
947 // addiu sp, sp, -16
948 // sw ra, 12(sp)
949 // sw a0, 0(sp)
950 // nal # Sets RA to point to the lw instruction below.
951 // move v0, ra
952 // lw ra, 12(sp)
953 // jr ra
954 // addiu sp, sp, 16
955 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
956}
957#endif
958
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000959} // namespace art