• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include <functional>
18 #include <memory>
19 
20 #include "base/macros.h"
21 #include "base/utils.h"
22 #include "builder.h"
23 #include "codegen_test_utils.h"
24 #include "dex/dex_file.h"
25 #include "dex/dex_instruction.h"
26 #include "driver/compiler_options.h"
27 #include "nodes.h"
28 #include "optimizing_unit_test.h"
29 #include "register_allocator_linear_scan.h"
30 #include "utils/arm/assembler_arm_vixl.h"
31 #include "utils/arm/managed_register_arm.h"
32 #include "utils/mips/managed_register_mips.h"
33 #include "utils/mips64/managed_register_mips64.h"
34 #include "utils/x86/managed_register_x86.h"
35 
36 #include "gtest/gtest.h"
37 
38 namespace art {
39 
40 // Return all combinations of ISA and code generator that are executable on
41 // hardware, or on simulator, and that we'd like to test.
GetTargetConfigs()42 static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
43   ::std::vector<CodegenTargetConfig> v;
44   ::std::vector<CodegenTargetConfig> test_config_candidates = {
45 #ifdef ART_ENABLE_CODEGEN_arm
46     // TODO: Should't this be `kThumb2` instead of `kArm` here?
47     CodegenTargetConfig(InstructionSet::kArm, create_codegen_arm_vixl32),
48 #endif
49 #ifdef ART_ENABLE_CODEGEN_arm64
50     CodegenTargetConfig(InstructionSet::kArm64, create_codegen_arm64),
51 #endif
52 #ifdef ART_ENABLE_CODEGEN_x86
53     CodegenTargetConfig(InstructionSet::kX86, create_codegen_x86),
54 #endif
55 #ifdef ART_ENABLE_CODEGEN_x86_64
56     CodegenTargetConfig(InstructionSet::kX86_64, create_codegen_x86_64),
57 #endif
58 #ifdef ART_ENABLE_CODEGEN_mips
59     CodegenTargetConfig(InstructionSet::kMips, create_codegen_mips),
60 #endif
61 #ifdef ART_ENABLE_CODEGEN_mips64
62     CodegenTargetConfig(InstructionSet::kMips64, create_codegen_mips64)
63 #endif
64   };
65 
66   for (const CodegenTargetConfig& test_config : test_config_candidates) {
67     if (CanExecute(test_config.GetInstructionSet())) {
68       v.push_back(test_config);
69     }
70   }
71 
72   return v;
73 }
74 
75 class CodegenTest : public OptimizingUnitTest {
76  protected:
77   void TestCode(const std::vector<uint16_t>& data, bool has_result = false, int32_t expected = 0);
78   void TestCodeLong(const std::vector<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 
TestCode(const std::vector<uint16_t> & data,bool has_result,int32_t expected)86 void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, int32_t expected) {
87   for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
88     ResetPoolAndAllocator();
89     HGraph* graph = CreateCFG(data);
90     // Remove suspend checks, they cannot be executed in this context.
91     RemoveSuspendChecks(graph);
92     OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
93     RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
94   }
95 }
96 
TestCodeLong(const std::vector<uint16_t> & data,bool has_result,int64_t expected)97 void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
98                                bool has_result, int64_t expected) {
99   for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
100     ResetPoolAndAllocator();
101     HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
102     // Remove suspend checks, they cannot be executed in this context.
103     RemoveSuspendChecks(graph);
104     OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
105     RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected);
106   }
107 }
108 
TEST_F(CodegenTest,ReturnVoid)109 TEST_F(CodegenTest, ReturnVoid) {
110   const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
111   TestCode(data);
112 }
113 
TEST_F(CodegenTest,CFG1)114 TEST_F(CodegenTest, CFG1) {
115   const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
116     Instruction::GOTO | 0x100,
117     Instruction::RETURN_VOID);
118 
119   TestCode(data);
120 }
121 
TEST_F(CodegenTest,CFG2)122 TEST_F(CodegenTest, CFG2) {
123   const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
124     Instruction::GOTO | 0x100,
125     Instruction::GOTO | 0x100,
126     Instruction::RETURN_VOID);
127 
128   TestCode(data);
129 }
130 
TEST_F(CodegenTest,CFG3)131 TEST_F(CodegenTest, CFG3) {
132   const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
133     Instruction::GOTO | 0x200,
134     Instruction::RETURN_VOID,
135     Instruction::GOTO | 0xFF00);
136 
137   TestCode(data1);
138 
139   const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
140     Instruction::GOTO_16, 3,
141     Instruction::RETURN_VOID,
142     Instruction::GOTO_16, 0xFFFF);
143 
144   TestCode(data2);
145 
146   const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
147     Instruction::GOTO_32, 4, 0,
148     Instruction::RETURN_VOID,
149     Instruction::GOTO_32, 0xFFFF, 0xFFFF);
150 
151   TestCode(data3);
152 }
153 
TEST_F(CodegenTest,CFG4)154 TEST_F(CodegenTest, CFG4) {
155   const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
156     Instruction::RETURN_VOID,
157     Instruction::GOTO | 0x100,
158     Instruction::GOTO | 0xFE00);
159 
160   TestCode(data);
161 }
162 
TEST_F(CodegenTest,CFG5)163 TEST_F(CodegenTest, CFG5) {
164   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
165     Instruction::CONST_4 | 0 | 0,
166     Instruction::IF_EQ, 3,
167     Instruction::GOTO | 0x100,
168     Instruction::RETURN_VOID);
169 
170   TestCode(data);
171 }
172 
TEST_F(CodegenTest,IntConstant)173 TEST_F(CodegenTest, IntConstant) {
174   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
175     Instruction::CONST_4 | 0 | 0,
176     Instruction::RETURN_VOID);
177 
178   TestCode(data);
179 }
180 
TEST_F(CodegenTest,Return1)181 TEST_F(CodegenTest, Return1) {
182   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
183     Instruction::CONST_4 | 0 | 0,
184     Instruction::RETURN | 0);
185 
186   TestCode(data, true, 0);
187 }
188 
TEST_F(CodegenTest,Return2)189 TEST_F(CodegenTest, Return2) {
190   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
191     Instruction::CONST_4 | 0 | 0,
192     Instruction::CONST_4 | 0 | 1 << 8,
193     Instruction::RETURN | 1 << 8);
194 
195   TestCode(data, true, 0);
196 }
197 
TEST_F(CodegenTest,Return3)198 TEST_F(CodegenTest, Return3) {
199   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
200     Instruction::CONST_4 | 0 | 0,
201     Instruction::CONST_4 | 1 << 8 | 1 << 12,
202     Instruction::RETURN | 1 << 8);
203 
204   TestCode(data, true, 1);
205 }
206 
TEST_F(CodegenTest,ReturnIf1)207 TEST_F(CodegenTest, ReturnIf1) {
208   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
209     Instruction::CONST_4 | 0 | 0,
210     Instruction::CONST_4 | 1 << 8 | 1 << 12,
211     Instruction::IF_EQ, 3,
212     Instruction::RETURN | 0 << 8,
213     Instruction::RETURN | 1 << 8);
214 
215   TestCode(data, true, 1);
216 }
217 
TEST_F(CodegenTest,ReturnIf2)218 TEST_F(CodegenTest, ReturnIf2) {
219   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
220     Instruction::CONST_4 | 0 | 0,
221     Instruction::CONST_4 | 1 << 8 | 1 << 12,
222     Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
223     Instruction::RETURN | 0 << 8,
224     Instruction::RETURN | 1 << 8);
225 
226   TestCode(data, true, 0);
227 }
228 
229 // Exercise bit-wise (one's complement) not-int instruction.
230 #define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)           \
231 TEST_F(CodegenTest, TEST_NAME) {                                  \
232   const int32_t input = INPUT;                                    \
233   const uint16_t input_lo = Low16Bits(input);                     \
234   const uint16_t input_hi = High16Bits(input);                    \
235   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(     \
236       Instruction::CONST | 0 << 8, input_lo, input_hi,            \
237       Instruction::NOT_INT | 1 << 8 | 0 << 12 ,                   \
238       Instruction::RETURN | 1 << 8);                              \
239                                                                   \
240   TestCode(data, true, EXPECTED_OUTPUT);                          \
241 }
242 
243 NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
244 NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
245 NOT_INT_TEST(ReturnNotInt0, 0, -1)
246 NOT_INT_TEST(ReturnNotInt1, 1, -2)
247 NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647)  // (2^31) - 1
248 NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
249 NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
250 NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648)  // -(2^31)
251 
252 #undef NOT_INT_TEST
253 
254 // Exercise bit-wise (one's complement) not-long instruction.
255 #define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)                 \
256 TEST_F(CodegenTest, TEST_NAME) {                                         \
257   const int64_t input = INPUT;                                           \
258   const uint16_t word0 = Low16Bits(Low32Bits(input));   /* LSW. */       \
259   const uint16_t word1 = High16Bits(Low32Bits(input));                   \
260   const uint16_t word2 = Low16Bits(High32Bits(input));                   \
261   const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */       \
262   const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(           \
263       Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,      \
264       Instruction::NOT_LONG | 2 << 8 | 0 << 12,                          \
265       Instruction::RETURN_WIDE | 2 << 8);                                \
266                                                                          \
267   TestCodeLong(data, true, EXPECTED_OUTPUT);                             \
268 }
269 
270 NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
271 NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
272 NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
273 NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
274 
275 NOT_LONG_TEST(ReturnNotLongINT32_MIN,
276               INT64_C(-2147483648),
277               INT64_C(2147483647))  // (2^31) - 1
278 NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
279               INT64_C(-2147483647),
280               INT64_C(2147483646))  // (2^31) - 2
281 NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
282               INT64_C(2147483646),
283               INT64_C(-2147483647))  // -(2^31) - 1
284 NOT_LONG_TEST(ReturnNotLongINT32_MAX,
285               INT64_C(2147483647),
286               INT64_C(-2147483648))  // -(2^31)
287 
288 // Note that the C++ compiler won't accept
289 // INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
290 // int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
291 NOT_LONG_TEST(ReturnNotINT64_MIN,
292               INT64_C(-9223372036854775807)-1,
293               INT64_C(9223372036854775807));  // (2^63) - 1
294 NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
295               INT64_C(-9223372036854775807),
296               INT64_C(9223372036854775806));  // (2^63) - 2
297 NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
298               INT64_C(9223372036854775806),
299               INT64_C(-9223372036854775807));  // -(2^63) - 1
300 NOT_LONG_TEST(ReturnNotLongINT64_MAX,
301               INT64_C(9223372036854775807),
302               INT64_C(-9223372036854775807)-1);  // -(2^63)
303 
304 #undef NOT_LONG_TEST
305 
TEST_F(CodegenTest,IntToLongOfLongToInt)306 TEST_F(CodegenTest, IntToLongOfLongToInt) {
307   const int64_t input = INT64_C(4294967296);             // 2^32
308   const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
309   const uint16_t word1 = High16Bits(Low32Bits(input));
310   const uint16_t word2 = Low16Bits(High32Bits(input));
311   const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
312   const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
313       Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
314       Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
315       Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
316       Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
317       Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
318       Instruction::RETURN_WIDE | 2 << 8);
319 
320   TestCodeLong(data, true, 1);
321 }
322 
TEST_F(CodegenTest,ReturnAdd1)323 TEST_F(CodegenTest, ReturnAdd1) {
324   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
325     Instruction::CONST_4 | 3 << 12 | 0,
326     Instruction::CONST_4 | 4 << 12 | 1 << 8,
327     Instruction::ADD_INT, 1 << 8 | 0,
328     Instruction::RETURN);
329 
330   TestCode(data, true, 7);
331 }
332 
TEST_F(CodegenTest,ReturnAdd2)333 TEST_F(CodegenTest, ReturnAdd2) {
334   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
335     Instruction::CONST_4 | 3 << 12 | 0,
336     Instruction::CONST_4 | 4 << 12 | 1 << 8,
337     Instruction::ADD_INT_2ADDR | 1 << 12,
338     Instruction::RETURN);
339 
340   TestCode(data, true, 7);
341 }
342 
TEST_F(CodegenTest,ReturnAdd3)343 TEST_F(CodegenTest, ReturnAdd3) {
344   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
345     Instruction::CONST_4 | 4 << 12 | 0 << 8,
346     Instruction::ADD_INT_LIT8, 3 << 8 | 0,
347     Instruction::RETURN);
348 
349   TestCode(data, true, 7);
350 }
351 
TEST_F(CodegenTest,ReturnAdd4)352 TEST_F(CodegenTest, ReturnAdd4) {
353   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
354     Instruction::CONST_4 | 4 << 12 | 0 << 8,
355     Instruction::ADD_INT_LIT16, 3,
356     Instruction::RETURN);
357 
358   TestCode(data, true, 7);
359 }
360 
TEST_F(CodegenTest,ReturnMulInt)361 TEST_F(CodegenTest, ReturnMulInt) {
362   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
363     Instruction::CONST_4 | 3 << 12 | 0,
364     Instruction::CONST_4 | 4 << 12 | 1 << 8,
365     Instruction::MUL_INT, 1 << 8 | 0,
366     Instruction::RETURN);
367 
368   TestCode(data, true, 12);
369 }
370 
TEST_F(CodegenTest,ReturnMulInt2addr)371 TEST_F(CodegenTest, ReturnMulInt2addr) {
372   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
373     Instruction::CONST_4 | 3 << 12 | 0,
374     Instruction::CONST_4 | 4 << 12 | 1 << 8,
375     Instruction::MUL_INT_2ADDR | 1 << 12,
376     Instruction::RETURN);
377 
378   TestCode(data, true, 12);
379 }
380 
TEST_F(CodegenTest,ReturnMulLong)381 TEST_F(CodegenTest, ReturnMulLong) {
382   const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
383     Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
384     Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
385     Instruction::MUL_LONG, 2 << 8 | 0,
386     Instruction::RETURN_WIDE);
387 
388   TestCodeLong(data, true, 12);
389 }
390 
TEST_F(CodegenTest,ReturnMulLong2addr)391 TEST_F(CodegenTest, ReturnMulLong2addr) {
392   const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
393     Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
394     Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
395     Instruction::MUL_LONG_2ADDR | 2 << 12,
396     Instruction::RETURN_WIDE);
397 
398   TestCodeLong(data, true, 12);
399 }
400 
TEST_F(CodegenTest,ReturnMulIntLit8)401 TEST_F(CodegenTest, ReturnMulIntLit8) {
402   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
403     Instruction::CONST_4 | 4 << 12 | 0 << 8,
404     Instruction::MUL_INT_LIT8, 3 << 8 | 0,
405     Instruction::RETURN);
406 
407   TestCode(data, true, 12);
408 }
409 
TEST_F(CodegenTest,ReturnMulIntLit16)410 TEST_F(CodegenTest, ReturnMulIntLit16) {
411   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
412     Instruction::CONST_4 | 4 << 12 | 0 << 8,
413     Instruction::MUL_INT_LIT16, 3,
414     Instruction::RETURN);
415 
416   TestCode(data, true, 12);
417 }
418 
TEST_F(CodegenTest,NonMaterializedCondition)419 TEST_F(CodegenTest, NonMaterializedCondition) {
420   for (CodegenTargetConfig target_config : GetTargetConfigs()) {
421     HGraph* graph = CreateGraph();
422 
423     HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
424     graph->AddBlock(entry);
425     graph->SetEntryBlock(entry);
426     entry->AddInstruction(new (GetAllocator()) HGoto());
427 
428     HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
429     graph->AddBlock(first_block);
430     entry->AddSuccessor(first_block);
431     HIntConstant* constant0 = graph->GetIntConstant(0);
432     HIntConstant* constant1 = graph->GetIntConstant(1);
433     HEqual* equal = new (GetAllocator()) HEqual(constant0, constant0);
434     first_block->AddInstruction(equal);
435     first_block->AddInstruction(new (GetAllocator()) HIf(equal));
436 
437     HBasicBlock* then_block = new (GetAllocator()) HBasicBlock(graph);
438     HBasicBlock* else_block = new (GetAllocator()) HBasicBlock(graph);
439     HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
440     graph->SetExitBlock(exit_block);
441 
442     graph->AddBlock(then_block);
443     graph->AddBlock(else_block);
444     graph->AddBlock(exit_block);
445     first_block->AddSuccessor(then_block);
446     first_block->AddSuccessor(else_block);
447     then_block->AddSuccessor(exit_block);
448     else_block->AddSuccessor(exit_block);
449 
450     exit_block->AddInstruction(new (GetAllocator()) HExit());
451     then_block->AddInstruction(new (GetAllocator()) HReturn(constant0));
452     else_block->AddInstruction(new (GetAllocator()) HReturn(constant1));
453 
454     ASSERT_FALSE(equal->IsEmittedAtUseSite());
455     graph->BuildDominatorTree();
456     PrepareForRegisterAllocation(graph, *compiler_options_).Run();
457     ASSERT_TRUE(equal->IsEmittedAtUseSite());
458 
459     auto hook_before_codegen = [](HGraph* graph_in) {
460       HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
461       HParallelMove* move = new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
462       block->InsertInstructionBefore(move, block->GetLastInstruction());
463     };
464 
465     OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
466     RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, 0);
467   }
468 }
469 
TEST_F(CodegenTest,MaterializedCondition1)470 TEST_F(CodegenTest, MaterializedCondition1) {
471   for (CodegenTargetConfig target_config : GetTargetConfigs()) {
472     // Check that condition are materialized correctly. A materialized condition
473     // should yield `1` if it evaluated to true, and `0` otherwise.
474     // We force the materialization of comparisons for different combinations of
475 
476     // inputs and check the results.
477 
478     int lhs[] = {1, 2, -1, 2, 0xabc};
479     int rhs[] = {2, 1, 2, -1, 0xabc};
480 
481     for (size_t i = 0; i < arraysize(lhs); i++) {
482       HGraph* graph = CreateGraph();
483 
484       HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
485       graph->AddBlock(entry_block);
486       graph->SetEntryBlock(entry_block);
487       entry_block->AddInstruction(new (GetAllocator()) HGoto());
488       HBasicBlock* code_block = new (GetAllocator()) HBasicBlock(graph);
489       graph->AddBlock(code_block);
490       HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
491       graph->AddBlock(exit_block);
492       exit_block->AddInstruction(new (GetAllocator()) HExit());
493 
494       entry_block->AddSuccessor(code_block);
495       code_block->AddSuccessor(exit_block);
496       graph->SetExitBlock(exit_block);
497 
498       HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
499       HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
500       HLessThan cmp_lt(cst_lhs, cst_rhs);
501       code_block->AddInstruction(&cmp_lt);
502       HReturn ret(&cmp_lt);
503       code_block->AddInstruction(&ret);
504 
505       graph->BuildDominatorTree();
506       auto hook_before_codegen = [](HGraph* graph_in) {
507         HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
508         HParallelMove* move =
509             new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
510         block->InsertInstructionBefore(move, block->GetLastInstruction());
511       };
512       OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
513       RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
514     }
515   }
516 }
517 
TEST_F(CodegenTest,MaterializedCondition2)518 TEST_F(CodegenTest, MaterializedCondition2) {
519   for (CodegenTargetConfig target_config : GetTargetConfigs()) {
520     // Check that HIf correctly interprets a materialized condition.
521     // We force the materialization of comparisons for different combinations of
522     // inputs. An HIf takes the materialized combination as input and returns a
523     // value that we verify.
524 
525     int lhs[] = {1, 2, -1, 2, 0xabc};
526     int rhs[] = {2, 1, 2, -1, 0xabc};
527 
528 
529     for (size_t i = 0; i < arraysize(lhs); i++) {
530       HGraph* graph = CreateGraph();
531 
532       HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
533       graph->AddBlock(entry_block);
534       graph->SetEntryBlock(entry_block);
535       entry_block->AddInstruction(new (GetAllocator()) HGoto());
536 
537       HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph);
538       graph->AddBlock(if_block);
539       HBasicBlock* if_true_block = new (GetAllocator()) HBasicBlock(graph);
540       graph->AddBlock(if_true_block);
541       HBasicBlock* if_false_block = new (GetAllocator()) HBasicBlock(graph);
542       graph->AddBlock(if_false_block);
543       HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
544       graph->AddBlock(exit_block);
545       exit_block->AddInstruction(new (GetAllocator()) HExit());
546 
547       graph->SetEntryBlock(entry_block);
548       entry_block->AddSuccessor(if_block);
549       if_block->AddSuccessor(if_true_block);
550       if_block->AddSuccessor(if_false_block);
551       if_true_block->AddSuccessor(exit_block);
552       if_false_block->AddSuccessor(exit_block);
553       graph->SetExitBlock(exit_block);
554 
555       HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
556       HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
557       HLessThan cmp_lt(cst_lhs, cst_rhs);
558       if_block->AddInstruction(&cmp_lt);
559       // We insert a dummy instruction to separate the HIf from the HLessThan
560       // and force the materialization of the condition.
561       HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
562       if_block->AddInstruction(&force_materialization);
563       HIf if_lt(&cmp_lt);
564       if_block->AddInstruction(&if_lt);
565 
566       HIntConstant* cst_lt = graph->GetIntConstant(1);
567       HReturn ret_lt(cst_lt);
568       if_true_block->AddInstruction(&ret_lt);
569       HIntConstant* cst_ge = graph->GetIntConstant(0);
570       HReturn ret_ge(cst_ge);
571       if_false_block->AddInstruction(&ret_ge);
572 
573       graph->BuildDominatorTree();
574       auto hook_before_codegen = [](HGraph* graph_in) {
575         HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
576         HParallelMove* move =
577             new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator());
578         block->InsertInstructionBefore(move, block->GetLastInstruction());
579       };
580       OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
581       RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
582     }
583   }
584 }
585 
TEST_F(CodegenTest,ReturnDivIntLit8)586 TEST_F(CodegenTest, ReturnDivIntLit8) {
587   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
588     Instruction::CONST_4 | 4 << 12 | 0 << 8,
589     Instruction::DIV_INT_LIT8, 3 << 8 | 0,
590     Instruction::RETURN);
591 
592   TestCode(data, true, 1);
593 }
594 
TEST_F(CodegenTest,ReturnDivInt2Addr)595 TEST_F(CodegenTest, ReturnDivInt2Addr) {
596   const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
597     Instruction::CONST_4 | 4 << 12 | 0,
598     Instruction::CONST_4 | 2 << 12 | 1 << 8,
599     Instruction::DIV_INT_2ADDR | 1 << 12,
600     Instruction::RETURN);
601 
602   TestCode(data, true, 2);
603 }
604 
605 // Helper method.
TestComparison(IfCondition condition,int64_t i,int64_t j,DataType::Type type,const CodegenTargetConfig target_config)606 void CodegenTest::TestComparison(IfCondition condition,
607                                  int64_t i,
608                                  int64_t j,
609                                  DataType::Type type,
610                                  const CodegenTargetConfig target_config) {
611   HGraph* graph = CreateGraph();
612 
613   HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
614   graph->AddBlock(entry_block);
615   graph->SetEntryBlock(entry_block);
616   entry_block->AddInstruction(new (GetAllocator()) HGoto());
617 
618   HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
619   graph->AddBlock(block);
620 
621   HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
622   graph->AddBlock(exit_block);
623   graph->SetExitBlock(exit_block);
624   exit_block->AddInstruction(new (GetAllocator()) HExit());
625 
626   entry_block->AddSuccessor(block);
627   block->AddSuccessor(exit_block);
628 
629   HInstruction* op1;
630   HInstruction* op2;
631   if (type == DataType::Type::kInt32) {
632     op1 = graph->GetIntConstant(i);
633     op2 = graph->GetIntConstant(j);
634   } else {
635     DCHECK_EQ(type, DataType::Type::kInt64);
636     op1 = graph->GetLongConstant(i);
637     op2 = graph->GetLongConstant(j);
638   }
639 
640   HInstruction* comparison = nullptr;
641   bool expected_result = false;
642   const uint64_t x = i;
643   const uint64_t y = j;
644   switch (condition) {
645     case kCondEQ:
646       comparison = new (GetAllocator()) HEqual(op1, op2);
647       expected_result = (i == j);
648       break;
649     case kCondNE:
650       comparison = new (GetAllocator()) HNotEqual(op1, op2);
651       expected_result = (i != j);
652       break;
653     case kCondLT:
654       comparison = new (GetAllocator()) HLessThan(op1, op2);
655       expected_result = (i < j);
656       break;
657     case kCondLE:
658       comparison = new (GetAllocator()) HLessThanOrEqual(op1, op2);
659       expected_result = (i <= j);
660       break;
661     case kCondGT:
662       comparison = new (GetAllocator()) HGreaterThan(op1, op2);
663       expected_result = (i > j);
664       break;
665     case kCondGE:
666       comparison = new (GetAllocator()) HGreaterThanOrEqual(op1, op2);
667       expected_result = (i >= j);
668       break;
669     case kCondB:
670       comparison = new (GetAllocator()) HBelow(op1, op2);
671       expected_result = (x < y);
672       break;
673     case kCondBE:
674       comparison = new (GetAllocator()) HBelowOrEqual(op1, op2);
675       expected_result = (x <= y);
676       break;
677     case kCondA:
678       comparison = new (GetAllocator()) HAbove(op1, op2);
679       expected_result = (x > y);
680       break;
681     case kCondAE:
682       comparison = new (GetAllocator()) HAboveOrEqual(op1, op2);
683       expected_result = (x >= y);
684       break;
685   }
686   block->AddInstruction(comparison);
687   block->AddInstruction(new (GetAllocator()) HReturn(comparison));
688 
689   graph->BuildDominatorTree();
690   OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default");
691   RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, true, expected_result);
692 }
693 
TEST_F(CodegenTest,ComparisonsInt)694 TEST_F(CodegenTest, ComparisonsInt) {
695   for (CodegenTargetConfig target_config : GetTargetConfigs()) {
696     for (int64_t i = -1; i <= 1; i++) {
697       for (int64_t j = -1; j <= 1; j++) {
698         for (int cond = kCondFirst; cond <= kCondLast; cond++) {
699           TestComparison(
700               static_cast<IfCondition>(cond), i, j, DataType::Type::kInt32, target_config);
701         }
702       }
703     }
704   }
705 }
706 
TEST_F(CodegenTest,ComparisonsLong)707 TEST_F(CodegenTest, ComparisonsLong) {
708   for (CodegenTargetConfig target_config : GetTargetConfigs()) {
709     for (int64_t i = -1; i <= 1; i++) {
710       for (int64_t j = -1; j <= 1; j++) {
711         for (int cond = kCondFirst; cond <= kCondLast; cond++) {
712           TestComparison(
713               static_cast<IfCondition>(cond), i, j, DataType::Type::kInt64, target_config);
714         }
715       }
716     }
717   }
718 }
719 
720 #ifdef ART_ENABLE_CODEGEN_arm
TEST_F(CodegenTest,ARMVIXLParallelMoveResolver)721 TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) {
722   OverrideInstructionSetFeatures(InstructionSet::kThumb2, "default");
723   HGraph* graph = CreateGraph();
724   arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_);
725 
726   codegen.Initialize();
727 
728   // This will result in calling EmitSwap -> void ParallelMoveResolverARMVIXL::Exchange(int mem1,
729   // int mem2) which was faulty (before the fix). So previously GPR and FP scratch registers were
730   // used as temps; however GPR scratch register is required for big stack offsets which don't fit
731   // LDR encoding. So the following code is a regression test for that situation.
732   HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
733   move->AddMove(Location::StackSlot(0), Location::StackSlot(8192), DataType::Type::kInt32, nullptr);
734   move->AddMove(Location::StackSlot(8192), Location::StackSlot(0), DataType::Type::kInt32, nullptr);
735   codegen.GetMoveResolver()->EmitNativeCode(move);
736 
737   InternalCodeAllocator code_allocator;
738   codegen.Finalize(&code_allocator);
739 }
740 #endif
741 
742 #ifdef ART_ENABLE_CODEGEN_arm64
743 // Regression test for b/34760542.
TEST_F(CodegenTest,ARM64ParallelMoveResolverB34760542)744 TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) {
745   OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
746   HGraph* graph = CreateGraph();
747   arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
748 
749   codegen.Initialize();
750 
751   // The following ParallelMove used to fail this assertion:
752   //
753   //   Assertion failed (!available->IsEmpty())
754   //
755   // 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 
777   HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
778   move->AddMove(Location::DoubleStackSlot(0),
779                 Location::DoubleStackSlot(257),
780                 DataType::Type::kFloat64,
781                 nullptr);
782   move->AddMove(Location::DoubleStackSlot(257),
783                 Location::DoubleStackSlot(0),
784                 DataType::Type::kFloat64,
785                 nullptr);
786   codegen.GetMoveResolver()->EmitNativeCode(move);
787 
788   InternalCodeAllocator code_allocator;
789   codegen.Finalize(&code_allocator);
790 }
791 
792 // Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off.
TEST_F(CodegenTest,ARM64ParallelMoveResolverSIMD)793 TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) {
794   OverrideInstructionSetFeatures(InstructionSet::kArm64, "default");
795   HGraph* graph = CreateGraph();
796   arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
797 
798   codegen.Initialize();
799 
800   graph->SetHasSIMD(true);
801   for (int i = 0; i < 2; i++) {
802     HParallelMove* move = new (graph->GetAllocator()) HParallelMove(graph->GetAllocator());
803     move->AddMove(Location::SIMDStackSlot(0),
804                   Location::SIMDStackSlot(257),
805                   DataType::Type::kFloat64,
806                   nullptr);
807     move->AddMove(Location::SIMDStackSlot(257),
808                   Location::SIMDStackSlot(0),
809                   DataType::Type::kFloat64,
810                   nullptr);
811     move->AddMove(Location::FpuRegisterLocation(0),
812                   Location::FpuRegisterLocation(1),
813                   DataType::Type::kFloat64,
814                   nullptr);
815     move->AddMove(Location::FpuRegisterLocation(1),
816                   Location::FpuRegisterLocation(0),
817                   DataType::Type::kFloat64,
818                   nullptr);
819     codegen.GetMoveResolver()->EmitNativeCode(move);
820     graph->SetHasSIMD(false);
821   }
822 
823   InternalCodeAllocator code_allocator;
824   codegen.Finalize(&code_allocator);
825 }
826 
827 // Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a75 as example).
TEST_F(CodegenTest,ARM64IsaVIXLFeaturesA75)828 TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA75) {
829   OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a75");
830   HGraph* graph = CreateGraph();
831   arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
832   vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
833 
834   EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
835   EXPECT_TRUE(features->Has(vixl::CPUFeatures::kDotProduct));
836   EXPECT_TRUE(features->Has(vixl::CPUFeatures::kFPHalf));
837   EXPECT_TRUE(features->Has(vixl::CPUFeatures::kAtomics));
838 }
839 
840 // Check that ART ISA Features are propagated to VIXL for arm64 (using cortex-a53 as example).
TEST_F(CodegenTest,ARM64IsaVIXLFeaturesA53)841 TEST_F(CodegenTest, ARM64IsaVIXLFeaturesA53) {
842   OverrideInstructionSetFeatures(InstructionSet::kArm64, "cortex-a53");
843   HGraph* graph = CreateGraph();
844   arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_);
845   vixl::CPUFeatures* features = codegen.GetVIXLAssembler()->GetCPUFeatures();
846 
847   EXPECT_TRUE(features->Has(vixl::CPUFeatures::kCRC32));
848   EXPECT_FALSE(features->Has(vixl::CPUFeatures::kDotProduct));
849   EXPECT_FALSE(features->Has(vixl::CPUFeatures::kFPHalf));
850   EXPECT_FALSE(features->Has(vixl::CPUFeatures::kAtomics));
851 }
852 
853 #endif
854 
855 #ifdef ART_ENABLE_CODEGEN_mips
TEST_F(CodegenTest,MipsClobberRA)856 TEST_F(CodegenTest, MipsClobberRA) {
857   OverrideInstructionSetFeatures(InstructionSet::kMips, "mips32r");
858   CHECK(!instruction_set_features_->AsMipsInstructionSetFeatures()->IsR6());
859   if (!CanExecute(InstructionSet::kMips)) {
860     // HMipsComputeBaseMethodAddress and the NAL instruction behind it
861     // should only be generated on non-R6.
862     return;
863   }
864 
865   HGraph* graph = CreateGraph();
866 
867   HBasicBlock* entry_block = new (GetAllocator()) HBasicBlock(graph);
868   graph->AddBlock(entry_block);
869   graph->SetEntryBlock(entry_block);
870   entry_block->AddInstruction(new (GetAllocator()) HGoto());
871 
872   HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
873   graph->AddBlock(block);
874 
875   HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
876   graph->AddBlock(exit_block);
877   graph->SetExitBlock(exit_block);
878   exit_block->AddInstruction(new (GetAllocator()) HExit());
879 
880   entry_block->AddSuccessor(block);
881   block->AddSuccessor(exit_block);
882 
883   // To simplify matters, don't create PC-relative HLoadClass or HLoadString.
884   // Instead, generate HMipsComputeBaseMethodAddress directly.
885   HMipsComputeBaseMethodAddress* base = new (GetAllocator()) HMipsComputeBaseMethodAddress();
886   block->AddInstruction(base);
887   // HMipsComputeBaseMethodAddress is defined as int, so just make the
888   // compiled method return it.
889   block->AddInstruction(new (GetAllocator()) HReturn(base));
890 
891   graph->BuildDominatorTree();
892 
893   mips::CodeGeneratorMIPS codegenMIPS(graph, *compiler_options_);
894   // Since there isn't HLoadClass or HLoadString, we need to manually indicate
895   // that RA is clobbered and the method entry code should generate a stack frame
896   // and preserve RA in it. And this is what we're testing here.
897   codegenMIPS.ClobberRA();
898   // Without ClobberRA() the code would be:
899   //   nal              # Sets RA to point to the jr instruction below
900   //   move  v0, ra     # and the CPU falls into an infinite loop.
901   //   jr    ra
902   //   nop
903   // The expected code is:
904   //   addiu sp, sp, -16
905   //   sw    ra, 12(sp)
906   //   sw    a0, 0(sp)
907   //   nal              # Sets RA to point to the lw instruction below.
908   //   move  v0, ra
909   //   lw    ra, 12(sp)
910   //   jr    ra
911   //   addiu sp, sp, 16
912   RunCode(&codegenMIPS, graph, [](HGraph*) {}, false, 0);
913 }
914 #endif
915 
916 }  // namespace art
917