blob: f4f44a04799cbd9503a88ed95cc022b9a2f397c8 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Nicolas Geoffray360231a2014-10-08 21:07:48 +010017#include <functional>
Anton Kirilov3a2e78e2017-01-06 13:33:42 +000018#include <memory>
Nicolas Geoffray360231a2014-10-08 21:07:48 +010019
Alexandre Rames92730742014-10-01 12:55:56 +010020#include "base/macros.h"
David Sehrc431b9d2018-03-02 12:01:51 -080021#include "base/utils.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000022#include "builder.h"
Alexandre Rames22aa54b2016-10-18 09:32:29 +010023#include "codegen_test_utils.h"
David Sehr9e734c72018-01-04 17:56:19 -080024#include "dex/dex_file.h"
25#include "dex/dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000026#include "driver/compiler_options.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000027#include "nodes.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000028#include "optimizing_unit_test.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070029#include "register_allocator_linear_scan.h"
Scott Wakelingfe885462016-09-22 10:24:38 +010030#include "utils/arm/assembler_arm_vixl.h"
Nicolas Geoffray5da21802015-04-20 09:29:18 +010031#include "utils/arm/managed_register_arm.h"
32#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033
34#include "gtest/gtest.h"
Nicolas Geoffraye6362282015-01-26 13:57:30 +000035
Vladimir Marko0a516052019-10-14 13:00:44 +000036namespace art {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000037
Scott Wakeling2c76e062016-08-31 09:48:54 +010038// Return all combinations of ISA and code generator that are executable on
39// hardware, or on simulator, and that we'd like to test.
40static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
41 ::std::vector<CodegenTargetConfig> v;
42 ::std::vector<CodegenTargetConfig> test_config_candidates = {
43#ifdef ART_ENABLE_CODEGEN_arm
Roland Levillain9983e302017-07-14 14:34:22 +010044 // TODO: Should't this be `kThumb2` instead of `kArm` here?
Vladimir Marko33bff252017-11-01 14:35:42 +000045 CodegenTargetConfig(InstructionSet::kArm, create_codegen_arm_vixl32),
Scott Wakeling2c76e062016-08-31 09:48:54 +010046#endif
47#ifdef ART_ENABLE_CODEGEN_arm64
Vladimir Marko33bff252017-11-01 14:35:42 +000048 CodegenTargetConfig(InstructionSet::kArm64, create_codegen_arm64),
Scott Wakeling2c76e062016-08-31 09:48:54 +010049#endif
50#ifdef ART_ENABLE_CODEGEN_x86
Vladimir Marko33bff252017-11-01 14:35:42 +000051 CodegenTargetConfig(InstructionSet::kX86, create_codegen_x86),
Scott Wakeling2c76e062016-08-31 09:48:54 +010052#endif
53#ifdef ART_ENABLE_CODEGEN_x86_64
Vladimir Marko33bff252017-11-01 14:35:42 +000054 CodegenTargetConfig(InstructionSet::kX86_64, create_codegen_x86_64),
Scott Wakeling2c76e062016-08-31 09:48:54 +010055#endif
David Brazdil58282f42016-01-14 12:45:10 +000056 };
57
Vladimir Marko7d157fc2017-05-10 16:29:23 +010058 for (const CodegenTargetConfig& test_config : test_config_candidates) {
Scott Wakeling2c76e062016-08-31 09:48:54 +010059 if (CanExecute(test_config.GetInstructionSet())) {
60 v.push_back(test_config);
David Brazdil58282f42016-01-14 12:45:10 +000061 }
62 }
63
64 return v;
65}
66
Vladimir Markoca6fff82017-10-03 14:49:14 +010067class CodegenTest : public OptimizingUnitTest {
68 protected:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080069 void TestCode(const std::vector<uint16_t>& data, bool has_result = false, int32_t expected = 0);
70 void TestCodeLong(const std::vector<uint16_t>& data, bool has_result, int64_t expected);
Vladimir Markoca6fff82017-10-03 14:49:14 +010071 void TestComparison(IfCondition condition,
72 int64_t i,
73 int64_t j,
74 DataType::Type type,
75 const CodegenTargetConfig target_config);
76};
77
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080078void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, int32_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010079 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010080 ResetPoolAndAllocator();
81 HGraph* graph = CreateCFG(data);
David Brazdil58282f42016-01-14 12:45:10 +000082 // Remove suspend checks, they cannot be executed in this context.
83 RemoveSuspendChecks(graph);
Vladimir Markof91fc122020-05-13 09:21:00 +010084 std::unique_ptr<CompilerOptions> compiler_options =
85 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
86 RunCode(target_config, *compiler_options, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +000087 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +010088}
89
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080090void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
91 bool has_result, int64_t expected) {
Vladimir Marko7d157fc2017-05-10 16:29:23 +010092 for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010093 ResetPoolAndAllocator();
94 HGraph* graph = CreateCFG(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);
Vladimir Markof91fc122020-05-13 09:21:00 +010097 std::unique_ptr<CompilerOptions> compiler_options =
98 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
99 RunCode(target_config, *compiler_options, graph, [](HGraph*) {}, has_result, expected);
David Brazdil58282f42016-01-14 12:45:10 +0000100 }
Roland Levillain55dcfb52014-10-24 18:09:09 +0100101}
102
David Brazdil58282f42016-01-14 12:45:10 +0000103TEST_F(CodegenTest, ReturnVoid) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800104 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800109 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800117 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800126 const std::vector<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
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800133 const std::vector<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
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800140 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800149 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800158 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000159 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800168 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000169 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800176 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000177 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800184 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000185 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800193 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000194 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800202 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000203 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800213 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000214 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.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800224#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
225TEST_F(CodegenTest, TEST_NAME) { \
226 const int32_t input = INPUT; \
227 const uint16_t input_lo = Low16Bits(input); \
228 const uint16_t input_hi = High16Bits(input); \
229 const std::vector<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 \
234 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. */ \
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800256 const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM( \
Roland Levillain55dcfb52014-10-24 18:09:09 +0100257 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.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800306 const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
Roland Levillain946e1432014-11-11 17:35:19 +0000307 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800318 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000319 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800328 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000329 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800338 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000339 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800347 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000348 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800356 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100357 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800366 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray5da21802015-04-20 09:29:18 +0100367 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800376 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800386 const std::vector<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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800396 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100397 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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800405 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravle34bacdf2014-10-07 20:23:36 +0100406 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()) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100415 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000416
Vladimir Markoca6fff82017-10-03 14:49:14 +0100417 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000418 graph->AddBlock(entry);
419 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100420 entry->AddInstruction(new (GetAllocator()) HGoto());
Alexandre Rames92730742014-10-01 12:55:56 +0100421
Vladimir Markoca6fff82017-10-03 14:49:14 +0100422 HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000423 graph->AddBlock(first_block);
424 entry->AddSuccessor(first_block);
425 HIntConstant* constant0 = graph->GetIntConstant(0);
426 HIntConstant* constant1 = graph->GetIntConstant(1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100427 HEqual* equal = new (GetAllocator()) HEqual(constant0, constant0);
David Brazdil58282f42016-01-14 12:45:10 +0000428 first_block->AddInstruction(equal);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100429 first_block->AddInstruction(new (GetAllocator()) HIf(equal));
David Brazdil58282f42016-01-14 12:45:10 +0000430
Vladimir Markoca6fff82017-10-03 14:49:14 +0100431 HBasicBlock* then_block = new (GetAllocator()) HBasicBlock(graph);
432 HBasicBlock* else_block = new (GetAllocator()) HBasicBlock(graph);
433 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Alexandre Rames92730742014-10-01 12:55:56 +0100434 graph->SetExitBlock(exit_block);
435
David Brazdil58282f42016-01-14 12:45:10 +0000436 graph->AddBlock(then_block);
437 graph->AddBlock(else_block);
438 graph->AddBlock(exit_block);
439 first_block->AddSuccessor(then_block);
440 first_block->AddSuccessor(else_block);
441 then_block->AddSuccessor(exit_block);
442 else_block->AddSuccessor(exit_block);
443
Vladimir Markoca6fff82017-10-03 14:49:14 +0100444 exit_block->AddInstruction(new (GetAllocator()) HExit());
445 then_block->AddInstruction(new (GetAllocator()) HReturn(constant0));
446 else_block->AddInstruction(new (GetAllocator()) HReturn(constant1));
David Brazdil58282f42016-01-14 12:45:10 +0000447
David Brazdilb11b0722016-01-28 16:22:40 +0000448 ASSERT_FALSE(equal->IsEmittedAtUseSite());
David Brazdilbadd8262016-02-02 16:28:56 +0000449 graph->BuildDominatorTree();
Vladimir Markof91fc122020-05-13 09:21:00 +0100450 std::unique_ptr<CompilerOptions> compiler_options =
451 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
452 PrepareForRegisterAllocation(graph, *compiler_options).Run();
David Brazdilb11b0722016-01-28 16:22:40 +0000453 ASSERT_TRUE(equal->IsEmittedAtUseSite());
Alexandre Rames92730742014-10-01 12:55:56 +0100454
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800455 auto hook_before_codegen = [](HGraph* graph_in) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100456 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100457 HParallelMove* move = new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
Alexandre Rames92730742014-10-01 12:55:56 +0100458 block->InsertInstructionBefore(move, block->GetLastInstruction());
459 };
460
Vladimir Markof91fc122020-05-13 09:21:00 +0100461 RunCode(target_config, *compiler_options, graph, hook_before_codegen, true, 0);
Alexandre Rames92730742014-10-01 12:55:56 +0100462 }
463}
464
David Brazdil58282f42016-01-14 12:45:10 +0000465TEST_F(CodegenTest, MaterializedCondition1) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100466 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000467 // Check that condition are materialized correctly. A materialized condition
468 // should yield `1` if it evaluated to true, and `0` otherwise.
469 // We force the materialization of comparisons for different combinations of
Alexandre Rames92730742014-10-01 12:55:56 +0100470
David Brazdil58282f42016-01-14 12:45:10 +0000471 // inputs and check the results.
Alexandre Rames92730742014-10-01 12:55:56 +0100472
David Brazdil58282f42016-01-14 12:45:10 +0000473 int lhs[] = {1, 2, -1, 2, 0xabc};
474 int rhs[] = {2, 1, 2, -1, 0xabc};
Alexandre Rames92730742014-10-01 12:55:56 +0100475
David Brazdil58282f42016-01-14 12:45:10 +0000476 for (size_t i = 0; i < arraysize(lhs); i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100477 HGraph* graph = CreateGraph();
Alexandre Rames92730742014-10-01 12:55:56 +0100478
Vladimir Markoca6fff82017-10-03 14:49:14 +0100479 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000480 graph->AddBlock(entry_block);
481 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100482 entry_block->AddInstruction(new (GetAllocator()) HGoto());
483 HBasicBlock* code_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000484 graph->AddBlock(code_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100485 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000486 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100487 exit_block->AddInstruction(new (GetAllocator()) HExit());
Alexandre Rames92730742014-10-01 12:55:56 +0100488
David Brazdil58282f42016-01-14 12:45:10 +0000489 entry_block->AddSuccessor(code_block);
490 code_block->AddSuccessor(exit_block);
491 graph->SetExitBlock(exit_block);
Alexandre Rames92730742014-10-01 12:55:56 +0100492
David Brazdil58282f42016-01-14 12:45:10 +0000493 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
494 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
495 HLessThan cmp_lt(cst_lhs, cst_rhs);
496 code_block->AddInstruction(&cmp_lt);
497 HReturn ret(&cmp_lt);
498 code_block->AddInstruction(&ret);
Alexandre Rames92730742014-10-01 12:55:56 +0100499
David Brazdilbadd8262016-02-02 16:28:56 +0000500 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000501 auto hook_before_codegen = [](HGraph* graph_in) {
502 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100503 HParallelMove* move =
504 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000505 block->InsertInstructionBefore(move, block->GetLastInstruction());
506 };
Vladimir Markof91fc122020-05-13 09:21:00 +0100507 std::unique_ptr<CompilerOptions> compiler_options =
508 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
509 RunCode(target_config, *compiler_options, 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++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100526 HGraph* graph = CreateGraph();
David Brazdil58282f42016-01-14 12:45:10 +0000527
Vladimir Markoca6fff82017-10-03 14:49:14 +0100528 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000529 graph->AddBlock(entry_block);
530 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100531 entry_block->AddInstruction(new (GetAllocator()) HGoto());
David Brazdil58282f42016-01-14 12:45:10 +0000532
Vladimir Markoca6fff82017-10-03 14:49:14 +0100533 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000534 graph->AddBlock(if_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100535 HBasicBlock* if_true_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000536 graph->AddBlock(if_true_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100537 HBasicBlock* if_false_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000538 graph->AddBlock(if_false_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100539 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
David Brazdil58282f42016-01-14 12:45:10 +0000540 graph->AddBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100541 exit_block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil58282f42016-01-14 12:45:10 +0000542
543 graph->SetEntryBlock(entry_block);
544 entry_block->AddSuccessor(if_block);
545 if_block->AddSuccessor(if_true_block);
546 if_block->AddSuccessor(if_false_block);
547 if_true_block->AddSuccessor(exit_block);
548 if_false_block->AddSuccessor(exit_block);
549 graph->SetExitBlock(exit_block);
550
551 HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
552 HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
553 HLessThan cmp_lt(cst_lhs, cst_rhs);
554 if_block->AddInstruction(&cmp_lt);
David Brazdil6e332522016-02-02 16:15:27 +0000555 // We insert a dummy instruction to separate the HIf from the HLessThan
556 // and force the materialization of the condition.
557 HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
David Brazdil58282f42016-01-14 12:45:10 +0000558 if_block->AddInstruction(&force_materialization);
559 HIf if_lt(&cmp_lt);
560 if_block->AddInstruction(&if_lt);
561
562 HIntConstant* cst_lt = graph->GetIntConstant(1);
563 HReturn ret_lt(cst_lt);
564 if_true_block->AddInstruction(&ret_lt);
565 HIntConstant* cst_ge = graph->GetIntConstant(0);
566 HReturn ret_ge(cst_ge);
567 if_false_block->AddInstruction(&ret_ge);
568
David Brazdilbadd8262016-02-02 16:28:56 +0000569 graph->BuildDominatorTree();
David Brazdil58282f42016-01-14 12:45:10 +0000570 auto hook_before_codegen = [](HGraph* graph_in) {
571 HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
Vladimir Markoca6fff82017-10-03 14:49:14 +0100572 HParallelMove* move =
573 new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
David Brazdil58282f42016-01-14 12:45:10 +0000574 block->InsertInstructionBefore(move, block->GetLastInstruction());
575 };
Vladimir Markof91fc122020-05-13 09:21:00 +0100576 std::unique_ptr<CompilerOptions> compiler_options =
577 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
578 RunCode(target_config, *compiler_options, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
David Brazdil58282f42016-01-14 12:45:10 +0000579 }
580 }
581}
582
583TEST_F(CodegenTest, ReturnDivIntLit8) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800584 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Calin Juravled0d48522014-11-04 16:40:20 +0000585 Instruction::CONST_4 | 4 << 12 | 0 << 8,
586 Instruction::DIV_INT_LIT8, 3 << 8 | 0,
587 Instruction::RETURN);
588
David Brazdil58282f42016-01-14 12:45:10 +0000589 TestCode(data, true, 1);
Calin Juravled0d48522014-11-04 16:40:20 +0000590}
591
David Brazdil58282f42016-01-14 12:45:10 +0000592TEST_F(CodegenTest, ReturnDivInt2Addr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800593 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Calin Juravle865fc882014-11-06 17:09:03 +0000594 Instruction::CONST_4 | 4 << 12 | 0,
595 Instruction::CONST_4 | 2 << 12 | 1 << 8,
596 Instruction::DIV_INT_2ADDR | 1 << 12,
597 Instruction::RETURN);
598
David Brazdil58282f42016-01-14 12:45:10 +0000599 TestCode(data, true, 2);
Calin Juravle865fc882014-11-06 17:09:03 +0000600}
601
Aart Bike9f37602015-10-09 11:15:55 -0700602// Helper method.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100603void CodegenTest::TestComparison(IfCondition condition,
604 int64_t i,
605 int64_t j,
606 DataType::Type type,
607 const CodegenTargetConfig target_config) {
608 HGraph* graph = CreateGraph();
Aart Bike9f37602015-10-09 11:15:55 -0700609
Vladimir Markoca6fff82017-10-03 14:49:14 +0100610 HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700611 graph->AddBlock(entry_block);
612 graph->SetEntryBlock(entry_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100613 entry_block->AddInstruction(new (GetAllocator()) HGoto());
Aart Bike9f37602015-10-09 11:15:55 -0700614
Vladimir Markoca6fff82017-10-03 14:49:14 +0100615 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700616 graph->AddBlock(block);
617
Vladimir Markoca6fff82017-10-03 14:49:14 +0100618 HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
Aart Bike9f37602015-10-09 11:15:55 -0700619 graph->AddBlock(exit_block);
620 graph->SetExitBlock(exit_block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100621 exit_block->AddInstruction(new (GetAllocator()) HExit());
Aart Bike9f37602015-10-09 11:15:55 -0700622
623 entry_block->AddSuccessor(block);
624 block->AddSuccessor(exit_block);
625
626 HInstruction* op1;
627 HInstruction* op2;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100628 if (type == DataType::Type::kInt32) {
Aart Bike9f37602015-10-09 11:15:55 -0700629 op1 = graph->GetIntConstant(i);
630 op2 = graph->GetIntConstant(j);
631 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100632 DCHECK_EQ(type, DataType::Type::kInt64);
Aart Bike9f37602015-10-09 11:15:55 -0700633 op1 = graph->GetLongConstant(i);
634 op2 = graph->GetLongConstant(j);
635 }
636
637 HInstruction* comparison = nullptr;
638 bool expected_result = false;
639 const uint64_t x = i;
640 const uint64_t y = j;
641 switch (condition) {
642 case kCondEQ:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100643 comparison = new (GetAllocator()) HEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700644 expected_result = (i == j);
645 break;
646 case kCondNE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100647 comparison = new (GetAllocator()) HNotEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700648 expected_result = (i != j);
649 break;
650 case kCondLT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100651 comparison = new (GetAllocator()) HLessThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700652 expected_result = (i < j);
653 break;
654 case kCondLE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100655 comparison = new (GetAllocator()) HLessThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700656 expected_result = (i <= j);
657 break;
658 case kCondGT:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100659 comparison = new (GetAllocator()) HGreaterThan(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700660 expected_result = (i > j);
661 break;
662 case kCondGE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100663 comparison = new (GetAllocator()) HGreaterThanOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700664 expected_result = (i >= j);
665 break;
666 case kCondB:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100667 comparison = new (GetAllocator()) HBelow(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700668 expected_result = (x < y);
669 break;
670 case kCondBE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100671 comparison = new (GetAllocator()) HBelowOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700672 expected_result = (x <= y);
673 break;
674 case kCondA:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100675 comparison = new (GetAllocator()) HAbove(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700676 expected_result = (x > y);
677 break;
678 case kCondAE:
Vladimir Markoca6fff82017-10-03 14:49:14 +0100679 comparison = new (GetAllocator()) HAboveOrEqual(op1, op2);
Aart Bike9f37602015-10-09 11:15:55 -0700680 expected_result = (x >= y);
681 break;
682 }
683 block->AddInstruction(comparison);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100684 block->AddInstruction(new (GetAllocator()) HReturn(comparison));
Aart Bike9f37602015-10-09 11:15:55 -0700685
David Brazdilbadd8262016-02-02 16:28:56 +0000686 graph->BuildDominatorTree();
Vladimir Markof91fc122020-05-13 09:21:00 +0100687 std::unique_ptr<CompilerOptions> compiler_options =
688 CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default");
689 RunCode(target_config, *compiler_options, graph, [](HGraph*) {}, true, expected_result);
Aart Bike9f37602015-10-09 11:15:55 -0700690}
691
David Brazdil58282f42016-01-14 12:45:10 +0000692TEST_F(CodegenTest, ComparisonsInt) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100693 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000694 for (int64_t i = -1; i <= 1; i++) {
695 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100696 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100697 TestComparison(
698 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100699 }
David Brazdil58282f42016-01-14 12:45:10 +0000700 }
Aart Bike9f37602015-10-09 11:15:55 -0700701 }
702 }
703}
704
David Brazdil58282f42016-01-14 12:45:10 +0000705TEST_F(CodegenTest, ComparisonsLong) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100706 for (CodegenTargetConfig target_config : GetTargetConfigs()) {
David Brazdil58282f42016-01-14 12:45:10 +0000707 for (int64_t i = -1; i <= 1; i++) {
708 for (int64_t j = -1; j <= 1; j++) {
Scott Wakeling2c76e062016-08-31 09:48:54 +0100709 for (int cond = kCondFirst; cond <= kCondLast; cond++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100710 TestComparison(
711 static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
Scott Wakeling2c76e062016-08-31 09:48:54 +0100712 }
David Brazdil58282f42016-01-14 12:45:10 +0000713 }
Aart Bike9f37602015-10-09 11:15:55 -0700714 }
715 }
716}
717
Artem Serov4593f7d2016-12-29 16:21:49 +0000718#ifdef ART_ENABLE_CODEGEN_arm
719TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100720 std::unique_ptr<CompilerOptions> compiler_options =
721 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kThumb2, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100722 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100723 arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options);
Artem Serov4593f7d2016-12-29 16:21:49 +0000724
725 codegen.Initialize();
726
727 // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
728 // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
729 // used as temps; however GPR scratch register is required for big stack offsets which don't fit
730 // LDR encoding. So the following code is a regression test for that situation.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100731 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100732 move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
733 move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
Artem Serov4593f7d2016-12-29 16:21:49 +0000734 codegen.GetMoveResolver()->EmitNativeCode(move);
735
736 InternalCodeAllocator code_allocator;
737 codegen.Finalize(&code_allocator);
738}
739#endif
740
Roland Levillain558dea12017-01-27 19:40:44 +0000741#ifdef ART_ENABLE_CODEGEN_arm64
742// Regression test for b/34760542.
743TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100744 std::unique_ptr<CompilerOptions> compiler_options =
745 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100746 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100747 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Roland Levillain558dea12017-01-27 19:40:44 +0000748
749 codegen.Initialize();
750
751 // The following ParallelMove used to fail this assertion:
752 //
753 // Assertion failed (!available->IsEmpty())
754 //
Roland Levillain952b2352017-05-03 19:49:14 +0100755 // in vixl::aarch64::UseScratchRegisterScope::AcquireNextAvailable,
756 // because of the following situation:
757 //
758 // 1. a temp register (IP0) is allocated as a scratch register by
759 // the parallel move resolver to solve a cycle (swap):
760 //
761 // [ source=DS0 destination=DS257 type=PrimDouble instruction=null ]
762 // [ source=DS257 destination=DS0 type=PrimDouble instruction=null ]
763 //
764 // 2. within CodeGeneratorARM64::MoveLocation, another temp
765 // register (IP1) is allocated to generate the swap between two
766 // double stack slots;
767 //
768 // 3. VIXL requires a third temp register to emit the `Ldr` or
769 // `Str` operation from CodeGeneratorARM64::MoveLocation (as
770 // one of the stack slots' offsets cannot be encoded as an
771 // immediate), but the pool of (core) temp registers is now
772 // empty.
773 //
774 // The solution used so far is to use a floating-point temp register
775 // (D31) in step #2, so that IP1 is available for step #3.
776
Vladimir Markoca6fff82017-10-03 14:49:14 +0100777 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Roland Levillain558dea12017-01-27 19:40:44 +0000778 move->AddMove(Location::DoubleStackSlot(0),
779 Location::DoubleStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100780 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000781 nullptr);
782 move->AddMove(Location::DoubleStackSlot(257),
783 Location::DoubleStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100784 DataType::Type::kFloat64,
Roland Levillain558dea12017-01-27 19:40:44 +0000785 nullptr);
786 codegen.GetMoveResolver()->EmitNativeCode(move);
787
788 InternalCodeAllocator code_allocator;
789 codegen.Finalize(&code_allocator);
790}
Artem Serovd4bccf12017-04-03 18:47:32 +0100791
792// Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
793TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100794 std::unique_ptr<CompilerOptions> compiler_options =
795 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "default");
Vladimir Markoca6fff82017-10-03 14:49:14 +0100796 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100797 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Artem Serovd4bccf12017-04-03 18:47:32 +0100798
799 codegen.Initialize();
800
801 graph->SetHasSIMD(true);
802 for (int i = 0; i < 2; i++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100803 HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
Artem Serovd4bccf12017-04-03 18:47:32 +0100804 move->AddMove(Location::SIMDStackSlot(0),
805 Location::SIMDStackSlot(257),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100806 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100807 nullptr);
808 move->AddMove(Location::SIMDStackSlot(257),
809 Location::SIMDStackSlot(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100810 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100811 nullptr);
812 move->AddMove(Location::FpuRegisterLocation(0),
813 Location::FpuRegisterLocation(1),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100814 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100815 nullptr);
816 move->AddMove(Location::FpuRegisterLocation(1),
817 Location::FpuRegisterLocation(0),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100818 DataType::Type::kFloat64,
Artem Serovd4bccf12017-04-03 18:47:32 +0100819 nullptr);
820 codegen.GetMoveResolver()->EmitNativeCode(move);
821 graph->SetHasSIMD(false);
822 }
823
824 InternalCodeAllocator code_allocator;
825 codegen.Finalize(&code_allocator);
826}
Artem Serovaa6f4832018-11-21 18:57:54 +0000827
828// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a75 as example).
829TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA75) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100830 std::unique_ptr<CompilerOptions> compiler_options =
831 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "cortex-a75");
Artem Serovaa6f4832018-11-21 18:57:54 +0000832 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100833 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Artem Serovaa6f4832018-11-21 18:57:54 +0000834 vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
835
836 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
837 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kDotProduct));
838 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kFPHalf));
Usama Arif142816a2019-11-06 16:15:31 +0000839 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kNEONHalf));
Artem Serovaa6f4832018-11-21 18:57:54 +0000840 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kAtomics));
841}
842
843// Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a53 as example).
844TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA53) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100845 std::unique_ptr<CompilerOptions> compiler_options =
846 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "cortex-a53");
Artem Serovaa6f4832018-11-21 18:57:54 +0000847 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100848 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Artem Serovaa6f4832018-11-21 18:57:54 +0000849 vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
850
851 EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
852 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kDotProduct));
853 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kFPHalf));
Usama Arif142816a2019-11-06 16:15:31 +0000854 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kNEONHalf));
Artem Serovaa6f4832018-11-21 18:57:54 +0000855 EXPECT_FALSE(features->Has(vixl::CPUFeatures::kAtomics));
856}
857
Artem Serov6a0b6572019-07-26 20:38:37 +0100858constexpr static size_t kExpectedFPSpillSize = 8 * vixl::aarch64::kDRegSizeInBytes;
859
860// The following two tests check that for both SIMD and non-SIMD graphs exactly 64-bit is
861// allocated on stack per callee-saved FP register to be preserved in the frame entry as
862// ABI states.
863TEST_F(CodegenTest, ARM64FrameSizeSIMD) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100864 std::unique_ptr<CompilerOptions> compiler_options =
865 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "default");
Artem Serov6a0b6572019-07-26 20:38:37 +0100866 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100867 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Artem Serov6a0b6572019-07-26 20:38:37 +0100868
869 codegen.Initialize();
870 graph->SetHasSIMD(true);
871
872 DCHECK_EQ(arm64::callee_saved_fp_registers.GetCount(), 8);
873 vixl::aarch64::CPURegList reg_list = arm64::callee_saved_fp_registers;
874 while (!reg_list.IsEmpty()) {
875 uint32_t reg_code = reg_list.PopLowestIndex().GetCode();
876 codegen.AddAllocatedRegister(Location::FpuRegisterLocation(reg_code));
877 }
878 codegen.ComputeSpillMask();
879
880 EXPECT_EQ(codegen.GetFpuSpillSize(), kExpectedFPSpillSize);
881}
882
883TEST_F(CodegenTest, ARM64FrameSizeNoSIMD) {
Vladimir Markof91fc122020-05-13 09:21:00 +0100884 std::unique_ptr<CompilerOptions> compiler_options =
885 CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "default");
Artem Serov6a0b6572019-07-26 20:38:37 +0100886 HGraph* graph = CreateGraph();
Vladimir Markof91fc122020-05-13 09:21:00 +0100887 arm64::CodeGeneratorARM64 codegen(graph, *compiler_options);
Artem Serov6a0b6572019-07-26 20:38:37 +0100888
889 codegen.Initialize();
890 graph->SetHasSIMD(false);
891
892 DCHECK_EQ(arm64::callee_saved_fp_registers.GetCount(), 8);
893 vixl::aarch64::CPURegList reg_list = arm64::callee_saved_fp_registers;
894 while (!reg_list.IsEmpty()) {
895 uint32_t reg_code = reg_list.PopLowestIndex().GetCode();
896 codegen.AddAllocatedRegister(Location::FpuRegisterLocation(reg_code));
897 }
898 codegen.ComputeSpillMask();
899
900 EXPECT_EQ(codegen.GetFpuSpillSize(), kExpectedFPSpillSize);
901}
902
Roland Levillain558dea12017-01-27 19:40:44 +0000903#endif
904
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000905} // namespace art