assembler_x86_64_test.cc revision 30687af6830f1d09aa510d864557528038b33284
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
21namespace art {
22
23TEST(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
32class 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
78TEST_F(AssemblerX86_64Test, Toolchain) {
79  EXPECT_TRUE(CheckTools());
80}
81
82
83TEST_F(AssemblerX86_64Test, PushqRegs) {
84  DriverStr(RepeatR(&x86_64::X86_64Assembler::pushq, "pushq %{reg}"), "pushq");
85}
86
87TEST_F(AssemblerX86_64Test, PushqImm) {
88  DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi");
89}
90
91
92TEST_F(AssemblerX86_64Test, MovqRegs) {
93  DriverStr(RepeatRR(&x86_64::X86_64Assembler::movq, "movq %{reg2}, %{reg1}"), "movq");
94}
95
96TEST_F(AssemblerX86_64Test, MovqImm) {
97  DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi");
98}
99
100
101TEST_F(AssemblerX86_64Test, AddqRegs) {
102  DriverStr(RepeatRR(&x86_64::X86_64Assembler::addq, "addq %{reg2}, %{reg1}"), "addq");
103}
104
105TEST_F(AssemblerX86_64Test, AddqImm) {
106  DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
107}
108
109
110TEST_F(AssemblerX86_64Test, SubqRegs) {
111  DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq");
112}
113
114TEST_F(AssemblerX86_64Test, SubqImm) {
115  DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi");
116}
117
118
119TEST_F(AssemblerX86_64Test, CmpqRegs) {
120  DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq");
121}
122
123
124TEST_F(AssemblerX86_64Test, XorqImm) {
125  DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
126}
127
128TEST_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
147TEST_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
155std::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
225TEST_F(AssemblerX86_64Test, SetCC) {
226  DriverFn(&setcc_test_fn, "setcc");
227}
228
229static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
230  return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
231}
232
233static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
234  return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
235}
236
237std::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
277TEST_F(AssemblerX86_64Test, BuildFrame) {
278  DriverFn(&buildframe_test_fn, "BuildFrame");
279}
280
281std::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
305TEST_F(AssemblerX86_64Test, RemoveFrame) {
306  DriverFn(&removeframe_test_fn, "RemoveFrame");
307}
308
309std::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
323TEST_F(AssemblerX86_64Test, IncreaseFrame) {
324  DriverFn(&increaseframe_test_fn, "IncreaseFrame");
325}
326
327std::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
341TEST_F(AssemblerX86_64Test, DecreaseFrame) {
342  DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
343}
344
345}  // namespace art
346