Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2016 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 "base/arena_allocator.h"
     18 #include "code_generator_mips.h"
     19 #include "optimizing_unit_test.h"
     20 #include "parallel_move_resolver.h"
     21 #include "utils/assembler_test_base.h"
     22 #include "utils/mips/assembler_mips.h"
     23 
     24 #include "gtest/gtest.h"
     25 
     26 namespace art {
     27 
     28 class EmitSwapMipsTest : public OptimizingUnitTest {
     29  public:
     30   void SetUp() OVERRIDE {
     31     graph_ = CreateGraph();
     32     isa_features_ = MipsInstructionSetFeatures::FromCppDefines();
     33     codegen_ = new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_,
     34                                                                     *isa_features_.get(),
     35                                                                     CompilerOptions());
     36     moves_ = new (GetAllocator()) HParallelMove(GetAllocator());
     37     test_helper_.reset(
     38         new AssemblerTestInfrastructure(GetArchitectureString(),
     39                                         GetAssemblerCmdName(),
     40                                         GetAssemblerParameters(),
     41                                         GetObjdumpCmdName(),
     42                                         GetObjdumpParameters(),
     43                                         GetDisassembleCmdName(),
     44                                         GetDisassembleParameters(),
     45                                         GetAssemblyHeader()));
     46   }
     47 
     48   void TearDown() OVERRIDE {
     49     test_helper_.reset();
     50     isa_features_.reset();
     51     ResetPoolAndAllocator();
     52   }
     53 
     54   // Get the typically used name for this architecture.
     55   std::string GetArchitectureString() {
     56     return "mips";
     57   }
     58 
     59   // Get the name of the assembler.
     60   std::string GetAssemblerCmdName() {
     61     return "as";
     62   }
     63 
     64   // Switches to the assembler command.
     65   std::string GetAssemblerParameters() {
     66     return " --no-warn -32 -march=mips32r2";
     67   }
     68 
     69   // Get the name of the objdump.
     70   std::string GetObjdumpCmdName() {
     71     return "objdump";
     72   }
     73 
     74   // Switches to the objdump command.
     75   std::string GetObjdumpParameters() {
     76     return " -h";
     77   }
     78 
     79   // Get the name of the objdump.
     80   std::string GetDisassembleCmdName() {
     81     return "objdump";
     82   }
     83 
     84   // Switches to the objdump command.
     85   std::string GetDisassembleParameters() {
     86     return " -D -bbinary -mmips:isa32r2";
     87   }
     88 
     89   // No need for assembly header here.
     90   const char* GetAssemblyHeader() {
     91     return nullptr;
     92   }
     93 
     94   void DriverWrapper(HParallelMove* move,
     95                      const std::string& assembly_text,
     96                      const std::string& test_name) {
     97     codegen_->GetMoveResolver()->EmitNativeCode(move);
     98     assembler_ = codegen_->GetAssembler();
     99     assembler_->FinalizeCode();
    100     std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(assembler_->CodeSize()));
    101     MemoryRegion code(&(*data)[0], data->size());
    102     assembler_->FinalizeInstructions(code);
    103     test_helper_->Driver(*data, assembly_text, test_name);
    104   }
    105 
    106  protected:
    107   HGraph* graph_;
    108   HParallelMove* moves_;
    109   mips::CodeGeneratorMIPS* codegen_;
    110   mips::MipsAssembler* assembler_;
    111   std::unique_ptr<AssemblerTestInfrastructure> test_helper_;
    112   std::unique_ptr<const MipsInstructionSetFeatures> isa_features_;
    113 };
    114 
    115 TEST_F(EmitSwapMipsTest, TwoRegisters) {
    116   moves_->AddMove(
    117       Location::RegisterLocation(4),
    118       Location::RegisterLocation(5),
    119       DataType::Type::kInt32,
    120       nullptr);
    121   moves_->AddMove(
    122       Location::RegisterLocation(5),
    123       Location::RegisterLocation(4),
    124       DataType::Type::kInt32,
    125       nullptr);
    126   const char* expected =
    127       "or $t8, $a1, $zero\n"
    128       "or $a1, $a0, $zero\n"
    129       "or $a0, $t8, $zero\n";
    130   DriverWrapper(moves_, expected, "TwoRegisters");
    131 }
    132 
    133 TEST_F(EmitSwapMipsTest, TwoRegisterPairs) {
    134   moves_->AddMove(
    135       Location::RegisterPairLocation(4, 5),
    136       Location::RegisterPairLocation(6, 7),
    137       DataType::Type::kInt64,
    138       nullptr);
    139   moves_->AddMove(
    140       Location::RegisterPairLocation(6, 7),
    141       Location::RegisterPairLocation(4, 5),
    142       DataType::Type::kInt64,
    143       nullptr);
    144   const char* expected =
    145       "or $t8, $a2, $zero\n"
    146       "or $a2, $a0, $zero\n"
    147       "or $a0, $t8, $zero\n"
    148       "or $t8, $a3, $zero\n"
    149       "or $a3, $a1, $zero\n"
    150       "or $a1, $t8, $zero\n";
    151   DriverWrapper(moves_, expected, "TwoRegisterPairs");
    152 }
    153 
    154 TEST_F(EmitSwapMipsTest, TwoFpuRegistersFloat) {
    155   moves_->AddMove(
    156       Location::FpuRegisterLocation(4),
    157       Location::FpuRegisterLocation(2),
    158       DataType::Type::kFloat32,
    159       nullptr);
    160   moves_->AddMove(
    161       Location::FpuRegisterLocation(2),
    162       Location::FpuRegisterLocation(4),
    163       DataType::Type::kFloat32,
    164       nullptr);
    165   const char* expected =
    166       "mov.s $f6, $f2\n"
    167       "mov.s $f2, $f4\n"
    168       "mov.s $f4, $f6\n";
    169   DriverWrapper(moves_, expected, "TwoFpuRegistersFloat");
    170 }
    171 
    172 TEST_F(EmitSwapMipsTest, TwoFpuRegistersDouble) {
    173   moves_->AddMove(
    174       Location::FpuRegisterLocation(4),
    175       Location::FpuRegisterLocation(2),
    176       DataType::Type::kFloat64,
    177       nullptr);
    178   moves_->AddMove(
    179       Location::FpuRegisterLocation(2),
    180       Location::FpuRegisterLocation(4),
    181       DataType::Type::kFloat64,
    182       nullptr);
    183   const char* expected =
    184       "mov.d $f6, $f2\n"
    185       "mov.d $f2, $f4\n"
    186       "mov.d $f4, $f6\n";
    187   DriverWrapper(moves_, expected, "TwoFpuRegistersDouble");
    188 }
    189 
    190 TEST_F(EmitSwapMipsTest, RegisterAndFpuRegister) {
    191   moves_->AddMove(
    192       Location::RegisterLocation(4),
    193       Location::FpuRegisterLocation(2),
    194       DataType::Type::kFloat32,
    195       nullptr);
    196   moves_->AddMove(
    197       Location::FpuRegisterLocation(2),
    198       Location::RegisterLocation(4),
    199       DataType::Type::kFloat32,
    200       nullptr);
    201   const char* expected =
    202       "or $t8, $a0, $zero\n"
    203       "mfc1 $a0, $f2\n"
    204       "mtc1 $t8, $f2\n";
    205   DriverWrapper(moves_, expected, "RegisterAndFpuRegister");
    206 }
    207 
    208 TEST_F(EmitSwapMipsTest, RegisterPairAndFpuRegister) {
    209   moves_->AddMove(
    210       Location::RegisterPairLocation(4, 5),
    211       Location::FpuRegisterLocation(4),
    212       DataType::Type::kFloat64,
    213       nullptr);
    214   moves_->AddMove(
    215       Location::FpuRegisterLocation(4),
    216       Location::RegisterPairLocation(4, 5),
    217       DataType::Type::kFloat64,
    218       nullptr);
    219   const char* expected =
    220       "mfc1 $t8, $f4\n"
    221       "mfc1 $at, $f5\n"
    222       "mtc1 $a0, $f4\n"
    223       "mtc1 $a1, $f5\n"
    224       "or $a0, $t8, $zero\n"
    225       "or $a1, $at, $zero\n";
    226   DriverWrapper(moves_, expected, "RegisterPairAndFpuRegister");
    227 }
    228 
    229 TEST_F(EmitSwapMipsTest, TwoStackSlots) {
    230   moves_->AddMove(
    231       Location::StackSlot(52),
    232       Location::StackSlot(48),
    233       DataType::Type::kInt32,
    234       nullptr);
    235   moves_->AddMove(
    236       Location::StackSlot(48),
    237       Location::StackSlot(52),
    238       DataType::Type::kInt32,
    239       nullptr);
    240   const char* expected =
    241       "addiu $sp, $sp, -16\n"
    242       "sw $v0, 0($sp)\n"
    243       "lw $v0, 68($sp)\n"
    244       "lw $t8, 64($sp)\n"
    245       "sw $v0, 64($sp)\n"
    246       "sw $t8, 68($sp)\n"
    247       "lw $v0, 0($sp)\n"
    248       "addiu $sp, $sp, 16\n";
    249   DriverWrapper(moves_, expected, "TwoStackSlots");
    250 }
    251 
    252 TEST_F(EmitSwapMipsTest, TwoDoubleStackSlots) {
    253   moves_->AddMove(
    254       Location::DoubleStackSlot(56),
    255       Location::DoubleStackSlot(48),
    256       DataType::Type::kInt64,
    257       nullptr);
    258   moves_->AddMove(
    259       Location::DoubleStackSlot(48),
    260       Location::DoubleStackSlot(56),
    261       DataType::Type::kInt64,
    262       nullptr);
    263   const char* expected =
    264       "addiu $sp, $sp, -16\n"
    265       "sw $v0, 0($sp)\n"
    266       "lw $v0, 72($sp)\n"
    267       "lw $t8, 64($sp)\n"
    268       "sw $v0, 64($sp)\n"
    269       "sw $t8, 72($sp)\n"
    270       "lw $v0, 76($sp)\n"
    271       "lw $t8, 68($sp)\n"
    272       "sw $v0, 68($sp)\n"
    273       "sw $t8, 76($sp)\n"
    274       "lw $v0, 0($sp)\n"
    275       "addiu $sp, $sp, 16\n";
    276   DriverWrapper(moves_, expected, "TwoDoubleStackSlots");
    277 }
    278 
    279 TEST_F(EmitSwapMipsTest, RegisterAndStackSlot) {
    280   moves_->AddMove(
    281       Location::RegisterLocation(4),
    282       Location::StackSlot(48),
    283       DataType::Type::kInt32,
    284       nullptr);
    285   moves_->AddMove(
    286       Location::StackSlot(48),
    287       Location::RegisterLocation(4),
    288       DataType::Type::kInt32,
    289       nullptr);
    290   const char* expected =
    291       "or $t8, $a0, $zero\n"
    292       "lw $a0, 48($sp)\n"
    293       "sw $t8, 48($sp)\n";
    294   DriverWrapper(moves_, expected, "RegisterAndStackSlot");
    295 }
    296 
    297 TEST_F(EmitSwapMipsTest, RegisterPairAndDoubleStackSlot) {
    298   moves_->AddMove(
    299       Location::RegisterPairLocation(4, 5),
    300       Location::DoubleStackSlot(32),
    301       DataType::Type::kInt64,
    302       nullptr);
    303   moves_->AddMove(
    304       Location::DoubleStackSlot(32),
    305       Location::RegisterPairLocation(4, 5),
    306       DataType::Type::kInt64,
    307       nullptr);
    308   const char* expected =
    309       "or $t8, $a0, $zero\n"
    310       "lw $a0, 32($sp)\n"
    311       "sw $t8, 32($sp)\n"
    312       "or $t8, $a1, $zero\n"
    313       "lw $a1, 36($sp)\n"
    314       "sw $t8, 36($sp)\n";
    315   DriverWrapper(moves_, expected, "RegisterPairAndDoubleStackSlot");
    316 }
    317 
    318 TEST_F(EmitSwapMipsTest, FpuRegisterAndStackSlot) {
    319   moves_->AddMove(
    320       Location::FpuRegisterLocation(4),
    321       Location::StackSlot(48),
    322       DataType::Type::kFloat32,
    323       nullptr);
    324   moves_->AddMove(
    325       Location::StackSlot(48),
    326       Location::FpuRegisterLocation(4),
    327       DataType::Type::kFloat32,
    328       nullptr);
    329   const char* expected =
    330       "mov.s $f6, $f4\n"
    331       "lwc1 $f4, 48($sp)\n"
    332       "swc1 $f6, 48($sp)\n";
    333   DriverWrapper(moves_, expected, "FpuRegisterAndStackSlot");
    334 }
    335 
    336 TEST_F(EmitSwapMipsTest, FpuRegisterAndDoubleStackSlot) {
    337   moves_->AddMove(
    338       Location::FpuRegisterLocation(4),
    339       Location::DoubleStackSlot(48),
    340       DataType::Type::kFloat64,
    341       nullptr);
    342   moves_->AddMove(
    343       Location::DoubleStackSlot(48),
    344       Location::FpuRegisterLocation(4),
    345       DataType::Type::kFloat64,
    346       nullptr);
    347   const char* expected =
    348       "mov.d $f6, $f4\n"
    349       "ldc1 $f4, 48($sp)\n"
    350       "sdc1 $f6, 48($sp)\n";
    351   DriverWrapper(moves_, expected, "FpuRegisterAndDoubleStackSlot");
    352 }
    353 
    354 }  // namespace art
    355