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 
TEST(AssemblerX86_64,CreateBuffer)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, ...
GetArchitectureString()36   std::string GetArchitectureString() OVERRIDE {
37     return "x86_64";
38   }
39 
GetDisassembleParameters()40   std::string GetDisassembleParameters() OVERRIDE {
41     return " -D -bbinary -mi386:x86-64 -Mx86-64,addr64,data32 --no-show-raw-insn";
42   }
43 
SetUpHelpers()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 
GetRegisters()65   std::vector<x86_64::CpuRegister*> GetRegisters() OVERRIDE {
66     return registers_;
67   }
68 
CreateImmediate(int64_t imm_value)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 
TEST_F(AssemblerX86_64Test,Toolchain)78 TEST_F(AssemblerX86_64Test, Toolchain) {
79   EXPECT_TRUE(CheckTools());
80 }
81 
82 
TEST_F(AssemblerX86_64Test,PushqRegs)83 TEST_F(AssemblerX86_64Test, PushqRegs) {
84   DriverStr(RepeatR(&x86_64::X86_64Assembler::pushq, "pushq %{reg}"), "pushq");
85 }
86 
TEST_F(AssemblerX86_64Test,PushqImm)87 TEST_F(AssemblerX86_64Test, PushqImm) {
88   DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi");
89 }
90 
91 
TEST_F(AssemblerX86_64Test,MovqRegs)92 TEST_F(AssemblerX86_64Test, MovqRegs) {
93   DriverStr(RepeatRR(&x86_64::X86_64Assembler::movq, "movq %{reg2}, %{reg1}"), "movq");
94 }
95 
TEST_F(AssemblerX86_64Test,MovqImm)96 TEST_F(AssemblerX86_64Test, MovqImm) {
97   DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi");
98 }
99 
100 
TEST_F(AssemblerX86_64Test,AddqRegs)101 TEST_F(AssemblerX86_64Test, AddqRegs) {
102   DriverStr(RepeatRR(&x86_64::X86_64Assembler::addq, "addq %{reg2}, %{reg1}"), "addq");
103 }
104 
TEST_F(AssemblerX86_64Test,AddqImm)105 TEST_F(AssemblerX86_64Test, AddqImm) {
106   DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
107 }
108 
109 
TEST_F(AssemblerX86_64Test,SubqRegs)110 TEST_F(AssemblerX86_64Test, SubqRegs) {
111   DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq");
112 }
113 
TEST_F(AssemblerX86_64Test,SubqImm)114 TEST_F(AssemblerX86_64Test, SubqImm) {
115   DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi");
116 }
117 
118 
TEST_F(AssemblerX86_64Test,CmpqRegs)119 TEST_F(AssemblerX86_64Test, CmpqRegs) {
120   DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq");
121 }
122 
123 
TEST_F(AssemblerX86_64Test,XorqImm)124 TEST_F(AssemblerX86_64Test, XorqImm) {
125   DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
126 }
127 
TEST_F(AssemblerX86_64Test,Movl)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 
TEST_F(AssemblerX86_64Test,Movw)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 
setcc_test_fn(x86_64::X86_64Assembler * assembler)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 
TEST_F(AssemblerX86_64Test,SetCC)225 TEST_F(AssemblerX86_64Test, SetCC) {
226   DriverFn(&setcc_test_fn, "setcc");
227 }
228 
ManagedFromCpu(x86_64::Register r)229 static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) {
230   return x86_64::X86_64ManagedRegister::FromCpuRegister(r);
231 }
232 
ManagedFromFpu(x86_64::FloatRegister r)233 static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) {
234   return x86_64::X86_64ManagedRegister::FromXmmRegister(r);
235 }
236 
buildframe_test_fn(x86_64::X86_64Assembler * assembler)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 
TEST_F(AssemblerX86_64Test,BuildFrame)277 TEST_F(AssemblerX86_64Test, BuildFrame) {
278   DriverFn(&buildframe_test_fn, "BuildFrame");
279 }
280 
removeframe_test_fn(x86_64::X86_64Assembler * assembler)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 
TEST_F(AssemblerX86_64Test,RemoveFrame)305 TEST_F(AssemblerX86_64Test, RemoveFrame) {
306   DriverFn(&removeframe_test_fn, "RemoveFrame");
307 }
308 
increaseframe_test_fn(x86_64::X86_64Assembler * assembler)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 
TEST_F(AssemblerX86_64Test,IncreaseFrame)323 TEST_F(AssemblerX86_64Test, IncreaseFrame) {
324   DriverFn(&increaseframe_test_fn, "IncreaseFrame");
325 }
326 
decreaseframe_test_fn(x86_64::X86_64Assembler * assembler)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 
TEST_F(AssemblerX86_64Test,DecreaseFrame)341 TEST_F(AssemblerX86_64Test, DecreaseFrame) {
342   DriverFn(&decreaseframe_test_fn, "DecreaseFrame");
343 }
344 
345 }  // namespace art
346