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(®isters_); 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(®isters); 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