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 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, ... 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 78 TEST_F(AssemblerX86_64Test, Toolchain) { 79 EXPECT_TRUE(CheckTools()); 80 } 81 82 83 TEST_F(AssemblerX86_64Test, PushqRegs) { 84 DriverStr(RepeatR(&x86_64::X86_64Assembler::pushq, "pushq %{reg}"), "pushq"); 85 } 86 87 TEST_F(AssemblerX86_64Test, PushqImm) { 88 DriverStr(RepeatI(&x86_64::X86_64Assembler::pushq, 4U, "pushq ${imm}"), "pushqi"); 89 } 90 91 92 TEST_F(AssemblerX86_64Test, MovqRegs) { 93 DriverStr(RepeatRR(&x86_64::X86_64Assembler::movq, "movq %{reg2}, %{reg1}"), "movq"); 94 } 95 96 TEST_F(AssemblerX86_64Test, MovqImm) { 97 DriverStr(RepeatRI(&x86_64::X86_64Assembler::movq, 8U, "movq ${imm}, %{reg}"), "movqi"); 98 } 99 100 101 TEST_F(AssemblerX86_64Test, AddqRegs) { 102 DriverStr(RepeatRR(&x86_64::X86_64Assembler::addq, "addq %{reg2}, %{reg1}"), "addq"); 103 } 104 105 TEST_F(AssemblerX86_64Test, AddqImm) { 106 DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi"); 107 } 108 109 110 TEST_F(AssemblerX86_64Test, SubqRegs) { 111 DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq"); 112 } 113 114 TEST_F(AssemblerX86_64Test, SubqImm) { 115 DriverStr(RepeatRI(&x86_64::X86_64Assembler::subq, 4U, "subq ${imm}, %{reg}"), "subqi"); 116 } 117 118 119 TEST_F(AssemblerX86_64Test, CmpqRegs) { 120 DriverStr(RepeatRR(&x86_64::X86_64Assembler::cmpq, "cmpq %{reg2}, %{reg1}"), "cmpq"); 121 } 122 123 124 TEST_F(AssemblerX86_64Test, XorqImm) { 125 DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi"); 126 } 127 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 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 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 225 TEST_F(AssemblerX86_64Test, SetCC) { 226 DriverFn(&setcc_test_fn, "setcc"); 227 } 228 229 static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) { 230 return x86_64::X86_64ManagedRegister::FromCpuRegister(r); 231 } 232 233 static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) { 234 return x86_64::X86_64ManagedRegister::FromXmmRegister(r); 235 } 236 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 277 TEST_F(AssemblerX86_64Test, BuildFrame) { 278 DriverFn(&buildframe_test_fn, "BuildFrame"); 279 } 280 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 305 TEST_F(AssemblerX86_64Test, RemoveFrame) { 306 DriverFn(&removeframe_test_fn, "RemoveFrame"); 307 } 308 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 323 TEST_F(AssemblerX86_64Test, IncreaseFrame) { 324 DriverFn(&increaseframe_test_fn, "IncreaseFrame"); 325 } 326 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 341 TEST_F(AssemblerX86_64Test, DecreaseFrame) { 342 DriverFn(&decreaseframe_test_fn, "DecreaseFrame"); 343 } 344 345 } // namespace art 346