blob: 4ba5c5580f1d4355945aec63f5f7128191290440 [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"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000021#include "builder.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010022#include "codegen_test_utils.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000023#include "dex_file.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000024#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000025#include "driver/compiler_options.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000026#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000027#include "optimizing_unit_test.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070028#include "register_allocator_linear_scan.h"
Roland Levillain55dcfb52014-10-24 18:09:09 +010029#include "utils.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
46 CodegenTargetConfig(kArm, create_codegen_arm),
47 CodegenTargetConfig(kThumb2, create_codegen_arm),
Scott Wakelingfe885462016-09-22 10:24:38 +010048 CodegenTargetConfig(kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +010049#endif
50#ifdef ART_ENABLE_CODEGEN_arm64
51 CodegenTargetConfig(kArm64, create_codegen_arm64),
52#endif
53#ifdef ART_ENABLE_CODEGEN_x86
54 CodegenTargetConfig(kX86, create_codegen_x86),
55#endif
56#ifdef ART_ENABLE_CODEGEN_x86_64
57 CodegenTargetConfig(kX86_64, create_codegen_x86_64),
58#endif
59#ifdef ART_ENABLE_CODEGEN_mips
60 CodegenTargetConfig(kMips, create_codegen_mips),
61#endif
62#ifdef ART_ENABLE_CODEGEN_mips64
63 CodegenTargetConfig(kMips64, create_codegen_mips64)
64#endif
David Brazdil58282f42016-01-14 12:45:10 +000065 };
66
Scott Wakeling2c76e062016-08-31 09:48:54 +010067 for (auto test_config : test_config_candidates) {
68 if (CanExecute(test_config.GetInstructionSet())) {
69 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +000070 }
71 }
72
73 return v;
74}
75
76static void TestCode(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +080077 bool has_result = false,
78 int32_t expected = 0) {
Scott Wakeling2c76e062016-08-31 09:48:54 +010079 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +000080 ArenaPool pool;
81 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000082 HGraph* graph = CreateCFG(&arena, data);
David Brazdil58282f42016-01-14 12:45:10 +000083 // Remove suspend checks, they cannot be executed in this context.
84 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010085 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000086 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010087}
88
David Brazdil58282f42016-01-14 12:45:10 +000089static void TestCodeLong(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +080090 bool has_result,
91 int64_t expected) {
Scott Wakeling2c76e062016-08-31 09:48:54 +010092 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +000093 ArenaPool pool;
94 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000095 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
David Brazdil58282f42016-01-14 12:45:10 +000096 // Remove suspend checks, they cannot be executed in this context.
97 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010098 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000099 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100100}
101
David Brazdil58282f42016-01-14 12:45:10 +0000102class CodegenTest : public CommonCompilerTest {};
Phil Wang751beff2015-08-28 15:17:15 +0800103
David Brazdil58282f42016-01-14 12:45:10 +0000104TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000105 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000106 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000107}
108
David Brazdil58282f42016-01-14 12:45:10 +0000109TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000110 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000111 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000112 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000113
David Brazdil58282f42016-01-14 12:45:10 +0000114 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000115}
116
David Brazdil58282f42016-01-14 12:45:10 +0000117TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000118 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000119 Instruction::GOTO | 0x100,
120 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000121 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000122
David Brazdil58282f42016-01-14 12:45:10 +0000123 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000124}
125
David Brazdil58282f42016-01-14 12:45:10 +0000126TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000127 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000128 Instruction::GOTO | 0x200,
129 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000130 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000131
David Brazdil58282f42016-01-14 12:45:10 +0000132 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000133
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000134 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000135 Instruction::GOTO_16, 3,
136 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000137 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000138
David Brazdil58282f42016-01-14 12:45:10 +0000139 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000140
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000141 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000142 Instruction::GOTO_32, 4, 0,
143 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000144 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000145
David Brazdil58282f42016-01-14 12:45:10 +0000146 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000147}
148
David Brazdil58282f42016-01-14 12:45:10 +0000149TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000150 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000151 Instruction::RETURN_VOID,
152 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000153 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000154
David Brazdil58282f42016-01-14 12:45:10 +0000155 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000156}
157
David Brazdil58282f42016-01-14 12:45:10 +0000158TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000159 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
160 Instruction::CONST_4 | 0 | 0,
161 Instruction::IF_EQ, 3,
162 Instruction::GOTO | 0x100,
163 Instruction::RETURN_VOID);
164
David Brazdil58282f42016-01-14 12:45:10 +0000165 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000166}
167
David Brazdil58282f42016-01-14 12:45:10 +0000168TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000169 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
170 Instruction::CONST_4 | 0 | 0,
171 Instruction::RETURN_VOID);
172
David Brazdil58282f42016-01-14 12:45:10 +0000173 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000174}
175
David Brazdil58282f42016-01-14 12:45:10 +0000176TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000177 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
178 Instruction::CONST_4 | 0 | 0,
179 Instruction::RETURN | 0);
180
David Brazdil58282f42016-01-14 12:45:10 +0000181 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000182}
183
David Brazdil58282f42016-01-14 12:45:10 +0000184TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000185 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
186 Instruction::CONST_4 | 0 | 0,
187 Instruction::CONST_4 | 0 | 1 << 8,
188 Instruction::RETURN | 1 << 8);
189
David Brazdil58282f42016-01-14 12:45:10 +0000190 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000191}
192
David Brazdil58282f42016-01-14 12:45:10 +0000193TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000194 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
195 Instruction::CONST_4 | 0 | 0,
196 Instruction::CONST_4 | 1 << 8 | 1 << 12,
197 Instruction::RETURN | 1 << 8);
198
David Brazdil58282f42016-01-14 12:45:10 +0000199 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000200}
201
David Brazdil58282f42016-01-14 12:45:10 +0000202TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000203 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
204 Instruction::CONST_4 | 0 | 0,
205 Instruction::CONST_4 | 1 << 8 | 1 << 12,
206 Instruction::IF_EQ, 3,
207 Instruction::RETURN | 0 << 8,
208 Instruction::RETURN | 1 << 8);
209
David Brazdil58282f42016-01-14 12:45:10 +0000210 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000211}
212
David Brazdil58282f42016-01-14 12:45:10 +0000213TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000214 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
215 Instruction::CONST_4 | 0 | 0,
216 Instruction::CONST_4 | 1 << 8 | 1 << 12,
217 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
218 Instruction::RETURN | 0 << 8,
219 Instruction::RETURN | 1 << 8);
220
David Brazdil58282f42016-01-14 12:45:10 +0000221 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000222}
223
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100224// Exercise bit-wise (one's complement) not-int instruction.
225#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000226TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100227 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100228 const uint16_t input_lo = Low16Bits(input); \
229 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100230 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
231 Instruction::CONST | 0 << 8, input_lo, input_hi, \
232 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
233 Instruction::RETURN | 1 << 8); \
234 \
David Brazdil58282f42016-01-14 12:45:10 +0000235 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100236}
237
238NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
239NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
240NOT_INT_TEST(ReturnNotInt0, 0, -1)
241NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100242NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
243NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
244NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
245NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100246
247#undef NOT_INT_TEST
248
Roland Levillain55dcfb52014-10-24 18:09:09 +0100249// Exercise bit-wise (one's complement) not-long instruction.
250#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000251TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100252 const int64_t input = INPUT; \
253 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
254 const uint16_t word1 = High16Bits(Low32Bits(input)); \
255 const uint16_t word2 = Low16Bits(High32Bits(input)); \
256 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
257 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
258 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
259 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
260 Instruction::RETURN_WIDE | 2 << 8); \
261 \
David Brazdil58282f42016-01-14 12:45:10 +0000262 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100263}
264
265NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
266NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
267NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
268NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
269
270NOT_LONG_TEST(ReturnNotLongINT32_MIN,
271 INT64_C(-2147483648),
272 INT64_C(2147483647)) // (2^31) - 1
273NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
274 INT64_C(-2147483647),
275 INT64_C(2147483646)) // (2^31) - 2
276NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
277 INT64_C(2147483646),
278 INT64_C(-2147483647)) // -(2^31) - 1
279NOT_LONG_TEST(ReturnNotLongINT32_MAX,
280 INT64_C(2147483647),
281 INT64_C(-2147483648)) // -(2^31)
282
283// Note that the C++ compiler won't accept
284// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
285// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
286NOT_LONG_TEST(ReturnNotINT64_MIN,
287 INT64_C(-9223372036854775807)-1,
288 INT64_C(9223372036854775807)); // (2^63) - 1
289NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
290 INT64_C(-9223372036854775807),
291 INT64_C(9223372036854775806)); // (2^63) - 2
292NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
293 INT64_C(9223372036854775806),
294 INT64_C(-9223372036854775807)); // -(2^63) - 1
295NOT_LONG_TEST(ReturnNotLongINT64_MAX,
296 INT64_C(9223372036854775807),
297 INT64_C(-9223372036854775807)-1); // -(2^63)
298
299#undef NOT_LONG_TEST
300
David Brazdil58282f42016-01-14 12:45:10 +0000301TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000302 const int64_t input = INT64_C(4294967296); // 2^32
303 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
304 const uint16_t word1 = High16Bits(Low32Bits(input));
305 const uint16_t word2 = Low16Bits(High32Bits(input));
306 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
307 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
308 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
309 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
310 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
311 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
312 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
313 Instruction::RETURN_WIDE | 2 << 8);
314
David Brazdil58282f42016-01-14 12:45:10 +0000315 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000316}
317
David Brazdil58282f42016-01-14 12:45:10 +0000318TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000319 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
320 Instruction::CONST_4 | 3 << 12 | 0,
321 Instruction::CONST_4 | 4 << 12 | 1 << 8,
322 Instruction::ADD_INT, 1 << 8 | 0,
323 Instruction::RETURN);
324
David Brazdil58282f42016-01-14 12:45:10 +0000325 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000326}
327
David Brazdil58282f42016-01-14 12:45:10 +0000328TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000329 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
330 Instruction::CONST_4 | 3 << 12 | 0,
331 Instruction::CONST_4 | 4 << 12 | 1 << 8,
332 Instruction::ADD_INT_2ADDR | 1 << 12,
333 Instruction::RETURN);
334
David Brazdil58282f42016-01-14 12:45:10 +0000335 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000336}
337
David Brazdil58282f42016-01-14 12:45:10 +0000338TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000339 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
340 Instruction::CONST_4 | 4 << 12 | 0 << 8,
341 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
342 Instruction::RETURN);
343
David Brazdil58282f42016-01-14 12:45:10 +0000344 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000345}
346
David Brazdil58282f42016-01-14 12:45:10 +0000347TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000348 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
349 Instruction::CONST_4 | 4 << 12 | 0 << 8,
350 Instruction::ADD_INT_LIT16, 3,
351 Instruction::RETURN);
352
David Brazdil58282f42016-01-14 12:45:10 +0000353 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000354}
355
David Brazdil58282f42016-01-14 12:45:10 +0000356TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100357 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
358 Instruction::CONST_4 | 3 << 12 | 0,
359 Instruction::CONST_4 | 4 << 12 | 1 << 8,
360 Instruction::MUL_INT, 1 << 8 | 0,
361 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100362
David Brazdil58282f42016-01-14 12:45:10 +0000363 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100364}
365
David Brazdil58282f42016-01-14 12:45:10 +0000366TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100367 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
368 Instruction::CONST_4 | 3 << 12 | 0,
369 Instruction::CONST_4 | 4 << 12 | 1 << 8,
370 Instruction::MUL_INT_2ADDR | 1 << 12,
371 Instruction::RETURN);
372
David Brazdil58282f42016-01-14 12:45:10 +0000373 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100374}
375
David Brazdil58282f42016-01-14 12:45:10 +0000376TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100377 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000378 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
379 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100380 Instruction::MUL_LONG, 2 << 8 | 0,
381 Instruction::RETURN_WIDE);
382
David Brazdil58282f42016-01-14 12:45:10 +0000383 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100384}
385
David Brazdil58282f42016-01-14 12:45:10 +0000386TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100387 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000388 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
389 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100390 Instruction::MUL_LONG_2ADDR | 2 << 12,
391 Instruction::RETURN_WIDE);
392
David Brazdil58282f42016-01-14 12:45:10 +0000393 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100394}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100395
David Brazdil58282f42016-01-14 12:45:10 +0000396TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100397 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
398 Instruction::CONST_4 | 4 << 12 | 0 << 8,
399 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
400 Instruction::RETURN);
401
David Brazdil58282f42016-01-14 12:45:10 +0000402 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100403}
404
David Brazdil58282f42016-01-14 12:45:10 +0000405TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100406 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
407 Instruction::CONST_4 | 4 << 12 | 0 << 8,
408 Instruction::MUL_INT_LIT16, 3,
409 Instruction::RETURN);
410
David Brazdil58282f42016-01-14 12:45:10 +0000411 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100412}
413
David Brazdil58282f42016-01-14 12:45:10 +0000414TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100415 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Alexandre Rames92730742014-10-01 12:55:56 +0100416 ArenaPool pool;
417 ArenaAllocator allocator(&pool);
David Brazdil58282f42016-01-14 12:45:10 +0000418
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100419 HGraph* graph = CreateGraph(&allocator);
David Brazdilbadd8262016-02-02 16:28:56 +0000420
David Brazdil58282f42016-01-14 12:45:10 +0000421 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
422 graph->AddBlock(entry);
423 graph->SetEntryBlock(entry);
424 entry->AddInstruction(new (&allocator) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100425
David Brazdil58282f42016-01-14 12:45:10 +0000426 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
427 graph->AddBlock(first_block);
428 entry->AddSuccessor(first_block);
429 HIntConstant* constant0 = graph->GetIntConstant(0);
430 HIntConstant* constant1 = graph->GetIntConstant(1);
431 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
432 first_block->AddInstruction(equal);
433 first_block->AddInstruction(new (&allocator) HIf(equal));
434
435 HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
436 HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100437 HBasicBlock* exit_block = new (&allocator) 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
448 exit_block->AddInstruction(new (&allocator) HExit());
449 then_block->AddInstruction(new (&allocator) HReturn(constant0));
450 else_block->AddInstruction(new (&allocator) HReturn(constant1));
451
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];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800459 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
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++) {
479 ArenaPool pool;
480 ArenaAllocator allocator(&pool);
481 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100482
David Brazdil58282f42016-01-14 12:45:10 +0000483 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
484 graph->AddBlock(entry_block);
485 graph->SetEntryBlock(entry_block);
486 entry_block->AddInstruction(new (&allocator) HGoto());
487 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
488 graph->AddBlock(code_block);
489 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
490 graph->AddBlock(exit_block);
491 exit_block->AddInstruction(new (&allocator) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100492
David Brazdil58282f42016-01-14 12:45:10 +0000493 entry_block->AddSuccessor(code_block);
494 code_block->AddSuccessor(exit_block);
495 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100496
David Brazdil58282f42016-01-14 12:45:10 +0000497 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
498 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
499 HLessThan cmp_lt(cst_lhs, cst_rhs);
500 code_block->AddInstruction(&cmp_lt);
501 HReturn ret(&cmp_lt);
502 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100503
David Brazdilbadd8262016-02-02 16:28:56 +0000504 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000505 auto hook_before_codegen = [](HGraph* graph_in) {
506 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
507 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
508 block->InsertInstructionBefore(move, block->GetLastInstruction());
509 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100510 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000511 }
Alexandre Rames92730742014-10-01 12:55:56 +0100512 }
513}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100514
David Brazdil58282f42016-01-14 12:45:10 +0000515TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100516 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000517 // Check that HIf correctly interprets a materialized condition.
518 // We force the materialization of comparisons for different combinations of
519 // inputs. An HIf takes the materialized combination as input and returns a
520 // value that we verify.
521
522 int lhs[] = {1, 2, -1, 2, 0xabc};
523 int rhs[] = {2, 1, 2, -1, 0xabc};
524
525
526 for (size_t i = 0; i < arraysize(lhs); i++) {
527 ArenaPool pool;
528 ArenaAllocator allocator(&pool);
529 HGraph* graph = CreateGraph(&allocator);
530
531 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
532 graph->AddBlock(entry_block);
533 graph->SetEntryBlock(entry_block);
534 entry_block->AddInstruction(new (&allocator) HGoto());
535
536 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
537 graph->AddBlock(if_block);
538 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
539 graph->AddBlock(if_true_block);
540 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
541 graph->AddBlock(if_false_block);
542 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
543 graph->AddBlock(exit_block);
544 exit_block->AddInstruction(new (&allocator) HExit());
545
546 graph->SetEntryBlock(entry_block);
547 entry_block->AddSuccessor(if_block);
548 if_block->AddSuccessor(if_true_block);
549 if_block->AddSuccessor(if_false_block);
550 if_true_block->AddSuccessor(exit_block);
551 if_false_block->AddSuccessor(exit_block);
552 graph->SetExitBlock(exit_block);
553
554 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
555 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
556 HLessThan cmp_lt(cst_lhs, cst_rhs);
557 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000558 // We insert a dummy instruction to separate the HIf from the HLessThan
559 // and force the materialization of the condition.
560 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000561 if_block->AddInstruction(&force_materialization);
562 HIf if_lt(&cmp_lt);
563 if_block->AddInstruction(&if_lt);
564
565 HIntConstant* cst_lt = graph->GetIntConstant(1);
566 HReturn ret_lt(cst_lt);
567 if_true_block->AddInstruction(&ret_lt);
568 HIntConstant* cst_ge = graph->GetIntConstant(0);
569 HReturn ret_ge(cst_ge);
570 if_false_block->AddInstruction(&ret_ge);
571
David Brazdilbadd8262016-02-02 16:28:56 +0000572 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000573 auto hook_before_codegen = [](HGraph* graph_in) {
574 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
575 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
576 block->InsertInstructionBefore(move, block->GetLastInstruction());
577 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100578 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000579 }
580 }
581}
582
583TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000584 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
585 Instruction::CONST_4 | 4 << 12 | 0 << 8,
586 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
587 Instruction::RETURN);
588
David Brazdil58282f42016-01-14 12:45:10 +0000589 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000590}
591
David Brazdil58282f42016-01-14 12:45:10 +0000592TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000593 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
594 Instruction::CONST_4 | 4 << 12 | 0,
595 Instruction::CONST_4 | 2 << 12 | 1 << 8,
596 Instruction::DIV_INT_2ADDR | 1 << 12,
597 Instruction::RETURN);
598
David Brazdil58282f42016-01-14 12:45:10 +0000599 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000600}
601
Aart Bike9f37602015-10-09 11:15:55 -0700602// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800603static void TestComparison(IfCondition condition,
604 int64_t i,
605 int64_t j,
606 Primitive::Type type,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100607 const CodegenTargetConfig target_config) {
Aart Bike9f37602015-10-09 11:15:55 -0700608 ArenaPool pool;
609 ArenaAllocator allocator(&pool);
610 HGraph* graph = CreateGraph(&allocator);
611
612 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
613 graph->AddBlock(entry_block);
614 graph->SetEntryBlock(entry_block);
615 entry_block->AddInstruction(new (&allocator) HGoto());
616
617 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
618 graph->AddBlock(block);
619
620 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
621 graph->AddBlock(exit_block);
622 graph->SetExitBlock(exit_block);
623 exit_block->AddInstruction(new (&allocator) HExit());
624
625 entry_block->AddSuccessor(block);
626 block->AddSuccessor(exit_block);
627
628 HInstruction* op1;
629 HInstruction* op2;
630 if (type == Primitive::kPrimInt) {
631 op1 = graph->GetIntConstant(i);
632 op2 = graph->GetIntConstant(j);
633 } else {
634 DCHECK_EQ(type, Primitive::kPrimLong);
635 op1 = graph->GetLongConstant(i);
636 op2 = graph->GetLongConstant(j);
637 }
638
639 HInstruction* comparison = nullptr;
640 bool expected_result = false;
641 const uint64_t x = i;
642 const uint64_t y = j;
643 switch (condition) {
644 case kCondEQ:
645 comparison = new (&allocator) HEqual(op1, op2);
646 expected_result = (i == j);
647 break;
648 case kCondNE:
649 comparison = new (&allocator) HNotEqual(op1, op2);
650 expected_result = (i != j);
651 break;
652 case kCondLT:
653 comparison = new (&allocator) HLessThan(op1, op2);
654 expected_result = (i < j);
655 break;
656 case kCondLE:
657 comparison = new (&allocator) HLessThanOrEqual(op1, op2);
658 expected_result = (i <= j);
659 break;
660 case kCondGT:
661 comparison = new (&allocator) HGreaterThan(op1, op2);
662 expected_result = (i > j);
663 break;
664 case kCondGE:
665 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
666 expected_result = (i >= j);
667 break;
668 case kCondB:
669 comparison = new (&allocator) HBelow(op1, op2);
670 expected_result = (x < y);
671 break;
672 case kCondBE:
673 comparison = new (&allocator) HBelowOrEqual(op1, op2);
674 expected_result = (x <= y);
675 break;
676 case kCondA:
677 comparison = new (&allocator) HAbove(op1, op2);
678 expected_result = (x > y);
679 break;
680 case kCondAE:
681 comparison = new (&allocator) HAboveOrEqual(op1, op2);
682 expected_result = (x >= y);
683 break;
684 }
685 block->AddInstruction(comparison);
686 block->AddInstruction(new (&allocator) HReturn(comparison));
687
David Brazdilbadd8262016-02-02 16:28:56 +0000688 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +0100689 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700690}
691
David Brazdil58282f42016-01-14 12:45:10 +0000692TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100693 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000694 for (int64_t i = -1; i <= 1; i++) {
695 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100696 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
697 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
698 }
David Brazdil58282f42016-01-14 12:45:10 +0000699 }
Aart Bike9f37602015-10-09 11:15:55 -0700700 }
701 }
702}
703
David Brazdil58282f42016-01-14 12:45:10 +0000704TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100705 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000706 for (int64_t i = -1; i <= 1; i++) {
707 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100708 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
709 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
710 }
David Brazdil58282f42016-01-14 12:45:10 +0000711 }
Aart Bike9f37602015-10-09 11:15:55 -0700712 }
713 }
714}
715
Artem Serov4593f7d2016-12-29 16:21:49 +0000716#ifdef ART_ENABLE_CODEGEN_arm
717TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
718 std::unique_ptr<const ArmInstructionSetFeatures> features(
719 ArmInstructionSetFeatures::FromCppDefines());
720 ArenaPool pool;
721 ArenaAllocator allocator(&pool);
722 HGraph* graph = CreateGraph(&allocator);
723 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
724
725 codegen.Initialize();
726
727 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
728 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
729 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
730 // LDR encoding. So the following code is a regression test for that situation.
731 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
732 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), Primitive::kPrimInt, nullptr);
733 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), Primitive::kPrimInt, nullptr);
734 codegen.GetMoveResolver()->EmitNativeCode(move);
735
736 InternalCodeAllocator code_allocator;
737 codegen.Finalize(&code_allocator);
738}
739#endif
740
Roland Levillain558dea12017-01-27 19:40:44 +0000741#ifdef ART_ENABLE_CODEGEN_arm64
742// Regression test for b/34760542.
743TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
744 std::unique_ptr<const Arm64InstructionSetFeatures> features(
745 Arm64InstructionSetFeatures::FromCppDefines());
746 ArenaPool pool;
747 ArenaAllocator allocator(&pool);
748 HGraph* graph = CreateGraph(&allocator);
749 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
750
751 codegen.Initialize();
752
753 // The following ParallelMove used to fail this assertion:
754 //
755 // Assertion failed (!available->IsEmpty())
756 //
757 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable.
758 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
759 move->AddMove(Location::DoubleStackSlot(0),
760 Location::DoubleStackSlot(257),
761 Primitive::kPrimDouble,
762 nullptr);
763 move->AddMove(Location::DoubleStackSlot(257),
764 Location::DoubleStackSlot(0),
765 Primitive::kPrimDouble,
766 nullptr);
767 codegen.GetMoveResolver()->EmitNativeCode(move);
768
769 InternalCodeAllocator code_allocator;
770 codegen.Finalize(&code_allocator);
771}
Artem Serovd4bccf12017-04-03 18:47:32 +0100772
773// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
774TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
775 std::unique_ptr<const Arm64InstructionSetFeatures> features(
776 Arm64InstructionSetFeatures::FromCppDefines());
777 ArenaPool pool;
778 ArenaAllocator allocator(&pool);
779 HGraph* graph = CreateGraph(&allocator);
780 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
781
782 codegen.Initialize();
783
784 graph->SetHasSIMD(true);
785 for (int i = 0; i < 2; i++) {
786 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
787 move->AddMove(Location::SIMDStackSlot(0),
788 Location::SIMDStackSlot(257),
789 Primitive::kPrimDouble,
790 nullptr);
791 move->AddMove(Location::SIMDStackSlot(257),
792 Location::SIMDStackSlot(0),
793 Primitive::kPrimDouble,
794 nullptr);
795 move->AddMove(Location::FpuRegisterLocation(0),
796 Location::FpuRegisterLocation(1),
797 Primitive::kPrimDouble,
798 nullptr);
799 move->AddMove(Location::FpuRegisterLocation(1),
800 Location::FpuRegisterLocation(0),
801 Primitive::kPrimDouble,
802 nullptr);
803 codegen.GetMoveResolver()->EmitNativeCode(move);
804 graph->SetHasSIMD(false);
805 }
806
807 InternalCodeAllocator code_allocator;
808 codegen.Finalize(&code_allocator);
809}
810
Roland Levillain558dea12017-01-27 19:40:44 +0000811#endif
812
Alexey Frunze58320ce2016-08-30 21:40:46 -0700813#ifdef ART_ENABLE_CODEGEN_mips
814TEST_F(CodegenTest, MipsClobberRA) {
815 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
816 MipsInstructionSetFeatures::FromCppDefines());
817 if (!CanExecute(kMips) || features_mips->IsR6()) {
818 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
819 // should only be generated on non-R6.
820 return;
821 }
822
823 ArenaPool pool;
824 ArenaAllocator allocator(&pool);
825 HGraph* graph = CreateGraph(&allocator);
826
827 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
828 graph->AddBlock(entry_block);
829 graph->SetEntryBlock(entry_block);
830 entry_block->AddInstruction(new (&allocator) HGoto());
831
832 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
833 graph->AddBlock(block);
834
835 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
836 graph->AddBlock(exit_block);
837 graph->SetExitBlock(exit_block);
838 exit_block->AddInstruction(new (&allocator) HExit());
839
840 entry_block->AddSuccessor(block);
841 block->AddSuccessor(exit_block);
842
843 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
844 // Instead, generate HMipsComputeBaseMethodAddress directly.
845 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
846 block->AddInstruction(base);
847 // HMipsComputeBaseMethodAddress is defined as int, so just make the
848 // compiled method return it.
849 block->AddInstruction(new (&allocator) HReturn(base));
850
851 graph->BuildDominatorTree();
852
853 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
854 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
855 // that RA is clobbered and the method entry code should generate a stack frame
856 // and preserve RA in it. And this is what we're testing here.
857 codegenMIPS.ClobberRA();
858 // Without ClobberRA() the code would be:
859 // nal # Sets RA to point to the jr instruction below
860 // move v0, ra # and the CPU falls into an infinite loop.
861 // jr ra
862 // nop
863 // The expected code is:
864 // addiu sp, sp, -16
865 // sw ra, 12(sp)
866 // sw a0, 0(sp)
867 // nal # Sets RA to point to the lw instruction below.
868 // move v0, ra
869 // lw ra, 12(sp)
870 // jr ra
871 // addiu sp, sp, 16
872 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
873}
874#endif
875
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000876} // namespace art