blob: e35c7c734bc36181a039e0f8c0019ae2afa49752 [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
Vladimir Markoca6fff82017-10-03 14:49:14 +010075class CodegenTest : public OptimizingUnitTest {
76 protected:
77 void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0);
78 void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected);
79 void TestComparison(IfCondition condition,
80 int64_t i,
81 int64_t j,
82 DataType::Type type,
83 const CodegenTargetConfig target_config);
84};
85
86void CodegenTest::TestCode(const uint16_t* data, bool has_result, int32_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010087 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010088 ResetPoolAndAllocator();
89 HGraph* graph = CreateCFG(data);
David Brazdil58282f42016-01-14 12:45:10 +000090 // Remove suspend checks, they cannot be executed in this context.
91 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +010092 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000093 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010094}
95
Vladimir Markoca6fff82017-10-03 14:49:14 +010096void CodegenTest::TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010097 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010098 ResetPoolAndAllocator();
99 HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
David Brazdil58282f42016-01-14 12:45:10 +0000100 // Remove suspend checks, they cannot be executed in this context.
101 RemoveSuspendChecks(graph);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100102 RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000103 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100104}
105
David Brazdil58282f42016-01-14 12:45:10 +0000106TEST_F(CodegenTest, ReturnVoid) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000107 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
David Brazdil58282f42016-01-14 12:45:10 +0000108 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000109}
110
David Brazdil58282f42016-01-14 12:45:10 +0000111TEST_F(CodegenTest, CFG1) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000112 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000113 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000114 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000115
David Brazdil58282f42016-01-14 12:45:10 +0000116 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000117}
118
David Brazdil58282f42016-01-14 12:45:10 +0000119TEST_F(CodegenTest, CFG2) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000120 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000121 Instruction::GOTO | 0x100,
122 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000123 Instruction::RETURN_VOID);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000124
David Brazdil58282f42016-01-14 12:45:10 +0000125 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000126}
127
David Brazdil58282f42016-01-14 12:45:10 +0000128TEST_F(CodegenTest, CFG3) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000129 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000130 Instruction::GOTO | 0x200,
131 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000132 Instruction::GOTO | 0xFF00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000133
David Brazdil58282f42016-01-14 12:45:10 +0000134 TestCode(data1);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000135
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000136 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000137 Instruction::GOTO_16, 3,
138 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000139 Instruction::GOTO_16, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000140
David Brazdil58282f42016-01-14 12:45:10 +0000141 TestCode(data2);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000142
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000143 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000144 Instruction::GOTO_32, 4, 0,
145 Instruction::RETURN_VOID,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000146 Instruction::GOTO_32, 0xFFFF, 0xFFFF);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000147
David Brazdil58282f42016-01-14 12:45:10 +0000148 TestCode(data3);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000149}
150
David Brazdil58282f42016-01-14 12:45:10 +0000151TEST_F(CodegenTest, CFG4) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000152 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000153 Instruction::RETURN_VOID,
154 Instruction::GOTO | 0x100,
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000155 Instruction::GOTO | 0xFE00);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000156
David Brazdil58282f42016-01-14 12:45:10 +0000157 TestCode(data);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000158}
159
David Brazdil58282f42016-01-14 12:45:10 +0000160TEST_F(CodegenTest, CFG5) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000161 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
162 Instruction::CONST_4 | 0 | 0,
163 Instruction::IF_EQ, 3,
164 Instruction::GOTO | 0x100,
165 Instruction::RETURN_VOID);
166
David Brazdil58282f42016-01-14 12:45:10 +0000167 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000168}
169
David Brazdil58282f42016-01-14 12:45:10 +0000170TEST_F(CodegenTest, IntConstant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000171 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
172 Instruction::CONST_4 | 0 | 0,
173 Instruction::RETURN_VOID);
174
David Brazdil58282f42016-01-14 12:45:10 +0000175 TestCode(data);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000176}
177
David Brazdil58282f42016-01-14 12:45:10 +0000178TEST_F(CodegenTest, Return1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000179 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
180 Instruction::CONST_4 | 0 | 0,
181 Instruction::RETURN | 0);
182
David Brazdil58282f42016-01-14 12:45:10 +0000183 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000184}
185
David Brazdil58282f42016-01-14 12:45:10 +0000186TEST_F(CodegenTest, Return2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000187 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
188 Instruction::CONST_4 | 0 | 0,
189 Instruction::CONST_4 | 0 | 1 << 8,
190 Instruction::RETURN | 1 << 8);
191
David Brazdil58282f42016-01-14 12:45:10 +0000192 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000193}
194
David Brazdil58282f42016-01-14 12:45:10 +0000195TEST_F(CodegenTest, Return3) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000196 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
197 Instruction::CONST_4 | 0 | 0,
198 Instruction::CONST_4 | 1 << 8 | 1 << 12,
199 Instruction::RETURN | 1 << 8);
200
David Brazdil58282f42016-01-14 12:45:10 +0000201 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000202}
203
David Brazdil58282f42016-01-14 12:45:10 +0000204TEST_F(CodegenTest, ReturnIf1) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000205 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
206 Instruction::CONST_4 | 0 | 0,
207 Instruction::CONST_4 | 1 << 8 | 1 << 12,
208 Instruction::IF_EQ, 3,
209 Instruction::RETURN | 0 << 8,
210 Instruction::RETURN | 1 << 8);
211
David Brazdil58282f42016-01-14 12:45:10 +0000212 TestCode(data, true, 1);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000213}
214
David Brazdil58282f42016-01-14 12:45:10 +0000215TEST_F(CodegenTest, ReturnIf2) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000216 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
217 Instruction::CONST_4 | 0 | 0,
218 Instruction::CONST_4 | 1 << 8 | 1 << 12,
219 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
220 Instruction::RETURN | 0 << 8,
221 Instruction::RETURN | 1 << 8);
222
David Brazdil58282f42016-01-14 12:45:10 +0000223 TestCode(data, true, 0);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000224}
225
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100226// Exercise bit-wise (one's complement) not-int instruction.
227#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000228TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100229 const int32_t input = INPUT; \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100230 const uint16_t input_lo = Low16Bits(input); \
231 const uint16_t input_hi = High16Bits(input); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100232 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
233 Instruction::CONST | 0 << 8, input_lo, input_hi, \
234 Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
235 Instruction::RETURN | 1 << 8); \
236 \
David Brazdil58282f42016-01-14 12:45:10 +0000237 TestCode(data, true, EXPECTED_OUTPUT); \
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100238}
239
240NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
241NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
242NOT_INT_TEST(ReturnNotInt0, 0, -1)
243NOT_INT_TEST(ReturnNotInt1, 1, -2)
Roland Levillain55dcfb52014-10-24 18:09:09 +0100244NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647) // (2^31) - 1
245NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646) // (2^31) - 2
246NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647) // -(2^31) - 1
247NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648) // -(2^31)
Roland Levillain1cc5f2512014-10-22 18:06:21 +0100248
249#undef NOT_INT_TEST
250
Roland Levillain55dcfb52014-10-24 18:09:09 +0100251// Exercise bit-wise (one's complement) not-long instruction.
252#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
David Brazdil58282f42016-01-14 12:45:10 +0000253TEST_F(CodegenTest, TEST_NAME) { \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100254 const int64_t input = INPUT; \
255 const uint16_t word0 = Low16Bits(Low32Bits(input)); /* LSW. */ \
256 const uint16_t word1 = High16Bits(Low32Bits(input)); \
257 const uint16_t word2 = Low16Bits(High32Bits(input)); \
258 const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
259 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
260 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
261 Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
262 Instruction::RETURN_WIDE | 2 << 8); \
263 \
David Brazdil58282f42016-01-14 12:45:10 +0000264 TestCodeLong(data, true, EXPECTED_OUTPUT); \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100265}
266
267NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
268NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
269NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
270NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
271
272NOT_LONG_TEST(ReturnNotLongINT32_MIN,
273 INT64_C(-2147483648),
274 INT64_C(2147483647)) // (2^31) - 1
275NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
276 INT64_C(-2147483647),
277 INT64_C(2147483646)) // (2^31) - 2
278NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
279 INT64_C(2147483646),
280 INT64_C(-2147483647)) // -(2^31) - 1
281NOT_LONG_TEST(ReturnNotLongINT32_MAX,
282 INT64_C(2147483647),
283 INT64_C(-2147483648)) // -(2^31)
284
285// Note that the C++ compiler won't accept
286// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
287// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
288NOT_LONG_TEST(ReturnNotINT64_MIN,
289 INT64_C(-9223372036854775807)-1,
290 INT64_C(9223372036854775807)); // (2^63) - 1
291NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
292 INT64_C(-9223372036854775807),
293 INT64_C(9223372036854775806)); // (2^63) - 2
294NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
295 INT64_C(9223372036854775806),
296 INT64_C(-9223372036854775807)); // -(2^63) - 1
297NOT_LONG_TEST(ReturnNotLongINT64_MAX,
298 INT64_C(9223372036854775807),
299 INT64_C(-9223372036854775807)-1); // -(2^63)
300
301#undef NOT_LONG_TEST
302
David Brazdil58282f42016-01-14 12:45:10 +0000303TEST_F(CodegenTest, IntToLongOfLongToInt) {
Roland Levillain946e1432014-11-11 17:35:19 +0000304 const int64_t input = INT64_C(4294967296); // 2^32
305 const uint16_t word0 = Low16Bits(Low32Bits(input)); // LSW.
306 const uint16_t word1 = High16Bits(Low32Bits(input));
307 const uint16_t word2 = Low16Bits(High32Bits(input));
308 const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
309 const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
310 Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
311 Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
312 Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
313 Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
314 Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
315 Instruction::RETURN_WIDE | 2 << 8);
316
David Brazdil58282f42016-01-14 12:45:10 +0000317 TestCodeLong(data, true, 1);
Roland Levillain946e1432014-11-11 17:35:19 +0000318}
319
David Brazdil58282f42016-01-14 12:45:10 +0000320TEST_F(CodegenTest, ReturnAdd1) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000321 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
322 Instruction::CONST_4 | 3 << 12 | 0,
323 Instruction::CONST_4 | 4 << 12 | 1 << 8,
324 Instruction::ADD_INT, 1 << 8 | 0,
325 Instruction::RETURN);
326
David Brazdil58282f42016-01-14 12:45:10 +0000327 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000328}
329
David Brazdil58282f42016-01-14 12:45:10 +0000330TEST_F(CodegenTest, ReturnAdd2) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000331 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
332 Instruction::CONST_4 | 3 << 12 | 0,
333 Instruction::CONST_4 | 4 << 12 | 1 << 8,
334 Instruction::ADD_INT_2ADDR | 1 << 12,
335 Instruction::RETURN);
336
David Brazdil58282f42016-01-14 12:45:10 +0000337 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000338}
339
David Brazdil58282f42016-01-14 12:45:10 +0000340TEST_F(CodegenTest, ReturnAdd3) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000341 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
342 Instruction::CONST_4 | 4 << 12 | 0 << 8,
343 Instruction::ADD_INT_LIT8, 3 << 8 | 0,
344 Instruction::RETURN);
345
David Brazdil58282f42016-01-14 12:45:10 +0000346 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000347}
348
David Brazdil58282f42016-01-14 12:45:10 +0000349TEST_F(CodegenTest, ReturnAdd4) {
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000350 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
351 Instruction::CONST_4 | 4 << 12 | 0 << 8,
352 Instruction::ADD_INT_LIT16, 3,
353 Instruction::RETURN);
354
David Brazdil58282f42016-01-14 12:45:10 +0000355 TestCode(data, true, 7);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000356}
357
David Brazdil58282f42016-01-14 12:45:10 +0000358TEST_F(CodegenTest, ReturnMulInt) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100359 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
360 Instruction::CONST_4 | 3 << 12 | 0,
361 Instruction::CONST_4 | 4 << 12 | 1 << 8,
362 Instruction::MUL_INT, 1 << 8 | 0,
363 Instruction::RETURN);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100364
David Brazdil58282f42016-01-14 12:45:10 +0000365 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100366}
367
David Brazdil58282f42016-01-14 12:45:10 +0000368TEST_F(CodegenTest, ReturnMulInt2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100369 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
370 Instruction::CONST_4 | 3 << 12 | 0,
371 Instruction::CONST_4 | 4 << 12 | 1 << 8,
372 Instruction::MUL_INT_2ADDR | 1 << 12,
373 Instruction::RETURN);
374
David Brazdil58282f42016-01-14 12:45:10 +0000375 TestCode(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100376}
377
David Brazdil58282f42016-01-14 12:45:10 +0000378TEST_F(CodegenTest, ReturnMulLong) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100379 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000380 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
381 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100382 Instruction::MUL_LONG, 2 << 8 | 0,
383 Instruction::RETURN_WIDE);
384
David Brazdil58282f42016-01-14 12:45:10 +0000385 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100386}
387
David Brazdil58282f42016-01-14 12:45:10 +0000388TEST_F(CodegenTest, ReturnMulLong2addr) {
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100389 const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
David Brazdil58282f42016-01-14 12:45:10 +0000390 Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
391 Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100392 Instruction::MUL_LONG_2ADDR | 2 << 12,
393 Instruction::RETURN_WIDE);
394
David Brazdil58282f42016-01-14 12:45:10 +0000395 TestCodeLong(data, true, 12);
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100396}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100397
David Brazdil58282f42016-01-14 12:45:10 +0000398TEST_F(CodegenTest, ReturnMulIntLit8) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100399 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
400 Instruction::CONST_4 | 4 << 12 | 0 << 8,
401 Instruction::MUL_INT_LIT8, 3 << 8 | 0,
402 Instruction::RETURN);
403
David Brazdil58282f42016-01-14 12:45:10 +0000404 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100405}
406
David Brazdil58282f42016-01-14 12:45:10 +0000407TEST_F(CodegenTest, ReturnMulIntLit16) {
Calin Juravle34bacdf2014-10-07 20:23:36 +0100408 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
409 Instruction::CONST_4 | 4 << 12 | 0 << 8,
410 Instruction::MUL_INT_LIT16, 3,
411 Instruction::RETURN);
412
David Brazdil58282f42016-01-14 12:45:10 +0000413 TestCode(data, true, 12);
Calin Juravle34bacdf2014-10-07 20:23:36 +0100414}
415
David Brazdil58282f42016-01-14 12:45:10 +0000416TEST_F(CodegenTest, NonMaterializedCondition) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100417 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100418 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000419
Vladimir Markoca6fff82017-10-03 14:49:14 +0100420 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000421 graph->AddBlock(entry);
422 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100423 entry->AddInstruction(new (GetAllocator()) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100424
Vladimir Markoca6fff82017-10-03 14:49:14 +0100425 HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000426 graph->AddBlock(first_block);
427 entry->AddSuccessor(first_block);
428 HIntConstant* constant0 = graph->GetIntConstant(0);
429 HIntConstant* constant1 = graph->GetIntConstant(1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100430 HEqual* equal = new (GetAllocator()) HEqual(constant0, constant0);
David Brazdil58282f42016-01-14 12:45:10 +0000431 first_block->AddInstruction(equal);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100432 first_block->AddInstruction(new (GetAllocator()) HIf(equal));
David Brazdil58282f42016-01-14 12:45:10 +0000433
Vladimir Markoca6fff82017-10-03 14:49:14 +0100434 HBasicBlock* then_block = new (GetAllocator()) HBasicBlock(graph);
435 HBasicBlock* else_block = new (GetAllocator()) HBasicBlock(graph);
436 HBasicBlock* exit_block = new (GetAllocator()) 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
Vladimir Markoca6fff82017-10-03 14:49:14 +0100447 exit_block->AddInstruction(new (GetAllocator()) HExit());
448 then_block->AddInstruction(new (GetAllocator()) HReturn(constant0));
449 else_block->AddInstruction(new (GetAllocator()) HReturn(constant1));
David Brazdil58282f42016-01-14 12:45:10 +0000450
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];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100458 HParallelMove* move = new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
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++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100478 HGraph* graph = CreateGraph();
Alexandre Rames92730742014-10-01 12:55:56 +0100479
Vladimir Markoca6fff82017-10-03 14:49:14 +0100480 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000481 graph->AddBlock(entry_block);
482 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100483 entry_block->AddInstruction(new (GetAllocator()) HGoto());
484 HBasicBlock* code_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000485 graph->AddBlock(code_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100486 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000487 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100488 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100489
David Brazdil58282f42016-01-14 12:45:10 +0000490 entry_block->AddSuccessor(code_block);
491 code_block->AddSuccessor(exit_block);
492 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100493
David Brazdil58282f42016-01-14 12:45:10 +0000494 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
495 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
496 HLessThan cmp_lt(cst_lhs, cst_rhs);
497 code_block->AddInstruction(&cmp_lt);
498 HReturn ret(&cmp_lt);
499 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100500
David Brazdilbadd8262016-02-02 16:28:56 +0000501 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000502 auto hook_before_codegen = [](HGraph* graph_in) {
503 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100504 HParallelMove* move =
505 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000506 block->InsertInstructionBefore(move, block->GetLastInstruction());
507 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100508 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000509 }
Alexandre Rames92730742014-10-01 12:55:56 +0100510 }
511}
Calin Juravle34bacdf2014-10-07 20:23:36 +0100512
David Brazdil58282f42016-01-14 12:45:10 +0000513TEST_F(CodegenTest, MaterializedCondition2) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100514 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000515 // Check that HIf correctly interprets a materialized condition.
516 // We force the materialization of comparisons for different combinations of
517 // inputs. An HIf takes the materialized combination as input and returns a
518 // value that we verify.
519
520 int lhs[] = {1, 2, -1, 2, 0xabc};
521 int rhs[] = {2, 1, 2, -1, 0xabc};
522
523
524 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100525 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000526
Vladimir Markoca6fff82017-10-03 14:49:14 +0100527 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000528 graph->AddBlock(entry_block);
529 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100530 entry_block->AddInstruction(new (GetAllocator()) HGoto());
David Brazdil58282f42016-01-14 12:45:10 +0000531
Vladimir Markoca6fff82017-10-03 14:49:14 +0100532 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000533 graph->AddBlock(if_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100534 HBasicBlock* if_true_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000535 graph->AddBlock(if_true_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100536 HBasicBlock* if_false_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000537 graph->AddBlock(if_false_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100538 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000539 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100540 exit_block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil58282f42016-01-14 12:45:10 +0000541
542 graph->SetEntryBlock(entry_block);
543 entry_block->AddSuccessor(if_block);
544 if_block->AddSuccessor(if_true_block);
545 if_block->AddSuccessor(if_false_block);
546 if_true_block->AddSuccessor(exit_block);
547 if_false_block->AddSuccessor(exit_block);
548 graph->SetExitBlock(exit_block);
549
550 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
551 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
552 HLessThan cmp_lt(cst_lhs, cst_rhs);
553 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000554 // We insert a dummy instruction to separate the HIf from the HLessThan
555 // and force the materialization of the condition.
556 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000557 if_block->AddInstruction(&force_materialization);
558 HIf if_lt(&cmp_lt);
559 if_block->AddInstruction(&if_lt);
560
561 HIntConstant* cst_lt = graph->GetIntConstant(1);
562 HReturn ret_lt(cst_lt);
563 if_true_block->AddInstruction(&ret_lt);
564 HIntConstant* cst_ge = graph->GetIntConstant(0);
565 HReturn ret_ge(cst_ge);
566 if_false_block->AddInstruction(&ret_ge);
567
David Brazdilbadd8262016-02-02 16:28:56 +0000568 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000569 auto hook_before_codegen = [](HGraph* graph_in) {
570 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100571 HParallelMove* move =
572 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000573 block->InsertInstructionBefore(move, block->GetLastInstruction());
574 };
Scott Wakeling2c76e062016-08-31 09:48:54 +0100575 RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000576 }
577 }
578}
579
580TEST_F(CodegenTest, ReturnDivIntLit8) {
Calin Juravled0d48522014-11-04 16:40:20 +0000581 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
582 Instruction::CONST_4 | 4 << 12 | 0 << 8,
583 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
584 Instruction::RETURN);
585
David Brazdil58282f42016-01-14 12:45:10 +0000586 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000587}
588
David Brazdil58282f42016-01-14 12:45:10 +0000589TEST_F(CodegenTest, ReturnDivInt2Addr) {
Calin Juravle865fc882014-11-06 17:09:03 +0000590 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
591 Instruction::CONST_4 | 4 << 12 | 0,
592 Instruction::CONST_4 | 2 << 12 | 1 << 8,
593 Instruction::DIV_INT_2ADDR | 1 << 12,
594 Instruction::RETURN);
595
David Brazdil58282f42016-01-14 12:45:10 +0000596 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000597}
598
Aart Bike9f37602015-10-09 11:15:55 -0700599// Helper method.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100600void CodegenTest::TestComparison(IfCondition condition,
601 int64_t i,
602 int64_t j,
603 DataType::Type type,
604 const CodegenTargetConfig target_config) {
605 HGraph* graph = CreateGraph();
Aart Bike9f37602015-10-09 11:15:55 -0700606
Vladimir Markoca6fff82017-10-03 14:49:14 +0100607 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700608 graph->AddBlock(entry_block);
609 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100610 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Aart Bike9f37602015-10-09 11:15:55 -0700611
Vladimir Markoca6fff82017-10-03 14:49:14 +0100612 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700613 graph->AddBlock(block);
614
Vladimir Markoca6fff82017-10-03 14:49:14 +0100615 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700616 graph->AddBlock(exit_block);
617 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100618 exit_block->AddInstruction(new (GetAllocator()) HExit());
Aart Bike9f37602015-10-09 11:15:55 -0700619
620 entry_block->AddSuccessor(block);
621 block->AddSuccessor(exit_block);
622
623 HInstruction* op1;
624 HInstruction* op2;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100625 if (type == DataType::Type::kInt32) {
Aart Bike9f37602015-10-09 11:15:55 -0700626 op1 = graph->GetIntConstant(i);
627 op2 = graph->GetIntConstant(j);
628 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100629 DCHECK_EQ(type, DataType::Type::kInt64);
Aart Bike9f37602015-10-09 11:15:55 -0700630 op1 = graph->GetLongConstant(i);
631 op2 = graph->GetLongConstant(j);
632 }
633
634 HInstruction* comparison = nullptr;
635 bool expected_result = false;
636 const uint64_t x = i;
637 const uint64_t y = j;
638 switch (condition) {
639 case kCondEQ:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100640 comparison = new (GetAllocator()) HEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700641 expected_result = (i == j);
642 break;
643 case kCondNE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100644 comparison = new (GetAllocator()) HNotEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700645 expected_result = (i != j);
646 break;
647 case kCondLT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100648 comparison = new (GetAllocator()) HLessThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700649 expected_result = (i < j);
650 break;
651 case kCondLE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100652 comparison = new (GetAllocator()) HLessThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700653 expected_result = (i <= j);
654 break;
655 case kCondGT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100656 comparison = new (GetAllocator()) HGreaterThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700657 expected_result = (i > j);
658 break;
659 case kCondGE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100660 comparison = new (GetAllocator()) HGreaterThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700661 expected_result = (i >= j);
662 break;
663 case kCondB:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100664 comparison = new (GetAllocator()) HBelow(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700665 expected_result = (x < y);
666 break;
667 case kCondBE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100668 comparison = new (GetAllocator()) HBelowOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700669 expected_result = (x <= y);
670 break;
671 case kCondA:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100672 comparison = new (GetAllocator()) HAbove(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700673 expected_result = (x > y);
674 break;
675 case kCondAE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100676 comparison = new (GetAllocator()) HAboveOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700677 expected_result = (x >= y);
678 break;
679 }
680 block->AddInstruction(comparison);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100681 block->AddInstruction(new (GetAllocator()) HReturn(comparison));
Aart Bike9f37602015-10-09 11:15:55 -0700682
David Brazdilbadd8262016-02-02 16:28:56 +0000683 graph->BuildDominatorTree();
Scott Wakeling2c76e062016-08-31 09:48:54 +0100684 RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700685}
686
David Brazdil58282f42016-01-14 12:45:10 +0000687TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100688 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000689 for (int64_t i = -1; i <= 1; i++) {
690 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100691 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100692 TestComparison(
693 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100694 }
David Brazdil58282f42016-01-14 12:45:10 +0000695 }
Aart Bike9f37602015-10-09 11:15:55 -0700696 }
697 }
698}
699
David Brazdil58282f42016-01-14 12:45:10 +0000700TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100701 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000702 for (int64_t i = -1; i <= 1; i++) {
703 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100704 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100705 TestComparison(
706 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100707 }
David Brazdil58282f42016-01-14 12:45:10 +0000708 }
Aart Bike9f37602015-10-09 11:15:55 -0700709 }
710 }
711}
712
Artem Serov4593f7d2016-12-29 16:21:49 +0000713#ifdef ART_ENABLE_CODEGEN_arm
714TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
715 std::unique_ptr<const ArmInstructionSetFeatures> features(
716 ArmInstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100717 HGraph* graph = CreateGraph();
Artem Serov4593f7d2016-12-29 16:21:49 +0000718 arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions());
719
720 codegen.Initialize();
721
722 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
723 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
724 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
725 // LDR encoding. So the following code is a regression test for that situation.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100726 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100727 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
728 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
Artem Serov4593f7d2016-12-29 16:21:49 +0000729 codegen.GetMoveResolver()->EmitNativeCode(move);
730
731 InternalCodeAllocator code_allocator;
732 codegen.Finalize(&code_allocator);
733}
734#endif
735
Roland Levillain558dea12017-01-27 19:40:44 +0000736#ifdef ART_ENABLE_CODEGEN_arm64
737// Regression test for b/34760542.
738TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
739 std::unique_ptr<const Arm64InstructionSetFeatures> features(
740 Arm64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100741 HGraph* graph = CreateGraph();
Roland Levillain558dea12017-01-27 19:40:44 +0000742 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
743
744 codegen.Initialize();
745
746 // The following ParallelMove used to fail this assertion:
747 //
748 // Assertion failed (!available->IsEmpty())
749 //
Roland Levillain952b2352017-05-03 19:49:14 +0100750 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
751 // because of the following situation:
752 //
753 // 1. a temp register (IP0) is allocated as a scratch register by
754 // the parallel move resolver to solve a cycle (swap):
755 //
756 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
757 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
758 //
759 // 2. within CodeGeneratorARM64::MoveLocation, another temp
760 // register (IP1) is allocated to generate the swap between two
761 // double stack slots;
762 //
763 // 3. VIXL requires a third temp register to emit the `Ldr` or
764 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
765 // one of the stack slots' offsets cannot be encoded as an
766 // immediate), but the pool of (core) temp registers is now
767 // empty.
768 //
769 // The solution used so far is to use a floating-point temp register
770 // (D31) in step #2, so that IP1 is available for step #3.
771
Vladimir Markoca6fff82017-10-03 14:49:14 +0100772 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Roland Levillain558dea12017-01-27 19:40:44 +0000773 move->AddMove(Location::DoubleStackSlot(0),
774 Location::DoubleStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100775 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000776 nullptr);
777 move->AddMove(Location::DoubleStackSlot(257),
778 Location::DoubleStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100779 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000780 nullptr);
781 codegen.GetMoveResolver()->EmitNativeCode(move);
782
783 InternalCodeAllocator code_allocator;
784 codegen.Finalize(&code_allocator);
785}
Artem Serovd4bccf12017-04-03 18:47:32 +0100786
787// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
788TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
789 std::unique_ptr<const Arm64InstructionSetFeatures> features(
790 Arm64InstructionSetFeatures::FromCppDefines());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100791 HGraph* graph = CreateGraph();
Artem Serovd4bccf12017-04-03 18:47:32 +0100792 arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions());
793
794 codegen.Initialize();
795
796 graph->SetHasSIMD(true);
797 for (int i = 0; i < 2; i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100798 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Artem Serovd4bccf12017-04-03 18:47:32 +0100799 move->AddMove(Location::SIMDStackSlot(0),
800 Location::SIMDStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100801 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100802 nullptr);
803 move->AddMove(Location::SIMDStackSlot(257),
804 Location::SIMDStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100805 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100806 nullptr);
807 move->AddMove(Location::FpuRegisterLocation(0),
808 Location::FpuRegisterLocation(1),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100809 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100810 nullptr);
811 move->AddMove(Location::FpuRegisterLocation(1),
812 Location::FpuRegisterLocation(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100813 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100814 nullptr);
815 codegen.GetMoveResolver()->EmitNativeCode(move);
816 graph->SetHasSIMD(false);
817 }
818
819 InternalCodeAllocator code_allocator;
820 codegen.Finalize(&code_allocator);
821}
Roland Levillain558dea12017-01-27 19:40:44 +0000822#endif
823
Alexey Frunze58320ce2016-08-30 21:40:46 -0700824#ifdef ART_ENABLE_CODEGEN_mips
825TEST_F(CodegenTest, MipsClobberRA) {
826 std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
827 MipsInstructionSetFeatures::FromCppDefines());
828 if (!CanExecute(kMips) || features_mips->IsR6()) {
829 // HMipsComputeBaseMethodAddress and the NAL instruction behind it
830 // should only be generated on non-R6.
831 return;
832 }
833
Vladimir Markoca6fff82017-10-03 14:49:14 +0100834 HGraph* graph = CreateGraph();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700835
Vladimir Markoca6fff82017-10-03 14:49:14 +0100836 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700837 graph->AddBlock(entry_block);
838 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100839 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700840
Vladimir Markoca6fff82017-10-03 14:49:14 +0100841 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700842 graph->AddBlock(block);
843
Vladimir Markoca6fff82017-10-03 14:49:14 +0100844 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexey Frunze58320ce2016-08-30 21:40:46 -0700845 graph->AddBlock(exit_block);
846 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100847 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexey Frunze58320ce2016-08-30 21:40:46 -0700848
849 entry_block->AddSuccessor(block);
850 block->AddSuccessor(exit_block);
851
852 // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
853 // Instead, generate HMipsComputeBaseMethodAddress directly.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100854 HMipsComputeBaseMethodAddress* base = new (GetAllocator()) HMipsComputeBaseMethodAddress();
Alexey Frunze58320ce2016-08-30 21:40:46 -0700855 block->AddInstruction(base);
856 // HMipsComputeBaseMethodAddress is defined as int, so just make the
857 // compiled method return it.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100858 block->AddInstruction(new (GetAllocator()) HReturn(base));
Alexey Frunze58320ce2016-08-30 21:40:46 -0700859
860 graph->BuildDominatorTree();
861
862 mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions());
863 // Since there isn't HLoadClass or HLoadString, we need to manually indicate
864 // that RA is clobbered and the method entry code should generate a stack frame
865 // and preserve RA in it. And this is what we're testing here.
866 codegenMIPS.ClobberRA();
867 // Without ClobberRA() the code would be:
868 // nal # Sets RA to point to the jr instruction below
869 // move v0, ra # and the CPU falls into an infinite loop.
870 // jr ra
871 // nop
872 // The expected code is:
873 // addiu sp, sp, -16
874 // sw ra, 12(sp)
875 // sw a0, 0(sp)
876 // nal # Sets RA to point to the lw instruction below.
877 // move v0, ra
878 // lw ra, 12(sp)
879 // jr ra
880 // addiu sp, sp, 16
881 RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
882}
883#endif
884
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000885} // namespace art