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