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