blob: 0a8e97cf0dd169963393cba4262709c35d93efe0 [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
Roland Levillain9983e302017-07-14 14:34:22 +010046 // TODO: Should't this be `kThumb2` instead of `kArm` here?
Scott Wakelingfe885462016-09-22 10:24:38 +010047 CodegenTargetConfig(kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +010048#endif
49#ifdef ART_ENABLE_CODEGEN_arm64
50 CodegenTargetConfig(kArm64, create_codegen_arm64),
51#endif
52#ifdef ART_ENABLE_CODEGEN_x86
53 CodegenTargetConfig(kX86, create_codegen_x86),
54#endif
55#ifdef ART_ENABLE_CODEGEN_x86_64
56 CodegenTargetConfig(kX86_64, create_codegen_x86_64),
57#endif
58#ifdef ART_ENABLE_CODEGEN_mips
59 CodegenTargetConfig(kMips, create_codegen_mips),
60#endif
61#ifdef ART_ENABLE_CODEGEN_mips64
62 CodegenTargetConfig(kMips64, create_codegen_mips64)
63#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
75static void TestCode(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +080076 bool has_result = false,
77 int32_t expected = 0) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010078 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +000079 ArenaPool pool;
80 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000081 HGraph* graph = CreateCFG(&arena, data);
David Brazdil58282f42016-01-14 12:45:10 +000082 // Remove suspend checks, they cannot be executed in this context.
83 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010084 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000085 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010086}
87
David Brazdil58282f42016-01-14 12:45:10 +000088static void TestCodeLong(const uint16_t* data,
Phil Wang751beff2015-08-28 15:17:15 +080089 bool has_result,
90 int64_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010091 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +000092 ArenaPool pool;
93 ArenaAllocator arena(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000094 HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
David Brazdil58282f42016-01-14 12:45:10 +000095 // Remove suspend checks, they cannot be executed in this context.
96 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010097 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000098 }
Roland Levillain55dcfb52014-10-24 18:09:09 +010099}
100
David Brazdil58282f42016-01-14 12:45:10 +0000101class CodegenTest : public CommonCompilerTest {};
Phil Wang751beff2015-08-28 15:17:15 +0800102
David Brazdil58282f42016-01-14 12:45:10 +0000103TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000104 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000105 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000106}
107
David Brazdil58282f42016-01-14 12:45:10 +0000108TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000109 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000110 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000111 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000112
David Brazdil58282f42016-01-14 12:45:10 +0000113 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000114}
115
David Brazdil58282f42016-01-14 12:45:10 +0000116TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000117 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000118 Instruction::GOTO | 0x100,
119 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000120 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000121
David Brazdil58282f42016-01-14 12:45:10 +0000122 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000123}
124
David Brazdil58282f42016-01-14 12:45:10 +0000125TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000126 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000127 Instruction::GOTO | 0x200,
128 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000129 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000130
David Brazdil58282f42016-01-14 12:45:10 +0000131 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000132
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000133 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000134 Instruction::GOTO_16, 3,
135 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000136 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000137
David Brazdil58282f42016-01-14 12:45:10 +0000138 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000139
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000140 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000141 Instruction::GOTO_32, 4, 0,
142 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000143 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000144
David Brazdil58282f42016-01-14 12:45:10 +0000145 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000146}
147
David Brazdil58282f42016-01-14 12:45:10 +0000148TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000149 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000150 Instruction::RETURN_VOID,
151 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000152 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000153
David Brazdil58282f42016-01-14 12:45:10 +0000154 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000155}
156
David Brazdil58282f42016-01-14 12:45:10 +0000157TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000158 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
159 Instruction::CONST_4 | 0 | 0,
160 Instruction::IF_EQ, 3,
161 Instruction::GOTO | 0x100,
162 Instruction::RETURN_VOID);
163
David Brazdil58282f42016-01-14 12:45:10 +0000164 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000165}
166
David Brazdil58282f42016-01-14 12:45:10 +0000167TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000168 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
169 Instruction::CONST_4 | 0 | 0,
170 Instruction::RETURN_VOID);
171
David Brazdil58282f42016-01-14 12:45:10 +0000172 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000173}
174
David Brazdil58282f42016-01-14 12:45:10 +0000175TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000176 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
177 Instruction::CONST_4 | 0 | 0,
178 Instruction::RETURN | 0);
179
David Brazdil58282f42016-01-14 12:45:10 +0000180 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000181}
182
David Brazdil58282f42016-01-14 12:45:10 +0000183TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000184 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
185 Instruction::CONST_4 | 0 | 0,
186 Instruction::CONST_4 | 0 | 1 << 8,
187 Instruction::RETURN | 1 << 8);
188
David Brazdil58282f42016-01-14 12:45:10 +0000189 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000190}
191
David Brazdil58282f42016-01-14 12:45:10 +0000192TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000193 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
194 Instruction::CONST_4 | 0 | 0,
195 Instruction::CONST_4 | 1 << 8 | 1 << 12,
196 Instruction::RETURN | 1 << 8);
197
David Brazdil58282f42016-01-14 12:45:10 +0000198 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000199}
200
David Brazdil58282f42016-01-14 12:45:10 +0000201TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000202 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
203 Instruction::CONST_4 | 0 | 0,
204 Instruction::CONST_4 | 1 << 8 | 1 << 12,
205 Instruction::IF_EQ, 3,
206 Instruction::RETURN | 0 << 8,
207 Instruction::RETURN | 1 << 8);
208
David Brazdil58282f42016-01-14 12:45:10 +0000209 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000210}
211
David Brazdil58282f42016-01-14 12:45:10 +0000212TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000213 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
214 Instruction::CONST_4 | 0 | 0,
215 Instruction::CONST_4 | 1 << 8 | 1 << 12,
216 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
217 Instruction::RETURN | 0 << 8,
218 Instruction::RETURN | 1 << 8);
219
David Brazdil58282f42016-01-14 12:45:10 +0000220 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000221}
222
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100223// Exercise bit-wise (one's complement) not-int instruction.
224#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000225TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100226 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100227 const uint16_t input_lo = Low16Bits(input); \
228 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100229 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
230 Instruction::CONST | 0 << 8, input_lo, input_hi, \
231 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
232 Instruction::RETURN | 1 << 8); \
233 \
David Brazdil58282f42016-01-14 12:45:10 +0000234 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100235}
236
237NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
238NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
239NOT_INT_TEST(ReturnNotInt0, 0, -1)
240NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100241NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
242NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
243NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
244NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100245
246#undef NOT_INT_TEST
247
Roland Levillain55dcfb52014-10-24 18:09:09 +0100248// Exercise bit-wise (one's complement) not-long instruction.
249#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000250TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100251 const int64_t input = INPUT; \
252 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
253 const uint16_t word1 = High16Bits(Low32Bits(input)); \
254 const uint16_t word2 = Low16Bits(High32Bits(input)); \
255 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
256 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
257 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
258 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
259 Instruction::RETURN_WIDE | 2 << 8); \
260 \
David Brazdil58282f42016-01-14 12:45:10 +0000261 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100262}
263
264NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
265NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
266NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
267NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
268
269NOT_LONG_TEST(ReturnNotLongINT32_MIN,
270 INT64_C(-2147483648),
271 INT64_C(2147483647)) // (2^31) - 1
272NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
273 INT64_C(-2147483647),
274 INT64_C(2147483646)) // (2^31) - 2
275NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
276 INT64_C(2147483646),
277 INT64_C(-2147483647)) // -(2^31) - 1
278NOT_LONG_TEST(ReturnNotLongINT32_MAX,
279 INT64_C(2147483647),
280 INT64_C(-2147483648)) // -(2^31)
281
282// Note that the C++ compiler won't accept
283// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
284// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
285NOT_LONG_TEST(ReturnNotINT64_MIN,
286 INT64_C(-9223372036854775807)-1,
287 INT64_C(9223372036854775807)); // (2^63) - 1
288NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
289 INT64_C(-9223372036854775807),
290 INT64_C(9223372036854775806)); // (2^63) - 2
291NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
292 INT64_C(9223372036854775806),
293 INT64_C(-9223372036854775807)); // -(2^63) - 1
294NOT_LONG_TEST(ReturnNotLongINT64_MAX,
295 INT64_C(9223372036854775807),
296 INT64_C(-9223372036854775807)-1); // -(2^63)
297
298#undef NOT_LONG_TEST
299
David Brazdil58282f42016-01-14 12:45:10 +0000300TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000301 const int64_t input = INT64_C(4294967296); // 2^32
302 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
303 const uint16_t word1 = High16Bits(Low32Bits(input));
304 const uint16_t word2 = Low16Bits(High32Bits(input));
305 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
306 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
307 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
308 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
309 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
310 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
311 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
312 Instruction::RETURN_WIDE | 2 << 8);
313
David Brazdil58282f42016-01-14 12:45:10 +0000314 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000315}
316
David Brazdil58282f42016-01-14 12:45:10 +0000317TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000318 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
319 Instruction::CONST_4 | 3 << 12 | 0,
320 Instruction::CONST_4 | 4 << 12 | 1 << 8,
321 Instruction::ADD_INT, 1 << 8 | 0,
322 Instruction::RETURN);
323
David Brazdil58282f42016-01-14 12:45:10 +0000324 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000325}
326
David Brazdil58282f42016-01-14 12:45:10 +0000327TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000328 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
329 Instruction::CONST_4 | 3 << 12 | 0,
330 Instruction::CONST_4 | 4 << 12 | 1 << 8,
331 Instruction::ADD_INT_2ADDR | 1 << 12,
332 Instruction::RETURN);
333
David Brazdil58282f42016-01-14 12:45:10 +0000334 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000335}
336
David Brazdil58282f42016-01-14 12:45:10 +0000337TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000338 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
339 Instruction::CONST_4 | 4 << 12 | 0 << 8,
340 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
341 Instruction::RETURN);
342
David Brazdil58282f42016-01-14 12:45:10 +0000343 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000344}
345
David Brazdil58282f42016-01-14 12:45:10 +0000346TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000347 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
348 Instruction::CONST_4 | 4 << 12 | 0 << 8,
349 Instruction::ADD_INT_LIT16, 3,
350 Instruction::RETURN);
351
David Brazdil58282f42016-01-14 12:45:10 +0000352 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000353}
354
David Brazdil58282f42016-01-14 12:45:10 +0000355TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100356 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
357 Instruction::CONST_4 | 3 << 12 | 0,
358 Instruction::CONST_4 | 4 << 12 | 1 << 8,
359 Instruction::MUL_INT, 1 << 8 | 0,
360 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100361
David Brazdil58282f42016-01-14 12:45:10 +0000362 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100363}
364
David Brazdil58282f42016-01-14 12:45:10 +0000365TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100366 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
367 Instruction::CONST_4 | 3 << 12 | 0,
368 Instruction::CONST_4 | 4 << 12 | 1 << 8,
369 Instruction::MUL_INT_2ADDR | 1 << 12,
370 Instruction::RETURN);
371
David Brazdil58282f42016-01-14 12:45:10 +0000372 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100373}
374
David Brazdil58282f42016-01-14 12:45:10 +0000375TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100376 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000377 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
378 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100379 Instruction::MUL_LONG, 2 << 8 | 0,
380 Instruction::RETURN_WIDE);
381
David Brazdil58282f42016-01-14 12:45:10 +0000382 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100383}
384
David Brazdil58282f42016-01-14 12:45:10 +0000385TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100386 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000387 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
388 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100389 Instruction::MUL_LONG_2ADDR | 2 << 12,
390 Instruction::RETURN_WIDE);
391
David Brazdil58282f42016-01-14 12:45:10 +0000392 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100393}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100394
David Brazdil58282f42016-01-14 12:45:10 +0000395TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100396 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
397 Instruction::CONST_4 | 4 << 12 | 0 << 8,
398 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
399 Instruction::RETURN);
400
David Brazdil58282f42016-01-14 12:45:10 +0000401 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100402}
403
David Brazdil58282f42016-01-14 12:45:10 +0000404TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100405 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
406 Instruction::CONST_4 | 4 << 12 | 0 << 8,
407 Instruction::MUL_INT_LIT16, 3,
408 Instruction::RETURN);
409
David Brazdil58282f42016-01-14 12:45:10 +0000410 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100411}
412
David Brazdil58282f42016-01-14 12:45:10 +0000413TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100414 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Alexandre Rames92730742014-10-01 12:55:56 +0100415 ArenaPool pool;
416 ArenaAllocator allocator(&pool);
David Brazdil58282f42016-01-14 12:45:10 +0000417
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100418 HGraph* graph = CreateGraph(&allocator);
David Brazdilbadd8262016-02-02 16:28:56 +0000419
David Brazdil58282f42016-01-14 12:45:10 +0000420 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
421 graph->AddBlock(entry);
422 graph->SetEntryBlock(entry);
423 entry->AddInstruction(new (&allocator) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100424
David Brazdil58282f42016-01-14 12:45:10 +0000425 HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
426 graph->AddBlock(first_block);
427 entry->AddSuccessor(first_block);
428 HIntConstant* constant0 = graph->GetIntConstant(0);
429 HIntConstant* constant1 = graph->GetIntConstant(1);
430 HEqual* equal = new (&allocator) HEqual(constant0, constant0);
431 first_block->AddInstruction(equal);
432 first_block->AddInstruction(new (&allocator) HIf(equal));
433
434 HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
435 HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100436 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100437 graph->SetExitBlock(exit_block);
438
David Brazdil58282f42016-01-14 12:45:10 +0000439 graph->AddBlock(then_block);
440 graph->AddBlock(else_block);
441 graph->AddBlock(exit_block);
442 first_block->AddSuccessor(then_block);
443 first_block->AddSuccessor(else_block);
444 then_block->AddSuccessor(exit_block);
445 else_block->AddSuccessor(exit_block);
446
447 exit_block->AddInstruction(new (&allocator) HExit());
448 then_block->AddInstruction(new (&allocator) HReturn(constant0));
449 else_block->AddInstruction(new (&allocator) HReturn(constant1));
450
David Brazdilb11b0722016-01-28 16:22:40 +0000451 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000452 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000453 PrepareForRegisterAllocation(graph).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000454 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100455
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800456 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100457 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800458 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
Alexandre Rames92730742014-10-01 12:55:56 +0100459 block->InsertInstructionBefore(move, block->GetLastInstruction());
460 };
461
Scott Wakeling2c76e062016-08-31 09:48:54 +0100462 RunCode(target_config, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100463 }
464}
465
David Brazdil58282f42016-01-14 12:45:10 +0000466TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100467 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000468 // Check that condition are materialized correctly. A materialized condition
469 // should yield `1` if it evaluated to true, and `0` otherwise.
470 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100471
David Brazdil58282f42016-01-14 12:45:10 +0000472 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100473
David Brazdil58282f42016-01-14 12:45:10 +0000474 int lhs[] = {1, 2, -1, 2, 0xabc};
475 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100476
David Brazdil58282f42016-01-14 12:45:10 +0000477 for (size_t i = 0; i < arraysize(lhs); i++) {
478 ArenaPool pool;
479 ArenaAllocator allocator(&pool);
480 HGraph* graph = CreateGraph(&allocator);
Alexandre Rames92730742014-10-01 12:55:56 +0100481
David Brazdil58282f42016-01-14 12:45:10 +0000482 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
483 graph->AddBlock(entry_block);
484 graph->SetEntryBlock(entry_block);
485 entry_block->AddInstruction(new (&allocator) HGoto());
486 HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
487 graph->AddBlock(code_block);
488 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
489 graph->AddBlock(exit_block);
490 exit_block->AddInstruction(new (&allocator) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100491
David Brazdil58282f42016-01-14 12:45:10 +0000492 entry_block->AddSuccessor(code_block);
493 code_block->AddSuccessor(exit_block);
494 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100495
David Brazdil58282f42016-01-14 12:45:10 +0000496 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
497 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
498 HLessThan cmp_lt(cst_lhs, cst_rhs);
499 code_block->AddInstruction(&cmp_lt);
500 HReturn ret(&cmp_lt);
501 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100502
David Brazdilbadd8262016-02-02 16:28:56 +0000503 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000504 auto hook_before_codegen = [](HGraph* graph_in) {
505 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
506 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
507 block->InsertInstructionBefore(move, block->GetLastInstruction());
508 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100509 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000510 }
Alexandre Rames92730742014-10-01 12:55:56 +0100511 }
512}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100513
David Brazdil58282f42016-01-14 12:45:10 +0000514TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100515 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000516 // Check that HIf correctly interprets a materialized condition.
517 // We force the materialization of comparisons for different combinations of
518 // inputs. An HIf takes the materialized combination as input and returns a
519 // value that we verify.
520
521 int lhs[] = {1, 2, -1, 2, 0xabc};
522 int rhs[] = {2, 1, 2, -1, 0xabc};
523
524
525 for (size_t i = 0; i < arraysize(lhs); i++) {
526 ArenaPool pool;
527 ArenaAllocator allocator(&pool);
528 HGraph* graph = CreateGraph(&allocator);
529
530 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
531 graph->AddBlock(entry_block);
532 graph->SetEntryBlock(entry_block);
533 entry_block->AddInstruction(new (&allocator) HGoto());
534
535 HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
536 graph->AddBlock(if_block);
537 HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
538 graph->AddBlock(if_true_block);
539 HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
540 graph->AddBlock(if_false_block);
541 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
542 graph->AddBlock(exit_block);
543 exit_block->AddInstruction(new (&allocator) HExit());
544
545 graph->SetEntryBlock(entry_block);
546 entry_block->AddSuccessor(if_block);
547 if_block->AddSuccessor(if_true_block);
548 if_block->AddSuccessor(if_false_block);
549 if_true_block->AddSuccessor(exit_block);
550 if_false_block->AddSuccessor(exit_block);
551 graph->SetExitBlock(exit_block);
552
553 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
554 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
555 HLessThan cmp_lt(cst_lhs, cst_rhs);
556 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000557 // We insert a dummy instruction to separate the HIf from the HLessThan
558 // and force the materialization of the condition.
559 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000560 if_block->AddInstruction(&force_materialization);
561 HIf if_lt(&cmp_lt);
562 if_block->AddInstruction(&if_lt);
563
564 HIntConstant* cst_lt = graph->GetIntConstant(1);
565 HReturn ret_lt(cst_lt);
566 if_true_block->AddInstruction(&ret_lt);
567 HIntConstant* cst_ge = graph->GetIntConstant(0);
568 HReturn ret_ge(cst_ge);
569 if_false_block->AddInstruction(&ret_ge);
570
David Brazdilbadd8262016-02-02 16:28:56 +0000571 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000572 auto hook_before_codegen = [](HGraph* graph_in) {
573 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
574 HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
575 block->InsertInstructionBefore(move, block->GetLastInstruction());
576 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100577 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000578 }
579 }
580}
581
582TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000583 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
584 Instruction::CONST_4 | 4 << 12 | 0 << 8,
585 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
586 Instruction::RETURN);
587
David Brazdil58282f42016-01-14 12:45:10 +0000588 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000589}
590
David Brazdil58282f42016-01-14 12:45:10 +0000591TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000592 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
593 Instruction::CONST_4 | 4 << 12 | 0,
594 Instruction::CONST_4 | 2 << 12 | 1 << 8,
595 Instruction::DIV_INT_2ADDR | 1 << 12,
596 Instruction::RETURN);
597
David Brazdil58282f42016-01-14 12:45:10 +0000598 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000599}
600
Aart Bike9f37602015-10-09 11:15:55 -0700601// Helper method.
Phil Wang751beff2015-08-28 15:17:15 +0800602static void TestComparison(IfCondition condition,
603 int64_t i,
604 int64_t j,
605 Primitive::Type type,
Scott Wakeling2c76e062016-08-31 09:48:54 +0100606 const CodegenTargetConfig target_config) {
Aart Bike9f37602015-10-09 11:15:55 -0700607 ArenaPool pool;
608 ArenaAllocator allocator(&pool);
609 HGraph* graph = CreateGraph(&allocator);
610
611 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
612 graph->AddBlock(entry_block);
613 graph->SetEntryBlock(entry_block);
614 entry_block->AddInstruction(new (&allocator) HGoto());
615
616 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
617 graph->AddBlock(block);
618
619 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
620 graph->AddBlock(exit_block);
621 graph->SetExitBlock(exit_block);
622 exit_block->AddInstruction(new (&allocator) HExit());
623
624 entry_block->AddSuccessor(block);
625 block->AddSuccessor(exit_block);
626
627 HInstruction* op1;
628 HInstruction* op2;
629 if (type == Primitive::kPrimInt) {
630 op1 = graph->GetIntConstant(i);
631 op2 = graph->GetIntConstant(j);
632 } else {
633 DCHECK_EQ(type, Primitive::kPrimLong);
634 op1 = graph->GetLongConstant(i);
635 op2 = graph->GetLongConstant(j);
636 }
637
638 HInstruction* comparison = nullptr;
639 bool expected_result = false;
640 const uint64_t x = i;
641 const uint64_t y = j;
642 switch (condition) {
643 case kCondEQ:
644 comparison = new (&allocator) HEqual(op1, op2);
645 expected_result = (i == j);
646 break;
647 case kCondNE:
648 comparison = new (&allocator) HNotEqual(op1, op2);
649 expected_result = (i != j);
650 break;
651 case kCondLT:
652 comparison = new (&allocator) HLessThan(op1, op2);
653 expected_result = (i < j);
654 break;
655 case kCondLE:
656 comparison = new (&allocator) HLessThanOrEqual(op1, op2);
657 expected_result = (i <= j);
658 break;
659 case kCondGT:
660 comparison = new (&allocator) HGreaterThan(op1, op2);
661 expected_result = (i > j);
662 break;
663 case kCondGE:
664 comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
665 expected_result = (i >= j);
666 break;
667 case kCondB:
668 comparison = new (&allocator) HBelow(op1, op2);
669 expected_result = (x < y);
670 break;
671 case kCondBE:
672 comparison = new (&allocator) HBelowOrEqual(op1, op2);
673 expected_result = (x <= y);
674 break;
675 case kCondA:
676 comparison = new (&allocator) HAbove(op1, op2);
677 expected_result = (x > y);
678 break;
679 case kCondAE:
680 comparison = new (&allocator) HAboveOrEqual(op1, op2);
681 expected_result = (x >= y);
682 break;
683 }
684 block->AddInstruction(comparison);
685 block->AddInstruction(new (&allocator) HReturn(comparison));
686
David Brazdilbadd8262016-02-02 16:28:56 +0000687 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +0100688 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700689}
690
David Brazdil58282f42016-01-14 12:45:10 +0000691TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100692 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000693 for (int64_t i = -1; i <= 1; i++) {
694 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100695 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
696 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
697 }
David Brazdil58282f42016-01-14 12:45:10 +0000698 }
Aart Bike9f37602015-10-09 11:15:55 -0700699 }
700 }
701}
702
David Brazdil58282f42016-01-14 12:45:10 +0000703TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100704 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000705 for (int64_t i = -1; i <= 1; i++) {
706 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100707 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
708 TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
709 }
David Brazdil58282f42016-01-14 12:45:10 +0000710 }
Aart Bike9f37602015-10-09 11:15:55 -0700711 }
712 }
713}
714
Artem Serov4593f7d2016-12-29 16:21:49 +0000715#ifdef ART_ENABLE_CODEGEN_arm
716TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
717 std::unique_ptr<const ArmInstructionSetFeatures> features(
718 ArmInstructionSetFeatures::FromCppDefines());
719 ArenaPool pool;
720 ArenaAllocator allocator(&pool);
721 HGraph* graph = CreateGraph(&allocator);
722 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
723
724 codegen.Initialize();
725
726 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
727 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
728 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
729 // LDR encoding. So the following code is a regression test for that situation.
730 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
731 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), Primitive::kPrimInt, nullptr);
732 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), Primitive::kPrimInt, nullptr);
733 codegen.GetMoveResolver()->EmitNativeCode(move);
734
735 InternalCodeAllocator code_allocator;
736 codegen.Finalize(&code_allocator);
737}
738#endif
739
Roland Levillain558dea12017-01-27 19:40:44 +0000740#ifdef ART_ENABLE_CODEGEN_arm64
741// Regression test for b/34760542.
742TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
743 std::unique_ptr<const Arm64InstructionSetFeatures> features(
744 Arm64InstructionSetFeatures::FromCppDefines());
745 ArenaPool pool;
746 ArenaAllocator allocator(&pool);
747 HGraph* graph = CreateGraph(&allocator);
748 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
749
750 codegen.Initialize();
751
752 // The following ParallelMove used to fail this assertion:
753 //
754 // Assertion failed (!available->IsEmpty())
755 //
Roland Levillain952b2352017-05-03 19:49:14 +0100756 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
757 // because of the following situation:
758 //
759 // 1. a temp register (IP0) is allocated as a scratch register by
760 // the parallel move resolver to solve a cycle (swap):
761 //
762 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
763 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
764 //
765 // 2. within CodeGeneratorARM64::MoveLocation, another temp
766 // register (IP1) is allocated to generate the swap between two
767 // double stack slots;
768 //
769 // 3. VIXL requires a third temp register to emit the `Ldr` or
770 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
771 // one of the stack slots' offsets cannot be encoded as an
772 // immediate), but the pool of (core) temp registers is now
773 // empty.
774 //
775 // The solution used so far is to use a floating-point temp register
776 // (D31) in step #2, so that IP1 is available for step #3.
777
Roland Levillain558dea12017-01-27 19:40:44 +0000778 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
779 move->AddMove(Location::DoubleStackSlot(0),
780 Location::DoubleStackSlot(257),
781 Primitive::kPrimDouble,
782 nullptr);
783 move->AddMove(Location::DoubleStackSlot(257),
784 Location::DoubleStackSlot(0),
785 Primitive::kPrimDouble,
786 nullptr);
787 codegen.GetMoveResolver()->EmitNativeCode(move);
788
789 InternalCodeAllocator code_allocator;
790 codegen.Finalize(&code_allocator);
791}
Artem Serovd4bccf12017-04-03 18:47:32 +0100792
793// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
794TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
795 std::unique_ptr<const Arm64InstructionSetFeatures> features(
796 Arm64InstructionSetFeatures::FromCppDefines());
797 ArenaPool pool;
798 ArenaAllocator allocator(&pool);
799 HGraph* graph = CreateGraph(&allocator);
800 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
801
802 codegen.Initialize();
803
804 graph->SetHasSIMD(true);
805 for (int i = 0; i < 2; i++) {
806 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
807 move->AddMove(Location::SIMDStackSlot(0),
808 Location::SIMDStackSlot(257),
809 Primitive::kPrimDouble,
810 nullptr);
811 move->AddMove(Location::SIMDStackSlot(257),
812 Location::SIMDStackSlot(0),
813 Primitive::kPrimDouble,
814 nullptr);
815 move->AddMove(Location::FpuRegisterLocation(0),
816 Location::FpuRegisterLocation(1),
817 Primitive::kPrimDouble,
818 nullptr);
819 move->AddMove(Location::FpuRegisterLocation(1),
820 Location::FpuRegisterLocation(0),
821 Primitive::kPrimDouble,
822 nullptr);
823 codegen.GetMoveResolver()->EmitNativeCode(move);
824 graph->SetHasSIMD(false);
825 }
826
827 InternalCodeAllocator code_allocator;
828 codegen.Finalize(&code_allocator);
829}
Roland Levillain558dea12017-01-27 19:40:44 +0000830#endif
831
Alexey Frunze58320ce2016-08-30 21:40:46 -0700832#ifdef ART_ENABLE_CODEGEN_mips
833TEST_F(CodegenTest, MipsClobberRA) {
834 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
835 MipsInstructionSetFeatures::FromCppDefines());
836 if (!CanExecute(kMips) || features_mips->IsR6()) {
837 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
838 // should only be generated on non-R6.
839 return;
840 }
841
842 ArenaPool pool;
843 ArenaAllocator allocator(&pool);
844 HGraph* graph = CreateGraph(&allocator);
845
846 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
847 graph->AddBlock(entry_block);
848 graph->SetEntryBlock(entry_block);
849 entry_block->AddInstruction(new (&allocator) HGoto());
850
851 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
852 graph->AddBlock(block);
853
854 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
855 graph->AddBlock(exit_block);
856 graph->SetExitBlock(exit_block);
857 exit_block->AddInstruction(new (&allocator) HExit());
858
859 entry_block->AddSuccessor(block);
860 block->AddSuccessor(exit_block);
861
862 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
863 // Instead, generate HMipsComputeBaseMethodAddress directly.
864 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
865 block->AddInstruction(base);
866 // HMipsComputeBaseMethodAddress is defined as int, so just make the
867 // compiled method return it.
868 block->AddInstruction(new (&allocator) HReturn(base));
869
870 graph->BuildDominatorTree();
871
872 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
873 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
874 // that RA is clobbered and the method entry code should generate a stack frame
875 // and preserve RA in it. And this is what we're testing here.
876 codegenMIPS.ClobberRA();
877 // Without ClobberRA() the code would be:
878 // nal # Sets RA to point to the jr instruction below
879 // move v0, ra # and the CPU falls into an infinite loop.
880 // jr ra
881 // nop
882 // The expected code is:
883 // addiu sp, sp, -16
884 // sw ra, 12(sp)
885 // sw a0, 0(sp)
886 // nal # Sets RA to point to the lw instruction below.
887 // move v0, ra
888 // lw ra, 12(sp)
889 // jr ra
890 // addiu sp, sp, 16
891 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
892}
893#endif
894
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000895} // namespace art