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