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