Home | History | Annotate | Download | only in x86_64
      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 "assembler_x86_64.h"
     18 
     19 #include "utils/assembler_test.h"
     20 
     21 namespace art {
     22 
     23 TEST(AssemblerX86_64, CreateBuffer) {
     24   AssemblerBuffer buffer;
     25   AssemblerBuffer::EnsureCapacity ensured(&buffer);
     26   buffer.Emit<uint8_t>(0x42);
     27   ASSERT_EQ(static_cast<size_t>(1), buffer.Size());
     28   buffer.Emit<int32_t>(42);
     29   ASSERT_EQ(static_cast<size_t>(5), buffer.Size());
     30 }
     31 
     32 class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler, x86_64::CpuRegister,
     33                                                  x86_64::Immediate> {
     34  protected:
     35   // Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
     36   std::string GetArchitectureString() OVERRIDE {
     37     return "x86_64";
     38   }
     39 
     40   std::string GetDisassembleParameters() OVERRIDE {
     41     return " -D -bbinary -mi386:x86-64 -Mx86-64,addr64,data32 --no-show-raw-insn";
     42   }
     43 
     44   void SetUpHelpers() OVERRIDE {
     45     if (registers_.size() == 0) {
     46       registers_.push_back(new x86_64::CpuRegister(x86_64::RAX));
     47       registers_.push_back(new x86_64::CpuRegister(x86_64::RBX));
     48       registers_.push_back(new x86_64::CpuRegister(x86_64::RCX));
     49       registers_.push_back(new x86_64::CpuRegister(x86_64::RDX));
     50       registers_.push_back(new x86_64::CpuRegister(x86_64::RBP));
     51       registers_.push_back(new x86_64::CpuRegister(x86_64::RSP));
     52       registers_.push_back(new x86_64::CpuRegister(x86_64::RSI));
     53       registers_.push_back(new x86_64::CpuRegister(x86_64::RDI));
     54       registers_.push_back(new x86_64::CpuRegister(x86_64::R8));
     55       registers_.push_back(new x86_64::CpuRegister(x86_64::R9));
     56       registers_.push_back(new x86_64::CpuRegister(x86_64::R10));
     57       registers_.push_back(new x86_64::CpuRegister(x86_64::R11));
     58       registers_.push_back(new x86_64::CpuRegister(x86_64::R12));
     59       registers_.push_back(new x86_64::CpuRegister(x86_64::R13));
     60       registers_.push_back(new x86_64::CpuRegister(x86_64::R14));
     61       registers_.push_back(new x86_64::CpuRegister(x86_64::R15));
     62     }
     63   }
     64 
     65   std::vector<x86_64::CpuRegister*> GetRegisters() OVERRIDE {
     66     return registers_;
     67   }
     68 
     69   x86_64::Immediate* CreateImmediate(int64_t imm_value) OVERRIDE {
     70     return new x86_64::Immediate(imm_value);
     71   }
     72 
     73  private:
     74   std::vector<x86_64::CpuRegister*> registers_;
     75 };
     76 
     77 
     78 TEST_F(AssemblerX86_64Test, Toolchain) {
     79   EXPECT_TRUE(CheckTools());
     80 }
     81 
     82 
     83 TEST_F(AssemblerX86_64Test, PushqRegs) {
     84   DriverStr(RepeatR(&x86_64::X86_64Assembler::pushq, "pushq %{reg}"), "pushq");
     85 }
     86 
     87 TEST_F(AssemblerX86_64Test, PushqImm) {
     88   DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi");
     89 }
     90 
     91 
     92 TEST_F(AssemblerX86_64Test, MovqRegs) {
     93   DriverStr(RepeatRR(&x86_64::X86_64Assembler::movq, "movq %{reg2}, %{reg1}"), "movq");
     94 }
     95 
     96 TEST_F(AssemblerX86_64Test, MovqImm) {
     97   DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi");
     98 }
     99 
    100 
    101 TEST_F(AssemblerX86_64Test, AddqRegs) {
    102   DriverStr(RepeatRR(&x86_64::X86_64Assembler::addq, "addq %{reg2}, %{reg1}"), "addq");
    103 }
    104 
    105 TEST_F(AssemblerX86_64Test, AddqImm) {
    106   DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
    107 }
    108 
    109 
    110 TEST_F(AssemblerX86_64Test, SubqRegs) {
    111   DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq");
    112 }
    113 
    114 TEST_F(AssemblerX86_64Test, SubqImm) {
    115   DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi");
    116 }
    117 
    118 
    119 TEST_F(AssemblerX86_64Test, CmpqRegs) {
    120   DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq");
    121 }
    122 
    123 
    124 TEST_F(AssemblerX86_64Test, XorqImm) {
    125   DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
    126 }
    127 
    128 TEST_F(AssemblerX86_64Test, Movl) {
    129   GetAssembler()->movl(x86_64::CpuRegister(x86_64::R8), x86_64::CpuRegister(x86_64::R11));
    130   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::CpuRegister(x86_64::R11));
    131   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
    132       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
    133   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::Address(
    134       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
    135   GetAssembler()->movl(x86_64::CpuRegister(x86_64::R8), x86_64::Address(
    136       x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
    137   const char* expected =
    138     "movl %R11d, %R8d\n"
    139     "movl %R11d, %EAX\n"
    140     "movl 0xc(%RDI,%RBX,4), %EAX\n"
    141     "movl 0xc(%RDI,%R9,4), %EAX\n"
    142     "movl 0xc(%RDI,%R9,4), %R8d\n";
    143 
    144   DriverStr(expected, "movl");
    145 }
    146 
    147 TEST_F(AssemblerX86_64Test, Movw) {
    148   GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
    149                        x86_64::CpuRegister(x86_64::R9));
    150   const char* expected = "movw %R9w, 0(%RAX)\n";
    151   DriverStr(expected, "movw");
    152 }
    153 
    154 
    155 std::string setcc_test_fn(x86_64::X86_64Assembler* assembler) {
    156   // From Condition
    157   /*
    158   kOverflow     =  0,
    159   kNoOverflow   =  1,
    160   kBelow        =  2,
    161   kAboveEqual   =  3,
    162   kEqual        =  4,
    163   kNotEqual     =  5,
    164   kBelowEqual   =  6,
    165   kAbove        =  7,
    166   kSign         =  8,
    167   kNotSign      =  9,
    168   kParityEven   = 10,
    169   kParityOdd    = 11,
    170   kLess         = 12,
    171   kGreaterEqual = 13,
    172   kLessEqual    = 14,
    173   */
    174   std::string suffixes[15] = { "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "pe", "po",
    175                                "l", "ge", "le" };
    176 
    177   std::vector<x86_64::CpuRegister*> registers;
    178   registers.push_back(new x86_64::CpuRegister(x86_64::RAX));
    179   registers.push_back(new x86_64::CpuRegister(x86_64::RBX));
    180   registers.push_back(new x86_64::CpuRegister(x86_64::RCX));
    181   registers.push_back(new x86_64::CpuRegister(x86_64::RDX));
    182   registers.push_back(new x86_64::CpuRegister(x86_64::RBP));
    183   registers.push_back(new x86_64::CpuRegister(x86_64::RSP));
    184   registers.push_back(new x86_64::CpuRegister(x86_64::RSI));
    185   registers.push_back(new x86_64::CpuRegister(x86_64::RDI));
    186   registers.push_back(new x86_64::CpuRegister(x86_64::R8));
    187   registers.push_back(new x86_64::CpuRegister(x86_64::R9));
    188   registers.push_back(new x86_64::CpuRegister(x86_64::R10));
    189   registers.push_back(new x86_64::CpuRegister(x86_64::R11));
    190   registers.push_back(new x86_64::CpuRegister(x86_64::R12));
    191   registers.push_back(new x86_64::CpuRegister(x86_64::R13));
    192   registers.push_back(new x86_64::CpuRegister(x86_64::R14));
    193   registers.push_back(new x86_64::CpuRegister(x86_64::R15));
    194 
    195   std::string byte_regs[16];
    196   byte_regs[x86_64::RAX] = "al";
    197   byte_regs[x86_64::RBX] = "bl";
    198   byte_regs[x86_64::RCX] = "cl";
    199   byte_regs[x86_64::RDX] = "dl";
    200   byte_regs[x86_64::RBP] = "bpl";
    201   byte_regs[x86_64::RSP] = "spl";
    202   byte_regs[x86_64::RSI] = "sil";
    203   byte_regs[x86_64::RDI] = "dil";
    204   byte_regs[x86_64::R8] = "r8b";
    205   byte_regs[x86_64::R9] = "r9b";
    206   byte_regs[x86_64::R10] = "r10b";
    207   byte_regs[x86_64::R11] = "r11b";
    208   byte_regs[x86_64::R12] = "r12b";
    209   byte_regs[x86_64::R13] = "r13b";
    210   byte_regs[x86_64::R14] = "r14b";
    211   byte_regs[x86_64::R15] = "r15b";
    212 
    213   std::ostringstream str;
    214 
    215   for (auto reg : registers) {
    216     for (size_t i = 0; i < 15; ++i) {
    217       assembler->setcc(static_cast<x86_64::Condition>(i), *reg);
    218       str << "set" << suffixes[i] << " %" << byte_regs[reg->AsRegister()] << "\n";
    219     }
    220   }
    221 
    222   return str.str();
    223 }
    224 
    225 TEST_F(AssemblerX86_64Test, SetCC) {
    226   DriverFn(&setcc_test_fn, "setcc");
    227 }
    228 
    229 static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
    230   return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
    231 }
    232 
    233 static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
    234   return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
    235 }
    236 
    237 std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) {
    238   // TODO: more interesting spill registers / entry spills.
    239 
    240   // Two random spill regs.
    241   std::vector<ManagedRegister> spill_regs;
    242   spill_regs.push_back(ManagedFromCpu(x86_64::R10));
    243   spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
    244 
    245   // Three random entry spills.
    246   ManagedRegisterEntrySpills entry_spills;
    247   ManagedRegisterSpill spill(ManagedFromCpu(x86_64::RAX), 8, 0);
    248   entry_spills.push_back(spill);
    249   ManagedRegisterSpill spill2(ManagedFromCpu(x86_64::RBX), 8, 8);
    250   entry_spills.push_back(spill2);
    251   ManagedRegisterSpill spill3(ManagedFromFpu(x86_64::XMM1), 8, 16);
    252   entry_spills.push_back(spill3);
    253 
    254   x86_64::X86_64ManagedRegister method_reg = ManagedFromCpu(x86_64::RDI);
    255 
    256   size_t frame_size = 10 * kStackAlignment;
    257   assembler->BuildFrame(10 * kStackAlignment, method_reg, spill_regs, entry_spills);
    258 
    259   // Construct assembly text counterpart.
    260   std::ostringstream str;
    261   // 1) Push the spill_regs.
    262   str << "pushq %rsi\n";
    263   str << "pushq %r10\n";
    264   // 2) Move down the stack pointer.
    265   ssize_t displacement = static_cast<ssize_t>(frame_size) - (spill_regs.size() * 8 + 8);
    266   str << "subq $" << displacement << ", %rsp\n";
    267   // 3) Store method reference.
    268   str << "movl %edi, (%rsp)\n";
    269   // 4) Entry spills.
    270   str << "movq %rax, " << frame_size + 0 << "(%rsp)\n";
    271   str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n";
    272   str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n";
    273 
    274   return str.str();
    275 }
    276 
    277 TEST_F(AssemblerX86_64Test, BuildFrame) {
    278   DriverFn(&buildframe_test_fn, "BuildFrame");
    279 }
    280 
    281 std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) {
    282   // TODO: more interesting spill registers / entry spills.
    283 
    284   // Two random spill regs.
    285   std::vector<ManagedRegister> spill_regs;
    286   spill_regs.push_back(ManagedFromCpu(x86_64::R10));
    287   spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
    288 
    289   size_t frame_size = 10 * kStackAlignment;
    290   assembler->RemoveFrame(10 * kStackAlignment, spill_regs);
    291 
    292   // Construct assembly text counterpart.
    293   std::ostringstream str;
    294   // 1) Move up the stack pointer.
    295   ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8;
    296   str << "addq $" << displacement << ", %rsp\n";
    297   // 2) Pop spill regs.
    298   str << "popq %r10\n";
    299   str << "popq %rsi\n";
    300   str << "ret\n";
    301 
    302   return str.str();
    303 }
    304 
    305 TEST_F(AssemblerX86_64Test, RemoveFrame) {
    306   DriverFn(&removeframe_test_fn, "RemoveFrame");
    307 }
    308 
    309 std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
    310   assembler->IncreaseFrameSize(0U);
    311   assembler->IncreaseFrameSize(kStackAlignment);
    312   assembler->IncreaseFrameSize(10 * kStackAlignment);
    313 
    314   // Construct assembly text counterpart.
    315   std::ostringstream str;
    316   str << "addq $0, %rsp\n";
    317   str << "addq $-" << kStackAlignment << ", %rsp\n";
    318   str << "addq $-" << 10 * kStackAlignment << ", %rsp\n";
    319 
    320   return str.str();
    321 }
    322 
    323 TEST_F(AssemblerX86_64Test, IncreaseFrame) {
    324   DriverFn(&increaseframe_test_fn, "IncreaseFrame");
    325 }
    326 
    327 std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
    328   assembler->DecreaseFrameSize(0U);
    329   assembler->DecreaseFrameSize(kStackAlignment);
    330   assembler->DecreaseFrameSize(10 * kStackAlignment);
    331 
    332   // Construct assembly text counterpart.
    333   std::ostringstream str;
    334   str << "addq $0, %rsp\n";
    335   str << "addq $" << kStackAlignment << ", %rsp\n";
    336   str << "addq $" << 10 * kStackAlignment << ", %rsp\n";
    337 
    338   return str.str();
    339 }
    340 
    341 TEST_F(AssemblerX86_64Test, DecreaseFrame) {
    342   DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
    343 }
    344 
    345 }  // namespace art
    346