assembler_x86_64_test.cc revision b5de00f1c8f53e6552f1778702673c6274a98bb3
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 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
189TEST_F(AssemblerX86_64Test, IMulImmediate) {
190  GetAssembler()->imull(x86_64::CpuRegister(x86_64::RAX), x86_64::Immediate(0x40000));
191  GetAssembler()->imull(x86_64::CpuRegister(x86_64::R8), x86_64::Immediate(0x40000));
192  const char* expected =
193    "imull $0x40000,%eax,%eax\n"
194    "imull $0x40000,%r8d,%r8d\n";
195  DriverStr(expected, "imul");
196}
197
198
199std::string setcc_test_fn(x86_64::X86_64Assembler* assembler) {
200  // From Condition
201  /*
202  kOverflow     =  0,
203  kNoOverflow   =  1,
204  kBelow        =  2,
205  kAboveEqual   =  3,
206  kEqual        =  4,
207  kNotEqual     =  5,
208  kBelowEqual   =  6,
209  kAbove        =  7,
210  kSign         =  8,
211  kNotSign      =  9,
212  kParityEven   = 10,
213  kParityOdd    = 11,
214  kLess         = 12,
215  kGreaterEqual = 13,
216  kLessEqual    = 14,
217  */
218  std::string suffixes[15] = { "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "pe", "po",
219                               "l", "ge", "le" };
220
221  std::vector<x86_64::CpuRegister*> registers;
222  registers.push_back(new x86_64::CpuRegister(x86_64::RAX));
223  registers.push_back(new x86_64::CpuRegister(x86_64::RBX));
224  registers.push_back(new x86_64::CpuRegister(x86_64::RCX));
225  registers.push_back(new x86_64::CpuRegister(x86_64::RDX));
226  registers.push_back(new x86_64::CpuRegister(x86_64::RBP));
227  registers.push_back(new x86_64::CpuRegister(x86_64::RSP));
228  registers.push_back(new x86_64::CpuRegister(x86_64::RSI));
229  registers.push_back(new x86_64::CpuRegister(x86_64::RDI));
230  registers.push_back(new x86_64::CpuRegister(x86_64::R8));
231  registers.push_back(new x86_64::CpuRegister(x86_64::R9));
232  registers.push_back(new x86_64::CpuRegister(x86_64::R10));
233  registers.push_back(new x86_64::CpuRegister(x86_64::R11));
234  registers.push_back(new x86_64::CpuRegister(x86_64::R12));
235  registers.push_back(new x86_64::CpuRegister(x86_64::R13));
236  registers.push_back(new x86_64::CpuRegister(x86_64::R14));
237  registers.push_back(new x86_64::CpuRegister(x86_64::R15));
238
239  std::string byte_regs[16];
240  byte_regs[x86_64::RAX] = "al";
241  byte_regs[x86_64::RBX] = "bl";
242  byte_regs[x86_64::RCX] = "cl";
243  byte_regs[x86_64::RDX] = "dl";
244  byte_regs[x86_64::RBP] = "bpl";
245  byte_regs[x86_64::RSP] = "spl";
246  byte_regs[x86_64::RSI] = "sil";
247  byte_regs[x86_64::RDI] = "dil";
248  byte_regs[x86_64::R8] = "r8b";
249  byte_regs[x86_64::R9] = "r9b";
250  byte_regs[x86_64::R10] = "r10b";
251  byte_regs[x86_64::R11] = "r11b";
252  byte_regs[x86_64::R12] = "r12b";
253  byte_regs[x86_64::R13] = "r13b";
254  byte_regs[x86_64::R14] = "r14b";
255  byte_regs[x86_64::R15] = "r15b";
256
257  std::ostringstream str;
258
259  for (auto reg : registers) {
260    for (size_t i = 0; i < 15; ++i) {
261      assembler->setcc(static_cast<x86_64::Condition>(i), *reg);
262      str << "set" << suffixes[i] << " %" << byte_regs[reg->AsRegister()] << "\n";
263    }
264  }
265
266  STLDeleteElements(&registers);
267  return str.str();
268}
269
270TEST_F(AssemblerX86_64Test, SetCC) {
271  DriverFn(&setcc_test_fn, "setcc");
272}
273
274static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
275  return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
276}
277
278static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
279  return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
280}
281
282std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) {
283  // TODO: more interesting spill registers / entry spills.
284
285  // Two random spill regs.
286  std::vector<ManagedRegister> spill_regs;
287  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
288  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
289
290  // Three random entry spills.
291  ManagedRegisterEntrySpills entry_spills;
292  ManagedRegisterSpill spill(ManagedFromCpu(x86_64::RAX), 8, 0);
293  entry_spills.push_back(spill);
294  ManagedRegisterSpill spill2(ManagedFromCpu(x86_64::RBX), 8, 8);
295  entry_spills.push_back(spill2);
296  ManagedRegisterSpill spill3(ManagedFromFpu(x86_64::XMM1), 8, 16);
297  entry_spills.push_back(spill3);
298
299  x86_64::X86_64ManagedRegister method_reg = ManagedFromCpu(x86_64::RDI);
300
301  size_t frame_size = 10 * kStackAlignment;
302  assembler->BuildFrame(10 * kStackAlignment, method_reg, spill_regs, entry_spills);
303
304  // Construct assembly text counterpart.
305  std::ostringstream str;
306  // 1) Push the spill_regs.
307  str << "pushq %rsi\n";
308  str << "pushq %r10\n";
309  // 2) Move down the stack pointer.
310  ssize_t displacement = static_cast<ssize_t>(frame_size) - (spill_regs.size() * 8 + 8);
311  str << "subq $" << displacement << ", %rsp\n";
312  // 3) Store method reference.
313  str << "movl %edi, (%rsp)\n";
314  // 4) Entry spills.
315  str << "movq %rax, " << frame_size + 0 << "(%rsp)\n";
316  str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n";
317  str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n";
318
319  return str.str();
320}
321
322TEST_F(AssemblerX86_64Test, BuildFrame) {
323  DriverFn(&buildframe_test_fn, "BuildFrame");
324}
325
326std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) {
327  // TODO: more interesting spill registers / entry spills.
328
329  // Two random spill regs.
330  std::vector<ManagedRegister> spill_regs;
331  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
332  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
333
334  size_t frame_size = 10 * kStackAlignment;
335  assembler->RemoveFrame(10 * kStackAlignment, spill_regs);
336
337  // Construct assembly text counterpart.
338  std::ostringstream str;
339  // 1) Move up the stack pointer.
340  ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8;
341  str << "addq $" << displacement << ", %rsp\n";
342  // 2) Pop spill regs.
343  str << "popq %r10\n";
344  str << "popq %rsi\n";
345  str << "ret\n";
346
347  return str.str();
348}
349
350TEST_F(AssemblerX86_64Test, RemoveFrame) {
351  DriverFn(&removeframe_test_fn, "RemoveFrame");
352}
353
354std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
355  assembler->IncreaseFrameSize(0U);
356  assembler->IncreaseFrameSize(kStackAlignment);
357  assembler->IncreaseFrameSize(10 * kStackAlignment);
358
359  // Construct assembly text counterpart.
360  std::ostringstream str;
361  str << "addq $0, %rsp\n";
362  str << "addq $-" << kStackAlignment << ", %rsp\n";
363  str << "addq $-" << 10 * kStackAlignment << ", %rsp\n";
364
365  return str.str();
366}
367
368TEST_F(AssemblerX86_64Test, IncreaseFrame) {
369  DriverFn(&increaseframe_test_fn, "IncreaseFrame");
370}
371
372std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
373  assembler->DecreaseFrameSize(0U);
374  assembler->DecreaseFrameSize(kStackAlignment);
375  assembler->DecreaseFrameSize(10 * kStackAlignment);
376
377  // Construct assembly text counterpart.
378  std::ostringstream str;
379  str << "addq $0, %rsp\n";
380  str << "addq $" << kStackAlignment << ", %rsp\n";
381  str << "addq $" << 10 * kStackAlignment << ", %rsp\n";
382
383  return str.str();
384}
385
386TEST_F(AssemblerX86_64Test, DecreaseFrame) {
387  DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
388}
389
390}  // namespace art
391