blob: 896fcfa20de506f5e29fede61708e5058d8ca257 [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);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010094 HGraph* graph = CreateCFG(&arena, data, DataType::Type::kInt64);
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,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100605 DataType::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;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100629 if (type == DataType::Type::kInt32) {
Aart Bike9f37602015-10-09 11:15:55 -0700630 op1 = graph->GetIntConstant(i);
631 op2 = graph->GetIntConstant(j);
632 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100633 DCHECK_EQ(type, DataType::Type::kInt64);
Aart Bike9f37602015-10-09 11:15:55 -0700634 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++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100696 TestComparison(
697 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100698 }
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++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100709 TestComparison(
710 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100711 }
David Brazdil58282f42016-01-14 12:45:10 +0000712 }
Aart Bike9f37602015-10-09 11:15:55 -0700713 }
714 }
715}
716
Artem Serov4593f7d2016-12-29 16:21:49 +0000717#ifdef ART_ENABLE_CODEGEN_arm
718TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
719 std::unique_ptr<const ArmInstructionSetFeatures> features(
720 ArmInstructionSetFeatures::FromCppDefines());
721 ArenaPool pool;
722 ArenaAllocator allocator(&pool);
723 HGraph* graph = CreateGraph(&allocator);
724 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
725
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.
732 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
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) {
745 std::unique_ptr<const Arm64InstructionSetFeatures> features(
746 Arm64InstructionSetFeatures::FromCppDefines());
747 ArenaPool pool;
748 ArenaAllocator allocator(&pool);
749 HGraph* graph = CreateGraph(&allocator);
750 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
751
752 codegen.Initialize();
753
754 // The following ParallelMove used to fail this assertion:
755 //
756 // Assertion failed (!available->IsEmpty())
757 //
Roland Levillain952b2352017-05-03 19:49:14 +0100758 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
759 // because of the following situation:
760 //
761 // 1. a temp register (IP0) is allocated as a scratch register by
762 // the parallel move resolver to solve a cycle (swap):
763 //
764 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
765 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
766 //
767 // 2. within CodeGeneratorARM64::MoveLocation, another temp
768 // register (IP1) is allocated to generate the swap between two
769 // double stack slots;
770 //
771 // 3. VIXL requires a third temp register to emit the `Ldr` or
772 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
773 // one of the stack slots' offsets cannot be encoded as an
774 // immediate), but the pool of (core) temp registers is now
775 // empty.
776 //
777 // The solution used so far is to use a floating-point temp register
778 // (D31) in step #2, so that IP1 is available for step #3.
779
Roland Levillain558dea12017-01-27 19:40:44 +0000780 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
781 move->AddMove(Location::DoubleStackSlot(0),
782 Location::DoubleStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100783 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000784 nullptr);
785 move->AddMove(Location::DoubleStackSlot(257),
786 Location::DoubleStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100787 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000788 nullptr);
789 codegen.GetMoveResolver()->EmitNativeCode(move);
790
791 InternalCodeAllocator code_allocator;
792 codegen.Finalize(&code_allocator);
793}
Artem Serovd4bccf12017-04-03 18:47:32 +0100794
795// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
796TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
797 std::unique_ptr<const Arm64InstructionSetFeatures> features(
798 Arm64InstructionSetFeatures::FromCppDefines());
799 ArenaPool pool;
800 ArenaAllocator allocator(&pool);
801 HGraph* graph = CreateGraph(&allocator);
802 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
803
804 codegen.Initialize();
805
806 graph->SetHasSIMD(true);
807 for (int i = 0; i < 2; i++) {
808 HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
809 move->AddMove(Location::SIMDStackSlot(0),
810 Location::SIMDStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100811 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100812 nullptr);
813 move->AddMove(Location::SIMDStackSlot(257),
814 Location::SIMDStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100815 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100816 nullptr);
817 move->AddMove(Location::FpuRegisterLocation(0),
818 Location::FpuRegisterLocation(1),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100819 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100820 nullptr);
821 move->AddMove(Location::FpuRegisterLocation(1),
822 Location::FpuRegisterLocation(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100823 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100824 nullptr);
825 codegen.GetMoveResolver()->EmitNativeCode(move);
826 graph->SetHasSIMD(false);
827 }
828
829 InternalCodeAllocator code_allocator;
830 codegen.Finalize(&code_allocator);
831}
Roland Levillain558dea12017-01-27 19:40:44 +0000832#endif
833
Alexey Frunze58320ce2016-08-30 21:40:46 -0700834#ifdef ART_ENABLE_CODEGEN_mips
835TEST_F(CodegenTest, MipsClobberRA) {
836 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
837 MipsInstructionSetFeatures::FromCppDefines());
838 if (!CanExecute(kMips) || features_mips->IsR6()) {
839 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
840 // should only be generated on non-R6.
841 return;
842 }
843
844 ArenaPool pool;
845 ArenaAllocator allocator(&pool);
846 HGraph* graph = CreateGraph(&allocator);
847
848 HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
849 graph->AddBlock(entry_block);
850 graph->SetEntryBlock(entry_block);
851 entry_block->AddInstruction(new (&allocator) HGoto());
852
853 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
854 graph->AddBlock(block);
855
856 HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
857 graph->AddBlock(exit_block);
858 graph->SetExitBlock(exit_block);
859 exit_block->AddInstruction(new (&allocator) HExit());
860
861 entry_block->AddSuccessor(block);
862 block->AddSuccessor(exit_block);
863
864 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
865 // Instead, generate HMipsComputeBaseMethodAddress directly.
866 HMipsComputeBaseMethodAddress* base = new (&allocator) HMipsComputeBaseMethodAddress();
867 block->AddInstruction(base);
868 // HMipsComputeBaseMethodAddress is defined as int, so just make the
869 // compiled method return it.
870 block->AddInstruction(new (&allocator) HReturn(base));
871
872 graph->BuildDominatorTree();
873
874 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
875 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
876 // that RA is clobbered and the method entry code should generate a stack frame
877 // and preserve RA in it. And this is what we're testing here.
878 codegenMIPS.ClobberRA();
879 // Without ClobberRA() the code would be:
880 // nal # Sets RA to point to the jr instruction below
881 // move v0, ra # and the CPU falls into an infinite loop.
882 // jr ra
883 // nop
884 // The expected code is:
885 // addiu sp, sp, -16
886 // sw ra, 12(sp)
887 // sw a0, 0(sp)
888 // nal # Sets RA to point to the lw instruction below.
889 // move v0, ra
890 // lw ra, 12(sp)
891 // jr ra
892 // addiu sp, sp, 16
893 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
894}
895#endif
896
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000897} // namespace art