codegen_test.cc revision a75b01a549f0c86669dd24e53c9e3e74f0bf5b40
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
19#include "arch/instruction_set.h"
20#include "arch/arm/instruction_set_features_arm.h"
21#include "arch/arm/registers_arm.h"
22#include "arch/arm64/instruction_set_features_arm64.h"
23#include "arch/mips/instruction_set_features_mips.h"
24#include "arch/mips/registers_mips.h"
25#include "arch/mips64/instruction_set_features_mips64.h"
26#include "arch/mips64/registers_mips64.h"
27#include "arch/x86/instruction_set_features_x86.h"
28#include "arch/x86/registers_x86.h"
29#include "arch/x86_64/instruction_set_features_x86_64.h"
30#include "base/macros.h"
31#include "builder.h"
32#include "code_simulator_container.h"
33#include "common_compiler_test.h"
34#include "dex_file.h"
35#include "dex_instruction.h"
36#include "driver/compiler_options.h"
37#include "graph_checker.h"
38#include "nodes.h"
39#include "optimizing_unit_test.h"
40#include "prepare_for_register_allocation.h"
41#include "register_allocator_linear_scan.h"
42#include "ssa_liveness_analysis.h"
43#include "utils.h"
44#include "utils/arm/managed_register_arm.h"
45#include "utils/mips/managed_register_mips.h"
46#include "utils/mips64/managed_register_mips64.h"
47#include "utils/x86/managed_register_x86.h"
48
49#ifdef ART_ENABLE_CODEGEN_arm
50#include "code_generator_arm.h"
51#endif
52
53#ifdef ART_ENABLE_CODEGEN_arm64
54#include "code_generator_arm64.h"
55#endif
56
57#ifdef ART_ENABLE_CODEGEN_x86
58#include "code_generator_x86.h"
59#endif
60
61#ifdef ART_ENABLE_CODEGEN_x86_64
62#include "code_generator_x86_64.h"
63#endif
64
65#ifdef ART_ENABLE_CODEGEN_mips
66#include "code_generator_mips.h"
67#endif
68
69#ifdef ART_ENABLE_CODEGEN_mips64
70#include "code_generator_mips64.h"
71#endif
72
73#include "gtest/gtest.h"
74
75namespace art {
76
77#ifdef ART_ENABLE_CODEGEN_arm
78// Provide our own codegen, that ensures the C calling conventions
79// are preserved. Currently, ART and C do not match as R4 is caller-save
80// in ART, and callee-save in C. Alternatively, we could use or write
81// the stub that saves and restores all registers, but it is easier
82// to just overwrite the code generator.
83class TestCodeGeneratorARM : public arm::CodeGeneratorARM {
84 public:
85  TestCodeGeneratorARM(HGraph* graph,
86                       const ArmInstructionSetFeatures& isa_features,
87                       const CompilerOptions& compiler_options)
88      : arm::CodeGeneratorARM(graph, isa_features, compiler_options) {
89    AddAllocatedRegister(Location::RegisterLocation(arm::R6));
90    AddAllocatedRegister(Location::RegisterLocation(arm::R7));
91  }
92
93  void SetupBlockedRegisters() const OVERRIDE {
94    arm::CodeGeneratorARM::SetupBlockedRegisters();
95    blocked_core_registers_[arm::R4] = true;
96    blocked_core_registers_[arm::R6] = false;
97    blocked_core_registers_[arm::R7] = false;
98    // Makes pair R6-R7 available.
99    blocked_register_pairs_[arm::R6_R7] = false;
100  }
101};
102#endif
103
104#ifdef ART_ENABLE_CODEGEN_x86
105class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 {
106 public:
107  TestCodeGeneratorX86(HGraph* graph,
108                       const X86InstructionSetFeatures& isa_features,
109                       const CompilerOptions& compiler_options)
110      : x86::CodeGeneratorX86(graph, isa_features, compiler_options) {
111    // Save edi, we need it for getting enough registers for long multiplication.
112    AddAllocatedRegister(Location::RegisterLocation(x86::EDI));
113  }
114
115  void SetupBlockedRegisters() const OVERRIDE {
116    x86::CodeGeneratorX86::SetupBlockedRegisters();
117    // ebx is a callee-save register in C, but caller-save for ART.
118    blocked_core_registers_[x86::EBX] = true;
119    blocked_register_pairs_[x86::EAX_EBX] = true;
120    blocked_register_pairs_[x86::EDX_EBX] = true;
121    blocked_register_pairs_[x86::ECX_EBX] = true;
122    blocked_register_pairs_[x86::EBX_EDI] = true;
123
124    // Make edi available.
125    blocked_core_registers_[x86::EDI] = false;
126    blocked_register_pairs_[x86::ECX_EDI] = false;
127  }
128};
129#endif
130
131class InternalCodeAllocator : public CodeAllocator {
132 public:
133  InternalCodeAllocator() : size_(0) { }
134
135  virtual uint8_t* Allocate(size_t size) {
136    size_ = size;
137    memory_.reset(new uint8_t[size]);
138    return memory_.get();
139  }
140
141  size_t GetSize() const { return size_; }
142  uint8_t* GetMemory() const { return memory_.get(); }
143
144 private:
145  size_t size_;
146  std::unique_ptr<uint8_t[]> memory_;
147
148  DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator);
149};
150
151static bool CanExecuteOnHardware(InstructionSet target_isa) {
152  return (target_isa == kRuntimeISA)
153      // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
154      || (kRuntimeISA == kArm && target_isa == kThumb2);
155}
156
157static bool CanExecute(InstructionSet target_isa) {
158  CodeSimulatorContainer simulator(target_isa);
159  return CanExecuteOnHardware(target_isa) || simulator.CanSimulate();
160}
161
162template <typename Expected>
163static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)());
164
165template <>
166bool SimulatorExecute<bool>(CodeSimulator* simulator, bool (*f)()) {
167  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
168  return simulator->GetCReturnBool();
169}
170
171template <>
172int32_t SimulatorExecute<int32_t>(CodeSimulator* simulator, int32_t (*f)()) {
173  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
174  return simulator->GetCReturnInt32();
175}
176
177template <>
178int64_t SimulatorExecute<int64_t>(CodeSimulator* simulator, int64_t (*f)()) {
179  simulator->RunFrom(reinterpret_cast<intptr_t>(f));
180  return simulator->GetCReturnInt64();
181}
182
183template <typename Expected>
184static void VerifyGeneratedCode(InstructionSet target_isa,
185                                Expected (*f)(),
186                                bool has_result,
187                                Expected expected) {
188  ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
189
190  // Verify on simulator.
191  CodeSimulatorContainer simulator(target_isa);
192  if (simulator.CanSimulate()) {
193    Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
194    if (has_result) {
195      ASSERT_EQ(expected, result);
196    }
197  }
198
199  // Verify on hardware.
200  if (CanExecuteOnHardware(target_isa)) {
201    Expected result = f();
202    if (has_result) {
203      ASSERT_EQ(expected, result);
204    }
205  }
206}
207
208template <typename Expected>
209static void Run(const InternalCodeAllocator& allocator,
210                const CodeGenerator& codegen,
211                bool has_result,
212                Expected expected) {
213  InstructionSet target_isa = codegen.GetInstructionSet();
214
215  typedef Expected (*fptr)();
216  CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize());
217  fptr f = reinterpret_cast<fptr>(allocator.GetMemory());
218  if (target_isa == kThumb2) {
219    // For thumb we need the bottom bit set.
220    f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1);
221  }
222  VerifyGeneratedCode(target_isa, f, has_result, expected);
223}
224
225template <typename Expected>
226static void RunCode(CodeGenerator* codegen,
227                    HGraph* graph,
228                    std::function<void(HGraph*)> hook_before_codegen,
229                    bool has_result,
230                    Expected expected) {
231  GraphChecker graph_checker(graph);
232  graph_checker.Run();
233  if (!graph_checker.IsValid()) {
234    for (auto error : graph_checker.GetErrors()) {
235      std::cout << error << std::endl;
236    }
237  }
238  ASSERT_TRUE(graph_checker.IsValid());
239
240  SsaLivenessAnalysis liveness(graph, codegen);
241
242  PrepareForRegisterAllocation(graph).Run();
243  liveness.Analyze();
244  RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
245  hook_before_codegen(graph);
246
247  InternalCodeAllocator allocator;
248  codegen->Compile(&allocator);
249  Run(allocator, *codegen, has_result, expected);
250}
251
252template <typename Expected>
253static void RunCode(InstructionSet target_isa,
254                    HGraph* graph,
255                    std::function<void(HGraph*)> hook_before_codegen,
256                    bool has_result,
257                    Expected expected) {
258  CompilerOptions compiler_options;
259#ifdef ART_ENABLE_CODEGEN_arm
260  if (target_isa == kArm || target_isa == kThumb2) {
261    std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
262        ArmInstructionSetFeatures::FromCppDefines());
263    TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
264    RunCode(&codegenARM, graph, hook_before_codegen, has_result, expected);
265  }
266#endif
267#ifdef ART_ENABLE_CODEGEN_arm64
268  if (target_isa == kArm64) {
269    std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
270        Arm64InstructionSetFeatures::FromCppDefines());
271    arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
272    RunCode(&codegenARM64, graph, hook_before_codegen, has_result, expected);
273  }
274#endif
275#ifdef ART_ENABLE_CODEGEN_x86
276  if (target_isa == kX86) {
277    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
278        X86InstructionSetFeatures::FromCppDefines());
279    TestCodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
280    RunCode(&codegenX86, graph, hook_before_codegen, has_result, expected);
281  }
282#endif
283#ifdef ART_ENABLE_CODEGEN_x86_64
284  if (target_isa == kX86_64) {
285    std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
286        X86_64InstructionSetFeatures::FromCppDefines());
287    x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
288    RunCode(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
289  }
290#endif
291#ifdef ART_ENABLE_CODEGEN_mips
292  if (target_isa == kMips) {
293    std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
294        MipsInstructionSetFeatures::FromCppDefines());
295    mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), compiler_options);
296    RunCode(&codegenMIPS, graph, hook_before_codegen, has_result, expected);
297  }
298#endif
299#ifdef ART_ENABLE_CODEGEN_mips64
300  if (target_isa == kMips64) {
301    std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
302        Mips64InstructionSetFeatures::FromCppDefines());
303    mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
304    RunCode(&codegenMIPS64, graph, hook_before_codegen, has_result, expected);
305  }
306#endif
307}
308
309static ::std::vector<InstructionSet> GetTargetISAs() {
310  ::std::vector<InstructionSet> v;
311  // Add all ISAs that are executable on hardware or on simulator.
312  const ::std::vector<InstructionSet> executable_isa_candidates = {
313    kArm,
314    kArm64,
315    kThumb2,
316    kX86,
317    kX86_64,
318    kMips,
319    kMips64
320  };
321
322  for (auto target_isa : executable_isa_candidates) {
323    if (CanExecute(target_isa)) {
324      v.push_back(target_isa);
325    }
326  }
327
328  return v;
329}
330
331static void TestCode(const uint16_t* data,
332                     bool has_result = false,
333                     int32_t expected = 0) {
334  for (InstructionSet target_isa : GetTargetISAs()) {
335    ArenaPool pool;
336    ArenaAllocator arena(&pool);
337    HGraph* graph = CreateCFG(&arena, data);
338    // Remove suspend checks, they cannot be executed in this context.
339    RemoveSuspendChecks(graph);
340    RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
341  }
342}
343
344static void TestCodeLong(const uint16_t* data,
345                         bool has_result,
346                         int64_t expected) {
347  for (InstructionSet target_isa : GetTargetISAs()) {
348    ArenaPool pool;
349    ArenaAllocator arena(&pool);
350    HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
351    // Remove suspend checks, they cannot be executed in this context.
352    RemoveSuspendChecks(graph);
353    RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
354  }
355}
356
357class CodegenTest : public CommonCompilerTest {};
358
359TEST_F(CodegenTest, ReturnVoid) {
360  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
361  TestCode(data);
362}
363
364TEST_F(CodegenTest, CFG1) {
365  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
366    Instruction::GOTO | 0x100,
367    Instruction::RETURN_VOID);
368
369  TestCode(data);
370}
371
372TEST_F(CodegenTest, CFG2) {
373  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
374    Instruction::GOTO | 0x100,
375    Instruction::GOTO | 0x100,
376    Instruction::RETURN_VOID);
377
378  TestCode(data);
379}
380
381TEST_F(CodegenTest, CFG3) {
382  const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
383    Instruction::GOTO | 0x200,
384    Instruction::RETURN_VOID,
385    Instruction::GOTO | 0xFF00);
386
387  TestCode(data1);
388
389  const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
390    Instruction::GOTO_16, 3,
391    Instruction::RETURN_VOID,
392    Instruction::GOTO_16, 0xFFFF);
393
394  TestCode(data2);
395
396  const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
397    Instruction::GOTO_32, 4, 0,
398    Instruction::RETURN_VOID,
399    Instruction::GOTO_32, 0xFFFF, 0xFFFF);
400
401  TestCode(data3);
402}
403
404TEST_F(CodegenTest, CFG4) {
405  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
406    Instruction::RETURN_VOID,
407    Instruction::GOTO | 0x100,
408    Instruction::GOTO | 0xFE00);
409
410  TestCode(data);
411}
412
413TEST_F(CodegenTest, CFG5) {
414  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
415    Instruction::CONST_4 | 0 | 0,
416    Instruction::IF_EQ, 3,
417    Instruction::GOTO | 0x100,
418    Instruction::RETURN_VOID);
419
420  TestCode(data);
421}
422
423TEST_F(CodegenTest, IntConstant) {
424  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
425    Instruction::CONST_4 | 0 | 0,
426    Instruction::RETURN_VOID);
427
428  TestCode(data);
429}
430
431TEST_F(CodegenTest, Return1) {
432  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
433    Instruction::CONST_4 | 0 | 0,
434    Instruction::RETURN | 0);
435
436  TestCode(data, true, 0);
437}
438
439TEST_F(CodegenTest, Return2) {
440  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
441    Instruction::CONST_4 | 0 | 0,
442    Instruction::CONST_4 | 0 | 1 << 8,
443    Instruction::RETURN | 1 << 8);
444
445  TestCode(data, true, 0);
446}
447
448TEST_F(CodegenTest, Return3) {
449  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
450    Instruction::CONST_4 | 0 | 0,
451    Instruction::CONST_4 | 1 << 8 | 1 << 12,
452    Instruction::RETURN | 1 << 8);
453
454  TestCode(data, true, 1);
455}
456
457TEST_F(CodegenTest, ReturnIf1) {
458  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
459    Instruction::CONST_4 | 0 | 0,
460    Instruction::CONST_4 | 1 << 8 | 1 << 12,
461    Instruction::IF_EQ, 3,
462    Instruction::RETURN | 0 << 8,
463    Instruction::RETURN | 1 << 8);
464
465  TestCode(data, true, 1);
466}
467
468TEST_F(CodegenTest, ReturnIf2) {
469  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
470    Instruction::CONST_4 | 0 | 0,
471    Instruction::CONST_4 | 1 << 8 | 1 << 12,
472    Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
473    Instruction::RETURN | 0 << 8,
474    Instruction::RETURN | 1 << 8);
475
476  TestCode(data, true, 0);
477}
478
479// Exercise bit-wise (one's complement) not-int instruction.
480#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
481TEST_F(CodegenTest, TEST_NAME) {                        \
482  const int32_t input = INPUT;                          \
483  const uint16_t input_lo = Low16Bits(input);           \
484  const uint16_t input_hi = High16Bits(input);          \
485  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(      \
486      Instruction::CONST | 0 << 8, input_lo, input_hi,  \
487      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,         \
488      Instruction::RETURN | 1 << 8);                    \
489                                                        \
490  TestCode(data, true, EXPECTED_OUTPUT);                \
491}
492
493NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
494NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
495NOT_INT_TEST(ReturnNotInt0, 0, -1)
496NOT_INT_TEST(ReturnNotInt1, 1, -2)
497NOT_INT_TEST(ReturnNotIntINT32_MIN, -2147483648, 2147483647)  // (2^31) - 1
498NOT_INT_TEST(ReturnNotIntINT32_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
499NOT_INT_TEST(ReturnNotIntINT32_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
500NOT_INT_TEST(ReturnNotIntINT32_MAX, 2147483647, -2147483648)  // -(2^31)
501
502#undef NOT_INT_TEST
503
504// Exercise bit-wise (one's complement) not-long instruction.
505#define NOT_LONG_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT)                 \
506TEST_F(CodegenTest, TEST_NAME) {                                         \
507  const int64_t input = INPUT;                                           \
508  const uint16_t word0 = Low16Bits(Low32Bits(input));   /* LSW. */       \
509  const uint16_t word1 = High16Bits(Low32Bits(input));                   \
510  const uint16_t word2 = Low16Bits(High32Bits(input));                   \
511  const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */       \
512  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(                      \
513      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,      \
514      Instruction::NOT_LONG | 2 << 8 | 0 << 12,                          \
515      Instruction::RETURN_WIDE | 2 << 8);                                \
516                                                                         \
517  TestCodeLong(data, true, EXPECTED_OUTPUT);                             \
518}
519
520NOT_LONG_TEST(ReturnNotLongMinus2, INT64_C(-2), INT64_C(1))
521NOT_LONG_TEST(ReturnNotLongMinus1, INT64_C(-1), INT64_C(0))
522NOT_LONG_TEST(ReturnNotLong0, INT64_C(0), INT64_C(-1))
523NOT_LONG_TEST(ReturnNotLong1, INT64_C(1), INT64_C(-2))
524
525NOT_LONG_TEST(ReturnNotLongINT32_MIN,
526              INT64_C(-2147483648),
527              INT64_C(2147483647))  // (2^31) - 1
528NOT_LONG_TEST(ReturnNotLongINT32_MINPlus1,
529              INT64_C(-2147483647),
530              INT64_C(2147483646))  // (2^31) - 2
531NOT_LONG_TEST(ReturnNotLongINT32_MAXMinus1,
532              INT64_C(2147483646),
533              INT64_C(-2147483647))  // -(2^31) - 1
534NOT_LONG_TEST(ReturnNotLongINT32_MAX,
535              INT64_C(2147483647),
536              INT64_C(-2147483648))  // -(2^31)
537
538// Note that the C++ compiler won't accept
539// INT64_C(-9223372036854775808) (that is, INT64_MIN) as a valid
540// int64_t literal, so we use INT64_C(-9223372036854775807)-1 instead.
541NOT_LONG_TEST(ReturnNotINT64_MIN,
542              INT64_C(-9223372036854775807)-1,
543              INT64_C(9223372036854775807));  // (2^63) - 1
544NOT_LONG_TEST(ReturnNotINT64_MINPlus1,
545              INT64_C(-9223372036854775807),
546              INT64_C(9223372036854775806));  // (2^63) - 2
547NOT_LONG_TEST(ReturnNotLongINT64_MAXMinus1,
548              INT64_C(9223372036854775806),
549              INT64_C(-9223372036854775807));  // -(2^63) - 1
550NOT_LONG_TEST(ReturnNotLongINT64_MAX,
551              INT64_C(9223372036854775807),
552              INT64_C(-9223372036854775807)-1);  // -(2^63)
553
554#undef NOT_LONG_TEST
555
556TEST_F(CodegenTest, IntToLongOfLongToInt) {
557  const int64_t input = INT64_C(4294967296);             // 2^32
558  const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
559  const uint16_t word1 = High16Bits(Low32Bits(input));
560  const uint16_t word2 = Low16Bits(High32Bits(input));
561  const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
562  const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
563      Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
564      Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
565      Instruction::ADD_LONG | 0, 0 << 8 | 2,             // v0 <- 2^32 + 1
566      Instruction::LONG_TO_INT | 4 << 8 | 0 << 12,
567      Instruction::INT_TO_LONG | 2 << 8 | 4 << 12,
568      Instruction::RETURN_WIDE | 2 << 8);
569
570  TestCodeLong(data, true, 1);
571}
572
573TEST_F(CodegenTest, ReturnAdd1) {
574  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
575    Instruction::CONST_4 | 3 << 12 | 0,
576    Instruction::CONST_4 | 4 << 12 | 1 << 8,
577    Instruction::ADD_INT, 1 << 8 | 0,
578    Instruction::RETURN);
579
580  TestCode(data, true, 7);
581}
582
583TEST_F(CodegenTest, ReturnAdd2) {
584  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
585    Instruction::CONST_4 | 3 << 12 | 0,
586    Instruction::CONST_4 | 4 << 12 | 1 << 8,
587    Instruction::ADD_INT_2ADDR | 1 << 12,
588    Instruction::RETURN);
589
590  TestCode(data, true, 7);
591}
592
593TEST_F(CodegenTest, ReturnAdd3) {
594  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
595    Instruction::CONST_4 | 4 << 12 | 0 << 8,
596    Instruction::ADD_INT_LIT8, 3 << 8 | 0,
597    Instruction::RETURN);
598
599  TestCode(data, true, 7);
600}
601
602TEST_F(CodegenTest, ReturnAdd4) {
603  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
604    Instruction::CONST_4 | 4 << 12 | 0 << 8,
605    Instruction::ADD_INT_LIT16, 3,
606    Instruction::RETURN);
607
608  TestCode(data, true, 7);
609}
610
611TEST_F(CodegenTest, ReturnMulInt) {
612  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
613    Instruction::CONST_4 | 3 << 12 | 0,
614    Instruction::CONST_4 | 4 << 12 | 1 << 8,
615    Instruction::MUL_INT, 1 << 8 | 0,
616    Instruction::RETURN);
617
618  TestCode(data, true, 12);
619}
620
621TEST_F(CodegenTest, ReturnMulInt2addr) {
622  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
623    Instruction::CONST_4 | 3 << 12 | 0,
624    Instruction::CONST_4 | 4 << 12 | 1 << 8,
625    Instruction::MUL_INT_2ADDR | 1 << 12,
626    Instruction::RETURN);
627
628  TestCode(data, true, 12);
629}
630
631TEST_F(CodegenTest, ReturnMulLong) {
632  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
633    Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
634    Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
635    Instruction::MUL_LONG, 2 << 8 | 0,
636    Instruction::RETURN_WIDE);
637
638  TestCodeLong(data, true, 12);
639}
640
641TEST_F(CodegenTest, ReturnMulLong2addr) {
642  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
643    Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
644    Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
645    Instruction::MUL_LONG_2ADDR | 2 << 12,
646    Instruction::RETURN_WIDE);
647
648  TestCodeLong(data, true, 12);
649}
650
651TEST_F(CodegenTest, ReturnMulIntLit8) {
652  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
653    Instruction::CONST_4 | 4 << 12 | 0 << 8,
654    Instruction::MUL_INT_LIT8, 3 << 8 | 0,
655    Instruction::RETURN);
656
657  TestCode(data, true, 12);
658}
659
660TEST_F(CodegenTest, ReturnMulIntLit16) {
661  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
662    Instruction::CONST_4 | 4 << 12 | 0 << 8,
663    Instruction::MUL_INT_LIT16, 3,
664    Instruction::RETURN);
665
666  TestCode(data, true, 12);
667}
668
669TEST_F(CodegenTest, NonMaterializedCondition) {
670  for (InstructionSet target_isa : GetTargetISAs()) {
671    ArenaPool pool;
672    ArenaAllocator allocator(&pool);
673
674    HGraph* graph = CreateGraph(&allocator);
675
676    HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
677    graph->AddBlock(entry);
678    graph->SetEntryBlock(entry);
679    entry->AddInstruction(new (&allocator) HGoto());
680
681    HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
682    graph->AddBlock(first_block);
683    entry->AddSuccessor(first_block);
684    HIntConstant* constant0 = graph->GetIntConstant(0);
685    HIntConstant* constant1 = graph->GetIntConstant(1);
686    HEqual* equal = new (&allocator) HEqual(constant0, constant0);
687    first_block->AddInstruction(equal);
688    first_block->AddInstruction(new (&allocator) HIf(equal));
689
690    HBasicBlock* then_block = new (&allocator) HBasicBlock(graph);
691    HBasicBlock* else_block = new (&allocator) HBasicBlock(graph);
692    HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
693    graph->SetExitBlock(exit_block);
694
695    graph->AddBlock(then_block);
696    graph->AddBlock(else_block);
697    graph->AddBlock(exit_block);
698    first_block->AddSuccessor(then_block);
699    first_block->AddSuccessor(else_block);
700    then_block->AddSuccessor(exit_block);
701    else_block->AddSuccessor(exit_block);
702
703    exit_block->AddInstruction(new (&allocator) HExit());
704    then_block->AddInstruction(new (&allocator) HReturn(constant0));
705    else_block->AddInstruction(new (&allocator) HReturn(constant1));
706
707    ASSERT_FALSE(equal->IsEmittedAtUseSite());
708    graph->BuildDominatorTree();
709    PrepareForRegisterAllocation(graph).Run();
710    ASSERT_TRUE(equal->IsEmittedAtUseSite());
711
712    auto hook_before_codegen = [](HGraph* graph_in) {
713      HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
714      HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
715      block->InsertInstructionBefore(move, block->GetLastInstruction());
716    };
717
718    RunCode(target_isa, graph, hook_before_codegen, true, 0);
719  }
720}
721
722TEST_F(CodegenTest, MaterializedCondition1) {
723  for (InstructionSet target_isa : GetTargetISAs()) {
724    // Check that condition are materialized correctly. A materialized condition
725    // should yield `1` if it evaluated to true, and `0` otherwise.
726    // We force the materialization of comparisons for different combinations of
727
728    // inputs and check the results.
729
730    int lhs[] = {1, 2, -1, 2, 0xabc};
731    int rhs[] = {2, 1, 2, -1, 0xabc};
732
733    for (size_t i = 0; i < arraysize(lhs); i++) {
734      ArenaPool pool;
735      ArenaAllocator allocator(&pool);
736      HGraph* graph = CreateGraph(&allocator);
737
738      HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
739      graph->AddBlock(entry_block);
740      graph->SetEntryBlock(entry_block);
741      entry_block->AddInstruction(new (&allocator) HGoto());
742      HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
743      graph->AddBlock(code_block);
744      HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
745      graph->AddBlock(exit_block);
746      exit_block->AddInstruction(new (&allocator) HExit());
747
748      entry_block->AddSuccessor(code_block);
749      code_block->AddSuccessor(exit_block);
750      graph->SetExitBlock(exit_block);
751
752      HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
753      HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
754      HLessThan cmp_lt(cst_lhs, cst_rhs);
755      code_block->AddInstruction(&cmp_lt);
756      HReturn ret(&cmp_lt);
757      code_block->AddInstruction(&ret);
758
759      graph->BuildDominatorTree();
760      auto hook_before_codegen = [](HGraph* graph_in) {
761        HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
762        HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
763        block->InsertInstructionBefore(move, block->GetLastInstruction());
764      };
765      RunCode(target_isa, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
766    }
767  }
768}
769
770TEST_F(CodegenTest, MaterializedCondition2) {
771  for (InstructionSet target_isa : GetTargetISAs()) {
772    // Check that HIf correctly interprets a materialized condition.
773    // We force the materialization of comparisons for different combinations of
774    // inputs. An HIf takes the materialized combination as input and returns a
775    // value that we verify.
776
777    int lhs[] = {1, 2, -1, 2, 0xabc};
778    int rhs[] = {2, 1, 2, -1, 0xabc};
779
780
781    for (size_t i = 0; i < arraysize(lhs); i++) {
782      ArenaPool pool;
783      ArenaAllocator allocator(&pool);
784      HGraph* graph = CreateGraph(&allocator);
785
786      HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
787      graph->AddBlock(entry_block);
788      graph->SetEntryBlock(entry_block);
789      entry_block->AddInstruction(new (&allocator) HGoto());
790
791      HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
792      graph->AddBlock(if_block);
793      HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
794      graph->AddBlock(if_true_block);
795      HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
796      graph->AddBlock(if_false_block);
797      HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
798      graph->AddBlock(exit_block);
799      exit_block->AddInstruction(new (&allocator) HExit());
800
801      graph->SetEntryBlock(entry_block);
802      entry_block->AddSuccessor(if_block);
803      if_block->AddSuccessor(if_true_block);
804      if_block->AddSuccessor(if_false_block);
805      if_true_block->AddSuccessor(exit_block);
806      if_false_block->AddSuccessor(exit_block);
807      graph->SetExitBlock(exit_block);
808
809      HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
810      HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
811      HLessThan cmp_lt(cst_lhs, cst_rhs);
812      if_block->AddInstruction(&cmp_lt);
813      // We insert a dummy instruction to separate the HIf from the HLessThan
814      // and force the materialization of the condition.
815      HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
816      if_block->AddInstruction(&force_materialization);
817      HIf if_lt(&cmp_lt);
818      if_block->AddInstruction(&if_lt);
819
820      HIntConstant* cst_lt = graph->GetIntConstant(1);
821      HReturn ret_lt(cst_lt);
822      if_true_block->AddInstruction(&ret_lt);
823      HIntConstant* cst_ge = graph->GetIntConstant(0);
824      HReturn ret_ge(cst_ge);
825      if_false_block->AddInstruction(&ret_ge);
826
827      graph->BuildDominatorTree();
828      auto hook_before_codegen = [](HGraph* graph_in) {
829        HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
830        HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
831        block->InsertInstructionBefore(move, block->GetLastInstruction());
832      };
833      RunCode(target_isa, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
834    }
835  }
836}
837
838TEST_F(CodegenTest, ReturnDivIntLit8) {
839  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
840    Instruction::CONST_4 | 4 << 12 | 0 << 8,
841    Instruction::DIV_INT_LIT8, 3 << 8 | 0,
842    Instruction::RETURN);
843
844  TestCode(data, true, 1);
845}
846
847TEST_F(CodegenTest, ReturnDivInt2Addr) {
848  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
849    Instruction::CONST_4 | 4 << 12 | 0,
850    Instruction::CONST_4 | 2 << 12 | 1 << 8,
851    Instruction::DIV_INT_2ADDR | 1 << 12,
852    Instruction::RETURN);
853
854  TestCode(data, true, 2);
855}
856
857// Helper method.
858static void TestComparison(IfCondition condition,
859                           int64_t i,
860                           int64_t j,
861                           Primitive::Type type,
862                           const InstructionSet target_isa) {
863  ArenaPool pool;
864  ArenaAllocator allocator(&pool);
865  HGraph* graph = CreateGraph(&allocator);
866
867  HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
868  graph->AddBlock(entry_block);
869  graph->SetEntryBlock(entry_block);
870  entry_block->AddInstruction(new (&allocator) HGoto());
871
872  HBasicBlock* block = new (&allocator) HBasicBlock(graph);
873  graph->AddBlock(block);
874
875  HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
876  graph->AddBlock(exit_block);
877  graph->SetExitBlock(exit_block);
878  exit_block->AddInstruction(new (&allocator) HExit());
879
880  entry_block->AddSuccessor(block);
881  block->AddSuccessor(exit_block);
882
883  HInstruction* op1;
884  HInstruction* op2;
885  if (type == Primitive::kPrimInt) {
886    op1 = graph->GetIntConstant(i);
887    op2 = graph->GetIntConstant(j);
888  } else {
889    DCHECK_EQ(type, Primitive::kPrimLong);
890    op1 = graph->GetLongConstant(i);
891    op2 = graph->GetLongConstant(j);
892  }
893
894  HInstruction* comparison = nullptr;
895  bool expected_result = false;
896  const uint64_t x = i;
897  const uint64_t y = j;
898  switch (condition) {
899    case kCondEQ:
900      comparison = new (&allocator) HEqual(op1, op2);
901      expected_result = (i == j);
902      break;
903    case kCondNE:
904      comparison = new (&allocator) HNotEqual(op1, op2);
905      expected_result = (i != j);
906      break;
907    case kCondLT:
908      comparison = new (&allocator) HLessThan(op1, op2);
909      expected_result = (i < j);
910      break;
911    case kCondLE:
912      comparison = new (&allocator) HLessThanOrEqual(op1, op2);
913      expected_result = (i <= j);
914      break;
915    case kCondGT:
916      comparison = new (&allocator) HGreaterThan(op1, op2);
917      expected_result = (i > j);
918      break;
919    case kCondGE:
920      comparison = new (&allocator) HGreaterThanOrEqual(op1, op2);
921      expected_result = (i >= j);
922      break;
923    case kCondB:
924      comparison = new (&allocator) HBelow(op1, op2);
925      expected_result = (x < y);
926      break;
927    case kCondBE:
928      comparison = new (&allocator) HBelowOrEqual(op1, op2);
929      expected_result = (x <= y);
930      break;
931    case kCondA:
932      comparison = new (&allocator) HAbove(op1, op2);
933      expected_result = (x > y);
934      break;
935    case kCondAE:
936      comparison = new (&allocator) HAboveOrEqual(op1, op2);
937      expected_result = (x >= y);
938      break;
939  }
940  block->AddInstruction(comparison);
941  block->AddInstruction(new (&allocator) HReturn(comparison));
942
943  graph->BuildDominatorTree();
944  RunCode(target_isa, graph, [](HGraph*) {}, true, expected_result);
945}
946
947TEST_F(CodegenTest, ComparisonsInt) {
948  for (InstructionSet target_isa : GetTargetISAs()) {
949    for (int64_t i = -1; i <= 1; i++) {
950      for (int64_t j = -1; j <= 1; j++) {
951        TestComparison(kCondEQ, i, j, Primitive::kPrimInt, target_isa);
952        TestComparison(kCondNE, i, j, Primitive::kPrimInt, target_isa);
953        TestComparison(kCondLT, i, j, Primitive::kPrimInt, target_isa);
954        TestComparison(kCondLE, i, j, Primitive::kPrimInt, target_isa);
955        TestComparison(kCondGT, i, j, Primitive::kPrimInt, target_isa);
956        TestComparison(kCondGE, i, j, Primitive::kPrimInt, target_isa);
957        TestComparison(kCondB,  i, j, Primitive::kPrimInt, target_isa);
958        TestComparison(kCondBE, i, j, Primitive::kPrimInt, target_isa);
959        TestComparison(kCondA,  i, j, Primitive::kPrimInt, target_isa);
960        TestComparison(kCondAE, i, j, Primitive::kPrimInt, target_isa);
961      }
962    }
963  }
964}
965
966TEST_F(CodegenTest, ComparisonsLong) {
967  // TODO: make MIPS work for long
968  if (kRuntimeISA == kMips || kRuntimeISA == kMips64) {
969    return;
970  }
971
972  for (InstructionSet target_isa : GetTargetISAs()) {
973    if (target_isa == kMips || target_isa == kMips64) {
974      continue;
975    }
976
977    for (int64_t i = -1; i <= 1; i++) {
978      for (int64_t j = -1; j <= 1; j++) {
979        TestComparison(kCondEQ, i, j, Primitive::kPrimLong, target_isa);
980        TestComparison(kCondNE, i, j, Primitive::kPrimLong, target_isa);
981        TestComparison(kCondLT, i, j, Primitive::kPrimLong, target_isa);
982        TestComparison(kCondLE, i, j, Primitive::kPrimLong, target_isa);
983        TestComparison(kCondGT, i, j, Primitive::kPrimLong, target_isa);
984        TestComparison(kCondGE, i, j, Primitive::kPrimLong, target_isa);
985        TestComparison(kCondB,  i, j, Primitive::kPrimLong, target_isa);
986        TestComparison(kCondBE, i, j, Primitive::kPrimLong, target_isa);
987        TestComparison(kCondA,  i, j, Primitive::kPrimLong, target_isa);
988        TestComparison(kCondAE, i, j, Primitive::kPrimLong, target_isa);
989      }
990    }
991  }
992}
993
994}  // namespace art
995