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