test-assembler-x64.cc revision 85b71799222b55eb5dd74ea26efe0c64ab655c8c
1// Copyright 2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29 30#include "v8.h" 31 32#include "macro-assembler.h" 33#include "factory.h" 34#include "platform.h" 35#include "serialize.h" 36#include "cctest.h" 37 38using v8::internal::Assembler; 39using v8::internal::CodeDesc; 40using v8::internal::FUNCTION_CAST; 41using v8::internal::Immediate; 42using v8::internal::Isolate; 43using v8::internal::Label; 44using v8::internal::OS; 45using v8::internal::Operand; 46using v8::internal::byte; 47using v8::internal::greater; 48using v8::internal::less_equal; 49using v8::internal::equal; 50using v8::internal::not_equal; 51using v8::internal::r13; 52using v8::internal::r15; 53using v8::internal::r8; 54using v8::internal::r9; 55using v8::internal::rax; 56using v8::internal::rbp; 57using v8::internal::rcx; 58using v8::internal::rdi; 59using v8::internal::rdx; 60using v8::internal::rsi; 61using v8::internal::rsp; 62using v8::internal::times_1; 63 64// Test the x64 assembler by compiling some simple functions into 65// a buffer and executing them. These tests do not initialize the 66// V8 library, create a context, or use any V8 objects. 67// The AMD64 calling convention is used, with the first six arguments 68// in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in 69// the XMM registers. The return value is in RAX. 70// This calling convention is used on Linux, with GCC, and on Mac OS, 71// with GCC. A different convention is used on 64-bit windows, 72// where the first four integer arguments are passed in RCX, RDX, R8 and R9. 73 74typedef int (*F0)(); 75typedef int (*F1)(int64_t x); 76typedef int (*F2)(int64_t x, int64_t y); 77 78#ifdef _WIN64 79static const v8::internal::Register arg1 = rcx; 80static const v8::internal::Register arg2 = rdx; 81#else 82static const v8::internal::Register arg1 = rdi; 83static const v8::internal::Register arg2 = rsi; 84#endif 85 86#define __ assm. 87 88 89TEST(AssemblerX64ReturnOperation) { 90 OS::Setup(); 91 // Allocate an executable page of memory. 92 size_t actual_size; 93 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 94 &actual_size, 95 true)); 96 CHECK(buffer); 97 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 98 99 // Assemble a simple function that copies argument 2 and returns it. 100 __ movq(rax, arg2); 101 __ nop(); 102 __ ret(0); 103 104 CodeDesc desc; 105 assm.GetCode(&desc); 106 // Call the function from C++. 107 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 108 CHECK_EQ(2, result); 109} 110 111TEST(AssemblerX64StackOperations) { 112 OS::Setup(); 113 // Allocate an executable page of memory. 114 size_t actual_size; 115 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 116 &actual_size, 117 true)); 118 CHECK(buffer); 119 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 120 121 // Assemble a simple function that copies argument 2 and returns it. 122 // We compile without stack frame pointers, so the gdb debugger shows 123 // incorrect stack frames when debugging this function (which has them). 124 __ push(rbp); 125 __ movq(rbp, rsp); 126 __ push(arg2); // Value at (rbp - 8) 127 __ push(arg2); // Value at (rbp - 16) 128 __ push(arg1); // Value at (rbp - 24) 129 __ pop(rax); 130 __ pop(rax); 131 __ pop(rax); 132 __ pop(rbp); 133 __ nop(); 134 __ ret(0); 135 136 CodeDesc desc; 137 assm.GetCode(&desc); 138 // Call the function from C++. 139 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 140 CHECK_EQ(2, result); 141} 142 143TEST(AssemblerX64ArithmeticOperations) { 144 OS::Setup(); 145 // Allocate an executable page of memory. 146 size_t actual_size; 147 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 148 &actual_size, 149 true)); 150 CHECK(buffer); 151 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 152 153 // Assemble a simple function that adds arguments returning the sum. 154 __ movq(rax, arg2); 155 __ addq(rax, arg1); 156 __ ret(0); 157 158 CodeDesc desc; 159 assm.GetCode(&desc); 160 // Call the function from C++. 161 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 162 CHECK_EQ(5, result); 163} 164 165TEST(AssemblerX64ImulOperation) { 166 OS::Setup(); 167 // Allocate an executable page of memory. 168 size_t actual_size; 169 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 170 &actual_size, 171 true)); 172 CHECK(buffer); 173 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 174 175 // Assemble a simple function that multiplies arguments returning the high 176 // word. 177 __ movq(rax, arg2); 178 __ imul(arg1); 179 __ movq(rax, rdx); 180 __ ret(0); 181 182 CodeDesc desc; 183 assm.GetCode(&desc); 184 // Call the function from C++. 185 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 186 CHECK_EQ(0, result); 187 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l); 188 CHECK_EQ(1, result); 189 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l); 190 CHECK_EQ(-1, result); 191} 192 193TEST(AssemblerX64MemoryOperands) { 194 OS::Setup(); 195 // Allocate an executable page of memory. 196 size_t actual_size; 197 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 198 &actual_size, 199 true)); 200 CHECK(buffer); 201 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 202 203 // Assemble a simple function that copies argument 2 and returns it. 204 __ push(rbp); 205 __ movq(rbp, rsp); 206 207 __ push(arg2); // Value at (rbp - 8) 208 __ push(arg2); // Value at (rbp - 16) 209 __ push(arg1); // Value at (rbp - 24) 210 211 const int kStackElementSize = 8; 212 __ movq(rax, Operand(rbp, -3 * kStackElementSize)); 213 __ pop(arg2); 214 __ pop(arg2); 215 __ pop(arg2); 216 __ pop(rbp); 217 __ nop(); 218 __ ret(0); 219 220 CodeDesc desc; 221 assm.GetCode(&desc); 222 // Call the function from C++. 223 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 224 CHECK_EQ(3, result); 225} 226 227TEST(AssemblerX64ControlFlow) { 228 OS::Setup(); 229 // Allocate an executable page of memory. 230 size_t actual_size; 231 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 232 &actual_size, 233 true)); 234 CHECK(buffer); 235 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 236 237 // Assemble a simple function that copies argument 1 and returns it. 238 __ push(rbp); 239 240 __ movq(rbp, rsp); 241 __ movq(rax, arg1); 242 Label target; 243 __ jmp(&target); 244 __ movq(rax, arg2); 245 __ bind(&target); 246 __ pop(rbp); 247 __ ret(0); 248 249 CodeDesc desc; 250 assm.GetCode(&desc); 251 // Call the function from C++. 252 int result = FUNCTION_CAST<F2>(buffer)(3, 2); 253 CHECK_EQ(3, result); 254} 255 256TEST(AssemblerX64LoopImmediates) { 257 OS::Setup(); 258 // Allocate an executable page of memory. 259 size_t actual_size; 260 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 261 &actual_size, 262 true)); 263 CHECK(buffer); 264 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); 265 // Assemble two loops using rax as counter, and verify the ending counts. 266 Label Fail; 267 __ movq(rax, Immediate(-3)); 268 Label Loop1_test; 269 Label Loop1_body; 270 __ jmp(&Loop1_test); 271 __ bind(&Loop1_body); 272 __ addq(rax, Immediate(7)); 273 __ bind(&Loop1_test); 274 __ cmpq(rax, Immediate(20)); 275 __ j(less_equal, &Loop1_body); 276 // Did the loop terminate with the expected value? 277 __ cmpq(rax, Immediate(25)); 278 __ j(not_equal, &Fail); 279 280 Label Loop2_test; 281 Label Loop2_body; 282 __ movq(rax, Immediate(0x11FEED00)); 283 __ jmp(&Loop2_test); 284 __ bind(&Loop2_body); 285 __ addq(rax, Immediate(-0x1100)); 286 __ bind(&Loop2_test); 287 __ cmpq(rax, Immediate(0x11FE8000)); 288 __ j(greater, &Loop2_body); 289 // Did the loop terminate with the expected value? 290 __ cmpq(rax, Immediate(0x11FE7600)); 291 __ j(not_equal, &Fail); 292 293 __ movq(rax, Immediate(1)); 294 __ ret(0); 295 __ bind(&Fail); 296 __ movq(rax, Immediate(0)); 297 __ ret(0); 298 299 CodeDesc desc; 300 assm.GetCode(&desc); 301 // Call the function from C++. 302 int result = FUNCTION_CAST<F0>(buffer)(); 303 CHECK_EQ(1, result); 304} 305 306 307TEST(OperandRegisterDependency) { 308 int offsets[4] = {0, 1, 0xfed, 0xbeefcad}; 309 for (int i = 0; i < 4; i++) { 310 int offset = offsets[i]; 311 CHECK(Operand(rax, offset).AddressUsesRegister(rax)); 312 CHECK(!Operand(rax, offset).AddressUsesRegister(r8)); 313 CHECK(!Operand(rax, offset).AddressUsesRegister(rcx)); 314 315 CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax)); 316 CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8)); 317 CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx)); 318 319 CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax)); 320 CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx)); 321 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8)); 322 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9)); 323 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx)); 324 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp)); 325 326 CHECK(Operand(rsp, offset).AddressUsesRegister(rsp)); 327 CHECK(!Operand(rsp, offset).AddressUsesRegister(rax)); 328 CHECK(!Operand(rsp, offset).AddressUsesRegister(r15)); 329 330 CHECK(Operand(rbp, offset).AddressUsesRegister(rbp)); 331 CHECK(!Operand(rbp, offset).AddressUsesRegister(rax)); 332 CHECK(!Operand(rbp, offset).AddressUsesRegister(r13)); 333 334 CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp)); 335 CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax)); 336 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx)); 337 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13)); 338 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8)); 339 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp)); 340 341 CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp)); 342 CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp)); 343 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax)); 344 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15)); 345 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13)); 346 } 347} 348 349 350TEST(AssemblerX64LabelChaining) { 351 // Test chaining of label usages within instructions (issue 1644). 352 v8::HandleScope scope; 353 Assembler assm(Isolate::Current(), NULL, 0); 354 355 Label target; 356 __ j(equal, &target); 357 __ j(not_equal, &target); 358 __ bind(&target); 359 __ nop(); 360} 361 362#undef __ 363