assembler_x86_64_test.cc revision e4ded41ae2648973d5fed8c6bafaebf917ea7d17
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  const char* expected =
132    "movl %R11d, %R8d\n"
133    "movl %R11d, %EAX\n";
134
135  DriverStr(expected, "movl");
136}
137
138TEST_F(AssemblerX86_64Test, Movw) {
139  GetAssembler()->movw(x86_64::Address(x86_64::CpuRegister(x86_64::RAX), 0),
140                       x86_64::CpuRegister(x86_64::R9));
141  const char* expected = "movw %R9w, 0(%RAX)\n";
142  DriverStr(expected, "movw");
143}
144
145
146std::string setcc_test_fn(x86_64::X86_64Assembler* assembler) {
147  // From Condition
148  /*
149  kOverflow     =  0,
150  kNoOverflow   =  1,
151  kBelow        =  2,
152  kAboveEqual   =  3,
153  kEqual        =  4,
154  kNotEqual     =  5,
155  kBelowEqual   =  6,
156  kAbove        =  7,
157  kSign         =  8,
158  kNotSign      =  9,
159  kParityEven   = 10,
160  kParityOdd    = 11,
161  kLess         = 12,
162  kGreaterEqual = 13,
163  kLessEqual    = 14,
164  */
165  std::string suffixes[15] = { "o", "no", "b", "ae", "e", "ne", "be", "a", "s", "ns", "pe", "po",
166                               "l", "ge", "le" };
167
168  std::vector<x86_64::CpuRegister*> registers;
169  registers.push_back(new x86_64::CpuRegister(x86_64::RAX));
170  registers.push_back(new x86_64::CpuRegister(x86_64::RBX));
171  registers.push_back(new x86_64::CpuRegister(x86_64::RCX));
172  registers.push_back(new x86_64::CpuRegister(x86_64::RDX));
173  registers.push_back(new x86_64::CpuRegister(x86_64::RBP));
174  registers.push_back(new x86_64::CpuRegister(x86_64::RSP));
175  registers.push_back(new x86_64::CpuRegister(x86_64::RSI));
176  registers.push_back(new x86_64::CpuRegister(x86_64::RDI));
177  registers.push_back(new x86_64::CpuRegister(x86_64::R8));
178  registers.push_back(new x86_64::CpuRegister(x86_64::R9));
179  registers.push_back(new x86_64::CpuRegister(x86_64::R10));
180  registers.push_back(new x86_64::CpuRegister(x86_64::R11));
181  registers.push_back(new x86_64::CpuRegister(x86_64::R12));
182  registers.push_back(new x86_64::CpuRegister(x86_64::R13));
183  registers.push_back(new x86_64::CpuRegister(x86_64::R14));
184  registers.push_back(new x86_64::CpuRegister(x86_64::R15));
185
186  std::string byte_regs[16];
187  byte_regs[x86_64::RAX] = "al";
188  byte_regs[x86_64::RBX] = "bl";
189  byte_regs[x86_64::RCX] = "cl";
190  byte_regs[x86_64::RDX] = "dl";
191  byte_regs[x86_64::RBP] = "bpl";
192  byte_regs[x86_64::RSP] = "spl";
193  byte_regs[x86_64::RSI] = "sil";
194  byte_regs[x86_64::RDI] = "dil";
195  byte_regs[x86_64::R8] = "r8b";
196  byte_regs[x86_64::R9] = "r9b";
197  byte_regs[x86_64::R10] = "r10b";
198  byte_regs[x86_64::R11] = "r11b";
199  byte_regs[x86_64::R12] = "r12b";
200  byte_regs[x86_64::R13] = "r13b";
201  byte_regs[x86_64::R14] = "r14b";
202  byte_regs[x86_64::R15] = "r15b";
203
204  std::ostringstream str;
205
206  for (auto reg : registers) {
207    for (size_t i = 0; i < 15; ++i) {
208      assembler->setcc(static_cast<x86_64::Condition>(i), *reg);
209      str << "set" << suffixes[i] << " %" << byte_regs[reg->AsRegister()] << "\n";
210    }
211  }
212
213  return str.str();
214}
215
216TEST_F(AssemblerX86_64Test, SetCC) {
217  DriverFn(&setcc_test_fn, "setcc");
218}
219
220static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
221  return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
222}
223
224static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
225  return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
226}
227
228std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) {
229  // TODO: more interesting spill registers / entry spills.
230
231  // Two random spill regs.
232  std::vector<ManagedRegister> spill_regs;
233  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
234  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
235
236  // Three random entry spills.
237  ManagedRegisterEntrySpills entry_spills;
238  ManagedRegisterSpill spill(ManagedFromCpu(x86_64::RAX), 8, 0);
239  entry_spills.push_back(spill);
240  ManagedRegisterSpill spill2(ManagedFromCpu(x86_64::RBX), 8, 8);
241  entry_spills.push_back(spill2);
242  ManagedRegisterSpill spill3(ManagedFromFpu(x86_64::XMM1), 8, 16);
243  entry_spills.push_back(spill3);
244
245  x86_64::X86_64ManagedRegister method_reg = ManagedFromCpu(x86_64::RDI);
246
247  size_t frame_size = 10 * kStackAlignment;
248  assembler->BuildFrame(10 * kStackAlignment, method_reg, spill_regs, entry_spills);
249
250  // Construct assembly text counterpart.
251  std::ostringstream str;
252  // 1) Push the spill_regs.
253  str << "pushq %rsi\n";
254  str << "pushq %r10\n";
255  // 2) Move down the stack pointer.
256  ssize_t displacement = static_cast<ssize_t>(frame_size) - (spill_regs.size() * 8 + 8);
257  str << "subq $" << displacement << ", %rsp\n";
258  // 3) Store method reference.
259  str << "movl %edi, (%rsp)\n";
260  // 4) Entry spills.
261  str << "movq %rax, " << frame_size + 0 << "(%rsp)\n";
262  str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n";
263  str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n";
264
265  return str.str();
266}
267
268TEST_F(AssemblerX86_64Test, BuildFrame) {
269  DriverFn(&buildframe_test_fn, "BuildFrame");
270}
271
272std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) {
273  // TODO: more interesting spill registers / entry spills.
274
275  // Two random spill regs.
276  std::vector<ManagedRegister> spill_regs;
277  spill_regs.push_back(ManagedFromCpu(x86_64::R10));
278  spill_regs.push_back(ManagedFromCpu(x86_64::RSI));
279
280  size_t frame_size = 10 * kStackAlignment;
281  assembler->RemoveFrame(10 * kStackAlignment, spill_regs);
282
283  // Construct assembly text counterpart.
284  std::ostringstream str;
285  // 1) Move up the stack pointer.
286  ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8;
287  str << "addq $" << displacement << ", %rsp\n";
288  // 2) Pop spill regs.
289  str << "popq %r10\n";
290  str << "popq %rsi\n";
291  str << "ret\n";
292
293  return str.str();
294}
295
296TEST_F(AssemblerX86_64Test, RemoveFrame) {
297  DriverFn(&removeframe_test_fn, "RemoveFrame");
298}
299
300std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
301  assembler->IncreaseFrameSize(0U);
302  assembler->IncreaseFrameSize(kStackAlignment);
303  assembler->IncreaseFrameSize(10 * kStackAlignment);
304
305  // Construct assembly text counterpart.
306  std::ostringstream str;
307  str << "addq $0, %rsp\n";
308  str << "addq $-" << kStackAlignment << ", %rsp\n";
309  str << "addq $-" << 10 * kStackAlignment << ", %rsp\n";
310
311  return str.str();
312}
313
314TEST_F(AssemblerX86_64Test, IncreaseFrame) {
315  DriverFn(&increaseframe_test_fn, "IncreaseFrame");
316}
317
318std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) {
319  assembler->DecreaseFrameSize(0U);
320  assembler->DecreaseFrameSize(kStackAlignment);
321  assembler->DecreaseFrameSize(10 * kStackAlignment);
322
323  // Construct assembly text counterpart.
324  std::ostringstream str;
325  str << "addq $0, %rsp\n";
326  str << "addq $" << kStackAlignment << ", %rsp\n";
327  str << "addq $" << 10 * kStackAlignment << ", %rsp\n";
328
329  return str.str();
330}
331
332TEST_F(AssemblerX86_64Test, DecreaseFrame) {
333  DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
334}
335
336}  // namespace art
337